Skip to content

Commit 2ad2690

Browse files
authored
Merge pull request #1 from codeboost/counted-types
Counted types
2 parents 2950311 + ee169ff commit 2ad2690

File tree

12 files changed

+234
-700
lines changed

12 files changed

+234
-700
lines changed

deps.edn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{:paths ["src" "test"]
22
:deps {org.clojure/clojure {:mvn/version "1.12.0"}
3-
io.github.radarroark/xitdb {:mvn/version "0.16.0"}}
3+
io.github.radarroark/xitdb {:mvn/version "0.20.0"}}
44

55
:aliases
66
{:test

src/xitdb/array_list.clj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@
132132
(.count wal))
133133

134134
(cons [this o]
135-
;;TODO: Figure out if it is correct to append to the end
136135
(operations/array-list-append-value! wal (common/unwrap o))
137136
this)
138137

src/xitdb/db.clj

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(ns xitdb.db
22
(:require
3+
[xitdb.common :as common]
34
[xitdb.util.conversion :as conversion]
45
[xitdb.xitdb-types :as xtypes])
56
(:import
@@ -47,6 +48,15 @@
4748
hasher (Hasher. (MessageDigest/getInstance "SHA-1"))]
4849
(Database. core hasher)))
4950

51+
(defn v->slot!
52+
"Converts a value to a slot which can be written to a cursor.
53+
For XITDB* types (which support ISlot), will return `-slot`,
54+
for all other types `conversion/v->slot!`"
55+
[^WriteCursor cursor v]
56+
(if (satisfies? common/ISlot v)
57+
(common/-slot v)
58+
(conversion/v->slot! cursor v)))
59+
5060
(defn xitdb-swap!
5161
"Returns history index."
5262
[db f & args]
@@ -58,7 +68,7 @@
5868
(fn [^WriteCursor cursor]
5969
(let [obj (xtypes/read-from-cursor cursor true)]
6070
(let [retval (apply f (into [obj] args))]
61-
(.write cursor (conversion/v->slot! cursor retval))))))))
71+
(.write cursor (v->slot! cursor retval))))))))
6272

6373
(defn xitdb-swap-with-lock!
6474
"Performs the 'swap!' operation while locking `db.lock`.

src/xitdb/hash_map.clj

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
(ns xitdb.hash-map
22
(:require
33
[xitdb.common :as common]
4-
[xitdb.util.conversion :as conversion]
54
[xitdb.util.operations :as operations])
65
(:import
7-
[io.github.radarroark.xitdb ReadCursor ReadHashMap WriteCursor WriteHashMap]))
6+
[io.github.radarroark.xitdb
7+
ReadCountedHashMap ReadCursor ReadHashMap
8+
WriteCountedHashMap WriteCursor WriteHashMap]))
89

910
(defn map-seq
1011
[rhm]
@@ -18,14 +19,14 @@
1819
(.valAt this key nil))
1920

2021
(valAt [this key not-found]
21-
(let [cursor (.getCursor rhm (conversion/db-key key))]
22+
(let [cursor (operations/map-read-cursor rhm key)]
2223
(if (nil? cursor)
2324
not-found
2425
(common/-read-from-cursor cursor))))
2526

2627
clojure.lang.Associative
2728
(containsKey [this key]
28-
(not (nil? (.getCursor rhm (conversion/db-key key)))))
29+
(operations/map-contains-key? rhm key))
2930

3031
(entryAt [this key]
3132
(let [v (.valAt this key nil)]
@@ -185,4 +186,11 @@
185186
(defn xhash-map [^ReadCursor read-cursor]
186187
(->XITDBHashMap (ReadHashMap. read-cursor)))
187188

189+
(defn xwrite-hash-map-counted [^WriteCursor write-cursor]
190+
(->XITDBWriteHashMap (WriteCountedHashMap. write-cursor)))
191+
192+
(defn xhash-map-counted [^ReadCursor read-cursor]
193+
(->XITDBHashMap (ReadCountedHashMap. read-cursor)))
194+
195+
188196

src/xitdb/hash_set.clj

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@
44
[xitdb.util.conversion :as conversion]
55
[xitdb.util.operations :as operations])
66
(:import
7-
[io.github.radarroark.xitdb ReadHashMap WriteCursor WriteHashMap]))
7+
[io.github.radarroark.xitdb
8+
ReadCountedHashSet ReadCursor ReadHashSet
9+
WriteCountedHashSet WriteCursor WriteHashSet]))
810

911
(defn set-seq
1012
[rhm]
1113
"The cursors used must implement the IReadFromCursor protocol."
12-
(map val (operations/map-seq rhm #(common/-read-from-cursor %))))
14+
(operations/set-seq rhm common/-read-from-cursor))
1315

14-
(deftype XITDBHashSet [^ReadHashMap rhm]
16+
(deftype XITDBHashSet [^ReadHashSet rhs]
1517
clojure.lang.IPersistentSet
1618
(disjoin [_ k]
1719
(throw (UnsupportedOperationException. "XITDBHashSet is read-only")))
1820

1921
(contains [this k]
20-
(not (nil? (.getCursor rhm (conversion/db-key (if (nil? k) 0 (.hashCode k)))))))
22+
(operations/set-contains? rhs k))
2123

2224
(get [this k]
2325
(when (.contains this k)
@@ -36,11 +38,11 @@
3638
(every? #(.contains this %) other)))
3739

3840
(count [_]
39-
(operations/map-item-count rhm))
41+
(operations/set-item-count rhs))
4042

4143
clojure.lang.Seqable
4244
(seq [_]
43-
(set-seq rhm))
45+
(set-seq rhs))
4446

4547
clojure.lang.ILookup
4648
(valAt [this k]
@@ -68,7 +70,7 @@
6870

6971
common/IUnwrap
7072
(-unwrap [_]
71-
rhm)
73+
rhs)
7274

7375
Object
7476
(toString [this]
@@ -84,26 +86,26 @@
8486
(into #{} (map common/materialize (seq this)))))
8587

8688
;; Writable version of the set
87-
(deftype XITDBWriteHashSet [^WriteHashMap whm]
89+
(deftype XITDBWriteHashSet [^WriteHashSet whs]
8890
clojure.lang.IPersistentSet
89-
(disjoin [this k]
90-
(operations/map-dissoc-key! whm (.hashCode k))
91+
(disjoin [this v]
92+
(operations/set-disj-value! whs (common/unwrap v))
9193
this)
9294

93-
(contains [this k]
94-
(operations/map-contains-key? whm (.hashCode k)))
95+
(contains [this v]
96+
(operations/set-contains? whs (common/unwrap v)))
9597

9698
(get [this k]
97-
(when (.contains this k)
99+
(when (.contains this (common/unwrap k))
98100
k))
99101

100102
clojure.lang.IPersistentCollection
101103
(cons [this o]
102-
(operations/set-assoc-value! whm (common/unwrap o))
104+
(operations/set-assoc-value! whs (common/unwrap o))
103105
this)
104106

105107
(empty [this]
106-
(operations/set-empty! whm)
108+
(operations/set-empty! whs)
107109
this)
108110

109111
(equiv [this other]
@@ -112,11 +114,11 @@
112114
(every? #(.contains this %) other)))
113115

114116
(count [_]
115-
(operations/map-item-count whm))
117+
(operations/set-item-count whs))
116118

117119
clojure.lang.Seqable
118120
(seq [_]
119-
(set-seq whm))
121+
(set-seq whs))
120122

121123
clojure.lang.ILookup
122124
(valAt [this k]
@@ -129,20 +131,25 @@
129131

130132
common/ISlot
131133
(-slot [_]
132-
(-> whm .cursor .slot))
134+
(-> whs .cursor .slot))
133135

134136
common/IUnwrap
135137
(-unwrap [_]
136-
whm)
138+
whs)
137139

138140
Object
139141
(toString [_]
140142
(str "XITDBWriteHashSet")))
141143

142144
;; Constructor functions
143145
(defn xwrite-hash-set [^WriteCursor write-cursor]
144-
(let [whm (operations/init-hash-set! write-cursor)]
145-
(->XITDBWriteHashSet whm)))
146+
(->XITDBWriteHashSet (WriteHashSet. write-cursor)))
147+
148+
(defn xhash-set [^ReadCursor read-cursor]
149+
(->XITDBHashSet (ReadHashSet. read-cursor)))
150+
151+
(defn xwrite-hash-set-counted [^WriteCursor write-cursor]
152+
(->XITDBWriteHashSet (WriteCountedHashSet. write-cursor)))
146153

147-
(defn xhash-set [^ReadHashMap read-cursor]
148-
(->XITDBHashSet (ReadHashMap. read-cursor)))
154+
(defn xhash-set-counted [^ReadCursor cursor]
155+
(->XITDBHashSet (ReadCountedHashSet. cursor)))

src/xitdb/util/conversion.clj

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
(:require
33
[xitdb.util.validation :as validation])
44
(:import
5-
[io.github.radarroark.xitdb Database$Float Database$Bytes Database$Int Database$Uint ReadArrayList ReadCursor ReadHashMap ReadLinkedArrayList Slot WriteArrayList WriteCursor WriteHashMap Tag WriteLinkedArrayList]))
5+
[io.github.radarroark.xitdb
6+
Database Database$Bytes Database$Float Database$Int
7+
ReadArrayList ReadCountedHashSet ReadCursor ReadHashMap ReadCountedHashMap
8+
ReadHashSet Slot Tag WriteArrayList WriteCountedHashSet WriteCursor WriteCountedHashMap
9+
WriteHashMap WriteHashSet WriteLinkedArrayList]
10+
[java.nio ByteBuffer]))
611

712
(defn xit-tag->keyword
813
"Converts a XitDB Tag enum to a corresponding Clojure keyword."
@@ -26,7 +31,7 @@
2631
{:keyword "kw"
2732
:boolean "bl"
2833
:key-integer "ki"
29-
:nil "nl"
34+
:nil "nl" ;; TODO: Could use Tag/NONE instead
3035
:inst "in"
3136
:date "da"})
3237

@@ -46,6 +51,18 @@
4651
(name key))
4752
key))
4853

54+
(defn db-key-hash
55+
"Returns a byte array representing the stable hash digest of (Clojure) value `v`.
56+
Uses the MessageDigest from the database."
57+
^bytes [^Database jdb v]
58+
(if (nil? v)
59+
(byte-array (-> jdb .-header .hashSize))
60+
(let [hash-code (hash v)
61+
buffer (ByteBuffer/allocate Integer/BYTES)
62+
_ (.putInt buffer hash-code)
63+
bytes (.array buffer)]
64+
(.digest (.md jdb) bytes))))
65+
4966
(defn ^Slot primitive-for
5067
"Converts a Clojure primitive value to its corresponding XitDB representation.
5168
Handles strings, keywords, integers, booleans, and floats.
@@ -105,13 +122,30 @@
105122
(instance? WriteHashMap v)
106123
(-> ^WriteHashMap v .cursor .slot)
107124

108-
;;TODO: Confirm that it is correct to return the Read slots
109125
(instance? ReadHashMap v)
110126
(-> ^ReadHashMap v .cursor .slot)
111127

128+
(instance? ReadCountedHashMap v)
129+
(-> ^ReadCountedHashMap v .cursor .slot)
130+
131+
(instance? WriteCountedHashMap v)
132+
(-> ^WriteCountedHashMap v .cursor .slot)
133+
112134
(instance? ReadArrayList v)
113135
(-> ^ReadArrayList v .cursor .slot)
114136

137+
(instance? ReadHashSet v)
138+
(-> ^ReadHashSet v .cursor .slot)
139+
140+
(instance? ReadCountedHashSet v)
141+
(-> ^ReadCountedHashSet v .cursor .slot)
142+
143+
(instance? WriteHashSet v)
144+
(-> ^WriteHashSet v .cursor .slot)
145+
146+
(instance? WriteCountedHashSet v)
147+
(-> ^WriteCountedHashSet v .cursor .slot)
148+
115149
(map? v)
116150
(do
117151
(.write cursor nil)
@@ -141,14 +175,14 @@
141175
[k]
142176
(cond
143177
(integer? k)
144-
(database-bytes (str k) "ki") ;integer keys are stored as strings with 'ki' format tag
178+
(database-bytes (str k) "ki") ;integer keys are stored as strings with 'ki' format tag
145179
:else
146180
(primitive-for k)))
147181

148182
(defn read-bytes-with-format-tag [^ReadCursor cursor]
149183
(let [bytes-obj (.readBytesObject cursor nil)
150-
str (String. (.value bytes-obj))
151-
fmt-tag (some-> bytes-obj .formatTag String.)]
184+
str (String. (.value bytes-obj))
185+
fmt-tag (some-> bytes-obj .formatTag String.)]
152186
(cond
153187

154188
(= fmt-tag (fmt-tag-value :keyword))
@@ -228,34 +262,27 @@
228262
(.append write-list (primitive-for v))))
229263
(.-cursor write-list)))
230264

231-
;; Forward declarations for mutual dependencies
232-
(declare map-assoc-value!)
233-
(declare init-hash-set!)
234-
(declare set-assoc-value!)
235-
236265
(defn ^WriteCursor map->WriteHashMapCursor!
237266
"Writes a Clojure map to a XitDB WriteHashMap.
238267
Returns the cursor of the created WriteHashMap."
239268
[^WriteCursor cursor m]
240-
(let [whm (WriteHashMap. cursor)]
269+
(let [whm (WriteCountedHashMap. cursor)]
241270
(doseq [[k v] m]
242-
(let [cursor (.putCursor whm (db-key k))]
271+
(let [hash-value (db-key-hash (-> cursor .db) k)
272+
key-cursor (.putKeyCursor whm hash-value)
273+
cursor (.putCursor whm hash-value)]
274+
(.writeIfEmpty key-cursor (v->slot! key-cursor k))
243275
(.write cursor (v->slot! cursor v))))
244276
(.-cursor whm)))
245277

246278
(defn ^WriteCursor set->WriteCursor!
247-
"Creates a hash-map and associates the internal key :is-set? to 1.
248-
Map is keyed by the .hashCode of the value, valued by the value :)"
279+
"Writes a Clojure set `s` to a XitDB WriteHashSet.
280+
Returns the cursor of the created WriteHashSet."
249281
[^WriteCursor cursor s]
250-
(let [whm (WriteHashMap. cursor)
251-
;; Mark as set
252-
is-set-key (db-key :%xitdb_set)]
253-
(-> whm
254-
(.putCursor is-set-key)
255-
(.write (primitive-for 1)))
256-
;; Add values
282+
(let [whm (WriteCountedHashSet. cursor)
283+
db (-> cursor .db)]
257284
(doseq [v s]
258-
(let [hash-code (if v (.hashCode v) 0)
259-
cursor (.putCursor whm (db-key hash-code))]
260-
(.write cursor (v->slot! cursor v))))
285+
(let [hash-code (db-key-hash db v)
286+
cursor (.putCursor whm hash-code)]
287+
(.writeIfEmpty cursor (v->slot! cursor v))))
261288
(.-cursor whm)))

0 commit comments

Comments
 (0)