Mercurial > hg > isophonics-drupal-site
comparison vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 /* | |
3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
14 * | |
15 * This software consists of voluntary contributions made by many individuals | |
16 * and is licensed under the MIT license. For more information, see | |
17 * <http://www.doctrine-project.org>. | |
18 */ | |
19 | |
20 namespace Doctrine\Common\Cache; | |
21 | |
22 use Riak\Bucket; | |
23 use Riak\Connection; | |
24 use Riak\Input; | |
25 use Riak\Exception; | |
26 use Riak\Object; | |
27 | |
28 /** | |
29 * Riak cache provider. | |
30 * | |
31 * @link www.doctrine-project.org | |
32 * @since 1.1 | |
33 * @author Guilherme Blanco <guilhermeblanco@hotmail.com> | |
34 */ | |
35 class RiakCache extends CacheProvider | |
36 { | |
37 const EXPIRES_HEADER = 'X-Riak-Meta-Expires'; | |
38 | |
39 /** | |
40 * @var \Riak\Bucket | |
41 */ | |
42 private $bucket; | |
43 | |
44 /** | |
45 * Sets the riak bucket instance to use. | |
46 * | |
47 * @param \Riak\Bucket $bucket | |
48 */ | |
49 public function __construct(Bucket $bucket) | |
50 { | |
51 $this->bucket = $bucket; | |
52 } | |
53 | |
54 /** | |
55 * {@inheritdoc} | |
56 */ | |
57 protected function doFetch($id) | |
58 { | |
59 try { | |
60 $response = $this->bucket->get($id); | |
61 | |
62 // No objects found | |
63 if ( ! $response->hasObject()) { | |
64 return false; | |
65 } | |
66 | |
67 // Check for attempted siblings | |
68 $object = ($response->hasSiblings()) | |
69 ? $this->resolveConflict($id, $response->getVClock(), $response->getObjectList()) | |
70 : $response->getFirstObject(); | |
71 | |
72 // Check for expired object | |
73 if ($this->isExpired($object)) { | |
74 $this->bucket->delete($object); | |
75 | |
76 return false; | |
77 } | |
78 | |
79 return unserialize($object->getContent()); | |
80 } catch (Exception\RiakException $e) { | |
81 // Covers: | |
82 // - Riak\ConnectionException | |
83 // - Riak\CommunicationException | |
84 // - Riak\UnexpectedResponseException | |
85 // - Riak\NotFoundException | |
86 } | |
87 | |
88 return false; | |
89 } | |
90 | |
91 /** | |
92 * {@inheritdoc} | |
93 */ | |
94 protected function doContains($id) | |
95 { | |
96 try { | |
97 // We only need the HEAD, not the entire object | |
98 $input = new Input\GetInput(); | |
99 | |
100 $input->setReturnHead(true); | |
101 | |
102 $response = $this->bucket->get($id, $input); | |
103 | |
104 // No objects found | |
105 if ( ! $response->hasObject()) { | |
106 return false; | |
107 } | |
108 | |
109 $object = $response->getFirstObject(); | |
110 | |
111 // Check for expired object | |
112 if ($this->isExpired($object)) { | |
113 $this->bucket->delete($object); | |
114 | |
115 return false; | |
116 } | |
117 | |
118 return true; | |
119 } catch (Exception\RiakException $e) { | |
120 // Do nothing | |
121 } | |
122 | |
123 return false; | |
124 } | |
125 | |
126 /** | |
127 * {@inheritdoc} | |
128 */ | |
129 protected function doSave($id, $data, $lifeTime = 0) | |
130 { | |
131 try { | |
132 $object = new Object($id); | |
133 | |
134 $object->setContent(serialize($data)); | |
135 | |
136 if ($lifeTime > 0) { | |
137 $object->addMetadata(self::EXPIRES_HEADER, (string) (time() + $lifeTime)); | |
138 } | |
139 | |
140 $this->bucket->put($object); | |
141 | |
142 return true; | |
143 } catch (Exception\RiakException $e) { | |
144 // Do nothing | |
145 } | |
146 | |
147 return false; | |
148 } | |
149 | |
150 /** | |
151 * {@inheritdoc} | |
152 */ | |
153 protected function doDelete($id) | |
154 { | |
155 try { | |
156 $this->bucket->delete($id); | |
157 | |
158 return true; | |
159 } catch (Exception\BadArgumentsException $e) { | |
160 // Key did not exist on cluster already | |
161 } catch (Exception\RiakException $e) { | |
162 // Covers: | |
163 // - Riak\Exception\ConnectionException | |
164 // - Riak\Exception\CommunicationException | |
165 // - Riak\Exception\UnexpectedResponseException | |
166 } | |
167 | |
168 return false; | |
169 } | |
170 | |
171 /** | |
172 * {@inheritdoc} | |
173 */ | |
174 protected function doFlush() | |
175 { | |
176 try { | |
177 $keyList = $this->bucket->getKeyList(); | |
178 | |
179 foreach ($keyList as $key) { | |
180 $this->bucket->delete($key); | |
181 } | |
182 | |
183 return true; | |
184 } catch (Exception\RiakException $e) { | |
185 // Do nothing | |
186 } | |
187 | |
188 return false; | |
189 } | |
190 | |
191 /** | |
192 * {@inheritdoc} | |
193 */ | |
194 protected function doGetStats() | |
195 { | |
196 // Only exposed through HTTP stats API, not Protocol Buffers API | |
197 return null; | |
198 } | |
199 | |
200 /** | |
201 * Check if a given Riak Object have expired. | |
202 * | |
203 * @param \Riak\Object $object | |
204 * | |
205 * @return bool | |
206 */ | |
207 private function isExpired(Object $object) | |
208 { | |
209 $metadataMap = $object->getMetadataMap(); | |
210 | |
211 return isset($metadataMap[self::EXPIRES_HEADER]) | |
212 && $metadataMap[self::EXPIRES_HEADER] < time(); | |
213 } | |
214 | |
215 /** | |
216 * On-read conflict resolution. Applied approach here is last write wins. | |
217 * Specific needs may override this method to apply alternate conflict resolutions. | |
218 * | |
219 * {@internal Riak does not attempt to resolve a write conflict, and store | |
220 * it as sibling of conflicted one. By following this approach, it is up to | |
221 * the next read to resolve the conflict. When this happens, your fetched | |
222 * object will have a list of siblings (read as a list of objects). | |
223 * In our specific case, we do not care about the intermediate ones since | |
224 * they are all the same read from storage, and we do apply a last sibling | |
225 * (last write) wins logic. | |
226 * If by any means our resolution generates another conflict, it'll up to | |
227 * next read to properly solve it.} | |
228 * | |
229 * @param string $id | |
230 * @param string $vClock | |
231 * @param array $objectList | |
232 * | |
233 * @return \Riak\Object | |
234 */ | |
235 protected function resolveConflict($id, $vClock, array $objectList) | |
236 { | |
237 // Our approach here is last-write wins | |
238 $winner = $objectList[count($objectList)]; | |
239 | |
240 $putInput = new Input\PutInput(); | |
241 $putInput->setVClock($vClock); | |
242 | |
243 $mergedObject = new Object($id); | |
244 $mergedObject->setContent($winner->getContent()); | |
245 | |
246 $this->bucket->put($mergedObject, $putInput); | |
247 | |
248 return $mergedObject; | |
249 } | |
250 } |