Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
(ns yeller.store.guava-cached-store
(:require [metrics.counters :refer [counter inc!]]
[metrics.gauges :refer [gauge]]
[liza.store :as store])
(:import (com.google.common.cache CacheBuilder CacheLoader
LoadingCache RemovalListener)
(java.util.concurrent TimeUnit)))
(deftype GuavaCachedBucket [original-bucket ^LoadingCache cache]
store/Bucket
(store/get [b k]
(try
(.get cache k)
(catch com.google.common.cache.CacheLoader$InvalidCacheLoadException _
nil)))
(store/put [b k v]
(store/put original-bucket k v))
store/MergeableBucket
(store/merge [b v1 v2]
(store/merge original-bucket v1 v2))
store/Wipeable
(store/wipe [b]
(store/wipe original-bucket)))
(defn track-cache-stats [bucket-name ^LoadingCache cache]
(gauge ["yeller.store.guava-cached-store" bucket-name "hit-rate"]
(.hitRate (.stats cache)))
(gauge ["yeller.store.guava-cached-store" bucket-name "eviction-count"]
(.evictionCount (.stats cache)))
(gauge ["yeller.store.guava-cached-store" bucket-name "average-load-penalty"]
(/ (.averageLoadPenalty (.stats cache)) 1000000)))
(defn guava-cached-bucket
([bucket-name original-bucket] (guava-cached-bucket bucket-name original-bucket {}))
([bucket-name original-bucket options]
(let [removal-counter (counter ["yeller.store.guava-cached-store" "removals" bucket-name])
cache
(-> (CacheBuilder/newBuilder)
(.maximumSize (:max-size options 1000))
(.expireAfterWrite (:expire-after-write options 1000) TimeUnit/MILLISECONDS)
(.removalListener
(reify RemovalListener
(onRemoval [_ _]
(inc! removal-counter))))
(.recordStats)
(.build
(proxy [CacheLoader] []
(load [k]
(store/get original-bucket k)))))]
(track-cache-stats bucket-name cache)
(GuavaCachedBucket. original-bucket cache))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment