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/index.js
CHANGED
|
@@ -6,14 +6,8 @@ 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
|
|
10
|
-
|
|
11
|
-
KeyPointer,
|
|
12
|
-
ValuePointer,
|
|
13
|
-
TreeNode,
|
|
14
|
-
TreeNodePointer,
|
|
15
|
-
EMPTY
|
|
16
|
-
} = require('./lib/tree.js')
|
|
9
|
+
const SessionConfig = require('./lib/session-config.js')
|
|
10
|
+
const { Pointer, KeyPointer, ValuePointer, TreeNode, EMPTY } = require('./lib/tree.js')
|
|
17
11
|
const { DeltaOp, DeltaCohort, OP_COHORT } = require('./lib/compression.js')
|
|
18
12
|
|
|
19
13
|
class Hyperbee {
|
|
@@ -22,12 +16,14 @@ class Hyperbee {
|
|
|
22
16
|
t = 128, // legacy number for now, should be 128 now
|
|
23
17
|
key = null,
|
|
24
18
|
encryption = null,
|
|
25
|
-
core = key ? store.get(key) : store.get({ key, name: 'bee', encryption }),
|
|
26
|
-
context = new CoreContext(store, core, core, encryption, t),
|
|
27
19
|
maxCacheSize = 4096,
|
|
28
|
-
|
|
20
|
+
config = new SessionConfig([], 0, true),
|
|
21
|
+
activeRequests = config.activeRequests,
|
|
22
|
+
timeout = config.timeout,
|
|
23
|
+
wait = config.wait,
|
|
24
|
+
core = key ? store.get(key) : store.get({ key, name: 'bee', encryption }),
|
|
25
|
+
context = new CoreContext(store, core, new NodeCache(maxCacheSize), core, encryption, t),
|
|
29
26
|
root = null,
|
|
30
|
-
activeRequests = [],
|
|
31
27
|
view = false,
|
|
32
28
|
writable = true,
|
|
33
29
|
unbatch = 0,
|
|
@@ -36,9 +32,8 @@ class Hyperbee {
|
|
|
36
32
|
|
|
37
33
|
this.store = store
|
|
38
34
|
this.root = root
|
|
39
|
-
this.cache = cache
|
|
40
35
|
this.context = context
|
|
41
|
-
this.
|
|
36
|
+
this.config = config.sub(activeRequests, timeout, wait)
|
|
42
37
|
this.view = view
|
|
43
38
|
this.writable = writable
|
|
44
39
|
this.unbatch = unbatch
|
|
@@ -58,6 +53,10 @@ class Hyperbee {
|
|
|
58
53
|
return { length: this.root.seq + 1, key: this.root.context.core.key }
|
|
59
54
|
}
|
|
60
55
|
|
|
56
|
+
get cache() {
|
|
57
|
+
return this.context.cache
|
|
58
|
+
}
|
|
59
|
+
|
|
61
60
|
get core() {
|
|
62
61
|
return this.context.core
|
|
63
62
|
}
|
|
@@ -84,8 +83,9 @@ class Hyperbee {
|
|
|
84
83
|
|
|
85
84
|
_makeView(context, root, writable, unbatch) {
|
|
86
85
|
return new Hyperbee(this.store, {
|
|
86
|
+
config: this.config,
|
|
87
|
+
core: context.core,
|
|
87
88
|
context,
|
|
88
|
-
cache: this.cache,
|
|
89
89
|
root,
|
|
90
90
|
view: true,
|
|
91
91
|
writable,
|
|
@@ -95,7 +95,7 @@ class Hyperbee {
|
|
|
95
95
|
|
|
96
96
|
checkout({ length = this.core.length, key = null, writable = false } = {}) {
|
|
97
97
|
const context = key ? this.context.getContextByKey(key) : this.context
|
|
98
|
-
const root = length === 0 ? EMPTY :
|
|
98
|
+
const root = length === 0 ? EMPTY : context.createTreeNode(0, length - 1, 0, false, null)
|
|
99
99
|
return this._makeView(context, root, writable, 0)
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -119,7 +119,7 @@ class Hyperbee {
|
|
|
119
119
|
this.root =
|
|
120
120
|
this.context.core.length === 0
|
|
121
121
|
? EMPTY
|
|
122
|
-
:
|
|
122
|
+
: this.context.createTreeNode(0, this.core.length - 1, 0, false, null)
|
|
123
123
|
|
|
124
124
|
if (this._autoUpdate) {
|
|
125
125
|
this.core.on('append', () => {
|
|
@@ -129,7 +129,7 @@ class Hyperbee {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
async close() {
|
|
132
|
-
if (this.activeRequests.length) Hypercore.clearRequests(this.activeRequests)
|
|
132
|
+
if (this.config.activeRequests.length) Hypercore.clearRequests(this.config.activeRequests)
|
|
133
133
|
if (!this.view) await this.store.close()
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -163,21 +163,21 @@ class Hyperbee {
|
|
|
163
163
|
|
|
164
164
|
bump(ptr) {
|
|
165
165
|
if (ptr.changed) return ptr.value
|
|
166
|
-
this.cache.bump(ptr)
|
|
167
|
-
this.cache.gc()
|
|
166
|
+
this.context.cache.bump(ptr)
|
|
167
|
+
this.context.cache.gc()
|
|
168
168
|
return ptr.value
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
// TODO: unslab these
|
|
172
|
-
async inflate(ptr,
|
|
171
|
+
// TODO: unslab these
|
|
172
|
+
async inflate(ptr, config) {
|
|
173
173
|
if (ptr.value) {
|
|
174
174
|
this.bump(ptr)
|
|
175
175
|
return ptr.value
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
const [block, context] = await Promise.all([
|
|
179
|
-
ptr.context.getBlock(ptr.seq, ptr.core,
|
|
180
|
-
ptr.context.getContext(ptr.core,
|
|
179
|
+
ptr.context.getBlock(ptr.seq, ptr.core, config),
|
|
180
|
+
ptr.context.getContext(ptr.core, config)
|
|
181
181
|
])
|
|
182
182
|
|
|
183
183
|
const tree = block.tree[ptr.offset]
|
|
@@ -187,15 +187,17 @@ class Hyperbee {
|
|
|
187
187
|
|
|
188
188
|
for (let i = 0; i < keys.length; i++) {
|
|
189
189
|
const d = tree.keys[i]
|
|
190
|
-
keys[i] = inflateKey(context, d, ptr, block,
|
|
190
|
+
keys[i] = inflateKey(context, d, ptr, block, config)
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
for (let i = 0; i < children.length; i++) {
|
|
194
194
|
const d = tree.children[i]
|
|
195
|
-
children[i] = inflateChild(context, d, ptr, block,
|
|
195
|
+
children[i] = inflateChild(context, d, ptr, block, config)
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
const
|
|
198
|
+
const [k, c] = await Promise.all([Promise.all(keys), Promise.all(children)])
|
|
199
|
+
|
|
200
|
+
const value = new TreeNode(k, c)
|
|
199
201
|
if (!ptr.value) ptr.value = value
|
|
200
202
|
|
|
201
203
|
this.bump(ptr)
|
|
@@ -203,8 +205,8 @@ class Hyperbee {
|
|
|
203
205
|
return ptr.value
|
|
204
206
|
}
|
|
205
207
|
|
|
206
|
-
async finalizeKeyPointer(key,
|
|
207
|
-
const value = key.value || (await this.inflateValue(key,
|
|
208
|
+
async finalizeKeyPointer(key, config) {
|
|
209
|
+
const value = key.value || (await this.inflateValue(key, config))
|
|
208
210
|
|
|
209
211
|
return {
|
|
210
212
|
core: key.context.getCore(key.core),
|
|
@@ -215,20 +217,20 @@ class Hyperbee {
|
|
|
215
217
|
}
|
|
216
218
|
}
|
|
217
219
|
|
|
218
|
-
async inflateValue(key,
|
|
220
|
+
async inflateValue(key, config) {
|
|
219
221
|
if (key.value) return key.value
|
|
220
222
|
if (!key.valuePointer) return null
|
|
221
223
|
|
|
222
224
|
const ptr = key.valuePointer
|
|
223
225
|
|
|
224
226
|
if (ptr.split === 0) {
|
|
225
|
-
const block = await ptr.context.getBlock(ptr.seq, ptr.core,
|
|
227
|
+
const block = await ptr.context.getBlock(ptr.seq, ptr.core, config)
|
|
226
228
|
return block.values[ptr.offset]
|
|
227
229
|
}
|
|
228
230
|
|
|
229
231
|
const blockPromises = new Array(ptr.split + 1)
|
|
230
232
|
for (let i = 0; i < blockPromises.length; i++) {
|
|
231
|
-
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)
|
|
232
234
|
}
|
|
233
235
|
const blocks = await Promise.all(blockPromises)
|
|
234
236
|
const splitValue = new Array(blockPromises.length)
|
|
@@ -239,13 +241,13 @@ class Hyperbee {
|
|
|
239
241
|
return b4a.concat(splitValue)
|
|
240
242
|
}
|
|
241
243
|
|
|
242
|
-
async bootstrap(
|
|
244
|
+
async bootstrap(config) {
|
|
243
245
|
if (!this.root) await this.ready()
|
|
244
|
-
if (this.unbatch) await this._rollback(
|
|
246
|
+
if (this.unbatch) await this._rollback(config)
|
|
245
247
|
return this.root === EMPTY ? null : this.root
|
|
246
248
|
}
|
|
247
249
|
|
|
248
|
-
async _rollback(
|
|
250
|
+
async _rollback(config) {
|
|
249
251
|
const expected = this.unbatch
|
|
250
252
|
|
|
251
253
|
let n = expected
|
|
@@ -254,21 +256,21 @@ class Hyperbee {
|
|
|
254
256
|
|
|
255
257
|
while (n > 0 && length > 0 && expected === this.unbatch) {
|
|
256
258
|
const seq = length - 1
|
|
257
|
-
const blk = await context.getBlock(seq, 0,
|
|
259
|
+
const blk = await context.getBlock(seq, 0, config)
|
|
258
260
|
|
|
259
261
|
if (!blk.previous) {
|
|
260
262
|
length = 0
|
|
261
263
|
break
|
|
262
264
|
}
|
|
263
265
|
|
|
264
|
-
context = await context.getContext(blk.previous.core,
|
|
266
|
+
context = await context.getContext(blk.previous.core, config)
|
|
265
267
|
length = blk.previous.seq + 1
|
|
266
268
|
n--
|
|
267
269
|
}
|
|
268
270
|
|
|
269
271
|
if (expected === this.unbatch) {
|
|
270
272
|
this.context = context
|
|
271
|
-
this.root = length === 0 ? EMPTY :
|
|
273
|
+
this.root = length === 0 ? EMPTY : context.createTreeNode(0, length - 1, 0, false, null)
|
|
272
274
|
this.unbatch = 0
|
|
273
275
|
}
|
|
274
276
|
}
|
|
@@ -278,12 +280,14 @@ class Hyperbee {
|
|
|
278
280
|
this.unbatch = 0
|
|
279
281
|
}
|
|
280
282
|
|
|
281
|
-
async get(key,
|
|
282
|
-
|
|
283
|
+
async get(key, opts) {
|
|
284
|
+
const config = this.config.options(opts)
|
|
285
|
+
|
|
286
|
+
let ptr = await this.bootstrap(config)
|
|
283
287
|
if (!ptr) return null
|
|
284
288
|
|
|
285
289
|
while (true) {
|
|
286
|
-
const v = ptr.value ? this.bump(ptr) : await this.inflate(ptr,
|
|
290
|
+
const v = ptr.value ? this.bump(ptr) : await this.inflate(ptr, config)
|
|
287
291
|
|
|
288
292
|
let s = 0
|
|
289
293
|
let e = v.keys.length
|
|
@@ -295,7 +299,7 @@ class Hyperbee {
|
|
|
295
299
|
|
|
296
300
|
c = b4a.compare(key, m.key)
|
|
297
301
|
|
|
298
|
-
if (c === 0) return this.finalizeKeyPointer(m,
|
|
302
|
+
if (c === 0) return this.finalizeKeyPointer(m, config)
|
|
299
303
|
|
|
300
304
|
if (c < 0) e = mid
|
|
301
305
|
else s = mid + 1
|
|
@@ -313,12 +317,12 @@ module.exports = Hyperbee
|
|
|
313
317
|
|
|
314
318
|
function noop() {}
|
|
315
319
|
|
|
316
|
-
function inflateKey(context, d, ptr, block,
|
|
317
|
-
if (d.type === OP_COHORT) return inflateKeyCohort(context, d, ptr, block,
|
|
318
|
-
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)
|
|
319
323
|
}
|
|
320
324
|
|
|
321
|
-
async function inflateKeyDelta(context, d, ptr, block,
|
|
325
|
+
async function inflateKeyDelta(context, d, ptr, block, config) {
|
|
322
326
|
const k = d.pointer
|
|
323
327
|
|
|
324
328
|
if (!k) return new DeltaOp(false, d.type, d.index, null)
|
|
@@ -326,7 +330,7 @@ async function inflateKeyDelta(context, d, ptr, block, activeRequests) {
|
|
|
326
330
|
const blk =
|
|
327
331
|
k.seq === ptr.seq && k.core === 0 && ptr.core === 0
|
|
328
332
|
? block
|
|
329
|
-
: await context.getBlock(k.seq, k.core,
|
|
333
|
+
: await context.getBlock(k.seq, k.core, config)
|
|
330
334
|
|
|
331
335
|
const bk = blk.keys[k.offset]
|
|
332
336
|
|
|
@@ -334,7 +338,7 @@ async function inflateKeyDelta(context, d, ptr, block, activeRequests) {
|
|
|
334
338
|
|
|
335
339
|
if (bk.valuePointer) {
|
|
336
340
|
const p = bk.valuePointer
|
|
337
|
-
const ctx = await context.getContext(k.core,
|
|
341
|
+
const ctx = await context.getContext(k.core, config)
|
|
338
342
|
vp = new ValuePointer(ctx, p.core, p.seq, p.offset, p.split)
|
|
339
343
|
}
|
|
340
344
|
|
|
@@ -342,20 +346,20 @@ async function inflateKeyDelta(context, d, ptr, block, activeRequests) {
|
|
|
342
346
|
return new DeltaOp(false, d.type, d.index, kp)
|
|
343
347
|
}
|
|
344
348
|
|
|
345
|
-
async function inflateKeyCohort(context, d, ptr, block,
|
|
349
|
+
async function inflateKeyCohort(context, d, ptr, block, config) {
|
|
346
350
|
const co = d.pointer
|
|
347
351
|
|
|
348
352
|
const blk =
|
|
349
353
|
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
350
354
|
? block
|
|
351
|
-
: await context.getBlock(co.seq, co.core,
|
|
355
|
+
: await context.getBlock(co.seq, co.core, config)
|
|
352
356
|
|
|
353
357
|
const cohort = blk.cohorts[co.offset]
|
|
354
358
|
const promises = new Array(cohort.length)
|
|
355
359
|
|
|
356
360
|
for (let i = 0; i < cohort.length; i++) {
|
|
357
361
|
const p = cohort[i]
|
|
358
|
-
const k = inflateKeyDelta(context, p, co, blk,
|
|
362
|
+
const k = inflateKeyDelta(context, p, co, blk, config)
|
|
359
363
|
promises[i] = k
|
|
360
364
|
}
|
|
361
365
|
|
|
@@ -363,31 +367,31 @@ async function inflateKeyCohort(context, d, ptr, block, activeRequests) {
|
|
|
363
367
|
return new DeltaCohort(false, p, await Promise.all(promises))
|
|
364
368
|
}
|
|
365
369
|
|
|
366
|
-
function inflateChild(context, d, ptr, block,
|
|
367
|
-
if (d.type === OP_COHORT) return inflateChildCohort(context, d, ptr, block,
|
|
368
|
-
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))
|
|
369
373
|
}
|
|
370
374
|
|
|
371
|
-
function inflateChildDelta(context, d, ptr, block,
|
|
375
|
+
function inflateChildDelta(context, d, ptr, block, config) {
|
|
372
376
|
const p = d.pointer
|
|
373
|
-
const c = p &&
|
|
377
|
+
const c = p && context.createTreeNode(p.core, p.seq, p.offset, false, null)
|
|
374
378
|
return new DeltaOp(false, d.type, d.index, c)
|
|
375
379
|
}
|
|
376
380
|
|
|
377
|
-
async function inflateChildCohort(context, d, ptr, block,
|
|
381
|
+
async function inflateChildCohort(context, d, ptr, block, config) {
|
|
378
382
|
const co = d.pointer
|
|
379
383
|
|
|
380
384
|
const blk =
|
|
381
385
|
co.seq === ptr.seq && co.core === 0 && ptr.core === 0
|
|
382
386
|
? block
|
|
383
|
-
: await context.getBlock(co.seq, co.core,
|
|
387
|
+
: await context.getBlock(co.seq, co.core, config)
|
|
384
388
|
|
|
385
389
|
const cohort = blk.cohorts[co.offset]
|
|
386
390
|
const deltas = new Array(cohort.length)
|
|
387
391
|
|
|
388
392
|
for (let i = 0; i < cohort.length; i++) {
|
|
389
393
|
const c = cohort[i]
|
|
390
|
-
deltas[i] = inflateChildDelta(context, c, co, blk,
|
|
394
|
+
deltas[i] = inflateChildDelta(context, c, co, blk, config)
|
|
391
395
|
}
|
|
392
396
|
|
|
393
397
|
const p = new Pointer(context, co.core, co.seq, co.offset)
|
package/lib/cache.js
CHANGED
|
@@ -3,6 +3,8 @@ module.exports = class NodeCache {
|
|
|
3
3
|
this.size = 0
|
|
4
4
|
this.maxSize = maxSize
|
|
5
5
|
this.latest = null
|
|
6
|
+
this.retained = 0
|
|
7
|
+
this.byId = new Map()
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
oldest() {
|
|
@@ -20,7 +22,7 @@ module.exports = class NodeCache {
|
|
|
20
22
|
gc() {
|
|
21
23
|
while (this.size > this.maxSize) {
|
|
22
24
|
const old = this.oldest()
|
|
23
|
-
if (old.
|
|
25
|
+
if (old.retained > this.retained) break
|
|
24
26
|
this.remove(old)
|
|
25
27
|
old.value = null
|
|
26
28
|
}
|
|
@@ -29,6 +31,10 @@ module.exports = class NodeCache {
|
|
|
29
31
|
bump(node) {
|
|
30
32
|
if (node === this.latest) return
|
|
31
33
|
|
|
34
|
+
if (node.next === null && node.prev === null) {
|
|
35
|
+
this.byId.set(cacheId(node), node)
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
if (node.prev) this.remove(node)
|
|
33
39
|
this.size++
|
|
34
40
|
|
|
@@ -44,6 +50,10 @@ module.exports = class NodeCache {
|
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
get(node) {
|
|
54
|
+
return this.byId.get(cacheId(node)) || null
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
remove(node) {
|
|
48
58
|
if (node.prev) {
|
|
49
59
|
this.size--
|
|
@@ -57,6 +67,11 @@ module.exports = class NodeCache {
|
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
node.prev = node.next = null
|
|
70
|
+
|
|
71
|
+
const id = cacheId(node)
|
|
72
|
+
if (this.byId.get(id) === node) {
|
|
73
|
+
this.byId.delete(id)
|
|
74
|
+
}
|
|
60
75
|
}
|
|
61
76
|
|
|
62
77
|
*[Symbol.iterator]() {
|
|
@@ -71,3 +86,8 @@ module.exports = class NodeCache {
|
|
|
71
86
|
} while (node !== next)
|
|
72
87
|
}
|
|
73
88
|
}
|
|
89
|
+
|
|
90
|
+
function cacheId(node) {
|
|
91
|
+
const id = node.core === 0 ? node.context.core.id : node.context.opened[node.core - 1].id
|
|
92
|
+
return id + '@' + node.seq + '.' + node.offset
|
|
93
|
+
}
|
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/compression.js
CHANGED
|
@@ -23,6 +23,8 @@ class CompressedArray {
|
|
|
23
23
|
constructor(delta) {
|
|
24
24
|
this.entries = []
|
|
25
25
|
this.delta = delta
|
|
26
|
+
this.uentries = null
|
|
27
|
+
this.updates = 0
|
|
26
28
|
|
|
27
29
|
for (const d of delta) {
|
|
28
30
|
if (d.type === OP_COHORT) {
|
|
@@ -39,8 +41,32 @@ class CompressedArray {
|
|
|
39
41
|
return this.entries.length
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
get ulength() {
|
|
45
|
+
return this.uentries ? this.uentries.length : this.entries.length
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
commit() {
|
|
49
|
+
const c = new CompressedArray([])
|
|
50
|
+
|
|
51
|
+
c.delta = this.delta
|
|
52
|
+
c.entries = this.uentries || this.entries.slice(0)
|
|
53
|
+
|
|
54
|
+
this.delta = this.delta.slice(0, this.updates)
|
|
55
|
+
this.uentries = null
|
|
56
|
+
this.updates = 0
|
|
57
|
+
|
|
58
|
+
return c
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_update() {
|
|
62
|
+
if (this.uentries) return
|
|
63
|
+
this.uentries = this.entries.slice(0)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
touch(index, pointer) {
|
|
67
|
+
if (pointer) this.entries[index] = pointer
|
|
68
|
+
else pointer = this.entries[index]
|
|
69
|
+
|
|
44
70
|
if (pointer.changedBy === this) return
|
|
45
71
|
this.set(index, pointer)
|
|
46
72
|
}
|
|
@@ -49,8 +75,13 @@ class CompressedArray {
|
|
|
49
75
|
return this.entries[index]
|
|
50
76
|
}
|
|
51
77
|
|
|
78
|
+
uget(index) {
|
|
79
|
+
return this.uentries ? this.uentries[index] : this.entries[index]
|
|
80
|
+
}
|
|
81
|
+
|
|
52
82
|
push(pointer) {
|
|
53
|
-
this.
|
|
83
|
+
if (!this.uentries) this._update()
|
|
84
|
+
this.insert(this.uentries.length, pointer)
|
|
54
85
|
}
|
|
55
86
|
|
|
56
87
|
unshift(pointer) {
|
|
@@ -58,37 +89,43 @@ class CompressedArray {
|
|
|
58
89
|
}
|
|
59
90
|
|
|
60
91
|
pop() {
|
|
61
|
-
if (this.
|
|
62
|
-
|
|
63
|
-
this.
|
|
92
|
+
if (!this.uentries) this._update()
|
|
93
|
+
if (this.uentries.length === 0) return
|
|
94
|
+
const head = this.uentries[this.uentries.length - 1]
|
|
95
|
+
this.delete(this.uentries.length - 1)
|
|
64
96
|
return head
|
|
65
97
|
}
|
|
66
98
|
|
|
67
99
|
shift() {
|
|
68
|
-
if (this.
|
|
69
|
-
|
|
100
|
+
if (!this.uentries) this._update()
|
|
101
|
+
if (this.uentries.length === 0) return
|
|
102
|
+
const tail = this.uentries[0]
|
|
70
103
|
this.delete(0)
|
|
71
104
|
return tail
|
|
72
105
|
}
|
|
73
106
|
|
|
74
107
|
_touch(pointer) {
|
|
108
|
+
this.updates++
|
|
75
109
|
if (pointer) pointer.changedBy = this
|
|
76
110
|
}
|
|
77
111
|
|
|
78
112
|
insert(index, pointer) {
|
|
79
|
-
if (!
|
|
113
|
+
if (!this.uentries) this._update()
|
|
114
|
+
if (!insert(this.uentries, index, pointer)) return
|
|
80
115
|
this._touch(pointer)
|
|
81
116
|
this.delta.push(new DeltaOp(true, OP_INSERT, index, pointer))
|
|
82
117
|
}
|
|
83
118
|
|
|
84
119
|
delete(index) {
|
|
85
|
-
if (!
|
|
120
|
+
if (!this.uentries) this._update()
|
|
121
|
+
if (!del(this.uentries, index)) return
|
|
86
122
|
this._touch(null)
|
|
87
123
|
this.delta.push(new DeltaOp(true, OP_DEL, index, null))
|
|
88
124
|
}
|
|
89
125
|
|
|
90
126
|
set(index, pointer) {
|
|
91
|
-
if (!
|
|
127
|
+
if (!this.uentries) this._update()
|
|
128
|
+
if (!set(this.uentries, index, pointer)) return
|
|
92
129
|
this._touch(pointer)
|
|
93
130
|
this.delta.push(new DeltaOp(true, OP_SET, index, pointer))
|
|
94
131
|
}
|