Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implement randomized merging

  • Loading branch information...
commit c0c06c00567e7c359ac5c2a803cd40d1326e3d96 1 parent c5b83dc
@michaelklishin authored
View
4 project.clj
@@ -2,13 +2,13 @@
:description "A yet another consistent hashing library for Clojure"
:dependencies [[org.clojure/clojure "1.4.0"]
[clojurewerkz/support "0.7.0-beta2"]]
- :profiles {:1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]}
+ :profiles {:1.3 {:dependencies [[org.clojure/clojure "1.3.0"]]}
:1.5 {:dependencies [[org.clojure/clojure "1.5.0-master-SNAPSHOT"]]}
:dev {:resource-paths ["test/resources"]
:plugins [[codox "0.6.1"]]
:codox {:sources ["src/clojure"]
:output-dir "doc/api"}}}
- :aliases {"all" ["with-profile" "dev:dev,1.4:dev,1.5"]}
+ :aliases {"all" ["with-profile" "dev:dev,1.3:dev,1.5"]}
:repositories {"sonatype" {:url "http://oss.sonatype.org/content/repositories/releases"
:snapshots false
:releases {:checksum :fail}}
View
12 src/clojure/clojurewerkz/chash/proplists.clj
@@ -42,9 +42,13 @@
[plist]
(set (sort (doall (map second plist)))))
+(defn index-of
+ [plist k]
+ (count (take-while (fn [[k' v]]
+ (not (= k' k))) plist)))
+
(defn assoc
[plist k v]
- (let [[before _ after] (partition-by (fn [[k' v]]
- (= k' k))
- plist)]
- (concat before [[k v]] after)))
+ (let [i (index-of plist k)
+ [before after] (split-at i plist)]
+ (concat before [[k v]] (rest after))))
View
55 src/clojure/clojurewerkz/chash/core.clj → src/clojure/clojurewerkz/chash/ring.clj
@@ -1,4 +1,4 @@
-(ns clojurewerkz.chash.core
+(ns clojurewerkz.chash.ring
(:refer-clojure :exclude [get merge count contains?])
(:require [clojurewerkz.support.hashing :as h]
[clojurewerkz.support.core :as c]
@@ -15,10 +15,10 @@
[^long n]
(quot ring-top n))
-(defrecord CHash [^long n-partitions ^clojure.lang.IPersistentList claims])
+(defrecord Ring [^long n-partitions ^clojure.lang.IPersistentList claims])
(defn max-n
- [^CHash chash ^long l]
+ [^Ring chash ^long l]
(min (.n-partitions chash) l))
@@ -27,59 +27,68 @@
;;
(defn contains?
- [chash node]
- )
+ [^Ring chash node]
+ (pl/contains? (.claims chash) node))
-(defn ^CHash fresh
+(defn ^Ring fresh
[^long n seed]
(let [delta (ring-increment n)
xs (doall (range 0 ring-top delta))]
- (CHash. n (reduce (fn [plist p]
+ (Ring. n (reduce (fn [plist p]
(conj plist [p seed]))
[] xs))))
(defn get
- [^CHash chash idx]
- )
+ [^Ring chash idx]
+ (pl/get (.claims chash) idx))
(defn ^bytes key-of
[value]
(.asLong (h/sha1-of value)))
(defn claims
- [^CHash chash]
+ [^Ring chash]
(.claims chash))
(defn claimants
- [^CHash chash]
+ [^Ring chash]
(pl/vals (.claims chash)))
(defn partitions
- [^CHash chash]
+ [^Ring chash]
(pl/keys (.claims chash)))
(defn claimant?
- [^CHash chash node]
+ [^Ring chash node]
(some #{node} (claimants chash)))
(defn count
- [^CHash chash]
+ [^Ring chash]
(.n-partitions chash))
+(defn- random-of
+ [& xs]
+ (rand-nth xs))
+
(defn merge
- [^CHash one ^CHash another]
- (comment TODO))
+ [^Ring one ^Ring another]
+ (if (= (count one) (count another))
+ (let [pairs (partition 2 (interleave (.claims one) (.claims another)))
+ merged (for [[a b] pairs]
+ (random-of a b))]
+ (Ring. (count one) merged))
+ (throw (IllegalArgumentException. "cannot merge two rings with different numbers of partitions"))))
(defn next-index
- [^CHash chash idx]
+ [^Ring chash idx]
(let [n (.n-partitions chash)
i (ring-increment n)]
(* i (rem (inc (quot idx i)) n))))
(defn predecessors
- ([^CHash chash idx]
+ ([^Ring chash idx]
(predecessors chash idx (.n-partitions chash)))
- ([^CHash chash idx n]
+ ([^Ring chash idx n]
(let [n' (max-n chash n)
i (ring-increment (.n-partitions chash))
;; split index
@@ -90,9 +99,9 @@
(take n' ordered))))
(defn successors
- ([^CHash chash idx]
+ ([^Ring chash idx]
(successors chash idx (.n-partitions chash)))
- ([^CHash chash idx n]
+ ([^Ring chash idx n]
(let [n' (max-n chash n)
i (ring-increment (.n-partitions chash))
;; split index
@@ -105,5 +114,5 @@
(take n' ordered)))))
(defn update
- [^CHash chash idx node]
- (CHash. (.n-partitions chash) (pl/assoc (.claims chash) idx node)))
+ [^Ring chash idx node]
+ (Ring. (.n-partitions chash) (pl/assoc (.claims chash) idx node)))
View
62 test/clojurewerkz/chash/proplists_test.clj
@@ -21,28 +21,28 @@
(testing "2-arity"
(let [p (pl/create :a 1 :b 2 :c 3 :d 4 :e 5)]
(are [k v] (is (= v (pl/get p k)))
- :a 1
- :b 2
- :c 3
- :d 4
- :e 5)))
+ :a 1
+ :b 2
+ :c 3
+ :d 4
+ :e 5)))
(testing "3-arity"
(let [p (pl/create :a 1 :b 2 :c 3 :d 4 :e 5)]
(are [k v] (is (= v (pl/get p k)))
- :a 1
- :b 2
- :c 3
- :d 4
- :e 5)
+ :a 1
+ :b 2
+ :c 3
+ :d 4
+ :e 5)
(is (= :default (pl/get p :z :default))))))
(deftest test-contains?
(let [p (pl/create :a 1 :b 2 :c 3 :d 4 :e 5)]
(are [k] (is (pl/contains? p k))
- :a :b :c :d :e)
+ :a :b :c :d :e)
(are [k] (is (not (pl/contains? p k)))
- :w :x :y :z :lol)))
+ :w :x :y :z :lol)))
(deftest test-keys
@@ -54,6 +54,38 @@
(is (= #{1 2 3 4 5} (pl/vals p)))))
(deftest test-assoc
- (let [p1 (pl/create :a 1 :b 2 :c 3 :d 4 :e 5)
- p2 (pl/create :a 1 :b 2 :c 30 :d 4 :e 5)]
- (is (= p2 (pl/assoc p1 :c 30)))))
+ (testing "case 1"
+ (let [p1 (pl/create :a 1 :b 2 :c 3 :d 4 :e 5)
+ p2 (pl/create :a 1 :b 2 :c 30 :d 4 :e 5)]
+ (is (= p2 (pl/assoc p1 :c 30)))))
+ (testing "case 2"
+ (let [p1 (pl/create 0 "node@giove.local"
+ 1.8268770466636286E47 "node@giove.local"
+ 3.6537540933272573E47 "node@giove.local"
+ 5.480631139990886E47 "node@giove.local"
+ 7.3075081866545146E47 "node@giove.local"
+ 9.134385233318143E47 "node@giove.local"
+ 1.0961262279981772E48 "node@giove.local"
+ 1.27881393266454E48 "node@giove.local")
+ p2 (pl/create 0 "another@giove.local"
+ 1.8268770466636286E47 "node@giove.local"
+ 3.6537540933272573E47 "node@giove.local"
+ 5.480631139990886E47 "node@giove.local"
+ 7.3075081866545146E47 "node@giove.local"
+ 9.134385233318143E47 "node@giove.local"
+ 1.0961262279981772E48 "node@giove.local"
+ 1.27881393266454E48 "node@giove.local")]
+ (is (= p2 (pl/assoc p1 0 "another@giove.local"))))))
+
+(deftest test-index-of
+ (let [p (pl/create :a 1 :b 2 :c 3 :d 4)]
+ (are [idx k] (is (= idx (pl/index-of p k)))
+ 0 :a
+ 1 :b
+ 2 :c
+ 3 :d)))
+
+(deftest test-rand-nth
+ (let [p (pl/create :a 1 :b 2 :c 3 :d 4 :e 5)
+ n (rand-nth p)]
+ (is n)))
View
27 test/clojurewerkz/chash/core_test.clj → test/clojurewerkz/chash/ring_test.clj
@@ -1,5 +1,5 @@
-(ns clojurewerkz.chash.core-test
- (:require [clojurewerkz.chash.core :as ch])
+(ns clojurewerkz.chash.ring-test
+ (:require [clojurewerkz.chash.ring :as ch])
(:use clojure.test))
@@ -138,5 +138,26 @@
(let [n 8
seed "node1@giove.local"
r (ch/fresh n seed)]
- (is (ch/partitions r) 1.8268770466636286E47)
+ (is (ch/partitions r) #{1.8268770466636286E47})
(is (= 1.8268770466636286E47 (ch/next-index r (ch/key-of 1))))))
+
+
+(deftest test-get
+ (let [n 8
+ seed "node@giove.local"
+ alt "node2@giove.local"
+ idx 1.8268770466636286E47
+ r (ch/fresh n seed)
+ r' (ch/update r idx alt)]
+ (is (= seed (ch/get r idx)))
+ (is (= alt (ch/get r' idx)))))
+
+
+(deftest test-merge
+ (let [n 8
+ node1 "node1@giove.local"
+ node2 "node2@giove.local"
+ r1 (ch/fresh n node1)
+ r2 (ch/update (ch/fresh n node2) 0 node1)
+ r3 (ch/merge r1 r2)]
+ (is (= node1 (ch/get r3 0)))))
Please sign in to comment.
Something went wrong with that request. Please try again.