Skip to content

Instantly share code, notes, and snippets.

@killme2008
Created March 30, 2013 05:57
Show Gist options
  • Select an option

  • Save killme2008/5275571 to your computer and use it in GitHub Desktop.

Select an option

Save killme2008/5275571 to your computer and use it in GitHub Desktop.
A LRU cache for core.cache that supports evict handler.
(ns cache.lru
(:use [clojure.core.cache :only [CacheProtocol defcache]]))
(defn- build-leastness-queue
[base limit start-at]
(merge
(into {} (take (- limit (count base)) (for [k (range (- limit) 0)] [k k])))
(into {} (for [[k _] base] [k start-at]))))
(defcache LRUCache [cache lru tick limit evict-handler]
CacheProtocol
(lookup [_ item]
(get cache item))
(lookup [_ item not-found]
(get cache item not-found))
(has? [_ item]
(contains? cache item))
(hit [_ item]
(let [tick+ (inc tick)]
(LRUCache. cache
(assoc lru item tick+)
tick+
limit
evict-handler)))
(miss [_ item result]
(let [tick+ (inc tick)]
(if-let [ks (keys lru)]
(let [k (if (contains? lru item)
item
(apply min-key lru ks)) ;; maybe evict case
sz (count ks)
c (if (>= sz limit)
(do
(evict-handler k (get cache k))
(-> cache (dissoc k) (assoc item result)))
(assoc cache item result))
l (if (>= sz limit)
(-> lru (dissoc k) (assoc item tick+))
(assoc lru item tick+))]
(LRUCache. c l tick+ limit evict-handler))
(LRUCache. (assoc cache item result) ;; no change case
(assoc lru item tick+)
tick+
limit
evict-handler))))
(evict [this key]
(let [v (get cache key ::miss)]
(if (= v ::miss)
this
(LRUCache. (do
(evict-handler key (get cache key))
(dissoc cache key))
(dissoc lru key)
(inc tick)
limit
evict-handler))))
(seed [_ base]
(LRUCache. base
(build-leastness-queue base limit 0)
0
limit
evict-handler))
Object
(toString [_]
(str cache \, \space lru \, \space tick \, \space limit)))
(defn- default-evict-handler [k v])
(defn lru-cache-factory
[base & {threshold :threshold
evict-handler :evict-handler
:or {threshold 32
evict-handler default-evict-handler}}]
{:pre [(number? threshold) (< 0 threshold)
(map? base)]}
(clojure.core.cache/seed (LRUCache. {} {} 0 threshold evict-handler) base))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment