All Projects → whitfin → retainer

whitfin / retainer

Licence: MIT License
Minimal async cache in Rust with support for key expirations

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to retainer

gocache
High performance and lightweight in-memory cache library with LRU and FIFO support as well as memory-usage-based-eviction
Stars: ✭ 15 (-34.78%)
Mutual labels:  caching, expiration
swift-standard-clients
Client declarations and live implementations for standard iOS managers
Stars: ✭ 28 (+21.74%)
Mutual labels:  caching
EasyTask MVVM Kotlin
Todo app based on MVVM, Kotlin Coroutines, Navigation Component, Room Database, Retrofit, Data Binding
Stars: ✭ 49 (+113.04%)
Mutual labels:  caching
openctp
CTP开放平台提供A股、港股、美股、期货、期权等全品种接入通道,通过提供中泰证券XTP、华鑫证券奇点、东方证券OST、东方财富证券EMT、盈透证券TWS等各通道的CTPAPI接口,CTP程序可以无缝对接各股票柜台。平台也提供了一套基于TTS交易系统的模拟环境,同样提供了CTPAPI兼容接口,可以替代Simnow,为CTP量化交易开发者提供7x24可用的模拟环境。
Stars: ✭ 389 (+1591.3%)
Mutual labels:  futures
unicycle
A futures abstraction that runs a set of futures which may complete in any order
Stars: ✭ 73 (+217.39%)
Mutual labels:  futures
WikiSearch
A flutter search engine based on MediaWiki with caching.
Stars: ✭ 39 (+69.57%)
Mutual labels:  caching
retrocache
This library provides an easy way for configure retrofit for use a 2 layer cache (RAM and Disk)
Stars: ✭ 35 (+52.17%)
Mutual labels:  caching
DropBeat
A Music Player with downloading, playing, searching, exploring functions.
Stars: ✭ 13 (-43.48%)
Mutual labels:  caching
soabase-stages
A tiny library that makes staged/pipelined CompletableFutures much easier to create and manage
Stars: ✭ 23 (+0%)
Mutual labels:  futures
indexed-cache
A tiny Javsacript library for sideloading static assets on pages and caching them in the browser's IndexedDB for longer-term storage.
Stars: ✭ 56 (+143.48%)
Mutual labels:  caching
future.mapreduce
[EXPERIMENTAL] R package: future.mapreduce - Utility Functions for Future Map-Reduce API Packages
Stars: ✭ 12 (-47.83%)
Mutual labels:  futures
node-version-assets
Version your static assets with MD5 hashes using node.js
Stars: ✭ 65 (+182.61%)
Mutual labels:  caching
PSCache
Generic PowerShell cache implementation
Stars: ✭ 43 (+86.96%)
Mutual labels:  caching
cache warmup
Generiert den Cache vorab, so dass die Website bereits beim Erstaufruf performant läuft
Stars: ✭ 36 (+56.52%)
Mutual labels:  caching
punic
Punic is a remote cache CLI built for Carthage and Apple .xcframework
Stars: ✭ 25 (+8.7%)
Mutual labels:  caching
variadic future
Variadic, completion-based futures for C++17
Stars: ✭ 41 (+78.26%)
Mutual labels:  futures
future.callr
🚀 R package future.callr: A Future API for Parallel Processing using 'callr'
Stars: ✭ 52 (+126.09%)
Mutual labels:  futures
more-executors
Library of composable Python executors
Stars: ✭ 18 (-21.74%)
Mutual labels:  futures
HAProxy-2-RPM-builder
Build latest HAProxy binary with prometheus metrics support
Stars: ✭ 28 (+21.74%)
Mutual labels:  caching
LocalSupport
A directory of local support services and volunteer opportunities
Stars: ✭ 60 (+160.87%)
Mutual labels:  caching

Retainer

Build Status Crates.io

This crate offers a very small cache with asynchronous bindings, allowing it to be used in async Rust contexts (Tokio, async-std, smol, etc.) without blocking the worker thread completely.

It also includes the ability to expire entries in the cache based on their time inside; this is done by spawning a monitor on your async runtime in order to perform cleanup tasks periodically. The eviction algorithm is similar to the one found inside Redis, although keys are not removed on access in order to reduce borrow complexity.

This crate is still a work in progress, so feel free to file any suggestions or improvements and I'll get to them as soon as possible :).

Getting Started

This crate is available on crates.io. The easiest way to use it is to add an entry to your Cargo.toml defining the dependency:

[dependencies]
retainer = "0.3"

Basic Usage

The construction of a cache is very simple, and (currently) requires no options. If you need to make use of key expiration, you must ensure to either await a monitor or spawn a monitor on your runtime.

There are many ways to provide an expiration time when inserting into a cache, by making use of several types implementing the Into<CacheExpiration> trait. Below are some examples of types which are available and some of the typical APIs you will find yourself using. This code uses the Tokio runtime, but this crate should be compatible with most of the popular asynchronous runtimes. Currently a small set of tests are run against async-std, smol and Tokio.

use retainer::*;
use tokio::time::sleep;

use std::sync::Arc;
use std::time::{Duration, Instant};

#[tokio::main]
async fn main() {
    // construct our cache
    let cache = Arc::new(Cache::new());
    let clone = cache.clone();

    // don't forget to monitor your cache to evict entries
    let monitor = tokio::spawn(async move {
        clone.monitor(4, 0.25, Duration::from_secs(3)).await
    });

    // insert using an `Instant` type to specify expiration
    cache.insert("one", 1usize, Instant::now()).await;

    // insert using a `Duration` type to wait before expiration
    cache.insert("two", 2, Duration::from_secs(2)).await;

    // insert using a number of milliseconds
    cache.insert("three", 3, 3500).await;

    // insert using a random number of milliseconds
    cache.insert("four", 4, 3500..5000).await;

    // insert without expiration (i.e. manual removal)
    cache.insert("five", 5, CacheExpiration::none()).await;

    // wait until the monitor has run once
    sleep(Duration::from_millis(3250)).await;

    // the first two keys should have been removed
    assert!(cache.get(&"one").await.is_none());
    assert!(cache.get(&"two").await.is_none());

    // the rest should be there still for now
    assert!(cache.get(&"three").await.is_some());
    assert!(cache.get(&"four").await.is_some());
    assert!(cache.get(&"five").await.is_some());

    // wait until the monitor has run again
    sleep(Duration::from_millis(3250)).await;

    // the other two keys should have been removed
    assert!(cache.get(&"three").await.is_none());
    assert!(cache.get(&"four").await.is_none());

    // the key with no expiration should still exist
    assert!(cache.get(&"five").await.is_some());

    // but we should be able to manually remove it
    assert!(cache.remove(&"five").await.is_some());
    assert!(cache.get(&"five").await.is_none());

    // and now our cache should be empty
    assert!(cache.is_empty().await);

    // shutdown monitor
    monitor.abort();
}

In the case this example is not kept up to date, you can look for any types which implement the Into<CacheExpiratio> trait in the documentation for a complete list.

Cache Monitoring

All key expiration is done on an interval, carried out when you await the future returned by Cache::monitor. The basis for how this is done has been lifted roughly from the implementation found inside Redis, as it's simple but still works well.

When you call Cache::monitor, you need to provide 3 arguments:

  • sample
  • frequency
  • threshold

Below is a summarization of the flow of eviction, hopefully in a clear way:

  1. Wait until the next tick of frequency.
  2. Take a batch of sample entries from the cache at random.
  3. Check for and remove any expired entries found in the batch.
  4. If more than threshold percent of the entries in the batch were removed, immediately goto #2, else goto #1.

This allows the user to control the aggressiveness of eviction quite effectively, by tweaking the threshold and frequency values. Naturally a cache uses more memory on average the higher your threshold is, so please do keep this in mind.

Cache Logging

As of v0.2, minimal logging is included using the log crate. You can attach any of the compatible logging backends to see what is happening in the cache (particularly the eviction loop) to better gauge your usage and parameters.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].