From 791706cbdc00bc51b719e246dc53f914fb816454 Mon Sep 17 00:00:00 2001 From: Efrain Date: Thu, 26 Mar 2015 13:24:31 +0000 Subject: [PATCH] Updated all the dependencies. Updated the code docs and tests accordingly. --- README.md | 4 +-- project.clj | 10 +++--- src/saolsen/steveskeys.clj | 14 ++++----- src/saolsen/steveskeys/file.clj | 37 ++++++++++++----------- test/saolsen/steveskeys/btree_test.clj | 42 +++++++++++++------------- test/saolsen/steveskeys/file_test.clj | 6 ++-- 6 files changed, 57 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 0ad55ab..343585f 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,9 @@ Ways this differs from a scala requirments. on is still safe and unchanged. This allows reads and writes to happen without blocking eachother and without any locking. (persistant data structures are awesome) * The nodes themselves are serialized and stored in a file. First the length of the serialized - node is written to the file (this is an int that serializes to 7 bytes) then the byte data of + node is written to the file (this is an int that serializes to 14 bytes) then the byte data of the node is written. The location in the file is returned (and stored in other nodes as pointers) - When a node is read from the file first 7 bytes are read from the location to get the size and then + When a node is read from the file first 14 bytes are read from the location to get the size and then that many bytes are read and deserialized to get the node. The reader and the writer each use a different file object so the random access jumping around of reads does not hinder the high throughput that linear writes to the end of the file has. diff --git a/project.clj b/project.clj index 53d17e1..96148b4 100644 --- a/project.clj +++ b/project.clj @@ -1,8 +1,8 @@ -(defproject steveskeys "0.1.0" +(defproject steveskeys "0.2.0" :description "file backed key value store" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[org.clojure/clojure "1.4.0"] - [org.clojure/math.numeric-tower "0.0.1"] - [com.google.guava/guava "10.0.1"] - [com.taoensso/nippy "1.0.0"]]) + :dependencies [[org.clojure/clojure "1.6.0"] + [org.clojure/math.numeric-tower "0.0.4"] + [com.google.guava/guava "18.0"] + [com.taoensso/nippy "2.8.0"]]) diff --git a/src/saolsen/steveskeys.clj b/src/saolsen/steveskeys.clj index 27f0495..f2274d8 100644 --- a/src/saolsen/steveskeys.clj +++ b/src/saolsen/steveskeys.clj @@ -14,8 +14,8 @@ (defrecord DiskStore [fs keys vals] PDiskStore (put! [_ key value] - (let [k (n/freeze-to-bytes key) - v (n/freeze-to-bytes value)] + (let [k (n/freeze key) + v (n/freeze value)] (if-let [val (get @vals v)] (swap! keys assoc k val) (let [new-val (file/write-node fs v)] @@ -24,10 +24,10 @@ true)) (get! [_ key option] - (let [k (n/freeze-to-bytes key) + (let [k (n/freeze key) v (get @keys k) val (file/read-node fs v)] - (n/thaw-from-bytes val))) + (n/thaw val))) (flush! [_] (file/commit fs (btree/get-root-loc @keys) (btree/get-root-loc @vals)) @@ -35,10 +35,10 @@ (traverse [_ start end] (let [kvps (btree/traverse @keys - (n/freeze-to-bytes start) - (n/freeze-to-bytes end)) + (n/freeze start) + (n/freeze end)) get-kv (map #(vector (:key %) (file/read-node fs (:val %))) kvps) - to-vals (map #(map n/thaw-from-bytes %) get-kv)] + to-vals (map #(map n/thaw %) get-kv)] (reduce #(conj %1 (first %2) (second %2)) [] to-vals))) ) diff --git a/src/saolsen/steveskeys/file.clj b/src/saolsen/steveskeys/file.clj index 78679a4..d3300b9 100644 --- a/src/saolsen/steveskeys/file.clj +++ b/src/saolsen/steveskeys/file.clj @@ -7,7 +7,7 @@ ;; ;; {:keys pointer :vals pointer} ;; -;; This when serialized by nippy takes up 31 bytes so the first 62 bytes of the +;; This when serialized by nippy takes up 37 bytes so the first 62 bytes of the ;; file are the two headers. The second header is written to first. If the ;; program fails during this write the first header will still contain the last ;; flush's root. Then the first header is written to, if the program fails @@ -38,14 +38,14 @@ (defn try-thaw [bytes] (try - (nippy/thaw-from-bytes bytes) + (nippy/thaw bytes) (catch Exception e nil))) (defn read-headers "reads the two headers" [f] - (let [b1 (byte-array 31) - b2 (byte-array 31)] + (let [b1 (byte-array 37) + b2 (byte-array 37)] (doto f (.seek 0) (.read b1) @@ -58,18 +58,19 @@ PFileManager (read-node [_ pointer] (.seek reader pointer) - (let [b1 (byte-array 7)] + (let [b1 (byte-array 14)] (.read reader b1) - (let [size (nippy/thaw-from-bytes b1) + (let [size (nippy/thaw b1) b2 (byte-array size)] (.read reader b2) - (nippy/thaw-from-bytes b2)))) + (nippy/thaw b2)))) (write-node [_ node] - (let [frozen (nippy/freeze-to-bytes node) - len (nippy/freeze-to-bytes (int (count frozen))) + (let [frozen (nippy/freeze node) + len (nippy/freeze (int (count frozen))) tail (.length writer)] - (assert (= (count len) 7)) + ;(println "Efrain node:" node "frozen:" frozen "len:" len "tail:" tail "count:" (count len)) + (assert (= (count len) 14)) (doto writer (.seek tail) (.write len) @@ -78,10 +79,10 @@ (commit [_ keys-root vals-root] (let [header {:keys (int keys-root) :vals (int vals-root)} - b (nippy/freeze-to-bytes header)] - (assert (= (count b) 31)) + b (nippy/freeze header)] + (assert (= (count b) 37)) (.close reader) - (write-header-and-close writer 31 b) + (write-header-and-close writer 37 b) (write-header-and-close (java.io.RandomAccessFile. filename "rws") 0 b) (FileManager. filename (java.io.RandomAccessFile. filename "rws") @@ -95,18 +96,18 @@ head1 ;; copy head1 to head2, return head1 (do - (.seek writer 31) - (.write writer (nippy/freeze-to-bytes head1)) + (.seek writer 37) + (.write writer (nippy/freeze head1)) head1)) (if head2 ;; copy head2 to head1, return head2 (do (.seek writer 0) - (.write writer (nippy/freeze-to-bytes head2)) + (.write writer (nippy/freeze head2)) head2) ;; database isn't initialized, write nil heads - (let [n (nippy/freeze-to-bytes {:keys (int 0) :vals (int 0)})] - (assert (= (count n) 31)) + (let [n (nippy/freeze {:keys (int 0) :vals (int 0)})] + (assert (= (count n) 37)) (.seek writer 0) (.write writer n) (.write writer n) diff --git a/test/saolsen/steveskeys/btree_test.clj b/test/saolsen/steveskeys/btree_test.clj index 9a37fa2..934fd35 100644 --- a/test/saolsen/steveskeys/btree_test.clj +++ b/test/saolsen/steveskeys/btree_test.clj @@ -6,20 +6,20 @@ ;; Manually built tree for testing the search (def test-nodes { - :root (->BPlusTreeNode [{:key (nippy/freeze-to-bytes 2) :val :a} - {:key (nippy/freeze-to-bytes 5) :val :b} - {:key (nippy/freeze-to-bytes 9) :val :c} + :root (->BPlusTreeNode [{:key (nippy/freeze 2) :val :a} + {:key (nippy/freeze 5) :val :b} + {:key (nippy/freeze 9) :val :c} {:key nil :val :d}]) - :a (->BPlusTreeLeaf [{:key (nippy/freeze-to-bytes 1) :val "one"} - {:key (nippy/freeze-to-bytes 2) :val "two"}]) - :b (->BPlusTreeLeaf [{:key (nippy/freeze-to-bytes 3) :val "three"} - {:key (nippy/freeze-to-bytes 4) :val "four"} - {:key (nippy/freeze-to-bytes 5) :val "five"}]) - :c (->BPlusTreeLeaf [{:key (nippy/freeze-to-bytes 6) :val "six"} - {:key (nippy/freeze-to-bytes 7) :val "seven"} - {:key (nippy/freeze-to-bytes 8) :val "eight"} - {:key (nippy/freeze-to-bytes 9) :val "nine"}]) - :d (->BPlusTreeLeaf [{:key (nippy/freeze-to-bytes 10) :val "ten"}]) + :a (->BPlusTreeLeaf [{:key (nippy/freeze 1) :val "one"} + {:key (nippy/freeze 2) :val "two"}]) + :b (->BPlusTreeLeaf [{:key (nippy/freeze 3) :val "three"} + {:key (nippy/freeze 4) :val "four"} + {:key (nippy/freeze 5) :val "five"}]) + :c (->BPlusTreeLeaf [{:key (nippy/freeze 6) :val "six"} + {:key (nippy/freeze 7) :val "seven"} + {:key (nippy/freeze 8) :val "eight"} + {:key (nippy/freeze 9) :val "nine"}]) + :d (->BPlusTreeLeaf [{:key (nippy/freeze 10) :val "ten"}]) :one "one" :two "two" :three "three" @@ -50,27 +50,27 @@ isn't in the tree it returns nil" [tree ks vs] (doseq [[k v] (map #(vector %1 %2) ks vs)] - (let [result (get tree (nippy/freeze-to-bytes k))] + (let [result (get tree (nippy/freeze k))] (is (= result v)))) - (is (= (get tree (nippy/freeze-to-bytes 100)) nil))) + (is (= (get tree (nippy/freeze 100)) nil))) (defn test-ranges "checks that a bunch of ranges work, assumes ks and vs are the only things in the tree" [tree ks vs] (dotimes [n 30] - (let [rks (map nippy/freeze-to-bytes ks) + (let [rks (map nippy/freeze ks) len (count ks) n (rand-int len) m (+ (rand-int (- len n)) n) keys (take (- (inc m) n) (drop n ks)) vals (take (- (inc m) n) (drop n vs)) kvps (map #(hash-map :key %1 :val %2) keys vals) - start (nippy/freeze-to-bytes (nth ks n)) - end (nippy/freeze-to-bytes (nth ks m)) + start (nippy/freeze (nth ks n)) + end (nippy/freeze (nth ks m)) traversal (traverse tree start end) checks (map #(and - (bequals (:key %1) (nippy/freeze-to-bytes (:key %2))) + (bequals (:key %1) (nippy/freeze (:key %2))) (= (:val %1) (:val %2))) traversal kvps)] (is (= (count kvps) (count traversal))) (doseq [check checks] @@ -99,14 +99,14 @@ id)) 4) s (flatten - (shuffle (map #(vector (nippy/freeze-to-bytes %1) %2) ks2 vs2))) + (shuffle (map #(vector (nippy/freeze %1) %2) ks2 vs2))) added (apply (partial assoc tree) s) _ (test-they-all-exist added ks2 vs2) _ (test-ranges added ks2 vs2) ;; test that after tree is made, duplicates can be replaced correctly t (flatten - (shuffle (map #(vector (nippy/freeze-to-bytes %1) %2) ks vs))) + (shuffle (map #(vector (nippy/freeze %1) %2) ks vs))) added-more (apply (partial assoc added) t) ] (test-they-all-exist added-more ks vs)))) diff --git a/test/saolsen/steveskeys/file_test.clj b/test/saolsen/steveskeys/file_test.clj index 772aa71..1c1a75c 100644 --- a/test/saolsen/steveskeys/file_test.clj +++ b/test/saolsen/steveskeys/file_test.clj @@ -5,14 +5,14 @@ ;; goodfirst has a root node of 0 as the first header and shit for the second (deftest test-recovering (testing "Making sure that it can recover from one of the header being bad") - (let [bad-buffer (byte-array 31 (map byte (range 10))) - fine-header (taoensso.nippy/freeze-to-bytes + (let [bad-buffer (byte-array 37 (map byte (range 10))) + fine-header (taoensso.nippy/freeze {:keys (int 5) :vals (int 3)}) f1 (java.io.File. "testdata/goodfirst") f2 (java.io.File. "testdata/goodsecond") raf1 (java.io.RandomAccessFile. f1 "rw") raf2 (java.io.RandomAccessFile. f2 "rw")] - (is (= (count fine-header) 31)) + (is (= (count fine-header) 37)) (.createNewFile f1) (.createNewFile f2) (.seek raf1 0)