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;
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.