Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commiteda0753

Browse files
author
André R
committed
[Cache] Add optimized FileSystem & Redis TagAware Adapters
Reduces cache lookups by 50% by changing logic of how tag information isstored to avoid having to look it up on getItem(s) calls.For Filesystem symlinks are used, for Redis "Set" datatype is used.
1 parent3895acd commiteda0753

File tree

3 files changed

+558
-0
lines changed

3 files changed

+558
-0
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespaceSymfony\Component\Cache\Adapter\TagAware;
15+
16+
usePsr\Cache\CacheItemInterface;
17+
usePsr\Log\LoggerAwareInterface;
18+
useSymfony\Component\Cache\Adapter\AdapterInterface;
19+
useSymfony\Component\Cache\CacheItem;
20+
useSymfony\Component\Cache\Exception\InvalidArgumentException;
21+
useSymfony\Component\Cache\ResettableInterface;
22+
useSymfony\Component\Cache\Traits\AbstractTrait;
23+
useSymfony\Component\Cache\Traits\ContractsTrait;
24+
useSymfony\Contracts\Cache\CacheInterface;
25+
26+
/**
27+
* @author Nicolas Grekas <p@tchwork.com>
28+
*/
29+
abstractclass AbstractTagAwareAdapterimplements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
30+
{
31+
use AbstractTrait { getIdasprotected; }
32+
use ContractsTrait;
33+
34+
protectedconstTAGS_PREFIX ="\0tags\0";
35+
36+
private$createCacheItem;
37+
private$mergeByLifetime;
38+
39+
protectedfunction__construct(string$namespace ='',int$defaultLifetime =0)
40+
{
41+
$this->namespace ='' ===$namespace ?'' : CacheItem::validateKey($namespace).':';
42+
if (null !==$this->maxIdLength &&\strlen($namespace) >$this->maxIdLength -24) {
43+
thrownewInvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")',$this->maxIdLength -24,\strlen($namespace),$namespace));
44+
}
45+
$this->createCacheItem = \Closure::bind(
46+
function ($key,$value,$isHit)use ($defaultLifetime) {
47+
$item =newCacheItem();
48+
$item->key =$key;
49+
$item->isHit =$isHit;
50+
$item->defaultLifetime =$defaultLifetime;
51+
//<diff:AbstractAdapter> extract Value and Tags from the cache value
52+
$item->value =$v =$value['value'];
53+
$item->metadata[CacheItem::METADATA_TAGS] =$value['tags'] ?? [];
54+
// Detect wrapped values that encode for their expiry and creation duration
55+
// For compactness, these values are packed
56+
if (isset($value['meta'])) {
57+
$v =\unpack('Ve/Nc',$value['meta']);
58+
$item->metadata[CacheItem::METADATA_EXPIRY] =$v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
59+
$item->metadata[CacheItem::METADATA_CTIME] =$v['c'];
60+
}
61+
//</diff:AbstractAdapter>
62+
63+
return$item;
64+
},
65+
null,
66+
CacheItem::class
67+
);
68+
$getId = \Closure::fromCallable([$this,'getId']);
69+
$this->mergeByLifetime = \Closure::bind(
70+
function ($deferred,$namespace, &$expiredIds)use ($getId) {
71+
$byLifetime = [];
72+
$now =microtime(true);
73+
$expiredIds = [];
74+
75+
foreach ($deferredas$key =>$item) {
76+
$key = (string)$key;
77+
if (null ===$item->expiry) {
78+
$ttl =0 <$item->defaultLifetime ?$item->defaultLifetime :0;
79+
}elseif (0 >=$ttl = (int) ($item->expiry -$now)) {
80+
$expiredIds[] =$getId($key);
81+
continue;
82+
}
83+
//<diff:AbstractAdapter> store Value and Tags on the cache value
84+
if (isset(($metadata =$item->newMetadata)[CacheItem::METADATA_TAGS])) {
85+
$value = ['value' =>$item->value,'tags' =>$metadata[CacheItem::METADATA_TAGS]];
86+
unset($metadata[CacheItem::METADATA_TAGS]);
87+
}else {
88+
$value = ['value' =>$item->value,'tags' => []];
89+
}
90+
91+
if ($metadata) {
92+
// For compactness, expiry and creation duration are packed, using magic numbers as separators
93+
$value['meta'] =pack('VN', (int)$metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET,$metadata[CacheItem::METADATA_CTIME]);
94+
}
95+
$byLifetime[$ttl][$getId($key)] =$value;
96+
//</diff:AbstractAdapter>
97+
}
98+
99+
return$byLifetime;
100+
},
101+
null,
102+
CacheItem::class
103+
);
104+
}
105+
106+
/**
107+
* {@inheritdoc}
108+
*/
109+
publicfunctiongetItem($key)
110+
{
111+
if ($this->deferred) {
112+
$this->commit();
113+
}
114+
$id =$this->getId($key);
115+
116+
$f =$this->createCacheItem;
117+
$isHit =false;
118+
$value =null;
119+
120+
try {
121+
foreach ($this->doFetch([$id])as$value) {
122+
$isHit =true;
123+
}
124+
}catch (\Exception$e) {
125+
CacheItem::log($this->logger,'Failed to fetch key "{key}"', ['key' =>$key,'exception' =>$e]);
126+
}
127+
128+
return$f($key,$value,$isHit);
129+
}
130+
131+
/**
132+
* {@inheritdoc}
133+
*/
134+
publicfunctiongetItems(array$keys = [])
135+
{
136+
if ($this->deferred) {
137+
$this->commit();
138+
}
139+
$ids = [];
140+
141+
foreach ($keysas$key) {
142+
$ids[] =$this->getId($key);
143+
}
144+
try {
145+
$items =$this->doFetch($ids);
146+
}catch (\Exception$e) {
147+
CacheItem::log($this->logger,'Failed to fetch requested items', ['keys' =>$keys,'exception' =>$e]);
148+
$items = [];
149+
}
150+
$ids =array_combine($ids,$keys);
151+
152+
return$this->generateItems($items,$ids);
153+
}
154+
155+
/**
156+
* {@inheritdoc}
157+
*/
158+
publicfunctionsave(CacheItemInterface$item)
159+
{
160+
if (!$iteminstanceof CacheItem) {
161+
returnfalse;
162+
}
163+
$this->deferred[$item->getKey()] =$item;
164+
165+
return$this->commit();
166+
}
167+
168+
/**
169+
* {@inheritdoc}
170+
*/
171+
publicfunctionsaveDeferred(CacheItemInterface$item)
172+
{
173+
if (!$iteminstanceof CacheItem) {
174+
returnfalse;
175+
}
176+
$this->deferred[$item->getKey()] =$item;
177+
178+
returntrue;
179+
}
180+
181+
/**
182+
* {@inheritdoc}
183+
*/
184+
publicfunctioncommit()
185+
{
186+
$ok =true;
187+
$byLifetime =$this->mergeByLifetime;
188+
$byLifetime =$byLifetime($this->deferred,$this->namespace,$expiredIds);
189+
$retry =$this->deferred = [];
190+
191+
if ($expiredIds) {
192+
$this->doDelete($expiredIds);
193+
}
194+
foreach ($byLifetimeas$lifetime =>$values) {
195+
try {
196+
$e =$this->doSave($values,$lifetime);
197+
}catch (\Exception$e) {
198+
}
199+
if (true ===$e || [] ===$e) {
200+
continue;
201+
}
202+
if (\is_array($e) ||1 ===\count($values)) {
203+
foreach (\is_array($e) ?$e :array_keys($values)as$id) {
204+
$ok =false;
205+
$v =$values[$id];
206+
$type =\is_object($v) ?\get_class($v) :\gettype($v);
207+
CacheItem::log($this->logger,'Failed to save key "{key}" ({type})', ['key' =>substr($id,\strlen($this->namespace)),'type' =>$type,'exception' =>$einstanceof \Exception ?$e :null]);
208+
}
209+
}else {
210+
foreach ($valuesas$id =>$v) {
211+
$retry[$lifetime][] =$id;
212+
}
213+
}
214+
}
215+
216+
// When bulk-save failed, retry each item individually
217+
foreach ($retryas$lifetime =>$ids) {
218+
foreach ($idsas$id) {
219+
try {
220+
$v =$byLifetime[$lifetime][$id];
221+
$e =$this->doSave([$id =>$v],$lifetime);
222+
}catch (\Exception$e) {
223+
}
224+
if (true ===$e || [] ===$e) {
225+
continue;
226+
}
227+
$ok =false;
228+
$type =\is_object($v) ?\get_class($v) :\gettype($v);
229+
CacheItem::log($this->logger,'Failed to save key "{key}" ({type})', ['key' =>substr($id,\strlen($this->namespace)),'type' =>$type,'exception' =>$einstanceof \Exception ?$e :null]);
230+
}
231+
}
232+
233+
return$ok;
234+
}
235+
236+
publicfunction__destruct()
237+
{
238+
if ($this->deferred) {
239+
$this->commit();
240+
}
241+
}
242+
243+
privatefunctiongenerateItems($items, &$keys)
244+
{
245+
$f =$this->createCacheItem;
246+
247+
try {
248+
foreach ($itemsas$id =>$value) {
249+
if (!isset($keys[$id])) {
250+
$id =key($keys);
251+
}
252+
$key =$keys[$id];
253+
unset($keys[$id]);
254+
yield$key =>$f($key,$value,true);
255+
}
256+
}catch (\Exception$e) {
257+
CacheItem::log($this->logger,'Failed to fetch requested items', ['keys' =>array_values($keys),'exception' =>$e]);
258+
}
259+
260+
foreach ($keysas$key) {
261+
yield$key =>$f($key,null,false);
262+
}
263+
}
264+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp