Crate sine_cache

Source
Expand description

This library provides a powerful in-memory caching solution with support for customizable eviction policies and persistence using Append-Only Files (AOF). It allows efficient management of key-value pairs, ensuring both performance optimization and data persistence across application lifecycles.

§Features

  • Multiple Eviction Policies: Choose from FIFO (First-In, First-Out), LRU (Least Recently Used), and LFU (Least Frequently Used) eviction policies to suit different data access patterns.

  • Customizable Eviction Strategies: Implement custom eviction policies by defining types that adhere to the EvictionPolicy trait, allowing tailored cache management.

  • Asynchronous Support: AsyncCache struct provides async methods for operations like get, put, and remove, ensuring efficient handling of concurrent requests in async-await contexts.

  • Persistence with Append-Only Files (AOF): Optionally persist cache state across restarts using AOF, ensuring data integrity and recovery after crashes.

  • Thread Safety: AsyncCache utilizes tokio::sync::Mutex to manage concurrent access safely, making it suitable for multi-threaded environments.

  • Efficient Memory Management: Optimizes memory usage with smart pointers and references, reducing redundancy and improving overall performance.

  • Configuration Flexibility: Configure cache size limits, eviction policies, and persistence settings through intuitive configuration structs (CacheSyncConfig and AsyncCacheConfig).

  • Detailed Documentation: Comprehensive API documentation and examples facilitate easy integration and usage within applications.

  • Safety and Reliability: Built with Rust’s strong type system and ownership model, ensuring memory safety and preventing common bugs like null pointer dereferencing and data races.

§Examples

§Cache - Synchronous Cache:

use sine_cache::{cache::Cache, config::CacheConfig};

fn main() {
    let capacity = 10; // Maximum number of entries in the cache.
    let mut cache = Cache::new(sine_cache::config::CacheSyncConfig::LFU(CacheConfig{max_size: capacity}));

    // Inserting key-value pairs into the cache
    cache.put(1, "One");
    cache.put(1, "one"); // Overwrites previous value
    cache.put(2, "Two");

    // Retrieving a value from the cache
    let value = cache.get(&1);
    assert!(value.is_some_and(|x| x == &"one"));
}

§AsyncCache - Asynchronous Cache:

  • §Without AOF:
use sine_cache::{cache::AsyncCache, config::{AsyncCacheConfig, EvictionAsyncConfig}};

#[tokio::main]
async fn main() {
    let capacity = 10; // Maximum number of entries in the cache.
    let mut cache = AsyncCache::new(AsyncCacheConfig::LFU(EvictionAsyncConfig {max_size: capacity, aof_config: None})).await;

    // Inserting key-value pairs into the cache
    cache.put(1, String::from("One")).await;
    cache.put(1, String::from("one")).await; // Overwrites previous value
    cache.put(2, String::from("Two")).await;

    // Retrieving a value from the cache
    let value = cache.get(&1).await;
    assert!(value.is_some_and(|x| x == "one"));
}
  • §With AOF:
use sine_cache::{cache::AsyncCache, config::{AsyncCacheConfig, EvictionAsyncConfig, EvictionAOFConfig}};

#[tokio::main]
async fn main() {
     
    let capacity = 10; // Maximum number of entries in the cache.
    let mut cache = AsyncCache::new(AsyncCacheConfig::LFU(EvictionAsyncConfig {
        max_size: capacity,
        aof_config: Some(EvictionAOFConfig {
            folder: String::from("./data"), //folder in which persistent file should be written.
            cache_name: String::from("async_lof_cache"), //Unique cache name as with same name file will be created.
            flush_time: Some(5000) //After every 5000 milliseconds data will be flushed to disk.
        })
    })).await;

    // Inserting key-value pairs into the cache
    cache.put(1, String::from("One")).await;
    cache.put(1, String::from("one")).await; // Overwrites previous value
    cache.put(2, String::from("Two")).await;

    // Retrieving a value from the cache
    let value = cache.get(&1).await;
    assert!(value.is_some_and(|x| x == "one"));
}

§Custom eviction policy

use sine_cache::eviction_policies::common::EvictionPolicy;
use sine_cache::{cache::AsyncCache, config::{AsyncCacheConfig, CustomEvictionAsyncConfig, CustomEvictionAOFConfig}};
 
pub struct CustomEviction<K> {
    _phantom: std::marker::PhantomData<K>,
}
impl<K: Eq + std::hash::Hash + Clone> CustomEviction<K> {
    pub fn new() -> Self{
        Self{
            _phantom: std::marker::PhantomData
        }
    }
}
 
impl<K: Eq + std::hash::Hash + Clone> EvictionPolicy<K> for CustomEviction<K> {
    fn on_get(&mut self, key: &K) {
        // nothing to do.
    }
 
    fn on_set(&mut self, key: K) {
        // nothing to do.
    }
 
    fn evict(&mut self) -> Option<K> {
        // nothing to do
        None
    }
 
    fn remove(&mut self, key: K) {
        //nothing to do
    }
}
 
#[tokio::main]
async fn main() {
     
    let capacity = 10; // Maximum number of entries in the cache.
    let mut cache = AsyncCache::new(AsyncCacheConfig::Custom(CustomEvictionAsyncConfig {
        max_size: capacity,
        aof_config: Some(CustomEvictionAOFConfig {
            folder: String::from("./data"), //folder in which persistent file should be written.
            cache_name: String::from("async_lof_custom_cache"), //Unique cache name as with same name file will be created.
            flush_time: Some(5000), //After every 5000 milliseconds data will be flushed to disk.
            persist_read_ops: true //whether to store reads also, true generally.
        }),
        policy: Box::new(CustomEviction::new())
    })).await;

    // Inserting key-value pairs into the cache
    cache.put(1, String::from("One")).await;
    cache.put(1, String::from("one")).await; // Overwrites previous value
    cache.put(2, String::from("Two")).await;

    // Retrieving a value from the cache
    let value = cache.get(&1).await;
    assert!(value.is_some_and(|x| x == "one"));
}
 

For detailed API documentation and further customization options, refer to the library’s documentation. For more examples, go through test modules on github library

Modules§

aof
Contains code for AOF for persisting data.
cache
Code of Cache and AsyncCache struct which provides functionalities of caching.
cache_events
Contains logic what to do when some event take place in ThreadSafeCache.
common
Contains common structs and traits used throughout the library.
config
Contains code to define different configurations to use Cache and AsyncCache
eviction_policies
This module provides various eviction policies that can be used with a cache implementation. An eviction policy defines the strategy for removing entries from a cache when it reaches its capacity. Different eviction policies prioritize different criteria for eviction, such as least recently used (LRU) or first-in-first-out (FIFO) or Least Frequently Used(LFU).