Download & Extend

Add an in-memory LRU cache

Project:Drupal core
Version:8.x-dev
Component:base system
Category:task
Priority:normal
Assigned:Unassigned
Status:needs review
Issue tags:memory, Performance

Issue Summary

#375494: Restrict the number of nodes held in the node_load() static cache adds an LRU cache for the entity cache, I wanted to see if we could make a generic in-memory LRU cache that could maybe be used elsewhere.

Turns out to be reasonably simple to write. I haven't benchmarked this or anything yet, just wanted to get something that works first. It does not yet allow for adding multiple items to the cache at once, that may be a useful feature to add for the entity case.

Patch only adds the class and a unit test, but marking CNR for the bot and hopefully feedback.

AttachmentSizeStatusTest resultOperations
lru.patch4.31 KBIdlePASSED: [[SimpleTest]]: [MySQL] 32,204 pass(es).View details | Re-test

Comments

#1

Just tested, seems to be working neatly.

// Replace the item in first position in the array.

I was mislead by this comment to believe the item was being replaced with the new one - which is not the case and would be nonsense. Maybe something like "Drop the first item - least recently used - to make room for the new item." would be clearer.

So currently entity controllers do like '$cache += $array_of_items;' which is not supported by ArrayObject. I guess a simple method that gets the items array as argument and iterates over them adding could do for now, right? Unless there is some performance impact in adding one by one.

#2

I've been pondering multiple add but haven't yet figure it out.

There's two issues:

- iterating is probably going to be a bit slower than +=, although since it only happens on (static) cache misses it might be fine.

- there is a chance that more items get added to the cache than it has capacity for - say you have a 30 limit but a list of 50 items all loaded at once.

#3

I thought about the second issue. And if you merge both - iterating a number of items above limit - we would most likely get a performance issue because of all the removals.

We could have a private property "$this->bypass" that defaults to FALSE. If it is true, offsetSet() would only call parent::offsetSet(). So this property can be used by an addMultiple() method so that it would handle removals and additions to $this->positions[] on itself and only once, avoiding endless iterations.

Concerning the second issue again, a simple solution would be to just cache a chunk of the maximum size, could be the last n items of the loaded items.