App

Overview

The Slate Cache is a light-weight LRU ( Least Recently Used ) Cache for both Android and Server. While there are many comprehensive Cache solutions available for the JVM, this is designed to be an in-memory light-weight cache with an emphasis on diagnostics and async functionality leveraging Kotlin Coroutines and Channels.

Diagram

A high-level diagram of the concepts in this component



Goals

Goal Description
1. Light-Weight Simple, light-weight with default implementations for sync and async based Caches.
2. Diagnostics Provides a reasonable level of diagnostics and cache metrics
3. Coroutines Async based cache leverages Coroutines / Channels for write operations


Status

This component is currently stable. Future versions will include support for:

Feature Status Description
Events Upcoming An event emitter for changes to cache
Refresh Upcoming Automatic / scheduled refresh of cache items
Stats Upcoming Enhanced stats to capture evictions/clearing of cache


Install

    repositories {
        // other repositories
        maven { url  "http://dl.bintray.com/codehelixinc/slatekit" }
    }

    dependencies {
        // other dependencies ...

        compile 'com.slatekit:slatekit-cache:1.0.0'
    }

Back to top



Sources

Jar slatekit.cache.jar
Package slatekit.cache
Sources slatekit-cache
Example Example_Cache.kt
Version
License
Requires See build.gradle for more info.

Back to top



Example

    
    import slatekit.cache.*

    // SimpleCache is the underlying Cache implementation
    val raw:Cache = SimpleCache(CacheSettings(10))

    // Synchronized cache wraps the raw cache
    // NOTE: Async cache via coroutines/channels avialable (see docs below)
    val cache:SyncCache = SimpleSyncCache(raw)

    // Writes
    // 1. Put new entry ( using a function to fetch )
    cache.put("promos", "promotion codes", 300) { listOf("p1", "p2") }

    // 2. Force a refresh
    cache.refresh("promos")

    // Reads
    // 1. Get existing cache item
    val c1 = cache.get<List<Country>>("countries")

    // 2. Get existing cache item or load it if expired
    val c2 = cache.getOrLoad<List<String>>("promos")

    // Stats
    cache.stats().forEach {
        println("key    : " + it.key)
        
        println("expiry.start   : " + it.expiry.started.toStringUtc())
        println("expiry.seconds : " + it.expiry.seconds )
        println("expiry.expires : " + it.expiry.expires.toStringUtc())
        
        println("hits.count     : " + it.hits.count)
        println("hits.time      : " + it.hits.timestamp?.toStringUtc() )
        
        println("value.created  : " + it.value.created?.toStringUtc() )
        println("value.updated  : " + it.value.updated?.toStringUtc() )
        println("value.applied  : " + it.value.applied)

        println("error.created  : " + it.error.created?.toStringUtc() )
        println("error.updated  : " + it.error.updated?.toStringUtc() )
        println("error.applied  : " + it.error.applied)
        println("\n")
    }

Back to top



Guide

Name Description More
1. Usage Usage of the features more
2. Stats Gettign stats and cache diagnostics more
3. Sync How to convert raw text into parsed parameters more
4. Async Working with parsed commands as CLI Requests more
5. Load Performance and load metrics more

Back to top



Usage

Showing simple usage of a synchronous cache implementation all operations on cache are using the @synchronized annotation on methods.

    import slatekit.cache.*

    // SimpleCache is the underlying Cache implementation
    val raw:Cache = SimpleCache(CacheSettings(10))

    // Synchronized cache wraps the raw cache
    // NOTE: Async cache via coroutines/channels avialable (see docs below)
    val cache:SyncCache = SimpleSyncCache(raw)

    // Writes: Both sync and async versions have these put/set/refresh methods
    // 1. Put new entry ( using a function to fetch )
    cache.put("promos", "promotion codes", 300) { listOf("p1", "p2") }

    // 2. Update existing entry with value
    cache.set("promos", listOf("p1", "p2"))

    // 3. Force a refresh
    cache.refresh("promos")

    // Reads: 
    // NOTES:
    // 1. The sync version returns the value
    // 2. The async version returns a Deferred<T> 
    val c1 = cache.get<List<Country>>("countries")

    // 2. Get existing cache item or load it if expired
    val c2 = cache.getOrLoad<List<String>>("promos")

    // 3. Get after refreshing it first
    val c3 = cache.getFresh<List<String>>("promos")

    println(c1)
    println(c2)
    println(c3)
Back to features Back to top


Stats

The main difference in the stats for this component is that both the created, updated timestamps are maintained while also typically keeping track of the counts of accesses, hits, misses.

Term Desc Example Ratio
Accesses Number of times a cache item is accessed 100 n/a
Hits Number of times a cache item is accessed and it exists 80 .8
Misses Number of times a cache item is accessed but does not exist 20 .2

    
    // ... setup ( see above )
    cache.stats().forEach {
        println("key    : " + it.key)

        println("expiry.start   : " + it.expiry.started.toStringUtc())
        println("expiry.seconds : " + it.expiry.seconds )
        println("expiry.expires : " + it.expiry.expires.toStringUtc())

        println("access.count     : " + it.reads?.count)
        println("access.time      : " + it.reads?.timestamp?.toStringUtc() )

        println("hits.count     : " + it.hits.count)
        println("hits.time      : " + it.hits.timestamp?.toStringUtc() )

        println("misses.count     : " + it.misses?.count)
        println("misses.time      : " + it.misses?.timestamp?.toStringUtc() )

        println("value.created  : " + it.value.created?.toStringUtc() )
        println("value.updated  : " + it.value.updated?.toStringUtc() )
        println("value.applied  : " + it.value.applied)

        println("error.created  : " + it.error.created?.toStringUtc() )
        println("error.updated  : " + it.error.updated?.toStringUtc() )
        println("error.applied  : " + it.error.applied)
        println("\n")
    }
Back to features Back to top


Sync

Showing usage of a synchronous cache implementation SimpleAsyncCache. All operations on cache are using the @synchronized annotation on methods. Synchronouse caches are implemented using the SyncCache interface.

    import slatekit.cache.*

    // SimpleCache is the underlying Cache implementation
    val raw:Cache = SimpleCache(CacheSettings(10))

    // Synchronized cache wraps the raw cache
    // NOTE: Async cache via coroutines/channels avialable (see docs below)
    val cache:SyncCache = SimpleSyncCache(raw)

    // Writes
    // 1. Put new entry ( using a function to fetch )
    cache.put("promos", "promotion codes", 300) { listOf("p1", "p2") }

    // 2. Update existing entry with value
    cache.set("promos", listOf("p1", "p2"))

    // 3. Force a refresh
    cache.refresh("promos")

    // Reads
    // 1. Get existing cache item
    val c1 = cache.get<List<Country>>("countries")

    // 2. Get existing cache item or load it if expired
    val c2 = cache.getOrLoad<List<String>>("promos")

    // 3. Get after refreshing it first
    val c3 = cache.getFresh<List<String>>("promos")

    println(c1)
    println(c2)
    println(c3)
Back to features Back to top


Async

Async functionality is based on using Coroutines and Channels for writes. The async cache implementation is SimpleAsyncCache. Async caches are implemented using the AsyncCache interface. In this approach, concurrent writes are handling by creating a CacheCommand representing the operation and sending them to a channel to be handled sequentially. Reads are handling by returning a kotlin Deferred[T].

     
    import slatekit.cache.*

    val logger = LoggerConsole()
    val coordinator = ChannelCoordinator(logger, Paired(), Channel<CacheCommand>(Channel.UNLIMITED))
    val asyncCache: AsyncCache = SimpleAsyncCache(raw, coordinator)

    // Writes
    // 1. Put new entry ( using a function to fetch )
    asyncCache.put("promos", "promotion codes", 300) { listOf("p1", "p2") }

    // 2. Update existing entry with value
    asyncCache.set("promos", listOf("p1", "p2"))

    // 3. Force a refresh
    asyncCache.refresh("promos")

    // Reads
    // 1. Get existing cache item
    val a1 = asyncCache.get<List<Country>>("countries").await()

    // 2. Get existing cache item or load it if expired
    val a2 = asyncCache.getOrLoad<List<String>>("promos").await()

    // 3. Get after refreshing it first
    val a3 = asyncCache.getFresh<List<String>>("promos").await()
     
Back to features Back to top



Back to top



Load

Performance and load docs coming soon

Back to features Back to top



Back to top