- for usage as Content Cache
- needed if the same tags apply to many elements
in Caches.yaml, do:
Neos_Fusion_Content:
backend: Sandstorm\OptimizedRedisCacheBackend\OptimizedRedisCacheBackend
Neos_Media_ImageSize:
backend: Sandstorm\OptimizedRedisCacheBackend\OptimizedRedisCacheBackend
Flow_Mvc_Routing_Route:
backend: Sandstorm\OptimizedRedisCacheBackend\OptimizedRedisCacheBackend
Flow_Mvc_Routing_Resolve:
backend: Sandstorm\OptimizedRedisCacheBackend\OptimizedRedisCacheBackend
-
When doing a flushByTag, we do the following (pseudocode):
- iterate over all entries for this tag
- "unlink" the entry from all tags this entry is additionally tagged with
- iterate over all tags for the current entry
- remove the entry
- remove the entry->tags relation
- "unlink" the entry from all tags this entry is additionally tagged with
- remove the tag
- iterate over all entries for this tag
-
You see, we have a twicely-nested iteration going on here. In a big customer project, the inner loop is sometimes called over 100 000 times for a single tag flush; making the Redis server unresponsive while the script runs.
When doing flushByTag, we just do the following:
- *iterate* over all entries for this tag
- remove the entry
- remove the entry->tags relation
- remove the tag
this means that the other tags for the cache entries are not removed.
-
This leaves some "cruft" in the Redis cache; namely tags where their assigned entries are already gone. This is not a big problem, as the entries might have also just timed out (because they have a TTL).
-
The only scenario I see where this might become a problem is:
- entry1 with tags A,B is inserted
- flushByTag(A) is done -> entry1 is removed, tag A is removed, tag B still exists, pointing to the (non-existing) entry1
- entry1 with tag A is inserted (Tag associations have changed!)
- -> there still is a connection between tag B (which has not been removed) and entry1.
-
When relying on findIdentifiersByTag() of TaggableBackendInterface, this might be a problem -- but this is never used in the content cache.
-
Aside from findIdentifiersByTag(), tags are only used for clearing certain parts of the cache. Thus, a stale edge from Tag B -> entry1 might lead to entry1 being flushed too often. We assume that this does not matter much for the content cache.
-
If the user wants to remove the cruft completely, he should call flush(), which completely resets the cache.
-
The whole scenario above is not so likely, because cache tags are mostly controlled by Fusion; and as long as this does not change, the cache tags stay stable.
The default Redis cache backend as an entries
list storing all cache entries (needed for iteration on legacy
Redis versions). Finding elements in the list is O(n) in the number of list entries.
Today, one could use KEYS for iterating over entries; but our content cache does not rely on IterableBackendInterface.
Thus, we just remove the entries
altogether.
For implementing flush(), we just iterate over the relevant part of the keyspace and remove all elements. Before, this was done through a similar logic as explained in FlushByTag, because the Redis Backend was freezable (but we do not need this for Neos Content Cache).