hyperbee2 2.2.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +63 -59
- package/lib/cache.js +21 -1
- package/lib/changes.js +17 -19
- package/lib/compression.js +48 -11
- package/lib/context.js +40 -15
- package/lib/diff.js +8 -6
- package/lib/ranges.js +7 -16
- package/lib/session-config.js +23 -0
- package/lib/tree.js +39 -28
- package/lib/write.js +82 -66
- package/package.json +2 -1
package/lib/write.js
CHANGED
|
@@ -2,15 +2,7 @@ const b4a = require('b4a')
|
|
|
2
2
|
const c = require('compact-encoding')
|
|
3
3
|
const { OP_COHORT } = require('./compression.js')
|
|
4
4
|
const { encodeBlock, TYPE_COMPAT, TYPE_LATEST } = require('./encoding.js')
|
|
5
|
-
const {
|
|
6
|
-
Pointer,
|
|
7
|
-
KeyPointer,
|
|
8
|
-
ValuePointer,
|
|
9
|
-
TreeNode,
|
|
10
|
-
TreeNodePointer,
|
|
11
|
-
INSERTED,
|
|
12
|
-
NEEDS_SPLIT
|
|
13
|
-
} = require('./tree.js')
|
|
5
|
+
const { Pointer, KeyPointer, ValuePointer, TreeNode, INSERTED, NEEDS_SPLIT } = require('./tree.js')
|
|
14
6
|
|
|
15
7
|
const PREFERRED_BLOCK_SIZE = 4096
|
|
16
8
|
const INLINE_VALUE_SIZE = 4096
|
|
@@ -31,6 +23,7 @@ module.exports = class WriteBatch {
|
|
|
31
23
|
} = opts
|
|
32
24
|
|
|
33
25
|
this.tree = tree
|
|
26
|
+
this.config = tree.config.options(opts)
|
|
34
27
|
this.deltaMax = deltaMax
|
|
35
28
|
this.deltaMin = deltaMin
|
|
36
29
|
this.inlineValueSize = inlineValueSize
|
|
@@ -76,7 +69,7 @@ module.exports = class WriteBatch {
|
|
|
76
69
|
try {
|
|
77
70
|
const ops = this.ops
|
|
78
71
|
|
|
79
|
-
const root = await this.tree.bootstrap()
|
|
72
|
+
const root = await this.tree.bootstrap(this.config)
|
|
80
73
|
|
|
81
74
|
const length = this._getLength(root)
|
|
82
75
|
const context = this._getContext(root)
|
|
@@ -86,7 +79,7 @@ module.exports = class WriteBatch {
|
|
|
86
79
|
const value = changed ? new TreeNode([], []) : null
|
|
87
80
|
|
|
88
81
|
this.length = length
|
|
89
|
-
this.root =
|
|
82
|
+
this.root = context.createTreeNode(0, seq, 0, changed, value)
|
|
90
83
|
|
|
91
84
|
for (const op of ops) {
|
|
92
85
|
if (op.put) op.applied = await this._put(op.key, op.value)
|
|
@@ -113,27 +106,29 @@ module.exports = class WriteBatch {
|
|
|
113
106
|
async _put(key, value) {
|
|
114
107
|
const stack = []
|
|
115
108
|
const target = key
|
|
109
|
+
const snap = this.snapshot
|
|
110
|
+
const conf = this.config
|
|
116
111
|
|
|
117
112
|
let ptr = this.root
|
|
118
113
|
|
|
119
114
|
while (true) {
|
|
120
|
-
const v =
|
|
121
|
-
if (!v.children.
|
|
115
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
116
|
+
if (!v.children.ulength) break
|
|
122
117
|
|
|
123
118
|
stack.push(ptr)
|
|
124
119
|
|
|
125
120
|
let s = 0
|
|
126
|
-
let e = v.keys.
|
|
121
|
+
let e = v.keys.ulength
|
|
127
122
|
let c = 0
|
|
128
123
|
|
|
129
124
|
while (s < e) {
|
|
130
125
|
const mid = (s + e) >> 1
|
|
131
|
-
const m = v.keys.
|
|
126
|
+
const m = v.keys.uget(mid)
|
|
132
127
|
|
|
133
128
|
c = b4a.compare(target, m.key)
|
|
134
129
|
|
|
135
130
|
if (c === 0) {
|
|
136
|
-
const existing = await
|
|
131
|
+
const existing = await snap.inflateValue(m, conf)
|
|
137
132
|
if (b4a.equals(existing, value)) return false
|
|
138
133
|
v.setValue(this.tree.context, mid, value)
|
|
139
134
|
for (let i = 0; i < stack.length; i++) stack[i].changed = true
|
|
@@ -145,16 +140,16 @@ module.exports = class WriteBatch {
|
|
|
145
140
|
}
|
|
146
141
|
|
|
147
142
|
const i = c < 0 ? e : s
|
|
148
|
-
ptr = v.children.
|
|
143
|
+
ptr = v.children.uget(i)
|
|
149
144
|
}
|
|
150
145
|
|
|
151
|
-
const v =
|
|
146
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
152
147
|
let status = v.insertLeaf(this.tree.context, target, value)
|
|
153
148
|
|
|
154
149
|
if (status >= 0) {
|
|
155
150
|
// already exists, upsert if changed
|
|
156
|
-
const m = v.keys.
|
|
157
|
-
const existing = await
|
|
151
|
+
const m = v.keys.uget(status)
|
|
152
|
+
const existing = await snap.inflateValue(m, conf)
|
|
158
153
|
if (b4a.equals(existing, value)) return false
|
|
159
154
|
v.setValue(this.tree.context, status, value)
|
|
160
155
|
}
|
|
@@ -163,20 +158,19 @@ module.exports = class WriteBatch {
|
|
|
163
158
|
for (let i = 0; i < stack.length; i++) stack[i].changed = true
|
|
164
159
|
|
|
165
160
|
while (status === NEEDS_SPLIT) {
|
|
166
|
-
const v =
|
|
161
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
167
162
|
const parent = stack.pop()
|
|
168
163
|
const { median, right } = v.split(this.tree.context)
|
|
169
164
|
|
|
170
165
|
if (parent) {
|
|
171
|
-
const p =
|
|
166
|
+
const p = await retainAndInflate(parent, snap, conf)
|
|
172
167
|
status = p.insertNode(this.tree.context, median, right)
|
|
173
168
|
ptr = parent
|
|
174
169
|
} else {
|
|
175
|
-
this.root =
|
|
170
|
+
this.root = this.tree.context.createTreeNode(0, 0, 0, true, new TreeNode([], []))
|
|
176
171
|
this.root.value.keys.push(median)
|
|
177
172
|
this.root.value.children.push(ptr)
|
|
178
173
|
this.root.value.children.push(right)
|
|
179
|
-
this.snapshot.bump(this.root)
|
|
180
174
|
status = INSERTED
|
|
181
175
|
}
|
|
182
176
|
}
|
|
@@ -190,19 +184,19 @@ module.exports = class WriteBatch {
|
|
|
190
184
|
const stack = []
|
|
191
185
|
|
|
192
186
|
while (true) {
|
|
193
|
-
const v = ptr
|
|
187
|
+
const v = await retainAndInflate(ptr, this.snapshot, this.config)
|
|
194
188
|
stack.push(ptr)
|
|
195
189
|
|
|
196
190
|
let s = 0
|
|
197
|
-
let e = v.keys.
|
|
191
|
+
let e = v.keys.ulength
|
|
198
192
|
let c = 0
|
|
199
193
|
|
|
200
194
|
while (s < e) {
|
|
201
195
|
const mid = (s + e) >> 1
|
|
202
|
-
c = b4a.compare(key, v.keys.
|
|
196
|
+
c = b4a.compare(key, v.keys.uget(mid).key)
|
|
203
197
|
|
|
204
198
|
if (c === 0) {
|
|
205
|
-
if (v.children.
|
|
199
|
+
if (v.children.ulength) await this._setKeyToNearestLeaf(v, mid, stack)
|
|
206
200
|
else v.removeKey(mid)
|
|
207
201
|
// we mark these as changed late, so we don't rewrite them if it is a 404
|
|
208
202
|
for (let i = 0; i < stack.length; i++) stack[i].changed = true
|
|
@@ -214,88 +208,95 @@ module.exports = class WriteBatch {
|
|
|
214
208
|
else s = mid + 1
|
|
215
209
|
}
|
|
216
210
|
|
|
217
|
-
if (!v.children.
|
|
211
|
+
if (!v.children.ulength) return false
|
|
218
212
|
|
|
219
213
|
const i = c < 0 ? e : s
|
|
220
|
-
ptr = v.children.
|
|
214
|
+
ptr = v.children.uget(i)
|
|
221
215
|
}
|
|
222
216
|
|
|
223
217
|
return false
|
|
224
218
|
}
|
|
225
219
|
|
|
226
220
|
async _setKeyToNearestLeaf(v, index, stack) {
|
|
227
|
-
|
|
228
|
-
|
|
221
|
+
const snap = this.snapshot
|
|
222
|
+
const conf = this.config
|
|
223
|
+
|
|
224
|
+
let left = v.children.uget(index)
|
|
225
|
+
let right = v.children.uget(index + 1)
|
|
229
226
|
|
|
230
227
|
const [ls, rs] = await Promise.all([this._leafSize(left, false), this._leafSize(right, true)])
|
|
231
228
|
|
|
232
229
|
if (ls < rs) {
|
|
233
230
|
// if fewer leaves on the left
|
|
234
231
|
stack.push(right)
|
|
235
|
-
let r =
|
|
236
|
-
while (r.children.
|
|
237
|
-
right = r.children.
|
|
232
|
+
let r = await retainAndInflate(right, snap, conf)
|
|
233
|
+
while (r.children.ulength) {
|
|
234
|
+
right = r.children.uget(0)
|
|
238
235
|
stack.push(right)
|
|
239
|
-
r =
|
|
236
|
+
r = await retainAndInflate(right, snap, conf)
|
|
240
237
|
}
|
|
241
238
|
v.keys.set(index, r.keys.shift())
|
|
242
239
|
} else {
|
|
243
240
|
// if fewer leaves on the right
|
|
244
241
|
stack.push(left)
|
|
245
|
-
let l =
|
|
246
|
-
while (l.children.
|
|
247
|
-
left = l.children.
|
|
242
|
+
let l = await retainAndInflate(left, snap, conf)
|
|
243
|
+
while (l.children.ulength) {
|
|
244
|
+
left = l.children.uget(l.children.ulength - 1)
|
|
248
245
|
stack.push(left)
|
|
249
|
-
l =
|
|
246
|
+
l = await retainAndInflate(left, snap, conf)
|
|
250
247
|
}
|
|
251
248
|
v.keys.set(index, l.keys.pop())
|
|
252
249
|
}
|
|
253
250
|
}
|
|
254
251
|
|
|
255
252
|
async _leafSize(ptr, goLeft) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
253
|
+
const snap = this.snapshot
|
|
254
|
+
const conf = this.config
|
|
255
|
+
|
|
256
|
+
let v = await retainAndInflate(ptr, snap, conf)
|
|
257
|
+
while (v.children.ulength) {
|
|
258
|
+
ptr = v.children.uget(goLeft ? 0 : v.children.ulength - 1)
|
|
259
|
+
v = await retainAndInflate(ptr, snap, conf)
|
|
260
260
|
}
|
|
261
|
-
return v.keys.
|
|
261
|
+
return v.keys.ulength
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
async _rebalance(stack) {
|
|
265
265
|
const root = stack[0]
|
|
266
266
|
const minKeys = this.tree.context.minKeys
|
|
267
|
+
const snap = this.snapshot
|
|
268
|
+
const conf = this.config
|
|
267
269
|
|
|
268
270
|
while (stack.length > 1) {
|
|
269
271
|
const ptr = stack.pop()
|
|
270
272
|
const parent = stack[stack.length - 1]
|
|
271
273
|
|
|
272
|
-
const v =
|
|
274
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
273
275
|
|
|
274
|
-
if (v.keys.
|
|
276
|
+
if (v.keys.ulength >= minKeys) return root
|
|
275
277
|
|
|
276
|
-
const p =
|
|
278
|
+
const p = await retainAndInflate(parent, snap, conf)
|
|
277
279
|
|
|
278
280
|
let { left, index, right } = v.siblings(p)
|
|
279
281
|
|
|
280
|
-
let l = left && (
|
|
282
|
+
let l = left && (await retainAndInflate(left, snap, conf))
|
|
281
283
|
|
|
282
284
|
// maybe borrow from left sibling?
|
|
283
|
-
if (l && l.keys.
|
|
285
|
+
if (l && l.keys.ulength > minKeys) {
|
|
284
286
|
left.changed = true
|
|
285
|
-
v.keys.unshift(p.keys.
|
|
286
|
-
if (l.children.
|
|
287
|
+
v.keys.unshift(p.keys.uget(index - 1))
|
|
288
|
+
if (l.children.ulength) v.children.unshift(l.children.pop())
|
|
287
289
|
p.keys.set(index - 1, l.keys.pop())
|
|
288
290
|
return root
|
|
289
291
|
}
|
|
290
292
|
|
|
291
|
-
let r =
|
|
292
|
-
right && (right.value ? this.snapshot.bump(right) : await this.snapshot.inflate(right))
|
|
293
|
+
let r = right && (await retainAndInflate(right, snap, conf))
|
|
293
294
|
|
|
294
295
|
// maybe borrow from right sibling?
|
|
295
|
-
if (r && r.keys.
|
|
296
|
+
if (r && r.keys.ulength > minKeys) {
|
|
296
297
|
right.changed = true
|
|
297
|
-
v.keys.push(p.keys.
|
|
298
|
-
if (r.children.
|
|
298
|
+
v.keys.push(p.keys.uget(index))
|
|
299
|
+
if (r.children.ulength) v.children.push(r.children.shift())
|
|
299
300
|
p.keys.set(index, r.keys.shift())
|
|
300
301
|
return root
|
|
301
302
|
}
|
|
@@ -311,15 +312,15 @@ module.exports = class WriteBatch {
|
|
|
311
312
|
}
|
|
312
313
|
|
|
313
314
|
left.changed = true
|
|
314
|
-
l.merge(r, p.keys.
|
|
315
|
+
l.merge(r, p.keys.uget(index))
|
|
315
316
|
|
|
316
317
|
parent.changed = true
|
|
317
318
|
p.removeKey(index)
|
|
318
319
|
}
|
|
319
320
|
|
|
320
|
-
const r =
|
|
321
|
+
const r = await retainAndInflate(root, snap, conf)
|
|
321
322
|
// check if the tree shrunk
|
|
322
|
-
if (!r.keys.
|
|
323
|
+
if (!r.keys.ulength && r.children.ulength) return r.children.uget(0)
|
|
323
324
|
return root
|
|
324
325
|
}
|
|
325
326
|
|
|
@@ -334,19 +335,21 @@ module.exports = class WriteBatch {
|
|
|
334
335
|
return
|
|
335
336
|
}
|
|
336
337
|
|
|
337
|
-
if (!this.root.value) await this.snapshot.inflate(this.root)
|
|
338
|
+
if (!this.root.value) await this.snapshot.inflate(this.root, this.config)
|
|
338
339
|
|
|
339
340
|
let update = { size: 0, nodes: [], keys: [], values: [] }
|
|
340
341
|
let minValue = -1
|
|
341
342
|
|
|
343
|
+
this.root = this.root.commit()
|
|
344
|
+
|
|
342
345
|
const batch = [update]
|
|
343
346
|
const stack = [this.root]
|
|
344
347
|
const values = []
|
|
345
348
|
|
|
346
349
|
const context = this.tree.context.getLocalContext()
|
|
347
|
-
const
|
|
350
|
+
const config = this.tree.config
|
|
348
351
|
|
|
349
|
-
await context.update(
|
|
352
|
+
await context.update(config)
|
|
350
353
|
|
|
351
354
|
while (stack.length > 0) {
|
|
352
355
|
const node = stack.pop()
|
|
@@ -382,8 +385,9 @@ module.exports = class WriteBatch {
|
|
|
382
385
|
for (let i = 0; i < children.entries.length; i++) {
|
|
383
386
|
const c = children.entries[i]
|
|
384
387
|
if (!c.value || !c.changed) continue
|
|
385
|
-
|
|
386
|
-
|
|
388
|
+
const node = c.commit()
|
|
389
|
+
children.touch(i, node)
|
|
390
|
+
stack.push(node)
|
|
387
391
|
}
|
|
388
392
|
}
|
|
389
393
|
|
|
@@ -486,7 +490,7 @@ module.exports = class WriteBatch {
|
|
|
486
490
|
const buffers = new Array(blocks.length)
|
|
487
491
|
|
|
488
492
|
if (blocks.length > 0 && this.length > 0) {
|
|
489
|
-
const core = this.key ? await context.getCoreOffsetByKey(this.key,
|
|
493
|
+
const core = this.key ? await context.getCoreOffsetByKey(this.key, config) : 0
|
|
490
494
|
blocks[blocks.length - 1].previous = { core, seq: this.length - 1 }
|
|
491
495
|
}
|
|
492
496
|
|
|
@@ -515,6 +519,9 @@ module.exports = class WriteBatch {
|
|
|
515
519
|
this.snapshot.bump(node)
|
|
516
520
|
}
|
|
517
521
|
}
|
|
522
|
+
|
|
523
|
+
context.cache.retained++
|
|
524
|
+
context.cache.gc()
|
|
518
525
|
}
|
|
519
526
|
}
|
|
520
527
|
|
|
@@ -597,3 +604,12 @@ function prepareCohorts(context, block, seq, deltas, keys) {
|
|
|
597
604
|
function supportsCompression(type) {
|
|
598
605
|
return type !== TYPE_COMPAT && type !== 0
|
|
599
606
|
}
|
|
607
|
+
|
|
608
|
+
async function retainAndInflate(ptr, snap, conf) {
|
|
609
|
+
if (ptr.value) {
|
|
610
|
+
ptr.retain()
|
|
611
|
+
return ptr.value
|
|
612
|
+
}
|
|
613
|
+
ptr.retain()
|
|
614
|
+
return await snap.inflate(ptr, conf)
|
|
615
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hyperbee2",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "btree",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"b4a": "^1.6.7",
|
|
20
20
|
"compact-encoding": "^2.16.1",
|
|
21
21
|
"hypercore": "^11.15.0",
|
|
22
|
+
"hypercore-errors": "^1.5.0",
|
|
22
23
|
"hyperschema": "^1.14.0",
|
|
23
24
|
"protocol-buffers-encodings": "^1.2.0",
|
|
24
25
|
"scope-lock": "^1.2.4",
|