hyperbee2 2.3.0 → 2.4.2
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 +49 -39
- package/lib/changes.js +17 -19
- package/lib/context.js +27 -13
- package/lib/diff.js +8 -6
- package/lib/ranges.js +7 -16
- package/lib/session-config.js +23 -0
- package/lib/write.js +30 -25
- package/package.json +2 -1
package/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const { ChangesStream } = require('./lib/changes.js')
|
|
|
6
6
|
const NodeCache = require('./lib/cache.js')
|
|
7
7
|
const WriteBatch = require('./lib/write.js')
|
|
8
8
|
const CoreContext = require('./lib/context.js')
|
|
9
|
+
const SessionConfig = require('./lib/session-config.js')
|
|
9
10
|
const { Pointer, KeyPointer, ValuePointer, TreeNode, EMPTY } = require('./lib/tree.js')
|
|
10
11
|
const { DeltaOp, DeltaCohort, OP_COHORT } = require('./lib/compression.js')
|
|
11
12
|
|
|
@@ -16,10 +17,13 @@ class Hyperbee {
|
|
|
16
17
|
key = null,
|
|
17
18
|
encryption = null,
|
|
18
19
|
maxCacheSize = 4096,
|
|
20
|
+
config = new SessionConfig([], 0, true),
|
|
21
|
+
activeRequests = config.activeRequests,
|
|
22
|
+
timeout = config.timeout,
|
|
23
|
+
wait = config.wait,
|
|
19
24
|
core = key ? store.get(key) : store.get({ key, name: 'bee', encryption }),
|
|
20
25
|
context = new CoreContext(store, core, new NodeCache(maxCacheSize), core, encryption, t),
|
|
21
26
|
root = null,
|
|
22
|
-
activeRequests = [],
|
|
23
27
|
view = false,
|
|
24
28
|
writable = true,
|
|
25
29
|
unbatch = 0,
|
|
@@ -29,7 +33,7 @@ class Hyperbee {
|
|
|
29
33
|
this.store = store
|
|
30
34
|
this.root = root
|
|
31
35
|
this.context = context
|
|
32
|
-
this.
|
|
36
|
+
this.config = config.sub(activeRequests, timeout, wait)
|
|
33
37
|
this.view = view
|
|
34
38
|
this.writable = writable
|
|
35
39
|
this.unbatch = unbatch
|
|
@@ -79,6 +83,8 @@ class Hyperbee {
|
|
|
79
83
|
|
|
80
84
|
_makeView(context, root, writable, unbatch) {
|
|
81
85
|
return new Hyperbee(this.store, {
|
|
86
|
+
config: this.config,
|
|
87
|
+
core: context.core,
|
|
82
88
|
context,
|
|
83
89
|
root,
|
|
84
90
|
view: true,
|
|
@@ -123,7 +129,7 @@ class Hyperbee {
|
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
async close() {
|
|
126
|
-
if (this.activeRequests.length) Hypercore.clearRequests(this.activeRequests)
|
|
132
|
+
if (this.config.activeRequests.length) Hypercore.clearRequests(this.config.activeRequests)
|
|
127
133
|
if (!this.view) await this.store.close()
|
|
128
134
|
}
|
|
129
135
|
|
|
@@ -163,15 +169,15 @@ class Hyperbee {
|
|
|
163
169
|
}
|
|
164
170
|
|
|
165
171
|
// TODO: unslab these
|
|
166
|
-
async inflate(ptr,
|
|
172
|
+
async inflate(ptr, config) {
|
|
167
173
|
if (ptr.value) {
|
|
168
174
|
this.bump(ptr)
|
|
169
175
|
return ptr.value
|
|
170
176
|
}
|
|
171
177
|
|
|
172
178
|
const [block, context] = await Promise.all([
|
|
173
|
-
ptr.context.getBlock(ptr.seq, ptr.core,
|
|
174
|
-
ptr.context.getContext(ptr.core,
|
|
179
|
+
ptr.context.getBlock(ptr.seq, ptr.core, config),
|
|
180
|
+
ptr.context.getContext(ptr.core, config)
|
|
175
181
|
])
|
|
176
182
|
|
|
177
183
|
const tree = block.tree[ptr.offset]
|
|
@@ -181,15 +187,17 @@ class Hyperbee {
|
|
|
181
187
|
|
|
182
188
|
for (let i = 0; i < keys.length; i++) {
|
|
183
189
|
const d = tree.keys[i]
|
|
184
|
-
keys[i] = inflateKey(context, d, ptr, block,
|
|
190
|
+
keys[i] = inflateKey(context, d, ptr, block, config)
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
for (let i = 0; i < children.length; i++) {
|
|
188
194
|
const d = tree.children[i]
|
|
189
|
-
children[i] = inflateChild(context, d, ptr, block,
|
|
195
|
+
children[i] = inflateChild(context, d, ptr, block, config)
|
|
190
196
|
}
|
|
191
197
|
|
|
192
|
-
const
|
|
198
|
+
const [k, c] = await Promise.all([Promise.all(keys), Promise.all(children)])
|
|
199
|
+
|
|
200
|
+
const value = new TreeNode(k, c)
|
|
193
201
|
if (!ptr.value) ptr.value = value
|
|
194
202
|
|
|
195
203
|
this.bump(ptr)
|
|
@@ -197,8 +205,8 @@ class Hyperbee {
|
|
|
197
205
|
return ptr.value
|
|
198
206
|
}
|
|
199
207
|
|
|
200
|
-
async finalizeKeyPointer(key,
|
|
201
|
-
const value = key.value || (await this.inflateValue(key,
|
|
208
|
+
async finalizeKeyPointer(key, config) {
|
|
209
|
+
const value = key.value || (await this.inflateValue(key, config))
|
|
202
210
|
|
|
203
211
|
return {
|
|
204
212
|
core: key.context.getCore(key.core),
|
|
@@ -209,20 +217,20 @@ class Hyperbee {
|
|
|
209
217
|
}
|
|
210
218
|
}
|
|
211
219
|
|
|
212
|
-
async inflateValue(key,
|
|
220
|
+
async inflateValue(key, config) {
|
|
213
221
|
if (key.value) return key.value
|
|
214
222
|
if (!key.valuePointer) return null
|
|
215
223
|
|
|
216
224
|
const ptr = key.valuePointer
|
|
217
225
|
|
|
218
226
|
if (ptr.split === 0) {
|
|
219
|
-
const block = await ptr.context.getBlock(ptr.seq, ptr.core,
|
|
227
|
+
const block = await ptr.context.getBlock(ptr.seq, ptr.core, config)
|
|
220
228
|
return block.values[ptr.offset]
|
|
221
229
|
}
|
|
222
230
|
|
|
223
231
|
const blockPromises = new Array(ptr.split + 1)
|
|
224
232
|
for (let i = 0; i < blockPromises.length; i++) {
|
|
225
|
-
blockPromises[i] = ptr.context.getBlock(ptr.seq - ptr.split + i, ptr.core,
|
|
233
|
+
blockPromises[i] = ptr.context.getBlock(ptr.seq - ptr.split + i, ptr.core, config)
|
|
226
234
|
}
|
|
227
235
|
const blocks = await Promise.all(blockPromises)
|
|
228
236
|
const splitValue = new Array(blockPromises.length)
|
|
@@ -233,13 +241,13 @@ class Hyperbee {
|
|
|
233
241
|
return b4a.concat(splitValue)
|
|
234
242
|
}
|
|
235
243
|
|
|
236
|
-
async bootstrap(
|
|
244
|
+
async bootstrap(config) {
|
|
237
245
|
if (!this.root) await this.ready()
|
|
238
|
-
if (this.unbatch) await this._rollback(
|
|
246
|
+
if (this.unbatch) await this._rollback(config)
|
|
239
247
|
return this.root === EMPTY ? null : this.root
|
|
240
248
|
}
|
|
241
249
|
|
|
242
|
-
async _rollback(
|
|
250
|
+
async _rollback(config) {
|
|
243
251
|
const expected = this.unbatch
|
|
244
252
|
|
|
245
253
|
let n = expected
|
|
@@ -248,14 +256,14 @@ class Hyperbee {
|
|
|
248
256
|
|
|
249
257
|
while (n > 0 && length > 0 && expected === this.unbatch) {
|
|
250
258
|
const seq = length - 1
|
|
251
|
-
const blk = await context.getBlock(seq, 0,
|
|
259
|
+
const blk = await context.getBlock(seq, 0, config)
|
|
252
260
|
|
|
253
261
|
if (!blk.previous) {
|
|
254
262
|
length = 0
|
|
255
263
|
break
|
|
256
264
|
}
|
|
257
265
|
|
|
258
|
-
context = await context.getContext(blk.previous.core,
|
|
266
|
+
context = await context.getContext(blk.previous.core, config)
|
|
259
267
|
length = blk.previous.seq + 1
|
|
260
268
|
n--
|
|
261
269
|
}
|
|
@@ -272,12 +280,14 @@ class Hyperbee {
|
|
|
272
280
|
this.unbatch = 0
|
|
273
281
|
}
|
|
274
282
|
|
|
275
|
-
async get(key,
|
|
276
|
-
|
|
283
|
+
async get(key, opts) {
|
|
284
|
+
const config = this.config.options(opts)
|
|
285
|
+
|
|
286
|
+
let ptr = await this.bootstrap(config)
|
|
277
287
|
if (!ptr) return null
|
|
278
288
|
|
|
279
289
|
while (true) {
|
|
280
|
-
const v = ptr.value ? this.bump(ptr) : await this.inflate(ptr,
|
|
290
|
+
const v = ptr.value ? this.bump(ptr) : await this.inflate(ptr, config)
|
|
281
291
|
|
|
282
292
|
let s = 0
|
|
283
293
|
let e = v.keys.length
|
|
@@ -289,7 +299,7 @@ class Hyperbee {
|
|
|
289
299
|
|
|
290
300
|
c = b4a.compare(key, m.key)
|
|
291
301
|
|
|
292
|
-
if (c === 0) return this.finalizeKeyPointer(m,
|
|
302
|
+
if (c === 0) return this.finalizeKeyPointer(m, config)
|
|
293
303
|
|
|
294
304
|
if (c < 0) e = mid
|
|
295
305
|
else s = mid + 1
|
|
@@ -307,12 +317,12 @@ module.exports = Hyperbee
|
|
|
307
317
|
|
|
308
318
|
function noop() {}
|
|
309
319
|
|
|
310
|
-
function inflateKey(context, d, ptr, block,
|
|
311
|
-
if (d.type === OP_COHORT) return inflateKeyCohort(context, d, ptr, block,
|
|
312
|
-
return inflateKeyDelta(context, d, ptr, block,
|
|
320
|
+
function inflateKey(context, d, ptr, block, config) {
|
|
321
|
+
if (d.type === OP_COHORT) return inflateKeyCohort(context, d, ptr, block, config)
|
|
322
|
+
return inflateKeyDelta(context, d, ptr, block, config)
|
|
313
323
|
}
|
|
314
324
|
|
|
315
|
-
async function inflateKeyDelta(context, d, ptr, block,
|
|
325
|
+
async function inflateKeyDelta(context, d, ptr, block, config) {
|
|
316
326
|
const k = d.pointer
|
|
317
327
|
|
|
318
328
|
if (!k) return new DeltaOp(false, d.type, d.index, null)
|
|
@@ -320,7 +330,7 @@ async function inflateKeyDelta(context, d, ptr, block, activeRequests) {
|
|
|
320
330
|
const blk =
|
|
321
331
|
k.seq === ptr.seq && k.core === 0 && ptr.core === 0
|
|
322
332
|
? block
|
|
323
|
-
: await context.getBlock(k.seq, k.core,
|
|
333
|
+
: await context.getBlock(k.seq, k.core, config)
|
|
324
334
|
|
|
325
335
|
const bk = blk.keys[k.offset]
|
|
326
336
|
|
|
@@ -328,7 +338,7 @@ async function inflateKeyDelta(context, d, ptr, block, activeRequests) {
|
|
|
328
338
|
|
|
329
339
|
if (bk.valuePointer) {
|
|
330
340
|
const p = bk.valuePointer
|
|
331
|
-
const ctx = await context.getContext(k.core,
|
|
341
|
+
const ctx = await context.getContext(k.core, config)
|
|
332
342
|
vp = new ValuePointer(ctx, p.core, p.seq, p.offset, p.split)
|
|
333
343
|
}
|
|
334
344
|
|
|
@@ -336,20 +346,20 @@ async function inflateKeyDelta(context, d, ptr, block, activeRequests) {
|
|
|
336
346
|
return new DeltaOp(false, d.type, d.index, kp)
|
|
337
347
|
}
|
|
338
348
|
|
|
339
|
-
async function inflateKeyCohort(context, d, ptr, block,
|
|
349
|
+
async function inflateKeyCohort(context, d, ptr, block, config) {
|
|
340
350
|
const co = d.pointer
|
|
341
351
|
|
|
342
352
|
const blk =
|
|
343
353
|
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
344
354
|
? block
|
|
345
|
-
: await context.getBlock(co.seq, co.core,
|
|
355
|
+
: await context.getBlock(co.seq, co.core, config)
|
|
346
356
|
|
|
347
357
|
const cohort = blk.cohorts[co.offset]
|
|
348
358
|
const promises = new Array(cohort.length)
|
|
349
359
|
|
|
350
360
|
for (let i = 0; i < cohort.length; i++) {
|
|
351
361
|
const p = cohort[i]
|
|
352
|
-
const k = inflateKeyDelta(context, p, co, blk,
|
|
362
|
+
const k = inflateKeyDelta(context, p, co, blk, config)
|
|
353
363
|
promises[i] = k
|
|
354
364
|
}
|
|
355
365
|
|
|
@@ -357,31 +367,31 @@ async function inflateKeyCohort(context, d, ptr, block, activeRequests) {
|
|
|
357
367
|
return new DeltaCohort(false, p, await Promise.all(promises))
|
|
358
368
|
}
|
|
359
369
|
|
|
360
|
-
function inflateChild(context, d, ptr, block,
|
|
361
|
-
if (d.type === OP_COHORT) return inflateChildCohort(context, d, ptr, block,
|
|
362
|
-
return Promise.resolve(inflateChildDelta(context, d, ptr, block,
|
|
370
|
+
function inflateChild(context, d, ptr, block, config) {
|
|
371
|
+
if (d.type === OP_COHORT) return inflateChildCohort(context, d, ptr, block, config)
|
|
372
|
+
return Promise.resolve(inflateChildDelta(context, d, ptr, block, config))
|
|
363
373
|
}
|
|
364
374
|
|
|
365
|
-
function inflateChildDelta(context, d, ptr, block,
|
|
375
|
+
function inflateChildDelta(context, d, ptr, block, config) {
|
|
366
376
|
const p = d.pointer
|
|
367
377
|
const c = p && context.createTreeNode(p.core, p.seq, p.offset, false, null)
|
|
368
378
|
return new DeltaOp(false, d.type, d.index, c)
|
|
369
379
|
}
|
|
370
380
|
|
|
371
|
-
async function inflateChildCohort(context, d, ptr, block,
|
|
381
|
+
async function inflateChildCohort(context, d, ptr, block, config) {
|
|
372
382
|
const co = d.pointer
|
|
373
383
|
|
|
374
384
|
const blk =
|
|
375
385
|
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
376
386
|
? block
|
|
377
|
-
: await context.getBlock(co.seq, co.core,
|
|
387
|
+
: await context.getBlock(co.seq, co.core, config)
|
|
378
388
|
|
|
379
389
|
const cohort = blk.cohorts[co.offset]
|
|
380
390
|
const deltas = new Array(cohort.length)
|
|
381
391
|
|
|
382
392
|
for (let i = 0; i < cohort.length; i++) {
|
|
383
393
|
const c = cohort[i]
|
|
384
|
-
deltas[i] = inflateChildDelta(context, c, co, blk,
|
|
394
|
+
deltas[i] = inflateChildDelta(context, c, co, blk, config)
|
|
385
395
|
}
|
|
386
396
|
|
|
387
397
|
const p = new Pointer(context, co.core, co.seq, co.offset)
|
package/lib/changes.js
CHANGED
|
@@ -1,43 +1,41 @@
|
|
|
1
1
|
const { Readable } = require('streamx')
|
|
2
2
|
|
|
3
3
|
class ChangesStream extends Readable {
|
|
4
|
-
constructor(tree,
|
|
5
|
-
const { highWaterMark } =
|
|
4
|
+
constructor(tree, opts = {}) {
|
|
5
|
+
const { highWaterMark, head = null } = opts
|
|
6
6
|
super({ eagerOpen: true, highWaterMark })
|
|
7
7
|
|
|
8
|
-
const { head = null, activeRequests = tree.activeRequests } = options
|
|
9
|
-
|
|
10
8
|
this.tree = tree
|
|
11
9
|
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
10
|
+
this.head = head
|
|
11
|
+
this.context = null
|
|
12
|
+
this.config = tree.config.options(opts)
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
async _openp() {
|
|
18
|
-
await this.tree.bootstrap(this.
|
|
19
|
-
if (this.
|
|
20
|
-
if (this.
|
|
16
|
+
await this.tree.bootstrap(this.config)
|
|
17
|
+
if (this.head === null) this.head = this.tree.head()
|
|
18
|
+
if (this.head !== null) this.context = this.tree.context.getContextByKey(this.head.key)
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
async _readp() {
|
|
24
|
-
if (!this.
|
|
22
|
+
if (!this.context || this.head.length === 0) {
|
|
25
23
|
this.push(null)
|
|
26
24
|
return
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
const data = {
|
|
30
|
-
head: this.
|
|
28
|
+
head: this.head,
|
|
31
29
|
batch: []
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
const seq = this.
|
|
35
|
-
const blk = await this.
|
|
32
|
+
const seq = this.head.length - 1
|
|
33
|
+
const blk = await this.context.getBlock(seq, 0, this.config)
|
|
36
34
|
const batchStart = seq - blk.batch.start
|
|
37
35
|
const remaining = new Array(blk.batch.start)
|
|
38
36
|
|
|
39
37
|
for (let i = 0; i < remaining.length; i++) {
|
|
40
|
-
remaining[i] = this.
|
|
38
|
+
remaining[i] = this.context.getBlock(batchStart + i, 0, this.config)
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
for (const blk of await Promise.all(remaining)) data.batch.push(blk)
|
|
@@ -46,13 +44,13 @@ class ChangesStream extends Readable {
|
|
|
46
44
|
this.push(data)
|
|
47
45
|
|
|
48
46
|
if (!blk.previous) {
|
|
49
|
-
this.
|
|
50
|
-
this.
|
|
47
|
+
this.head = null
|
|
48
|
+
this.context = null
|
|
51
49
|
return
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
this.
|
|
55
|
-
this.
|
|
52
|
+
this.context = await this.context.getContext(blk.previous.core, this.config)
|
|
53
|
+
this.head = { key: this.context.core.key, length: blk.previous.seq + 1 }
|
|
56
54
|
}
|
|
57
55
|
|
|
58
56
|
async _open(cb) {
|
package/lib/context.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const b4a = require('b4a')
|
|
2
2
|
const ScopeLock = require('scope-lock')
|
|
3
|
+
const { BLOCK_NOT_AVAILABLE } = require('hypercore-errors')
|
|
3
4
|
const { TreeNodePointer } = require('./tree.js')
|
|
4
5
|
const { decodeBlock } = require('./encoding.js')
|
|
5
6
|
|
|
@@ -27,20 +28,26 @@ class CoreContext {
|
|
|
27
28
|
// return '[CoreContext]'
|
|
28
29
|
// }
|
|
29
30
|
|
|
30
|
-
async update(
|
|
31
|
+
async update(config) {
|
|
31
32
|
await this.core.ready()
|
|
32
33
|
|
|
33
34
|
if (this.length === this.core.length || this.core.length === 0) return
|
|
34
35
|
|
|
35
36
|
const length = this.core.length
|
|
36
37
|
const seq = length - 1
|
|
37
|
-
const buffer = await this.core.get(seq,
|
|
38
|
+
const buffer = await this.core.get(seq, config)
|
|
38
39
|
const block = decodeBlock(buffer, seq)
|
|
40
|
+
|
|
41
|
+
await this._inflateCheckpoint(length, block, config)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async _inflateCheckpoint(length, block, config) {
|
|
39
45
|
const checkpoint = block.checkpoint
|
|
40
46
|
|
|
41
47
|
if (checkpoint > 0) {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
48
|
+
const seq = checkpoint - 1
|
|
49
|
+
const buffer = await this.core.get(seq, config)
|
|
50
|
+
const block = decodeBlock(buffer, seq)
|
|
44
51
|
|
|
45
52
|
if (length < this.length) return
|
|
46
53
|
|
|
@@ -84,12 +91,12 @@ class CoreContext {
|
|
|
84
91
|
return this.cores.length
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
async getCoreOffset(context, core,
|
|
88
|
-
if (core !== 0 && core - 1 >= context.cores.length) await context.update(
|
|
94
|
+
async getCoreOffset(context, core, config) {
|
|
95
|
+
if (core !== 0 && core - 1 >= context.cores.length) await context.update(config)
|
|
89
96
|
return this.getCoreOffsetLocal(context, core)
|
|
90
97
|
}
|
|
91
98
|
|
|
92
|
-
async getCoreOffsetByKey(key,
|
|
99
|
+
async getCoreOffsetByKey(key, config) {
|
|
93
100
|
await this.core.ready()
|
|
94
101
|
|
|
95
102
|
if (b4a.equals(key, this.core.key)) return 0
|
|
@@ -101,7 +108,7 @@ class CoreContext {
|
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
|
|
104
|
-
await this.update(
|
|
111
|
+
await this.update(config)
|
|
105
112
|
|
|
106
113
|
for (let i = 0; i < this.cores.length; i++) {
|
|
107
114
|
const k = this.cores[i].key
|
|
@@ -135,11 +142,18 @@ class CoreContext {
|
|
|
135
142
|
return this.cores[index - 1].key
|
|
136
143
|
}
|
|
137
144
|
|
|
138
|
-
async getBlock(seq, core,
|
|
139
|
-
if (core !== 0 && core - 1 >= this.cores.length) await this.update(
|
|
145
|
+
async getBlock(seq, core, config) {
|
|
146
|
+
if (core !== 0 && core - 1 >= this.cores.length) await this.update(config)
|
|
147
|
+
|
|
140
148
|
const hc = this.getCore(core)
|
|
141
|
-
const buffer = await hc.get(seq,
|
|
149
|
+
const buffer = await hc.get(seq, config)
|
|
150
|
+
if (buffer === null) throw BLOCK_NOT_AVAILABLE()
|
|
142
151
|
const block = decodeBlock(buffer, seq)
|
|
152
|
+
|
|
153
|
+
if (block.checkpoint > this.checkpoint) {
|
|
154
|
+
await this._inflateCheckpoint(seq + 1, block, config)
|
|
155
|
+
}
|
|
156
|
+
|
|
143
157
|
return block
|
|
144
158
|
}
|
|
145
159
|
|
|
@@ -158,9 +172,9 @@ class CoreContext {
|
|
|
158
172
|
return ctx
|
|
159
173
|
}
|
|
160
174
|
|
|
161
|
-
async getContext(core,
|
|
175
|
+
async getContext(core, config) {
|
|
162
176
|
if (core === 0) return this
|
|
163
|
-
if (core > this.cores.length) await this.update(
|
|
177
|
+
if (core > this.cores.length) await this.update(config)
|
|
164
178
|
if (core > this.cores.length) throw new Error('Bad core index: ' + core)
|
|
165
179
|
|
|
166
180
|
const hex = b4a.toString(this.cores[core - 1].key, 'hex')
|
package/lib/diff.js
CHANGED
|
@@ -3,7 +3,9 @@ const b4a = require('b4a')
|
|
|
3
3
|
const { RangeIterator } = require('./ranges.js')
|
|
4
4
|
|
|
5
5
|
class DiffIterator {
|
|
6
|
-
constructor(tree, left, right,
|
|
6
|
+
constructor(tree, left, right, opts = {}) {
|
|
7
|
+
const { limit = -1 } = opts
|
|
8
|
+
|
|
7
9
|
this.tree = tree
|
|
8
10
|
|
|
9
11
|
this.left = left
|
|
@@ -11,7 +13,7 @@ class DiffIterator {
|
|
|
11
13
|
|
|
12
14
|
this.left.limit = this.right.limit = -1
|
|
13
15
|
|
|
14
|
-
this.
|
|
16
|
+
this.config = tree.config.options(opts)
|
|
15
17
|
this.limit = limit
|
|
16
18
|
|
|
17
19
|
this.nextLeft = null
|
|
@@ -23,14 +25,14 @@ class DiffIterator {
|
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
async _shiftRight() {
|
|
26
|
-
const right = await this.tree.finalizeKeyPointer(this.nextRight, this.
|
|
28
|
+
const right = await this.tree.finalizeKeyPointer(this.nextRight, this.config)
|
|
27
29
|
this.nextRight = null
|
|
28
30
|
if (this.limit > 0) this.limit--
|
|
29
31
|
return { left: null, right }
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
async _shiftLeft() {
|
|
33
|
-
const left = await this.tree.finalizeKeyPointer(this.nextLeft, this.
|
|
35
|
+
const left = await this.tree.finalizeKeyPointer(this.nextLeft, this.config)
|
|
34
36
|
this.nextLeft = null
|
|
35
37
|
if (this.limit > 0) this.limit--
|
|
36
38
|
return { left, right: null }
|
|
@@ -77,8 +79,8 @@ class DiffIterator {
|
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
const [left, right] = await Promise.all([
|
|
80
|
-
this.tree.finalizeKeyPointer(leftKey, this.
|
|
81
|
-
this.tree.finalizeKeyPointer(rightKey, this.
|
|
82
|
+
this.tree.finalizeKeyPointer(leftKey, this.config),
|
|
83
|
+
this.tree.finalizeKeyPointer(rightKey, this.config)
|
|
82
84
|
])
|
|
83
85
|
|
|
84
86
|
if (this.limit > 0) this.limit--
|
package/lib/ranges.js
CHANGED
|
@@ -3,21 +3,12 @@ const b4a = require('b4a')
|
|
|
3
3
|
|
|
4
4
|
class RangeIterator {
|
|
5
5
|
constructor(tree, opts = {}) {
|
|
6
|
-
const {
|
|
7
|
-
activeRequests = [],
|
|
8
|
-
prefetch = true,
|
|
9
|
-
reverse = false,
|
|
10
|
-
limit = -1,
|
|
11
|
-
gte,
|
|
12
|
-
gt,
|
|
13
|
-
lte,
|
|
14
|
-
lt
|
|
15
|
-
} = opts
|
|
6
|
+
const { prefetch = true, reverse = false, limit = -1, gte, gt, lte, lt } = opts
|
|
16
7
|
|
|
17
8
|
this.tree = tree
|
|
18
9
|
this.root = null
|
|
19
10
|
this.stack = []
|
|
20
|
-
this.
|
|
11
|
+
this.config = tree.config.options(opts)
|
|
21
12
|
this.reverse = reverse
|
|
22
13
|
this.limit = limit
|
|
23
14
|
this.start = gte || gt || null
|
|
@@ -29,7 +20,7 @@ class RangeIterator {
|
|
|
29
20
|
}
|
|
30
21
|
|
|
31
22
|
async open() {
|
|
32
|
-
if (!this.root) this.root = await this.tree.bootstrap(this.
|
|
23
|
+
if (!this.root) this.root = await this.tree.bootstrap(this.config)
|
|
33
24
|
if (!this.root) return
|
|
34
25
|
|
|
35
26
|
if (this.limit === 0) return
|
|
@@ -44,7 +35,7 @@ class RangeIterator {
|
|
|
44
35
|
const top = this.stack[this.stack.length - 1]
|
|
45
36
|
const v = top.node.value
|
|
46
37
|
? this.tree.bump(top.node)
|
|
47
|
-
: await this.tree.inflate(top.node, this.
|
|
38
|
+
: await this.tree.inflate(top.node, this.config)
|
|
48
39
|
|
|
49
40
|
for (let i = 0; i < v.keys.length; i++) {
|
|
50
41
|
const j = this.reverse ? v.keys.length - 1 - i : i
|
|
@@ -75,7 +66,7 @@ class RangeIterator {
|
|
|
75
66
|
|
|
76
67
|
async next() {
|
|
77
68
|
const key = await this.nextKey()
|
|
78
|
-
return key === null ? key : this.tree.finalizeKeyPointer(key, this.
|
|
69
|
+
return key === null ? key : this.tree.finalizeKeyPointer(key, this.config)
|
|
79
70
|
}
|
|
80
71
|
|
|
81
72
|
async nextKey() {
|
|
@@ -83,7 +74,7 @@ class RangeIterator {
|
|
|
83
74
|
const top = this.stack.pop()
|
|
84
75
|
const v = top.node.value
|
|
85
76
|
? this.tree.bump(top.node)
|
|
86
|
-
: await this.tree.inflate(top.node, this.
|
|
77
|
+
: await this.tree.inflate(top.node, this.config)
|
|
87
78
|
|
|
88
79
|
const offset = top.offset++
|
|
89
80
|
const child = (offset & 1) === 0
|
|
@@ -150,7 +141,7 @@ class RangeIterator {
|
|
|
150
141
|
if (cmp > this.compare) break
|
|
151
142
|
|
|
152
143
|
const c = pv.children.get(i)
|
|
153
|
-
if (!c.value) this.tree.inflate(c, this.
|
|
144
|
+
if (!c.value) this.tree.inflate(c, this.config).catch(noop)
|
|
154
145
|
|
|
155
146
|
limit = Math.max(limit - this.tree.context.minKeys, 0)
|
|
156
147
|
if (limit === 0) break
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class SessionConfig {
|
|
2
|
+
constructor(activeRequests, timeout, wait) {
|
|
3
|
+
this.activeRequests = activeRequests
|
|
4
|
+
this.timeout = timeout
|
|
5
|
+
this.wait = wait
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
sub(activeRequests, timeout, wait) {
|
|
9
|
+
if (this.activeRequests === activeRequests && this.timeout === timeout && this.wait === wait) {
|
|
10
|
+
return this
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return new SessionConfig(activeRequests, timeout, wait)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
options(opts) {
|
|
17
|
+
if (!opts) return this
|
|
18
|
+
const { activeRequests = this.activeRequests, timeout = this.timeout, wait = this.wait } = opts
|
|
19
|
+
return this.sub(activeRequests, timeout, wait)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = SessionConfig
|
package/lib/write.js
CHANGED
|
@@ -23,6 +23,7 @@ module.exports = class WriteBatch {
|
|
|
23
23
|
} = opts
|
|
24
24
|
|
|
25
25
|
this.tree = tree
|
|
26
|
+
this.config = tree.config.options(opts)
|
|
26
27
|
this.deltaMax = deltaMax
|
|
27
28
|
this.deltaMin = deltaMin
|
|
28
29
|
this.inlineValueSize = inlineValueSize
|
|
@@ -68,7 +69,7 @@ module.exports = class WriteBatch {
|
|
|
68
69
|
try {
|
|
69
70
|
const ops = this.ops
|
|
70
71
|
|
|
71
|
-
const root = await this.tree.bootstrap()
|
|
72
|
+
const root = await this.tree.bootstrap(this.config)
|
|
72
73
|
|
|
73
74
|
const length = this._getLength(root)
|
|
74
75
|
const context = this._getContext(root)
|
|
@@ -106,11 +107,12 @@ module.exports = class WriteBatch {
|
|
|
106
107
|
const stack = []
|
|
107
108
|
const target = key
|
|
108
109
|
const snap = this.snapshot
|
|
110
|
+
const conf = this.config
|
|
109
111
|
|
|
110
112
|
let ptr = this.root
|
|
111
113
|
|
|
112
114
|
while (true) {
|
|
113
|
-
const v = await retainAndInflate(ptr, snap)
|
|
115
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
114
116
|
if (!v.children.ulength) break
|
|
115
117
|
|
|
116
118
|
stack.push(ptr)
|
|
@@ -126,7 +128,7 @@ module.exports = class WriteBatch {
|
|
|
126
128
|
c = b4a.compare(target, m.key)
|
|
127
129
|
|
|
128
130
|
if (c === 0) {
|
|
129
|
-
const existing = await snap.inflateValue(m)
|
|
131
|
+
const existing = await snap.inflateValue(m, conf)
|
|
130
132
|
if (b4a.equals(existing, value)) return false
|
|
131
133
|
v.setValue(this.tree.context, mid, value)
|
|
132
134
|
for (let i = 0; i < stack.length; i++) stack[i].changed = true
|
|
@@ -141,13 +143,13 @@ module.exports = class WriteBatch {
|
|
|
141
143
|
ptr = v.children.uget(i)
|
|
142
144
|
}
|
|
143
145
|
|
|
144
|
-
const v = await retainAndInflate(ptr, snap)
|
|
146
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
145
147
|
let status = v.insertLeaf(this.tree.context, target, value)
|
|
146
148
|
|
|
147
149
|
if (status >= 0) {
|
|
148
150
|
// already exists, upsert if changed
|
|
149
151
|
const m = v.keys.uget(status)
|
|
150
|
-
const existing = await snap.inflateValue(m)
|
|
152
|
+
const existing = await snap.inflateValue(m, conf)
|
|
151
153
|
if (b4a.equals(existing, value)) return false
|
|
152
154
|
v.setValue(this.tree.context, status, value)
|
|
153
155
|
}
|
|
@@ -156,12 +158,12 @@ module.exports = class WriteBatch {
|
|
|
156
158
|
for (let i = 0; i < stack.length; i++) stack[i].changed = true
|
|
157
159
|
|
|
158
160
|
while (status === NEEDS_SPLIT) {
|
|
159
|
-
const v = await retainAndInflate(ptr, snap)
|
|
161
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
160
162
|
const parent = stack.pop()
|
|
161
163
|
const { median, right } = v.split(this.tree.context)
|
|
162
164
|
|
|
163
165
|
if (parent) {
|
|
164
|
-
const p = await retainAndInflate(parent, snap)
|
|
166
|
+
const p = await retainAndInflate(parent, snap, conf)
|
|
165
167
|
status = p.insertNode(this.tree.context, median, right)
|
|
166
168
|
ptr = parent
|
|
167
169
|
} else {
|
|
@@ -182,7 +184,7 @@ module.exports = class WriteBatch {
|
|
|
182
184
|
const stack = []
|
|
183
185
|
|
|
184
186
|
while (true) {
|
|
185
|
-
const v = await retainAndInflate(ptr, this.snapshot)
|
|
187
|
+
const v = await retainAndInflate(ptr, this.snapshot, this.config)
|
|
186
188
|
stack.push(ptr)
|
|
187
189
|
|
|
188
190
|
let s = 0
|
|
@@ -217,6 +219,7 @@ module.exports = class WriteBatch {
|
|
|
217
219
|
|
|
218
220
|
async _setKeyToNearestLeaf(v, index, stack) {
|
|
219
221
|
const snap = this.snapshot
|
|
222
|
+
const conf = this.config
|
|
220
223
|
|
|
221
224
|
let left = v.children.uget(index)
|
|
222
225
|
let right = v.children.uget(index + 1)
|
|
@@ -226,21 +229,21 @@ module.exports = class WriteBatch {
|
|
|
226
229
|
if (ls < rs) {
|
|
227
230
|
// if fewer leaves on the left
|
|
228
231
|
stack.push(right)
|
|
229
|
-
let r = await retainAndInflate(right, snap)
|
|
232
|
+
let r = await retainAndInflate(right, snap, conf)
|
|
230
233
|
while (r.children.ulength) {
|
|
231
234
|
right = r.children.uget(0)
|
|
232
235
|
stack.push(right)
|
|
233
|
-
r = await retainAndInflate(right, snap)
|
|
236
|
+
r = await retainAndInflate(right, snap, conf)
|
|
234
237
|
}
|
|
235
238
|
v.keys.set(index, r.keys.shift())
|
|
236
239
|
} else {
|
|
237
240
|
// if fewer leaves on the right
|
|
238
241
|
stack.push(left)
|
|
239
|
-
let l = await retainAndInflate(left, snap)
|
|
242
|
+
let l = await retainAndInflate(left, snap, conf)
|
|
240
243
|
while (l.children.ulength) {
|
|
241
244
|
left = l.children.uget(l.children.ulength - 1)
|
|
242
245
|
stack.push(left)
|
|
243
|
-
l = await retainAndInflate(left, snap)
|
|
246
|
+
l = await retainAndInflate(left, snap, conf)
|
|
244
247
|
}
|
|
245
248
|
v.keys.set(index, l.keys.pop())
|
|
246
249
|
}
|
|
@@ -248,11 +251,12 @@ module.exports = class WriteBatch {
|
|
|
248
251
|
|
|
249
252
|
async _leafSize(ptr, goLeft) {
|
|
250
253
|
const snap = this.snapshot
|
|
254
|
+
const conf = this.config
|
|
251
255
|
|
|
252
|
-
let v = await retainAndInflate(ptr, snap)
|
|
256
|
+
let v = await retainAndInflate(ptr, snap, conf)
|
|
253
257
|
while (v.children.ulength) {
|
|
254
258
|
ptr = v.children.uget(goLeft ? 0 : v.children.ulength - 1)
|
|
255
|
-
v = await retainAndInflate(ptr, snap)
|
|
259
|
+
v = await retainAndInflate(ptr, snap, conf)
|
|
256
260
|
}
|
|
257
261
|
return v.keys.ulength
|
|
258
262
|
}
|
|
@@ -261,20 +265,21 @@ module.exports = class WriteBatch {
|
|
|
261
265
|
const root = stack[0]
|
|
262
266
|
const minKeys = this.tree.context.minKeys
|
|
263
267
|
const snap = this.snapshot
|
|
268
|
+
const conf = this.config
|
|
264
269
|
|
|
265
270
|
while (stack.length > 1) {
|
|
266
271
|
const ptr = stack.pop()
|
|
267
272
|
const parent = stack[stack.length - 1]
|
|
268
273
|
|
|
269
|
-
const v = await retainAndInflate(ptr, snap)
|
|
274
|
+
const v = await retainAndInflate(ptr, snap, conf)
|
|
270
275
|
|
|
271
276
|
if (v.keys.ulength >= minKeys) return root
|
|
272
277
|
|
|
273
|
-
const p = await retainAndInflate(parent, snap)
|
|
278
|
+
const p = await retainAndInflate(parent, snap, conf)
|
|
274
279
|
|
|
275
280
|
let { left, index, right } = v.siblings(p)
|
|
276
281
|
|
|
277
|
-
let l = left && (await retainAndInflate(left, snap))
|
|
282
|
+
let l = left && (await retainAndInflate(left, snap, conf))
|
|
278
283
|
|
|
279
284
|
// maybe borrow from left sibling?
|
|
280
285
|
if (l && l.keys.ulength > minKeys) {
|
|
@@ -285,7 +290,7 @@ module.exports = class WriteBatch {
|
|
|
285
290
|
return root
|
|
286
291
|
}
|
|
287
292
|
|
|
288
|
-
let r = right && (await retainAndInflate(right, snap))
|
|
293
|
+
let r = right && (await retainAndInflate(right, snap, conf))
|
|
289
294
|
|
|
290
295
|
// maybe borrow from right sibling?
|
|
291
296
|
if (r && r.keys.ulength > minKeys) {
|
|
@@ -313,7 +318,7 @@ module.exports = class WriteBatch {
|
|
|
313
318
|
p.removeKey(index)
|
|
314
319
|
}
|
|
315
320
|
|
|
316
|
-
const r = await retainAndInflate(root, snap)
|
|
321
|
+
const r = await retainAndInflate(root, snap, conf)
|
|
317
322
|
// check if the tree shrunk
|
|
318
323
|
if (!r.keys.ulength && r.children.ulength) return r.children.uget(0)
|
|
319
324
|
return root
|
|
@@ -330,7 +335,7 @@ module.exports = class WriteBatch {
|
|
|
330
335
|
return
|
|
331
336
|
}
|
|
332
337
|
|
|
333
|
-
if (!this.root.value) await this.snapshot.inflate(this.root)
|
|
338
|
+
if (!this.root.value) await this.snapshot.inflate(this.root, this.config)
|
|
334
339
|
|
|
335
340
|
let update = { size: 0, nodes: [], keys: [], values: [] }
|
|
336
341
|
let minValue = -1
|
|
@@ -342,9 +347,9 @@ module.exports = class WriteBatch {
|
|
|
342
347
|
const values = []
|
|
343
348
|
|
|
344
349
|
const context = this.tree.context.getLocalContext()
|
|
345
|
-
const
|
|
350
|
+
const config = this.tree.config
|
|
346
351
|
|
|
347
|
-
await context.update(
|
|
352
|
+
await context.update(config)
|
|
348
353
|
|
|
349
354
|
while (stack.length > 0) {
|
|
350
355
|
const node = stack.pop()
|
|
@@ -485,7 +490,7 @@ module.exports = class WriteBatch {
|
|
|
485
490
|
const buffers = new Array(blocks.length)
|
|
486
491
|
|
|
487
492
|
if (blocks.length > 0 && this.length > 0) {
|
|
488
|
-
const core = this.key ? await context.getCoreOffsetByKey(this.key,
|
|
493
|
+
const core = this.key ? await context.getCoreOffsetByKey(this.key, config) : 0
|
|
489
494
|
blocks[blocks.length - 1].previous = { core, seq: this.length - 1 }
|
|
490
495
|
}
|
|
491
496
|
|
|
@@ -600,11 +605,11 @@ function supportsCompression(type) {
|
|
|
600
605
|
return type !== TYPE_COMPAT && type !== 0
|
|
601
606
|
}
|
|
602
607
|
|
|
603
|
-
async function retainAndInflate(ptr, snap) {
|
|
608
|
+
async function retainAndInflate(ptr, snap, conf) {
|
|
604
609
|
if (ptr.value) {
|
|
605
610
|
ptr.retain()
|
|
606
611
|
return ptr.value
|
|
607
612
|
}
|
|
608
613
|
ptr.retain()
|
|
609
|
-
return await snap.inflate(ptr)
|
|
614
|
+
return await snap.inflate(ptr, conf)
|
|
610
615
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hyperbee2",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.2",
|
|
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",
|