Cache handling in Koha
The cache mechanism in Koha brings us speed efficiency and allows us to cache data we often need.
2-levels of cache
All currently supported versions of Koha have a 2-levels cache mechanism, the L1 cache and the L2 cache.
L1 cache
The L1 cache is an in-memory cache. When a variable is not cached yet in the L1 cache, the value is fetched from the L2 cache. After it has been accessed the first time the value is cached to avoid a future re-fetch.
In a PSGI environment, the L1 cache must be flushed between each request to make sure the cache value is up-to-date. If not you could have a L1 cache's value that will be returned whereas the value has been modified by another worker. The action is done in the plack.psgi file:
Koha::Caches->flush_L1_caches();
L2 cache
The L2 cache is Memcached
Other caches
DBMS cache
We should also note that MySQL has its own cache system.
FastMmap
It is known to not work and should not replace Memcached, bug 16067.
Cache::Memory
The use of Cache::Memory as a default L2 cache has been removed by bug 21955. If the about page is telling you that it is used, you must install and configure Memcached.
How to set it up correctly?
If you installed Koha using the debian package, the caches should have been setup correctly. To know if the configuration is correct you can check the about page of Koha, tab "Server information". You will see a "Memcached" entry that will tell you from where the config has been read if it is correctly working.
It must says something like `Memcached: Servers: 127.0.0.1:11211 | Namespace: koha_kohadev | Status: running. | Config read from: koha-conf.xml`
If you want to change the default configuration of Memcached you need to edit your koha-conf.xml file and modify the entries memcached_servers and memcached_namespace.
memcached_servers should contain the host and the port and can list several hosts (comma separated)
Technical information
What is cached?
We need to cache data that is often fetched, or that takes time to process. So far we are caching the following information:
L2 cache:
- The last patron's login date (syspref TrackLastPatronActivity)
- The MARC structure, per framework
The koha configuration (koha-conf.xml)removed by Bug 28276- The system preferences' values
- The overdrive tokens
- The default values for items
- The authorized values (but only 5 seconds, #FIXME the code needs to be optimized to cache it longer, i.e. flush it when needed)
- The columns settings yaml file
- The calendar's holidays
L1 cache only:
- The interface's language of the current logged-in user
How to cache?
Sometime it is not needed to cache at L2 level (for instance the language of the logged-in user) and the Koha::Cache::Memory::Lite must be used to cache at L1 level only. When a value is cached we need to make sure the cache's value will always be up-to-date, and so that the cache's value will be flushed or updated when modified.
A standard pattern to cache a value (can be a structure) is:
sub get {
my ( $self, $var ) = @_;
my $cache = Koha::Caches->get_instance();
my $cache_key = 'my_var';
my $cached_value = $cache->get_from_cache($cache_key);
return $cached_value if defined $cached_value;
my $value = $self->$var;
$cache->set_in_cache($cache_key, $value);
return $value;
}
sub set {
my ( $self, $var, $val ) = @_;
my $cache = Koha::Caches->get_instance();
my $cache_key = 'my_var';
$self->set({ $var => $val });
$cache->clear_from_cache($cache_key); # Note that we could set_in_cache instead
}
Sometimes caching stuffs is more expensive than retrieving the value from DB, we should not "cache everything!" but think about what really need to be cached.
Interaction with the tests
We need to make sure the value is not modified by the tests when they are ran. The cache's values must be invalidated if the tests modified them, for instance if the DB has been changed without calling the Koha methods.