hyperbee2 2.8.0 → 2.9.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 +32 -163
- package/lib/context.js +3 -0
- package/lib/inflate.js +140 -0
- package/lib/session-config.js +17 -6
- package/lib/tree.js +16 -0
- package/lib/write.js +18 -8
- package/package.json +5 -5
package/index.js
CHANGED
|
@@ -8,8 +8,8 @@ const NodeCache = require('./lib/cache.js')
|
|
|
8
8
|
const WriteBatch = require('./lib/write.js')
|
|
9
9
|
const CoreContext = require('./lib/context.js')
|
|
10
10
|
const SessionConfig = require('./lib/session-config.js')
|
|
11
|
-
const {
|
|
12
|
-
const {
|
|
11
|
+
const { inflate, inflateValue } = require('./lib/inflate.js')
|
|
12
|
+
const { EMPTY } = require('./lib/tree.js')
|
|
13
13
|
|
|
14
14
|
class Hyperbee extends EventEmitter {
|
|
15
15
|
constructor(store, opts = {}) {
|
|
@@ -21,10 +21,11 @@ class Hyperbee extends EventEmitter {
|
|
|
21
21
|
encryption = null,
|
|
22
22
|
getEncryptionProvider = toEncryptionProvider(encryption),
|
|
23
23
|
maxCacheSize = 4096,
|
|
24
|
-
config = new SessionConfig([], 0, true),
|
|
24
|
+
config = new SessionConfig([], 0, true, null),
|
|
25
25
|
activeRequests = config.activeRequests,
|
|
26
26
|
timeout = config.timeout,
|
|
27
27
|
wait = config.wait,
|
|
28
|
+
trace = config.trace,
|
|
28
29
|
core = key
|
|
29
30
|
? store.get({ key, encryption: getEncryptionProvider(key) })
|
|
30
31
|
: store.get({ key, name: 'bee', encryption: getEncryptionProvider(key) }),
|
|
@@ -40,14 +41,14 @@ class Hyperbee extends EventEmitter {
|
|
|
40
41
|
view = false,
|
|
41
42
|
writable = true,
|
|
42
43
|
unbatch = 0,
|
|
43
|
-
autoUpdate =
|
|
44
|
+
autoUpdate = !writable && !view,
|
|
44
45
|
preload = null
|
|
45
46
|
} = opts
|
|
46
47
|
|
|
47
48
|
this.store = store
|
|
48
49
|
this.root = root
|
|
49
50
|
this.context = context
|
|
50
|
-
this.config = config.sub(activeRequests, timeout, wait)
|
|
51
|
+
this.config = config.sub(activeRequests, timeout, wait, trace)
|
|
51
52
|
this.view = view
|
|
52
53
|
this.writable = writable
|
|
53
54
|
this.unbatch = unbatch
|
|
@@ -117,12 +118,9 @@ class Hyperbee extends EventEmitter {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
move({ length = this.core.length, key = null, writable = this.writable } = {}) {
|
|
120
|
-
|
|
121
|
-
const root = length === 0 ? EMPTY : context.createTreeNode(0, length - 1, 0, false, null)
|
|
122
|
-
this.context = context
|
|
121
|
+
this.context = key ? this.context.getContextByKey(key) : this.context
|
|
123
122
|
this.writable = writable
|
|
124
|
-
this.
|
|
125
|
-
this.emit('update')
|
|
123
|
+
this._setRoot(this._nodeAtSeq(length - 1), true)
|
|
126
124
|
}
|
|
127
125
|
|
|
128
126
|
snapshot() {
|
|
@@ -138,21 +136,28 @@ class Hyperbee extends EventEmitter {
|
|
|
138
136
|
return new WriteBatch(this, opts)
|
|
139
137
|
}
|
|
140
138
|
|
|
139
|
+
update(root = null) {
|
|
140
|
+
if (root === null) root = this._lastNodeInCore()
|
|
141
|
+
this._setRoot(root, true)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
_lastNodeInCore() {
|
|
145
|
+
return this._nodeAtSeq(this.context.core.length - 1)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_nodeAtSeq(seq) {
|
|
149
|
+
return seq < 0 ? EMPTY : this.context.createTreeNode(0, seq, 0, false, null)
|
|
150
|
+
}
|
|
151
|
+
|
|
141
152
|
async ready() {
|
|
142
153
|
if (!this.core.opened) await this.core.ready()
|
|
143
154
|
if (this.root) return
|
|
144
155
|
if (this.preload) await this.preload()
|
|
145
156
|
if (this.root) return
|
|
146
157
|
|
|
147
|
-
this.
|
|
148
|
-
this.context.core.length === 0
|
|
149
|
-
? EMPTY
|
|
150
|
-
: this.context.createTreeNode(0, this.core.length - 1, 0, false, null)
|
|
151
|
-
|
|
158
|
+
this._setRoot(this._lastNodeInCore(), false)
|
|
152
159
|
if (this.autoUpdate) {
|
|
153
|
-
this.core.on('append', ()
|
|
154
|
-
this.update()
|
|
155
|
-
})
|
|
160
|
+
this.core.on('append', this.update.bind(this, null))
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
this.emit('ready')
|
|
@@ -202,45 +207,16 @@ class Hyperbee extends EventEmitter {
|
|
|
202
207
|
return ptr.value
|
|
203
208
|
}
|
|
204
209
|
|
|
205
|
-
// TODO: unslab these
|
|
206
210
|
async inflate(ptr, config) {
|
|
207
|
-
if (ptr.value) {
|
|
208
|
-
|
|
209
|
-
return ptr.value
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const [block, context] = await Promise.all([
|
|
213
|
-
ptr.context.getBlock(ptr.seq, ptr.core, config),
|
|
214
|
-
ptr.context.getContext(ptr.core, config)
|
|
215
|
-
])
|
|
216
|
-
|
|
217
|
-
const tree = block.tree[ptr.offset]
|
|
218
|
-
|
|
219
|
-
const keys = new Array(tree.keys.length)
|
|
220
|
-
const children = new Array(tree.children.length)
|
|
221
|
-
|
|
222
|
-
for (let i = 0; i < keys.length; i++) {
|
|
223
|
-
const d = tree.keys[i]
|
|
224
|
-
keys[i] = inflateKey(context, d, ptr, block, config)
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
for (let i = 0; i < children.length; i++) {
|
|
228
|
-
const d = tree.children[i]
|
|
229
|
-
children[i] = inflateChild(context, d, ptr, block, config)
|
|
211
|
+
if (!ptr.value) {
|
|
212
|
+
await inflate(ptr, config)
|
|
230
213
|
}
|
|
231
|
-
|
|
232
|
-
const [k, c] = await Promise.all([Promise.all(keys), Promise.all(children)])
|
|
233
|
-
|
|
234
|
-
const value = new TreeNode(k, c)
|
|
235
|
-
if (!ptr.value) ptr.value = value
|
|
236
|
-
|
|
237
214
|
this.bump(ptr)
|
|
238
|
-
|
|
239
215
|
return ptr.value
|
|
240
216
|
}
|
|
241
217
|
|
|
242
218
|
async finalizeKeyPointer(key, config) {
|
|
243
|
-
const value = key.value || (await
|
|
219
|
+
const value = key.value || (await inflateValue(key, config))
|
|
244
220
|
|
|
245
221
|
return {
|
|
246
222
|
core: key.context.getCore(key.core),
|
|
@@ -251,30 +227,6 @@ class Hyperbee extends EventEmitter {
|
|
|
251
227
|
}
|
|
252
228
|
}
|
|
253
229
|
|
|
254
|
-
async inflateValue(key, config) {
|
|
255
|
-
if (key.value) return key.value
|
|
256
|
-
if (!key.valuePointer) return null
|
|
257
|
-
|
|
258
|
-
const ptr = key.valuePointer
|
|
259
|
-
|
|
260
|
-
if (ptr.split === 0) {
|
|
261
|
-
const block = await ptr.context.getBlock(ptr.seq, ptr.core, config)
|
|
262
|
-
return block.values[ptr.offset]
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const blockPromises = new Array(ptr.split + 1)
|
|
266
|
-
for (let i = 0; i < blockPromises.length; i++) {
|
|
267
|
-
blockPromises[i] = ptr.context.getBlock(ptr.seq - ptr.split + i, ptr.core, config)
|
|
268
|
-
}
|
|
269
|
-
const blocks = await Promise.all(blockPromises)
|
|
270
|
-
const splitValue = new Array(blockPromises.length)
|
|
271
|
-
for (let i = 0; i < splitValue.length - 1; i++) {
|
|
272
|
-
splitValue[i] = blocks[i].values[0]
|
|
273
|
-
}
|
|
274
|
-
splitValue[splitValue.length - 1] = blocks[blocks.length - 1].buffer[ptr.offset]
|
|
275
|
-
return b4a.concat(splitValue)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
230
|
async bootstrap(config) {
|
|
279
231
|
if (!this.root) await this.ready()
|
|
280
232
|
if (this.unbatch) await this._rollback(config)
|
|
@@ -304,16 +256,16 @@ class Hyperbee extends EventEmitter {
|
|
|
304
256
|
|
|
305
257
|
if (expected === this.unbatch) {
|
|
306
258
|
this.context = context
|
|
307
|
-
this.
|
|
308
|
-
this.unbatch = 0
|
|
309
|
-
this.emit('update')
|
|
259
|
+
this._setRoot(this._nodeAtSeq(length - 1), true)
|
|
310
260
|
}
|
|
311
261
|
}
|
|
312
262
|
|
|
313
|
-
|
|
314
|
-
this.root
|
|
263
|
+
_setRoot(root, emit) {
|
|
264
|
+
if (root === null || !root.equivalentTo(this.root)) {
|
|
265
|
+
this.root = root
|
|
266
|
+
if (emit) this.emit('update')
|
|
267
|
+
}
|
|
315
268
|
this.unbatch = 0
|
|
316
|
-
this.emit('update')
|
|
317
269
|
}
|
|
318
270
|
|
|
319
271
|
async get(key, opts) {
|
|
@@ -353,89 +305,6 @@ module.exports = Hyperbee
|
|
|
353
305
|
|
|
354
306
|
function noop() {}
|
|
355
307
|
|
|
356
|
-
function inflateKey(context, d, ptr, block, config) {
|
|
357
|
-
if (d.type === OP_COHORT) return inflateKeyCohort(context, d, ptr, block, config)
|
|
358
|
-
return inflateKeyDelta(context, d, ptr, block, config)
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
async function inflateKeyDelta(context, d, ptr, block, config) {
|
|
362
|
-
const k = d.pointer
|
|
363
|
-
|
|
364
|
-
if (!k) return new DeltaOp(false, d.type, d.index, null)
|
|
365
|
-
|
|
366
|
-
const blk =
|
|
367
|
-
k.seq === ptr.seq && k.core === 0 && ptr.core === 0
|
|
368
|
-
? block
|
|
369
|
-
: await context.getBlock(k.seq, k.core, config)
|
|
370
|
-
|
|
371
|
-
const bk = blk.keys[k.offset]
|
|
372
|
-
|
|
373
|
-
let vp = null
|
|
374
|
-
|
|
375
|
-
if (bk.valuePointer) {
|
|
376
|
-
const p = bk.valuePointer
|
|
377
|
-
const ctx = await context.getContext(k.core, config)
|
|
378
|
-
vp = new ValuePointer(ctx, p.core, p.seq, p.offset, p.split)
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const kp = new KeyPointer(context, k.core, k.seq, k.offset, false, bk.key, bk.value, vp)
|
|
382
|
-
return new DeltaOp(false, d.type, d.index, kp)
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
async function inflateKeyCohort(context, d, ptr, block, config) {
|
|
386
|
-
const co = d.pointer
|
|
387
|
-
|
|
388
|
-
const blk =
|
|
389
|
-
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
390
|
-
? block
|
|
391
|
-
: await context.getBlock(co.seq, co.core, config)
|
|
392
|
-
|
|
393
|
-
const cohort = blk.cohorts[co.offset]
|
|
394
|
-
const promises = new Array(cohort.length)
|
|
395
|
-
|
|
396
|
-
for (let i = 0; i < cohort.length; i++) {
|
|
397
|
-
const p = cohort[i]
|
|
398
|
-
const k = inflateKeyDelta(context, p, co, blk, config)
|
|
399
|
-
promises[i] = k
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
const p = new Pointer(context, co.core, co.seq, co.offset)
|
|
403
|
-
return new DeltaCohort(false, p, await Promise.all(promises))
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
async function inflateChild(context, d, ptr, block, config) {
|
|
407
|
-
if (d.type === OP_COHORT) return inflateChildCohort(context, d, ptr, block, config)
|
|
408
|
-
if (d.pointer && !context.hasCore(d.pointer.core)) await context.update(config)
|
|
409
|
-
return inflateChildDelta(context, d, ptr, block, config)
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
function inflateChildDelta(context, d, ptr, block, config) {
|
|
413
|
-
const p = d.pointer
|
|
414
|
-
const c = p && context.createTreeNode(p.core, p.seq, p.offset, false, null)
|
|
415
|
-
return new DeltaOp(false, d.type, d.index, c)
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
async function inflateChildCohort(context, d, ptr, block, config) {
|
|
419
|
-
const co = d.pointer
|
|
420
|
-
|
|
421
|
-
const blk =
|
|
422
|
-
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
423
|
-
? block
|
|
424
|
-
: await context.getBlock(co.seq, co.core, config)
|
|
425
|
-
|
|
426
|
-
const cohort = blk.cohorts[co.offset]
|
|
427
|
-
const deltas = new Array(cohort.length)
|
|
428
|
-
|
|
429
|
-
for (let i = 0; i < cohort.length; i++) {
|
|
430
|
-
const c = cohort[i]
|
|
431
|
-
if (c.pointer && !context.hasCore(c.pointer.core)) await context.update(config)
|
|
432
|
-
deltas[i] = inflateChildDelta(context, c, co, blk, config)
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const p = new Pointer(context, co.core, co.seq, co.offset)
|
|
436
|
-
return new DeltaCohort(false, p, deltas)
|
|
437
|
-
}
|
|
438
|
-
|
|
439
308
|
function toEncryptionProvider(encryption) {
|
|
440
309
|
if (encryption) return (key) => encryption
|
|
441
310
|
return () => null
|
package/lib/context.js
CHANGED
|
@@ -161,6 +161,9 @@ class CoreContext {
|
|
|
161
161
|
const hc = this.getCore(core)
|
|
162
162
|
const buffer = await hc.get(seq, config)
|
|
163
163
|
if (buffer === null) throw BLOCK_NOT_AVAILABLE()
|
|
164
|
+
|
|
165
|
+
if (config.trace !== null) config.trace(core, seq)
|
|
166
|
+
|
|
164
167
|
const block = decodeBlock(buffer, seq)
|
|
165
168
|
return block
|
|
166
169
|
}
|
package/lib/inflate.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
const b4a = require('b4a')
|
|
2
|
+
const { Pointer, KeyPointer, ValuePointer, TreeNode } = require('./tree.js')
|
|
3
|
+
const { DeltaOp, DeltaCohort, OP_COHORT } = require('./compression.js')
|
|
4
|
+
|
|
5
|
+
exports.inflate = async function inflate(ptr, config) {
|
|
6
|
+
if (ptr.value) return ptr.value
|
|
7
|
+
|
|
8
|
+
const [block, context] = await Promise.all([
|
|
9
|
+
ptr.context.getBlock(ptr.seq, ptr.core, config),
|
|
10
|
+
ptr.context.getContext(ptr.core, config)
|
|
11
|
+
])
|
|
12
|
+
|
|
13
|
+
const tree = block.tree[ptr.offset]
|
|
14
|
+
|
|
15
|
+
const keys = new Array(tree.keys.length)
|
|
16
|
+
const children = new Array(tree.children.length)
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < keys.length; i++) {
|
|
19
|
+
const d = tree.keys[i]
|
|
20
|
+
keys[i] = inflateKey(context, d, ptr, block, config)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (let i = 0; i < children.length; i++) {
|
|
24
|
+
const d = tree.children[i]
|
|
25
|
+
children[i] = inflateChild(context, d, ptr, block, config)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const [k, c] = await Promise.all([Promise.all(keys), Promise.all(children)])
|
|
29
|
+
|
|
30
|
+
const value = new TreeNode(k, c)
|
|
31
|
+
if (!ptr.value) ptr.value = value
|
|
32
|
+
return ptr.value
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function inflateKey(context, d, ptr, block, config) {
|
|
36
|
+
if (d.type === OP_COHORT) return inflateKeyCohort(context, d, ptr, block, config)
|
|
37
|
+
return inflateKeyDelta(context, d, ptr, block, config)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function inflateKeyDelta(context, d, ptr, block, config) {
|
|
41
|
+
const k = d.pointer
|
|
42
|
+
|
|
43
|
+
if (!k) return new DeltaOp(false, d.type, d.index, null)
|
|
44
|
+
|
|
45
|
+
const blk =
|
|
46
|
+
k.seq === ptr.seq && k.core === 0 && ptr.core === 0
|
|
47
|
+
? block
|
|
48
|
+
: await context.getBlock(k.seq, k.core, config)
|
|
49
|
+
|
|
50
|
+
const bk = blk.keys[k.offset]
|
|
51
|
+
|
|
52
|
+
let vp = null
|
|
53
|
+
|
|
54
|
+
if (bk.valuePointer) {
|
|
55
|
+
const p = bk.valuePointer
|
|
56
|
+
const ctx = await context.getContext(k.core, config)
|
|
57
|
+
vp = new ValuePointer(ctx, p.core, p.seq, p.offset, p.split)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const kp = new KeyPointer(context, k.core, k.seq, k.offset, false, bk.key, bk.value, vp)
|
|
61
|
+
return new DeltaOp(false, d.type, d.index, kp)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
exports.inflateValue = async function inflateValue(key, config) {
|
|
65
|
+
if (key.value) return key.value
|
|
66
|
+
if (!key.valuePointer) return null
|
|
67
|
+
|
|
68
|
+
const ptr = key.valuePointer
|
|
69
|
+
|
|
70
|
+
if (ptr.split === 0) {
|
|
71
|
+
const block = await ptr.context.getBlock(ptr.seq, ptr.core, config)
|
|
72
|
+
return block.values[ptr.offset]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const blockPromises = new Array(ptr.split + 1)
|
|
76
|
+
for (let i = 0; i < blockPromises.length; i++) {
|
|
77
|
+
blockPromises[i] = ptr.context.getBlock(ptr.seq - ptr.split + i, ptr.core, config)
|
|
78
|
+
}
|
|
79
|
+
const blocks = await Promise.all(blockPromises)
|
|
80
|
+
const splitValue = new Array(blockPromises.length)
|
|
81
|
+
for (let i = 0; i < splitValue.length - 1; i++) {
|
|
82
|
+
splitValue[i] = blocks[i].values[0]
|
|
83
|
+
}
|
|
84
|
+
splitValue[splitValue.length - 1] = blocks[blocks.length - 1].buffer[ptr.offset]
|
|
85
|
+
return b4a.concat(splitValue)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function inflateKeyCohort(context, d, ptr, block, config) {
|
|
89
|
+
const co = d.pointer
|
|
90
|
+
|
|
91
|
+
const blk =
|
|
92
|
+
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
93
|
+
? block
|
|
94
|
+
: await context.getBlock(co.seq, co.core, config)
|
|
95
|
+
|
|
96
|
+
const cohort = blk.cohorts[co.offset]
|
|
97
|
+
const promises = new Array(cohort.length)
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < cohort.length; i++) {
|
|
100
|
+
const p = cohort[i]
|
|
101
|
+
const k = inflateKeyDelta(context, p, co, blk, config)
|
|
102
|
+
promises[i] = k
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const p = new Pointer(context, co.core, co.seq, co.offset)
|
|
106
|
+
return new DeltaCohort(false, p, await Promise.all(promises))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function inflateChild(context, d, ptr, block, config) {
|
|
110
|
+
if (d.type === OP_COHORT) return inflateChildCohort(context, d, ptr, block, config)
|
|
111
|
+
if (d.pointer && !context.hasCore(d.pointer.core)) await context.update(config)
|
|
112
|
+
return inflateChildDelta(context, d, ptr, block, config)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function inflateChildDelta(context, d, ptr, block, config) {
|
|
116
|
+
const p = d.pointer
|
|
117
|
+
const c = p && context.createTreeNode(p.core, p.seq, p.offset, false, null)
|
|
118
|
+
return new DeltaOp(false, d.type, d.index, c)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function inflateChildCohort(context, d, ptr, block, config) {
|
|
122
|
+
const co = d.pointer
|
|
123
|
+
|
|
124
|
+
const blk =
|
|
125
|
+
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
126
|
+
? block
|
|
127
|
+
: await context.getBlock(co.seq, co.core, config)
|
|
128
|
+
|
|
129
|
+
const cohort = blk.cohorts[co.offset]
|
|
130
|
+
const deltas = new Array(cohort.length)
|
|
131
|
+
|
|
132
|
+
for (let i = 0; i < cohort.length; i++) {
|
|
133
|
+
const c = cohort[i]
|
|
134
|
+
if (c.pointer && !context.hasCore(c.pointer.core)) await context.update(config)
|
|
135
|
+
deltas[i] = inflateChildDelta(context, c, co, blk, config)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const p = new Pointer(context, co.core, co.seq, co.offset)
|
|
139
|
+
return new DeltaCohort(false, p, deltas)
|
|
140
|
+
}
|
package/lib/session-config.js
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
class SessionConfig {
|
|
2
|
-
constructor(activeRequests, timeout, wait) {
|
|
2
|
+
constructor(activeRequests, timeout, wait, trace) {
|
|
3
3
|
this.activeRequests = activeRequests
|
|
4
4
|
this.timeout = timeout
|
|
5
5
|
this.wait = wait
|
|
6
|
+
this.trace = trace
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
sub(activeRequests, timeout, wait) {
|
|
9
|
-
if (
|
|
9
|
+
sub(activeRequests, timeout, wait, trace) {
|
|
10
|
+
if (
|
|
11
|
+
this.activeRequests === activeRequests &&
|
|
12
|
+
this.timeout === timeout &&
|
|
13
|
+
this.wait === wait &&
|
|
14
|
+
this.trace === trace
|
|
15
|
+
) {
|
|
10
16
|
return this
|
|
11
17
|
}
|
|
12
18
|
|
|
13
|
-
return new SessionConfig(activeRequests, timeout, wait)
|
|
19
|
+
return new SessionConfig(activeRequests, timeout, wait, trace)
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
options(opts) {
|
|
17
23
|
if (!opts) return this
|
|
18
|
-
const {
|
|
19
|
-
|
|
24
|
+
const {
|
|
25
|
+
activeRequests = this.activeRequests,
|
|
26
|
+
timeout = this.timeout,
|
|
27
|
+
wait = this.wait,
|
|
28
|
+
trace = this.trace
|
|
29
|
+
} = opts
|
|
30
|
+
return this.sub(activeRequests, timeout, wait, trace)
|
|
20
31
|
}
|
|
21
32
|
}
|
|
22
33
|
|
package/lib/tree.js
CHANGED
|
@@ -28,6 +28,22 @@ class Pointer {
|
|
|
28
28
|
this.changedBy = null
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// Compare two pointers to see if they point to equivalent positions
|
|
32
|
+
equivalentTo(other) {
|
|
33
|
+
// EMPTY is a special case that can look equivalent to a first entry
|
|
34
|
+
// in a hypercore but actually contains different data.
|
|
35
|
+
if (other === exports.EMPTY) return this === exports.EMPTY
|
|
36
|
+
if (!other) return false
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
this.seq === other.seq &&
|
|
40
|
+
this.offset === other.offset &&
|
|
41
|
+
this.changed === other.changed &&
|
|
42
|
+
this.context === other.context &&
|
|
43
|
+
this.core === other.core
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
31
47
|
retain() {
|
|
32
48
|
this.retained = this.context.cache.retained + 1
|
|
33
49
|
}
|
package/lib/write.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const b4a = require('b4a')
|
|
2
|
-
const c = require('compact-encoding')
|
|
3
2
|
const { OP_COHORT } = require('./compression.js')
|
|
4
3
|
const { encodeBlock, TYPE_COMPAT, TYPE_LATEST } = require('./encoding.js')
|
|
5
4
|
const { Pointer, KeyPointer, ValuePointer, TreeNode, INSERTED, NEEDS_SPLIT } = require('./tree.js')
|
|
5
|
+
const { inflateValue } = require('./inflate.js')
|
|
6
6
|
|
|
7
7
|
const PREFERRED_BLOCK_SIZE = 4096
|
|
8
8
|
const INLINE_VALUE_SIZE = 1024
|
|
@@ -41,14 +41,17 @@ module.exports = class WriteBatch {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
tryPut(key, value) {
|
|
44
|
+
this.checkIfClosed()
|
|
44
45
|
this.ops.push({ put: true, applied: false, key, value })
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
tryDelete(key) {
|
|
49
|
+
this.checkIfClosed()
|
|
48
50
|
this.ops.push({ put: false, applied: false, key, value: null })
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
tryClear() {
|
|
54
|
+
this.checkIfClosed()
|
|
52
55
|
this.ops = []
|
|
53
56
|
this.length = 0
|
|
54
57
|
}
|
|
@@ -76,9 +79,12 @@ module.exports = class WriteBatch {
|
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
async flush() {
|
|
82
|
+
this.checkIfClosed()
|
|
79
83
|
await this.lock()
|
|
80
84
|
|
|
81
85
|
try {
|
|
86
|
+
this.checkIfClosed()
|
|
87
|
+
|
|
82
88
|
const ops = this.ops
|
|
83
89
|
|
|
84
90
|
const root = await this.tree.bootstrap(this.config)
|
|
@@ -100,10 +106,10 @@ module.exports = class WriteBatch {
|
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
await this._flush()
|
|
103
|
-
await this.
|
|
109
|
+
await this.close()
|
|
104
110
|
|
|
105
111
|
if (this.autoUpdate) {
|
|
106
|
-
this.tree.
|
|
112
|
+
this.tree._setRoot(this.root, true)
|
|
107
113
|
}
|
|
108
114
|
} finally {
|
|
109
115
|
this._unlock()
|
|
@@ -140,7 +146,7 @@ module.exports = class WriteBatch {
|
|
|
140
146
|
c = b4a.compare(target, m.key)
|
|
141
147
|
|
|
142
148
|
if (c === 0) {
|
|
143
|
-
const existing = await
|
|
149
|
+
const existing = await inflateValue(m, conf)
|
|
144
150
|
if (b4a.equals(existing, value)) return false
|
|
145
151
|
v.setValue(this.tree.context, mid, value)
|
|
146
152
|
for (let i = 0; i < stack.length; i++) stack[i].changed = true
|
|
@@ -161,7 +167,7 @@ module.exports = class WriteBatch {
|
|
|
161
167
|
if (status >= 0) {
|
|
162
168
|
// already exists, upsert if changed
|
|
163
169
|
const m = v.keys.uget(status)
|
|
164
|
-
const existing = await
|
|
170
|
+
const existing = await inflateValue(m, conf)
|
|
165
171
|
if (b4a.equals(existing, value)) return false
|
|
166
172
|
v.setValue(this.tree.context, status, value)
|
|
167
173
|
}
|
|
@@ -517,9 +523,7 @@ module.exports = class WriteBatch {
|
|
|
517
523
|
buffers[i] = encodeBlock(blocks[i])
|
|
518
524
|
}
|
|
519
525
|
|
|
520
|
-
|
|
521
|
-
throw new Error('Write batch is closed')
|
|
522
|
-
}
|
|
526
|
+
this.checkIfClosed()
|
|
523
527
|
|
|
524
528
|
await context.core.append(buffers)
|
|
525
529
|
|
|
@@ -535,6 +539,12 @@ module.exports = class WriteBatch {
|
|
|
535
539
|
context.cache.retained++
|
|
536
540
|
context.cache.gc()
|
|
537
541
|
}
|
|
542
|
+
|
|
543
|
+
checkIfClosed() {
|
|
544
|
+
if (this.closed) {
|
|
545
|
+
throw new Error('Write batch is closed')
|
|
546
|
+
}
|
|
547
|
+
}
|
|
538
548
|
}
|
|
539
549
|
|
|
540
550
|
async function toCompatType(context, batch, ops) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hyperbee2",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.1",
|
|
4
4
|
"description": "Scalable P2P BTree",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
|
44
|
-
"url": "https://github.com/
|
|
44
|
+
"url": "https://github.com/holepunchto/hyperbee2.git"
|
|
45
45
|
},
|
|
46
|
-
"author": "
|
|
46
|
+
"author": "Holepunch Inc.",
|
|
47
47
|
"license": "Apache-2.0",
|
|
48
48
|
"bugs": {
|
|
49
|
-
"url": "https://github.com/
|
|
49
|
+
"url": "https://github.com/holepunchto/hyperbee2/issues"
|
|
50
50
|
},
|
|
51
|
-
"homepage": "https://github.com/
|
|
51
|
+
"homepage": "https://github.com/holepunchto/hyperbee2"
|
|
52
52
|
}
|