ANN: Releases of ringo

On behalf of Nomadic Labs, I am please to announce the first few releases of Ringo: a library for caches. Ringo offers two kinds of caches: Maps for caches of key-value pairs and Sets for caches of simple elements. In addition, each kind of cache can be tweaked to handle their bounds differently.

Ringo versions 0.1, 0.2 and 0.3 are available on opam. As the version number and the bundled announce suggests, this library is still in early phases of release: additional replacement policies will be added, the interface will probably change somewhat, etc. Suggestions welcome!

Even though the interface is still in early phases of release, the implementation is covered by a lot of tests and is already in use in the Tezos project.

The code is available at


Version 0.4 of ringo is now available in opam. This version includes bug-fixes, minor (sometimes breaking) interface and semantics improvements, and, most importantly, a ringo-lwt package.

ringo-lwt provides wrapper for using caches in an Lwt-heavy application. Specifically, it provides a functor that transform a Ringo cache into a Ringo-lwt cache featuring:

  • val find_or_replace : 'a t -> key -> (key -> 'a Lwt.t) -> 'a Lwt.t which helps avoid race conditions,
  • automatic cleanup by which promises that are rejected are removed from the table automatically.

Additional functors for option (with automatic cleanup of None) and result (with automatic cleanup of Error) are also provided.


Version 0.5 of ringo and ringo-lwt are now available in opam. Although this version changes ringo-lwt only, both packages are released anew to keep the version numbers in sync. This version includes:

  • Improvement in documentation.
  • Simplifications and reduction in the memory footprint of lwt-wrapped caches.
  • Fix for a race condition in the automatic cleanup (previously, on weak caches only, a promise being rejected could cause a different promise to be removed from the cache)
  • Fix a leak
  • More test, including a test for leakiness.

What is ringo?
Caches (bounded-size key-value stores) and other bounded-size stores says opam.
When advertizing a software, you should always remind what this software is about.
99.9999% of the people know nothing about what you are talking/advertizing…

And by the way, what are the uses cases for ringo?

Are there any alternatives to it?


1 Like

Ringo provides bounded-size key-value stores. More specifically, it provides a functor similar to Hastbl.Make except that the number of bindings held by the tables is limited: inserting additional bindings when the limit has been reached causes some previously inserted binding to be removed.

More more specifically, Ringo provides a function map_maker that takes parameters to customise the policies that determine the behaviour of the cache when supernumerary bindings are inserted, and returns the functor described above. Once a module Cache is instantiated using this functor, it can be used as follows:

let cache = Cache.create size
let fetch_data uri =
  match Cache.find_opt cache uri with
  | Some data -> data
  | None ->
    let data = really_fetch_data uri in
    Cache.replace cache uri data;

The cache will only hold up to [size] bindings, which avoids leaking memory. Additionally, the parameters for map_maker allow you to customise:

  • The replacement policy: which binding is removed when a supernumerary is inserted (currently supports least-recently used and first-in first-out).
  • The overflow policy: whether the cache can weakly hold some supernumerary elements (if so, the cache may hold more but the GC can always collect them if space is lacking).
  • The accounting precision: whether to keep precise track of removed/replaced elements.

In addition, Ringo also provide set-caches: i.e., sets (rather than maps) with bounded size and all the same properties as above.

Also note Ringo-Lwt (ringo-lwt) provides Lwt wrappers around Ringo caches.

If you have suggestions for a different concise synopsis for opam, feel free to send them this way.

Use cases are, I guess, caches. In particular those that might receive many elements not all of which you can hold in memory. We use it in a few places in the Tezos project to hold resources (blocks, operations, etc.) that are fetched from the P2p layer: it avoids having to fetch them again from the network.

I think anycache, lru, and lru-cache are all alternatives available on opam.


The documentation is now available online at

Of particular interest: