Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
25 - 1
<?php
2
/*
3
 * Copyright 2008 Google Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
 
18
/**
19
 * A persistent storage class based on the memcache, which is not
20
 * really very persistent, as soon as you restart your memcache daemon
21
 * the storage will be wiped, however for debugging and/or speed
22
 * it can be useful, kinda, and cache is a lot cheaper then storage.
23
 *
24
 * @author Chris Chabot <chabotc@google.com>
25
 */
26
class Google_MemcacheCache extends Google_Cache {
27
  private $connection = false;
28
 
29
  public function __construct() {
30
    global $apiConfig;
31
    if (! function_exists('memcache_connect')) {
32
      throw new Google_CacheException("Memcache functions not available");
33
    }
34
    $this->host = $apiConfig['ioMemCacheCache_host'];
35
    $this->port = $apiConfig['ioMemCacheCache_port'];
36
    if (empty($this->host) || empty($this->port)) {
37
      throw new Google_CacheException("You need to supply a valid memcache host and port");
38
    }
39
  }
40
 
41
  private function isLocked($key) {
42
    $this->check();
43
    if ((@memcache_get($this->connection, $key . '.lock')) === false) {
44
      return false;
45
    }
46
    return true;
47
  }
48
 
49
  private function createLock($key) {
50
    $this->check();
51
    // the interesting thing is that this could fail if the lock was created in the meantime..
52
    // but we'll ignore that out of convenience
53
    @memcache_add($this->connection, $key . '.lock', '', 0, 5);
54
  }
55
 
56
  private function removeLock($key) {
57
    $this->check();
58
    // suppress all warnings, if some other process removed it that's ok too
59
    @memcache_delete($this->connection, $key . '.lock');
60
  }
61
 
62
  private function waitForLock($key) {
63
    $this->check();
64
    // 20 x 250 = 5 seconds
65
    $tries = 20;
66
    $cnt = 0;
67
    do {
68
      // 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
69
      usleep(250);
70
      $cnt ++;
71
    } while ($cnt <= $tries && $this->isLocked($key));
72
    if ($this->isLocked($key)) {
73
      // 5 seconds passed, assume the owning process died off and remove it
74
      $this->removeLock($key);
75
    }
76
  }
77
 
78
  // I prefer lazy initialization since the cache isn't used every request
79
  // so this potentially saves a lot of overhead
80
  private function connect() {
81
    if (! $this->connection = @memcache_pconnect($this->host, $this->port)) {
82
      throw new Google_CacheException("Couldn't connect to memcache server");
83
    }
84
  }
85
 
86
  private function check() {
87
    if (! $this->connection) {
88
      $this->connect();
89
    }
90
  }
91
 
92
  /**
93
   * @inheritDoc
94
   */
95
  public function get($key, $expiration = false) {
96
    $this->check();
97
    if (($ret = @memcache_get($this->connection, $key)) === false) {
98
      return false;
99
    }
100
    if (! $expiration || (time() - $ret['time'] > $expiration)) {
101
      $this->delete($key);
102
      return false;
103
    }
104
    return $ret['data'];
105
  }
106
 
107
  /**
108
   * @inheritDoc
109
   * @param string $key
110
   * @param string $value
111
   * @throws Google_CacheException
112
   */
113
  public function set($key, $value) {
114
    $this->check();
115
    // we store it with the cache_time default expiration so objects will at least get cleaned eventually.
116
    if (@memcache_set($this->connection, $key, array('time' => time(),
117
        'data' => $value), false) == false) {
118
      throw new Google_CacheException("Couldn't store data in cache");
119
    }
120
  }
121
 
122
  /**
123
   * @inheritDoc
124
   * @param String $key
125
   */
126
  public function delete($key) {
127
    $this->check();
128
    @memcache_delete($this->connection, $key);
129
  }
130
}