libvmemcache - buffer-based LRU cache

Posted May 07, 2019         « Previous post    


libvmemcache is a volatile key-value store optimized for operating on NVDIMM based space. However, it can work with any filesystem whether it is stored in memory (tmpfs) or on any storage device. Consequently, libvmemcache will be significantly less performant if it is stored on the storage device other than NVDIMMs.

libvmemcache is an embeddable and lightweight in-memory caching solution. It is designed to fully take advantage of large capacity memory, such as persistent memory with DAX through memory mapping in an efficient and scalable way.

Creation of cache

At the very beginning you have to call vmemcache_new() in order to create a new vmemcache instance:

	cache = vmemcache_new();

It creates an empty unconfigured vmemcache instance initialized with the default values.

Next, you can configure the parameters of cache to change their default values.

You can set the size of cache - it will be rounded up to a whole page size (4KB on x86):

	vmemcache_set_size(cache, new_size);

You can set the block size of cache (256 bytes minimum, strongly recommended to be a multiple of 64 bytes). If cache is backed by a non byte-addressable medium, the block size should be 4096 (or a multiple) or performance will greatly suffer.

	vmemcache_set_extent_size(cache, block_size);

You can also set the replacement policy that defines what will happen when an element is inserted into full cache:

	vmemcache_set_eviction_policy(cache, repl_p);

Then you have to call the vmemcache_add() function in order to associate cache with a backing storage medium in the given path:

	vmemcache_add(cache, "/path/to/backing/storage/medium");

which may be a /dev/dax device or a directory on a regular filesystem (which may or may not be mounted with -o dax, either on persistent memory or any other backing storage).

Cache is ready to be used now.

Use of cache

There are three basic operations on cache.

You can put a new element into cache using the vmemcache_put() function

	vmemcache_put(cache, key, key_size, value, value_size);

that inserts a given (key, value) pair into cache.

You can get an element from cache using the vmemcache_get() function:

	vmemcache_get(cache, key, key_size, vbuf, vbufsize, offset, vsize);

that searches for an entry with the given key.

You can also evict an element from cache using the vmemcache_evict() function:

	vmemcache_evict(cache, key, ksize);

that removes the given key from cache.


You can register a hook to be called during eviction or after a cache miss, using vmemcache_callback_on_evict() or vmemcache_callback_on_miss(), respectively:

	vmemcache_callback_on_evict(cache, callback_on_evict, arg);
	vmemcache_callback_on_miss(cache, callback_on_miss, arg);

The extra arg will be passed to your function.

The ‘on evict’ callback function is called when an entry is being removed from cache. The function cannot prevent the eviction but the entry remains available for queries until the callback function returns. The thread that triggered the eviction is blocked in the meantime.

The ‘on miss’ callback function is called when a get query fails in order to provide an opportunity to insert the missing key. If the callback function calls put for that specific key, the get will return its value even if it does not fit into cache.


It is possible to obtain a piece of statistics about cache using the vmemcache_get_stat() function:

	vmemcache_get_stat(cache, statistic, value, value_size);

The statistic can be one of the following:

Statistics are enabled by default. They can be disabled at the compile time of the vmemcache library if the STATS_ENABLED CMake option is set to OFF.

A human-friendly description of the last error can be retrieved using the vmemcache_errormsg() function:


Delete cache

At the end you have to free any structures associated with cache:


The complete example code can be found in the vmemcache repository.


The complete libvmemcache manual can be found at

Posted by @ldorau         « Previous post