Skip to content

Commit cbc0763

Browse files
author
Andy Chambers
committed
Rename SQLite->JDBC; Add data structure docs for JDCB backend
1 parent 839f110 commit cbc0763

File tree

3 files changed

+57
-38
lines changed

3 files changed

+57
-38
lines changed

env/profiling/hitchhiker/bench.clj

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
(:require [clojure.pprint :as pp]
33
[clojure.string :as str]
44
[clojure.tools.cli :refer [parse-opts]]
5-
[clojure.java.jdbc :as jdbc]
65
[excel-templates.build :as excel]
76
[hitchhiker.redis :as redis]
8-
[hitchhiker.sqlite :as sqlite]
7+
[hitchhiker.jdbc :as jdbc]
98
[hitchhiker.tree.core :as core]
109
[hitchhiker.tree.messaging :as msg])
1110
(:import [java.io File FileWriter]))
@@ -131,7 +130,7 @@
131130
:validate [#(#{"fractal" "b-tree" "sorted-set"} %) "Data structure must be fractal, b-tree, or sorted set"]]
132131
[nil "--backend testing" "Runs the benchmark with the specified backend"
133132
:default "testing"
134-
:validate [#(#{"redis" "sqlite" "testing"} %) "Backend must be redis, sqlite or testing"]]
133+
:validate [#(#{"redis" "jdbc" "testing"} %) "Backend must be redis, jdbc or testing"]]
135134
["-d" "--delete-pattern PATTERN" "Specifies how the operations will be reordered on delete"
136135
:default "forward"
137136
:validate [#(#{"forward" "reverse" "shuffle" "zero"} %) "Incorrect delete pattern"]
@@ -218,8 +217,8 @@
218217
"testing" (core/->TestingBackend)
219218
"redis" (do (redis/start-expiry-thread!)
220219
(redis/->RedisBackend))
221-
"sqlite" (sqlite/->SQLiteBackend
222-
(sqlite/find-or-create-db "/tmp/yolo.sqlite")))
220+
"jdbc" (jdbc/->JDBCBackend
221+
(jdbc/find-or-create-db "/tmp/yolo.sqlite")))
223222
delete-xform (case (:delete-pattern options)
224223
"forward" identity
225224
"reverse" reverse

src/hitchhiker/sqlite.clj src/hitchhiker/jdbc.clj

+44-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
(ns hitchhiker.sqlite
1+
(ns hitchhiker.jdbc
22
(:require [clojure.java.jdbc :as jdbc]
33
[clojure.edn :as edn]
44
[clojure.string :as str]
@@ -8,6 +8,27 @@
88
[taoensso.nippy :as nippy])
99
(:import [java.sql SQLException]))
1010

11+
;;; References in a Relational DB
12+
;;;
13+
;;; The SQLite backend uses a simple relational model to keep track of
14+
;;; keys and their references. Each key is listed in hh_keys, and whenever
15+
;;; we'd like to have some key point to another, we call add-refs with the
16+
;;; "pointer" key and a list of pointee keys. For each pointee, add-refs will
17+
;;; add a `(pointer, pointee)` tuple in hh_refs.
18+
;;;
19+
;;; hh_keys
20+
;;; k the name of the key
21+
;;; v a binary blob representing the value of `k`
22+
;;;
23+
;;; hh_refs
24+
;;; pointer the name of the pointer key
25+
;;; pointee the name of the pointee key
26+
;;;
27+
;;; To delete a key, use `drop-key` which also takes care of deleting any
28+
;;; keys that are only hanging around because they point to the key being
29+
;;; deleted.
30+
;;;
31+
1132
(defn underscore [x]
1233
(str/replace (str x) "-" "_"))
1334

@@ -18,28 +39,28 @@
1839
{:entities underscore})
1940

2041
:hh-ref (jdbc/create-table-ddl :hh-ref
21-
[[:parent :string "references hh_key(k) on delete cascade"]
22-
[:child :string "references hh_key(k) on delete cascade"]]
42+
[[:pointer :string "references hh_key(k) on delete cascade"]
43+
[:pointee :string "references hh_key(k) on delete cascade"]]
2344
{:entities underscore})
2445

25-
:hh-ref-by-parent "create index if not exists hh_ref_by_parent on hh_ref (parent);"
26-
:hh-ref-by-child "create index if not exists hh_ref_by_child on hh_ref (child);"})
46+
:hh-ref-by-pointer "create index if not exists hh_ref_by_pointer on hh_ref (pointer);"
47+
:hh-ref-by-pointee "create index if not exists hh_ref_by_pointee on hh_ref (pointee);"})
2748

2849
(def query
2950
{:table-exists? "select 1 from sqlite_master where type='table' and name=?"
3051
:index-exists? "select 1 from sqlite_master where type='index' and name=?"
3152
:find-key "select * from hh_key where k=?"
3253
:dead-keys "select k
3354
from hh_key
34-
where k not in ( select child from hh_ref )"})
55+
where k not in ( select pointee from hh_ref )"})
3556

36-
(defn drop-ref [db key]
57+
(defn drop-key [db key]
3758
(jdbc/delete! db :hh-key ["k = ?" key]
3859
{:entities underscore})
3960

4061
(let [dead-keys (jdbc/query db (query :dead-keys))]
4162
(doseq [{:keys [k] :as dead-key} dead-keys]
42-
(drop-ref db k))))
63+
(drop-key db k))))
4364

4465

4566
(defn db-spec [subname]
@@ -93,7 +114,7 @@
93114
:exists? table-exists?
94115
:create! create-table})
95116

96-
(ensure {:items [:hh-ref-by-parent :hh-ref-by-child]
117+
(ensure {:items [:hh-ref-by-pointer :hh-ref-by-pointee]
97118
:exists? index-exists?
98119
:create! create-index})
99120

@@ -126,18 +147,18 @@
126147
(defn delete-key [db k]
127148
(jdbc/delete! :hh-key ["k = ?" k]))
128149

129-
(defn add-refs [db {:keys [parent children]}]
130-
(let [mk-ref (fn [child]
131-
[parent child])]
150+
(defn add-refs [db {:keys [pointer pointees]}]
151+
(let [mk-ref (fn [pointee]
152+
[pointer pointee])]
132153
(try
133-
(jdbc/insert-multi! db :hh-ref (for [child children]
134-
{:parent parent
135-
:child child})
154+
(jdbc/insert-multi! db :hh-ref (for [pointee pointees]
155+
{:pointer pointer
156+
:pointee pointee})
136157
{:entities underscore})
137158
(catch Exception e
138-
(throw (ex-info "Failed to link parent with children"
139-
{:parent parent
140-
:children children}
159+
(throw (ex-info "Failed to link pointer with pointees"
160+
{:pointer pointer
161+
:pointee pointees}
141162
e))))))
142163

143164
(defn synthesize-storage-addr
@@ -199,7 +220,7 @@
199220
redis-key (nippy/thaw-from-in! data-input)]
200221
(sqlite-addr last-key redis-key)))
201222

202-
(defrecord SQLiteBackend [db]
223+
(defrecord JDBCBackend [db]
203224
core/IBackend
204225
(new-session [_] (atom {:writes 0
205226
:deletes 0}))
@@ -219,10 +240,10 @@
219240
(binding [*db* tx]
220241
(add-node db {:k key, :v node})
221242
(when (core/index-node? node)
222-
(add-refs db {:parent key
223-
:children (for [child (:children node)
224-
:let [child-key @(:storage-addr child)]]
225-
child-key)}))))
243+
(add-refs db {:pointer key
244+
:pointees (for [pointee (:pointees node)
245+
:let [pointee-key @(:storage-addr pointee)]]
246+
pointee-key)}))))
226247

227248
(seed-cache! key (doto (promise)
228249
(deliver node)))

test/hitchhiker/sqlite_test.clj test/hitchhiker/jdbc_test.clj

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
(ns hitchhiker.sqlite-test
1+
(ns hitchhiker.jdbc-test
22
(:require [clojure.test.check.clojure-test :refer [defspec]]
33
[clojure.test.check.generators :as gen]
44
[clojure.test.check.properties :as prop]
5-
[hitchhiker.sqlite :as sqlite]
5+
[hitchhiker.jdbc :as jdbc]
66
[hitchhiker.tree.core :as core]
77
hitchhiker.tree.core-test
8-
[hitchhiker.tree.messaging :as msg]
9-
[clojure.java.jdbc :as jdbc]))
8+
[hitchhiker.tree.messaging :as msg]))
109

1110
(defn insert
1211
[t k]
@@ -20,23 +19,23 @@
2019
"This is like the basic mixed-op-seq tests, but it also mixes in flushes to sqlite
2120
and automatically deletes the old tree"
2221
[add-freq del-freq flush-freq universe-size num-ops]
23-
(let [db (sqlite/find-or-create-db "/tmp/yolo.sqlite")]
22+
(let [db (jdbc/find-or-create-db "/tmp/yolo.sqlite")]
2423
(prop/for-all [ops (gen/vector (gen/frequency
2524
[[add-freq (gen/tuple (gen/return :add)
2625
(gen/no-shrink gen/int))]
2726
[flush-freq (gen/return [:flush])]
2827
[del-freq (gen/tuple (gen/return :del)
2928
(gen/no-shrink gen/int))]])
3029
40)]
31-
(assert (empty? (sqlite/list-keys db))
30+
(assert (empty? (jdbc/list-keys db))
3231
"Start with no keys")
3332
(let [[b-tree root set]
3433
(reduce (fn [[t root set] [op x]]
3534
(let [x-reduced (when x (mod x universe-size))]
3635
(condp = op
37-
:flush (let [t (:tree (core/flush-tree t (sqlite/->SQLiteBackend db)))]
36+
:flush (let [t (:tree (core/flush-tree t (jdbc/->JDBCBackend db)))]
3837
(when root
39-
(sqlite/drop-ref db root))
38+
(jdbc/drop-key db root))
4039
#_(println "flush" root)
4140
[t @(:storage-addr t) set])
4241
:add (do #_(println "add" x) [(insert t x-reduced) root (conj set x-reduced)])
@@ -47,8 +46,8 @@
4746
(let [b-tree-order (lookup-fwd-iter b-tree -1)
4847
res (= b-tree-order (seq (sort set)))]
4948

50-
(sqlite/drop-ref db root)
51-
(assert (empty? (sqlite/list-keys db))
49+
(jdbc/drop-key db root)
50+
(assert (empty? (jdbc/list-keys db))
5251
"End with no keys")
5352

5453
(assert res (str "These are unequal: " (pr-str b-tree-order) " " (pr-str (seq (sort set)))))

0 commit comments

Comments
 (0)