Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

some updates

  • Loading branch information...
commit 6ffd3d6b3463f0aafb5b4a566595e45166cd7407 1 parent 67e5c30
@davidhmartin authored
Showing with 294 additions and 102 deletions.
  1. +1 −1  project.clj
  2. +98 −15 src/mcache/cache.clj
  3. +195 −86 test/mcache/test/cache.clj
View
2  project.clj
@@ -1,4 +1,4 @@
-(defproject mcache "0.1.0"
+(defproject mcache "0.2.0"
:description "A protocol-based interface to memory cache clients."
:url "https://github.com/davidhmartin/mcache"
:dependencies [[org.clojure/clojure "1.2.1"]
View
113 src/mcache/cache.clj
@@ -17,9 +17,7 @@
follow the memcached protocol, wherein the time unit is seconds,
and a value between 1 and 30 days is treated as time-to-live,
and any higher value is treated as a unix-style timestamp (seconds
- since Jan 1 1970).
-
- "
+ since Jan 1 1970)."
(default-exp [mc]
"Return the default expiration")
@@ -86,33 +84,37 @@
(fetch-all
[mc keys]
"Gets values for keys. Returns a map of keys to values, omitting
- keys that are not in the cache."))
+ keys that are not in the cache.")
+
+ (clear [mc] "clear the cache")
+
+ )
(defmacro with-cache
"key is a string, value-fn is a function. Returns keyed value from cache;
if not found, uses value-fn to obtain the value and adds it to cache
before returning."
([cache key value-fn]
- `(if-let [cached-val# (.lookup ~cache ~key)]
+ `(if-let [cached-val# (fetch ~cache ~key)]
cached-val#
(let [val# (~value-fn ~key)]
(if (nil? val#)
nil
- (if (.get (.put-if-absent ~cache ~key val#))
+ (if (.get (put-if-absent ~cache ~key val#))
val#
- (.lookup ~cache ~key))))))
+ (fetch ~cache ~key))))))
([cache key value-fn exp]
- `(if-let [cached-val# (.lookup ~cache ~key)]
+ `(if-let [cached-val# (fetch ~cache ~key)]
cached-val#
(let [val# (~value-fn ~key)]
(if (nil? val#)
nil
- (if (.get (.put-if-absent ~cache ~key val# ~exp))
+ (if (.get (put-if-absent ~cache ~key val# ~exp))
val#
- (.lookup ~cache ~key)))))))
+ (fetch ~cache ~key)))))))
(defn cache-fetch
- ([cache id query-fn key-fn] (cache-fetch cache id query-fn key-fn (.default-exp cache)))
+ ([cache id query-fn key-fn] (cache-fetch cache id query-fn key-fn (default-exp cache)))
([cache id query-fn key-fn exp]
"To be used in conjunction with a persistent storage api. 'id' is
a unique identifier (e.g. a primary key) for a persisted object.
@@ -122,10 +124,10 @@
will first attempt to locate the object in cache; if not found, it
uses query-fn to get the object and caches it before returning.
Returns nil if object is not found at all."
- (if-let [cached-obj (.lookup cache (key-fn id))]
+ (if-let [cached-obj (fetch cache (key-fn id))]
cached-obj
(when-let [obj (query-fn id)]
- (.put-if-absent cache (key-fn id) obj exp)
+ (put-if-absent cache (key-fn id) obj exp)
obj))))
(defn- remove-nil-vals [map]
@@ -140,7 +142,7 @@
(letfn [(add-to-cache
[cache id2val key-fn]
(doseq [[id val] id2val]
- (.put-if-absent cache (key-fn id) val)))
+ (put-if-absent cache (key-fn id) val)))
(from-cache
[cache ids key-fn]
(let [keys (map key-fn ids)]
@@ -162,6 +164,86 @@
(map (fn [k_v] [(first k_v) (cache-updating-fctn mc (first k_v) (second k_v) exp)]) key-val-map)))
+
+(extend-type net.spy.memcached.MemcachedClient
+ Memcache
+ (default-exp [mc] DEFAULT-EXP)
+
+ (put-if-absent
+ ([mc key value]
+ (put-if-absent mc key value DEFAULT-EXP))
+ ([mc key value exp]
+ (.. mc (add key exp value))))
+
+ (put-all-if-absent
+ ([mc key-val-map]
+ (put-all-if-absent mc key-val-map DEFAULT-EXP))
+ ([mc key-val-map exp]
+ (cache-update-multi put-if-absent mc key-val-map exp)))
+
+ (put
+ ([mc key value]
+ (.. mc (set key DEFAULT-EXP value)))
+ ([mc key value exp]
+ (.. mc (set key exp value))))
+
+ (put-all
+ ([mc key-val-map] (put-all mc key-val-map DEFAULT-EXP))
+ ([mc key-val-map exp]
+ (cache-update-multi put mc key-val-map exp)))
+
+ (put-if-present
+ ([mc key value] (put-if-present mc key value DEFAULT-EXP))
+ ([mc key value exp]
+ (.. mc (replace key exp value))))
+
+ (put-all-if-present
+ ([mc key-val-map] (put-all-if-present mc key-val-map DEFAULT-EXP))
+ ([mc key-val-map exp]
+ (cache-update-multi put-if-present mc key-val-map exp)))
+
+ (delete [mc key]
+ (.. mc (delete key)))
+
+ (delete-all [mc keys]
+ (doall (map #(delete mc %) keys)))
+
+ (incr
+ ([mc key]
+ (.. mc (incr key 1)))
+ ([mc key by]
+ (.. mc (incr key by)))
+ ([mc key by default]
+ (.. mc (incr key by default)))
+ ([mc key by default exp]
+ (.. mc (incr key by default exp))))
+
+ (decr
+ ([mc key]
+ (.. mc (decr key 1)))
+ ([mc key by]
+ (.. mc (decr key by)))
+ ([mc key by default]
+ (.. mc (decr key by default)))
+ ([mc key by default exp]
+ (.. mc (decr key by default exp))))
+
+ (fetch [mc key]
+ (.. mc (get key)))
+
+ (fetch-all [mc keys]
+ (into {} (.. mc (getBulk keys))))
+
+ (clear [mc] (.. mc (flush)))
+
+ )
+
+
+
+
+
+
+
(defcache MemcachedCache [mc exp]
CacheProtocol
(lookup
@@ -221,7 +303,6 @@
(put
[this key value]
- (println "put value: " value " of type: " (class value))
(.. mc (set key DEFAULT-EXP value)))
(put
[this key value exp]
@@ -285,6 +366,8 @@
[this keys]
(into {} (.. mc (getBulk keys))))
+ (clear [this] (.. mc (flush)))
+
)
View
281 test/mcache/test/cache.clj
@@ -1,7 +1,6 @@
(ns mcache.test.cache
(:use [mcache.cache])
(:use [clojure.test])
- ;; (:require [clojure.core.cache.tests :as coretests])
(:import [clojure.core.cache CacheProtocol]
[mcache.cache MemcachedCache])
)
@@ -12,43 +11,40 @@
(defn clear-cache-fixture
"Flushes the cache before and after. NOTE: Flush is asynchronous, so
it can't really be relied on to bring the cache to a clean state
- between tests. Therefore, it is best to avoid using the same keys in
+ between tests. An acceptable workaround is to avoid using the same keys in
different tests."
[f]
- (.. (.mc mc) (flush))
+ (clear mc)
(f)
- (.. (.mc mc) (flush)))
+ (clear mc))
(use-fixtures :each clear-cache-fixture)
-(deftest test-lookup
- (testing "lookup"
- (.get (put mc "a" 1))
- (.get (put mc "b" 2))
- (is (= 1 (.lookup mc "a")))))
+(defn do-test-lookup [mc]
+ (.get (put mc "a" 1))
+ (.get (put mc "b" 2))
+ (is (= 1 (.lookup mc "a"))))
-(deftest test-put-if-absent
- (testing "put-if-absent"
+(defn do-test-put-if-absent [mc]
(is (nil? (fetch mc "key1")))
;; put-if-add is asynchronous and returns a Future<Boolean>, so we
;; use .get to wait for the response
(is (.get (put-if-absent mc "key1" "val1")))
(is (= "val1" (fetch mc "key1")))
(is (not (.get (put-if-absent mc "key1" "val2"))))
- (is (= "val1" (fetch mc "key1")))))
+ (is (= "val1" (fetch mc "key1"))))
-(deftest test-put-all-if-absent
- (testing "Add multiple items to cache"
+(defn do-test-put-all-if-absent [mc]
(let [input {"one" 1 "two" 2 "three" "the number three"}
- results (.put-all-if-absent mc input)]
+ results (put-all-if-absent mc input)]
(is (= (set (keys input)) (set (keys results))))
(doseq [[k v] results]
(is (.get v))))
(let [input {"one" "a" "two" "b" "three" 3 "four" 4}
- results (.put-all-if-absent mc input)]
+ results (put-all-if-absent mc input)]
(is (= (set (keys input)) (set (keys results))))
(is (false? (.get (get results "one"))))
(is (false? (.get (get results "two"))))
@@ -57,19 +53,17 @@
(is (= 1 (fetch mc "one")))
(is (= 2 (fetch mc "two")))
(is (= "the number three" (fetch mc "three")))
- (is (= 4 (fetch mc "four"))))))
+ (is (= 4 (fetch mc "four")))))
-(deftest test-put
- (testing "Put into cache"
- (is (.get (.put mc "setkey1" "val1")))
- (is (= "val1" (.lookup mc "setkey1")))
- (is (.get (.put mc "setkey1" "val2")))
- (is (= "val2" (.lookup mc "setkey1")))))
+(defn do-test-put [mc]
+ (is (.get (put mc "setkey1" "val1")))
+ (is (= "val1" (fetch mc "setkey1")))
+ (is (.get (put mc "setkey1" "val2")))
+ (is (= "val2" (fetch mc "setkey1"))))
-(deftest test-put-all
- (testing "Put multiple into cache"
+(defn do-test-put-all [mc]
(let [input {"one" 1 "two" 2 "three" "the number three"}
- results (.put-all mc input)]
+ results (put-all mc input)]
(is (= (set (keys input)) (set (keys results))))
(doseq [[k v] results]
(is (.get v))))
@@ -80,105 +74,95 @@
(is (true? (.get (get results "two"))))
(is (true? (.get (get results "three"))))
(is (true? (.get (get results "four"))))
- (is (= "a" (.lookup mc "one")))
- (is (= "b" (.lookup mc "two")))
- (is (= 3 (.lookup mc "three")))
- (is (= 4 (.lookup mc "four"))))))
+ (is (= "a" (fetch mc "one")))
+ (is (= "b" (fetch mc "two")))
+ (is (= 3 (fetch mc "three")))
+ (is (= 4 (fetch mc "four")))))
-(deftest test-put-if-present
- (testing "Replace in cache"
+(defn do-test-put-if-present [mc]
(is (false? (.get (put-if-present mc "repkey1" "foo"))))
- (is (nil? (.lookup mc "repkey1")))
+ (is (nil? (fetch mc "repkey1")))
(.get (put mc "repkey1" "bar"))
(is (true? (.get (put-if-present mc "repkey1" "foo"))))
- (is (= "foo" (.lookup mc "repkey1")))))
+ (is (= "foo" (fetch mc "repkey1"))))
-(deftest test-put-all-if-present ;;;;;
- (testing "Replace multiple"
+(defn do-test-put-all-if-present [mc]
(let [input {"one" 1 "two" 2 "three" "the number three"}
- results (.put-all mc input)])
+ results (put-all mc input)])
(let [input {"one" "a" "two" "b" "three" 3 "four" 4}
- results (.put-all-if-present mc input)]
+ results (put-all-if-present mc input)]
(is (= (set (keys input)) (set (keys results))))
(is (true? (.get (get results "one"))))
(is (true? (.get (get results "two"))))
(is (true? (.get (get results "three"))))
(is (false? (.get (get results "four"))))
- (is (= "a" (.lookup mc "one")))
- (is (= "b" (.lookup mc "two")))
- (is (= 3 (.lookup mc "three")))
- (is (nil? (.lookup mc "four"))))))
+ (is (= "a" (fetch mc "one")))
+ (is (= "b" (fetch mc "two")))
+ (is (= 3 (fetch mc "three")))
+ (is (nil? (fetch mc "four")))))
-(deftest test-delete
- (testing "Delete"
+(defn do-test-delete [mc]
(put mc "is-there" "thing")
- (is (false? (.get (.delete mc "not-there"))))
- (is (true? (.get (.delete mc "is-there"))))
- (is (nil? (.lookup mc "is-there")))))
+ (is (false? (.get (delete mc "not-there"))))
+ (is (true? (.get (delete mc "is-there"))))
+ (is (nil? (fetch mc "is-there"))))
-(deftest test-delete-all
- (testing "Delete all"
- (.get (.put mc "a" 1))
- (.get (.put mc "b" 2))
- (let [resp (.delete-all mc ["a" "b" "x"])]
+(defn do-test-delete-all [mc]
+ (.get (put mc "a" 1))
+ (.get (put mc "b" 2))
+ (let [resp (delete-all mc ["a" "b" "x"])]
(is (true? (.get (nth resp 0))))
(is (true? (.get (nth resp 1))))
- (is (false? (.get (nth resp 2)))))))
+ (is (false? (.get (nth resp 2))))))
-(deftest test-incr
- (testing "Increment"
- (is (= -1 (.incr mc "n")))
- (.get (.put mc "n" 0))
- (is (= 1 (.incr mc "n")))
- (is (= 11 (.incr mc "n" 10)))
- (is (= 0 (.incr mc "m" 1 0)))))
+(defn do-test-incr [mc]
+ (is (= -1 (incr mc "n")))
+ (.get (put mc "n" "0"))
+ (is (= 1 (incr mc "n")))
+ (is (= 11 (incr mc "n" 10)))
+ (is (= 0 (incr mc "m" 1 0))))
-(deftest test-decr
- (testing "Decrement"
- (is (= -1 (.decr mc "nn")))
- (.get (.put mc "nn" 0))
- (is (= 0 (.decr mc "nn")))
- (is (= 10 (.decr mc "mm" 1 10)))
- (is (= 9 (.decr mc "mm")))
- (is (= 6 (.decr mc "mm" 3)))))
+(defn do-test-decr [mc]
+ (is (= -1 (decr mc "nn")))
+ (.get (put mc "nn" 0))
+ (is (= 0 (decr mc "nn")))
+ (is (= 10 (decr mc "mm" 1 10)))
+ (is (= 9 (decr mc "mm")))
+ (is (= 6 (decr mc "mm" 3))))
-(deftest test-get-all
- (testing "Get list of keys"
- (.get (.put mc "a" 1))
- (.get (.put mc "b" 2))
- (.get (.put mc "c" "three"))
- (let [results (.fetch-all mc ["a" "b" "c" "d"])]
+(defn do-test-get-all [mc]
+ (.get (put mc "a" 1))
+ (.get (put mc "b" 2))
+ (.get (put mc "c" "three"))
+ (let [results (fetch-all mc ["a" "b" "c" "d"])]
(is (= 1 (get results "a")))
(is (= 2 (get results "b")))
(is (= "three" (get results "c")))
- (is (nil? (get results "d"))))))
+ (is (nil? (get results "d")))))
-(deftest test-with-cache
- (testing "with-cache macro"
+(defn do-test-with-cache [mc]
(letfn [(qfcn [id]
(if (< (Integer/parseInt id) 100)
(str "foo" id)
nil))]
(is (nil? (with-cache mc "200" qfcn)))
(is (= "foo50" (with-cache mc "50" qfcn)))
- (is (= "foo50" (.lookup mc "50")))
- (is (= "foo50" (with-cache mc "50" qfcn))))))
+ (is (= "foo50" (fetch mc "50")))
+ (is (= "foo50" (with-cache mc "50" qfcn)))))
-(deftest test-cache-fetch
- (testing "Cached fetch"
+(defn do-test-cache-fetch [mc]
(letfn [(qfcn [id]
(if (< id 100)
(str "foo" id)
nil))]
(is (nil? (cache-fetch mc 200 qfcn str)))
(is (= "foo50" (cache-fetch mc 50 qfcn str)))
- (is (= "foo50" (.lookup mc "50")))
- (is (= "foo50" (cache-fetch mc 50 qfcn str))))))
+ (is (= "foo50" (fetch mc "50")))
+ (is (= "foo50" (cache-fetch mc 50 qfcn str)))))
-(deftest test-cache-fetch-all
- (testing "Cached fetch"
+(defn do-test-cache-fetch-all [mc]
(letfn [(qfcn [ids]
(zipmap ids (map
#(if (< % 100)
@@ -187,6 +171,131 @@
(is (= {1 "foo1" 4 "foo4" 5 "foo5" 6 "foo6"}
(cache-fetch-all mc [1 4 120 5 300 6] qfcn str)))
(is (= {1 "foo1" 5 "foo5" 19 "foo19"}
- (cache-fetch-all mc [1 120 5 19] qfcn str))))))
+ (cache-fetch-all mc [1 120 5 19] qfcn str)))))
+
+
+;;;;;;;;;;;;;;;;;;;
+
+;; Unit tests for MemcachedClient extending the Memcache protocol
+
+(deftest test-put-if-absent
+ (testing "put-if-absent"
+ (do-test-put-if-absent spy)))
+
+(deftest test-put-all-if-absent
+ (testing "Add multiple items to cache"
+ (do-test-put-all-if-absent spy)))
+
+(deftest test-put
+ (testing "Put into cache"
+ (do-test-put spy)))
+
+(deftest test-put-all
+ (testing "Put multiple into cache"
+ (do-test-put-all spy)))
+
+(deftest test-put-if-present
+ (testing "Replace in cache"
+ (do-test-put-if-present spy)))
+
+(deftest test-put-all-if-present ;;;;;
+ (testing "Replace multiple"
+ (do-test-put-all-if-present spy)))
+
+(deftest test-delete
+ (testing "Delete"
+ (do-test-delete spy)))
+
+(deftest test-delete-all
+ (testing "Delete all"
+ (do-test-delete-all spy)))
+
+(deftest test-incr
+ (testing "Increment"
+ (do-test-incr spy)))
+
+(deftest test-decr
+ (testing "Decrement"
+ (do-test-decr spy)))
+
+(deftest test-get-all
+ (testing "Get list of keys"
+ (do-test-get-all spy)))
+
+(deftest test-with-cache
+ (testing "with-cache macro"
+ (do-test-with-cache spy)))
+
+(deftest test-cache-fetch
+ (testing "Cached fetch"
+ (do-test-cache-fetch spy)))
+
+(deftest test-cache-fetch-all
+ (testing "Cached fetch"
+ (do-test-cache-fetch-all spy)))
+
+
+;; now test MemcachedCache, which integrates the same functionality
+;; into clojure.core.cache
+
+(deftest test-lookup-cache
+ (testing "lookup"
+ (do-test-lookup mc)))
+
+(deftest test-put-if-absent-cache
+ (testing "put-if-absent"
+ (do-test-put-if-absent mc)))
+
+(deftest test-put-all-if-absent-cache
+ (testing "Add multiple items to cache"
+ (do-test-put-all-if-absent mc)))
+
+(deftest test-put-cache
+ (testing "Put into cache"
+ (do-test-put mc)))
+
+(deftest test-put-all-cache
+ (testing "Put multiple into cache"
+ (do-test-put-all mc)))
+
+(deftest test-put-if-present-cache
+ (testing "Replace in cache"
+ (do-test-put-if-present mc)))
+
+(deftest test-put-all-if-present ;;;;;
+ (testing "Replace multiple"
+ (do-test-put-all-if-present mc)))
+
+(deftest test-delete-cache
+ (testing "Delete"
+ (do-test-delete mc)))
+
+(deftest test-delete-all-cache
+ (testing "Delete all"
+ (do-test-delete-all mc)))
+
+(deftest test-incr-cache
+ (testing "Increment"
+ (do-test-incr mc)))
+
+(deftest test-decr-cache
+ (testing "Decrement"
+ (do-test-decr mc)))
+
+(deftest test-get-all-cache
+ (testing "Get list of keys"
+ (do-test-get-all mc)))
+
+(deftest test-with-cache-cache
+ (testing "with-cache macro"
+ (do-test-with-cache mc)))
+
+(deftest test-cache-fetch-cache
+ (testing "Cached fetch"
+ (do-test-cache-fetch mc)))
+
+(deftest test-cache-fetch-all-cache
+ (testing "Cached fetch"
+ (do-test-cache-fetch-all mc)))
Please sign in to comment.
Something went wrong with that request. Please try again.