@@ -33,11 +33,14 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R
3333 private $ getTagsByKey ;
3434 private $ invalidateTags ;
3535 private $ tags ;
36+ private $ knownTagVersions = array ();
37+ private $ knownTagVersionsTtl ;
3638
37- public function __construct (AdapterInterface $ itemsPool , AdapterInterface $ tagsPool = null )
39+ public function __construct (AdapterInterface $ itemsPool , AdapterInterface $ tagsPool = null , $ knownTagVersionsTtl = 0.15 )
3840 {
3941 $ this ->pool = $ itemsPool ;
4042 $ this ->tags = $ tagsPool ?: $ itemsPool ;
43+ $ this ->knownTagVersionsTtl = $ knownTagVersionsTtl ;
4144 $ this ->createCacheItem = \Closure ::bind (
4245 function ($ key , $ value , CacheItem $ protoItem ) {
4346 $ item = new CacheItem ();
@@ -87,8 +90,7 @@ function ($deferred) {
8790 );
8891 $ this ->invalidateTags = \Closure ::bind (
8992 function (AdapterInterface $ tagsAdapter , array $ tags ) {
90- foreach ($ tagsAdapter ->getItems ($ tags ) as $ v ) {
91- $ v ->set (1 + (int ) $ v ->get ());
93+ foreach ($ tags as $ v ) {
9294 $ v ->defaultLifetime = 0 ;
9395 $ v ->expiry = null ;
9496 $ tagsAdapter ->saveDeferred ($ v );
@@ -106,14 +108,42 @@ function (AdapterInterface $tagsAdapter, array $tags) {
106108 */
107109 public function invalidateTags (array $ tags )
108110 {
109- foreach ($ tags as $ k => $ tag ) {
110- if ('' !== $ tag && \is_string ($ tag )) {
111- $ tags [$ k ] = $ tag .static ::TAGS_PREFIX ;
111+ $ ok = true ;
112+ $ tagsByKey = array ();
113+ $ invalidatedTags = array ();
114+ foreach ($ tags as $ tag ) {
115+ CacheItem ::validateKey ($ tag );
116+ $ invalidatedTags [$ tag ] = 0 ;
117+ }
118+
119+ if ($ this ->deferred ) {
120+ $ items = $ this ->deferred ;
121+ foreach ($ items as $ key => $ item ) {
122+ if (!$ this ->pool ->saveDeferred ($ item )) {
123+ unset($ this ->deferred [$ key ]);
124+ $ ok = false ;
125+ }
112126 }
127+
128+ $ f = $ this ->getTagsByKey ;
129+ $ tagsByKey = $ f ($ items );
130+ $ this ->deferred = array ();
131+ }
132+
133+ $ tagVersions = $ this ->getTagVersions ($ tagsByKey , $ invalidatedTags );
134+ $ f = $ this ->createCacheItem ;
135+
136+ foreach ($ tagsByKey as $ key => $ tags ) {
137+ $ this ->pool ->saveDeferred ($ f (static ::TAGS_PREFIX .$ key , array_intersect_key ($ tagVersions , $ tags ), $ items [$ key ]));
138+ }
139+ $ ok = $ this ->pool ->commit () && $ ok ;
140+
141+ if ($ invalidatedTags ) {
142+ $ f = $ this ->invalidateTags ;
143+ $ ok = $ f ($ this ->tags , $ invalidatedTags ) && $ ok ;
113144 }
114- $ f = $ this ->invalidateTags ;
115145
116- return $ f ( $ this -> tags , $ tags ) ;
146+ return $ ok ;
117147 }
118148
119149 /**
@@ -132,7 +162,7 @@ public function hasItem($key)
132162 }
133163
134164 foreach ($ this ->getTagVersions (array ($ itemTags )) as $ tag => $ version ) {
135- if ($ itemTags [$ tag ] !== $ version ) {
165+ if ($ itemTags [$ tag ] !== $ version && 1 !== $ itemTags [ $ tag ] - $ version ) {
136166 return false ;
137167 }
138168 }
@@ -241,29 +271,7 @@ public function saveDeferred(CacheItemInterface $item)
241271 */
242272 public function commit ()
243273 {
244- $ ok = true ;
245-
246- if ($ this ->deferred ) {
247- $ items = $ this ->deferred ;
248- foreach ($ items as $ key => $ item ) {
249- if (!$ this ->pool ->saveDeferred ($ item )) {
250- unset($ this ->deferred [$ key ]);
251- $ ok = false ;
252- }
253- }
254-
255- $ f = $ this ->getTagsByKey ;
256- $ tagsByKey = $ f ($ items );
257- $ this ->deferred = array ();
258- $ tagVersions = $ this ->getTagVersions ($ tagsByKey );
259- $ f = $ this ->createCacheItem ;
260-
261- foreach ($ tagsByKey as $ key => $ tags ) {
262- $ this ->pool ->saveDeferred ($ f (static ::TAGS_PREFIX .$ key , array_intersect_key ($ tagVersions , $ tags ), $ items [$ key ]));
263- }
264- }
265-
266- return $ this ->pool ->commit () && $ ok ;
274+ return $ this ->invalidateTags (array ());
267275 }
268276
269277 public function __destruct ()
@@ -294,7 +302,7 @@ private function generateItems($items, array $tagKeys)
294302
295303 foreach ($ itemTags as $ key => $ tags ) {
296304 foreach ($ tags as $ tag => $ version ) {
297- if ($ tagVersions [$ tag ] !== $ version ) {
305+ if ($ tagVersions [$ tag ] !== $ version && 1 !== $ version - $ tagVersions [ $ tag ] ) {
298306 unset($ itemTags [$ key ]);
299307 continue 2 ;
300308 }
@@ -310,23 +318,54 @@ private function generateItems($items, array $tagKeys)
310318 }
311319 }
312320
313- private function getTagVersions (array $ tagsByKey )
321+ private function getTagVersions (array $ tagsByKey, array & $ invalidatedTags = array () )
314322 {
315- $ tagVersions = array () ;
323+ $ tagVersions = $ invalidatedTags ;
316324
317325 foreach ($ tagsByKey as $ tags ) {
318326 $ tagVersions += $ tags ;
319327 }
320328
321- if ($ tagVersions ) {
322- $ tags = array ();
323- foreach ($ tagVersions as $ tag => $ version ) {
324- $ tagVersions [$ tag ] = $ tag .static ::TAGS_PREFIX ;
325- $ tags [$ tag .static ::TAGS_PREFIX ] = $ tag ;
329+ if (!$ tagVersions ) {
330+ return array ();
331+ }
332+
333+ if (!$ fetchTagVersions = 1 !== \func_num_args ()) {
334+ foreach ($ tagsByKey as $ tags ) {
335+ foreach ($ tags as $ tag => $ version ) {
336+ if ($ tagVersions [$ tag ] > $ version ) {
337+ $ tagVersions [$ tag ] = $ version ;
338+ }
339+ }
340+ }
341+ }
342+
343+ $ now = microtime (true );
344+ $ tags = array ();
345+ foreach ($ tagVersions as $ tag => $ version ) {
346+ $ tags [$ tag .static ::TAGS_PREFIX ] = $ tag ;
347+ if ($ fetchTagVersions || !isset ($ this ->knownTagVersions [$ tag ])) {
348+ continue ;
349+ }
350+ $ version -= $ this ->knownTagVersions [$ tag ][1 ];
351+ if ((0 !== $ version && 1 !== $ version ) || $ this ->knownTagVersionsTtl > $ now - $ this ->knownTagVersions [$ tag ][0 ]) {
352+ // reuse previously fetched tag versions up to the ttl, unless we are storing items or a potential miss arises
353+ $ fetchTagVersions = true ;
354+ } else {
355+ $ this ->knownTagVersions [$ tag ][1 ] += $ version ;
326356 }
327- foreach ($ this ->tags ->getItems ($ tagVersions ) as $ tag => $ version ) {
328- $ tagVersions [$ tags [$ tag ]] = $ version ->get () ?: 0 ;
357+ }
358+
359+ if (!$ fetchTagVersions ) {
360+ return $ tagVersions ;
361+ }
362+
363+ foreach ($ this ->tags ->getItems (array_keys ($ tags )) as $ tag => $ version ) {
364+ $ tagVersions [$ tag = $ tags [$ tag ]] = $ version ->get () ?: 0 ;
365+ if (isset ($ invalidatedTags [$ tag ])) {
366+ $ invalidatedTags [$ tag ] = $ version ->set (++$ tagVersions [$ tag ]);
329367 }
368+ $ this ->knownTagVersions [$ tag ] = array ($ now , $ tagVersions [$ tag ]);
330369 }
331370
332371 return $ tagVersions ;
0 commit comments