1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20:
21: class NMemcachedStorage extends NObject implements ICacheStorage
22: {
23:
24: const META_CALLBACKS = 'callbacks',
25: META_DATA = 'data',
26: META_DELTA = 'delta';
27:
28:
29: private $memcache;
30:
31:
32: private $prefix;
33:
34:
35: private $journal;
36:
37:
38:
39: 40: 41: 42:
43: public static function isAvailable()
44: {
45: return extension_loaded('memcache');
46: }
47:
48:
49:
50: public function __construct($host = 'localhost', $port = 11211, $prefix = '', ICacheJournal $journal = NULL)
51: {
52: if (!self::isAvailable()) {
53: throw new NotSupportedException("PHP extension 'memcache' is not loaded.");
54: }
55:
56: $this->prefix = $prefix;
57: $this->journal = $journal;
58: $this->memcache = new Memcache;
59: if ($host) {
60: $this->addServer($host, $port);
61: }
62: }
63:
64:
65:
66: public function addServer($host = 'localhost', $port = 11211, $timeout = 1)
67: {
68: NDebugger::tryError();
69: $this->memcache->addServer($host, $port, TRUE, 1, $timeout);
70: if (NDebugger::catchError($e)) {
71: throw new InvalidStateException('Memcache::addServer(): ' . $e->getMessage(), 0, $e);
72: }
73: }
74:
75:
76:
77: 78: 79:
80: public function getConnection()
81: {
82: return $this->memcache;
83: }
84:
85:
86:
87: 88: 89: 90: 91:
92: public function read($key)
93: {
94: $key = $this->prefix . $key;
95: $meta = $this->memcache->get($key);
96: if (!$meta) {
97: return NULL;
98: }
99:
100:
101:
102:
103:
104:
105:
106:
107:
108: if (!empty($meta[self::META_CALLBACKS]) && !NCache::checkCallbacks($meta[self::META_CALLBACKS])) {
109: $this->memcache->delete($key, 0);
110: return NULL;
111: }
112:
113: if (!empty($meta[self::META_DELTA])) {
114: $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time());
115: }
116:
117: return $meta[self::META_DATA];
118: }
119:
120:
121:
122: 123: 124: 125: 126:
127: public function lock($key)
128: {
129: }
130:
131:
132:
133: 134: 135: 136: 137: 138: 139:
140: public function write($key, $data, array $dp)
141: {
142: if (isset($dp[NCache::ITEMS])) {
143: throw new NotSupportedException('Dependent items are not supported by MemcachedStorage.');
144: }
145:
146: $key = $this->prefix . $key;
147: $meta = array(
148: self::META_DATA => $data,
149: );
150:
151: $expire = 0;
152: if (isset($dp[NCache::EXPIRATION])) {
153: $expire = (int) $dp[NCache::EXPIRATION];
154: if (!empty($dp[NCache::SLIDING])) {
155: $meta[self::META_DELTA] = $expire;
156: }
157: }
158:
159: if (isset($dp[NCache::CALLBACKS])) {
160: $meta[self::META_CALLBACKS] = $dp[NCache::CALLBACKS];
161: }
162:
163: if (isset($dp[NCache::TAGS]) || isset($dp[NCache::PRIORITY])) {
164: if (!$this->journal) {
165: throw new InvalidStateException('CacheJournal has not been provided.');
166: }
167: $this->journal->write($key, $dp);
168: }
169:
170: $this->memcache->set($key, $meta, 0, $expire);
171: }
172:
173:
174:
175: 176: 177: 178: 179:
180: public function remove($key)
181: {
182: $this->memcache->delete($this->prefix . $key, 0);
183: }
184:
185:
186:
187: 188: 189: 190: 191:
192: public function clean(array $conds)
193: {
194: if (!empty($conds[NCache::ALL])) {
195: $this->memcache->flush();
196:
197: } elseif ($this->journal) {
198: foreach ($this->journal->clean($conds) as $entry) {
199: $this->memcache->delete($entry, 0);
200: }
201: }
202: }
203:
204: }
205: