Skip to content

Instantly share code, notes, and snippets.

@ghoseb
Forked from purcell/redis_memo.clj
Created January 1, 2010 11:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ghoseb/267088 to your computer and use it in GitHub Desktop.
Save ghoseb/267088 to your computer and use it in GitHub Desktop.
Clojure Memoize to Redis
(ns redis-memo
(:require redis)
(:import (java.net URLEncoder)))
;; --------------------------------------------------------------------------------
;; Default connection params
;; --------------------------------------------------------------------------------
(def memo-server {:host "localhost" :port 6379 :db 14})
;; --------------------------------------------------------------------------------
;; Helpers
;; --------------------------------------------------------------------------------
(defn- encode-value
"Encode an object so that it is safe to pass to Redis, which complains about key
strings containing spaces etc. (redis-clojure doesn't escape keys)"
[value]
(pr-str value))
(defn- decode-value [value]
(with-in-str value (read)))
(defn- encode-key
"Encode an object so that it is safe to use as a Redis key,
avoiding invalid command strings containing spaces."
[key]
(URLEncoder/encode (encode-value key)))
;; --------------------------------------------------------------------------------
;; Public API
;; --------------------------------------------------------------------------------
(defmacro with-memo-server
"Executes forms with a redis connection to memo-server."
[& forms]
`(redis/with-server memo-server ~@forms))
(defn memoize-with-redis
"Returns a memoized version of a referentially transparent function. The
memoized version of the function uses Redis to keep a cache of the
mapping from arguments to results.
Unlike clojure.core/memoize, this explicitly shortcuts calling the oroginal
function when a nil result has previously been memoized."
[keyprefix f]
(fn [& args]
(with-memo-server
(let [k (encode-key (cons keyprefix args))]
(if-let [v (redis/get k)]
(decode-value v)
(let [ret (apply f args)]
(redis/set k (encode-value ret))
ret))))))
(defmacro defn-redis-memo
"Just like defn, but memoizes the function using memoize-with-redis"
[fn-name & defn-stuff]
`(do
(defn ~fn-name ~@defn-stuff)
(alter-var-root (var ~fn-name) (partial memoize-with-redis (str (var ~fn-name))))
(var ~fn-name)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment