autobee 1.0.0 → 1.0.3
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/README.md +242 -2
- package/encoding/compat.js +341 -0
- package/encoding/legacy.js +317 -0
- package/encoding/spec/autobee/index.js +987 -0
- package/{spec/hyperschema → encoding/spec/autobee}/schema.json +371 -157
- package/index.js +73 -15
- package/lib/apply-calls.js +7 -4
- package/lib/encoding.js +1 -1
- package/lib/system.js +23 -10
- package/lib/topo.js +114 -39
- package/lib/writers.js +56 -10
- package/package.json +7 -3
- package/spec/hyperschema/index.js +0 -644
package/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const { ActiveWriters } = require('./lib/writers.js')
|
|
|
18
18
|
const UpdateChanges = require('./lib/updates.js')
|
|
19
19
|
|
|
20
20
|
const EMPTY_HEAD = { length: 0, key: null }
|
|
21
|
+
const INTERRUPT = new Error('Apply interrupted')
|
|
21
22
|
|
|
22
23
|
module.exports = class Autobee extends ReadyResource {
|
|
23
24
|
constructor(store, key = null, handlers = {}) {
|
|
@@ -81,6 +82,10 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
81
82
|
this._updateLocalCore = null
|
|
82
83
|
this._host = new ApplyCalls(this)
|
|
83
84
|
|
|
85
|
+
this.interrupted = null
|
|
86
|
+
this._interrupting = false
|
|
87
|
+
this._onErrorBound = this._onError.bind(this)
|
|
88
|
+
|
|
84
89
|
this._wakeup = new AutobeeWakeup(this, handlers)
|
|
85
90
|
this.wakeupCapability = null
|
|
86
91
|
|
|
@@ -126,6 +131,22 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
126
131
|
this._wakeup.setCapability(this.wakeupCapability.key, this.wakeupCapability.discoveryKey)
|
|
127
132
|
}
|
|
128
133
|
|
|
134
|
+
getExternalWriters() {
|
|
135
|
+
const keys = []
|
|
136
|
+
for (const w of this.writers.active.values()) {
|
|
137
|
+
if (w === this.writers.localWriter) continue
|
|
138
|
+
keys.push(w.core.key)
|
|
139
|
+
}
|
|
140
|
+
return keys
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async getWriterViews(key) {
|
|
144
|
+
const id = b4a.toString(key, 'hex')
|
|
145
|
+
const w = this.writers.active.get(id)
|
|
146
|
+
if (!w) return []
|
|
147
|
+
return w.views()
|
|
148
|
+
}
|
|
149
|
+
|
|
129
150
|
views() {
|
|
130
151
|
const sys = this.system.bee.context.local
|
|
131
152
|
const view = this._workingBee.context.local
|
|
@@ -138,7 +159,8 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
138
159
|
}
|
|
139
160
|
|
|
140
161
|
async _close() {
|
|
141
|
-
|
|
162
|
+
this._interrupting = true
|
|
163
|
+
if (this._draining) await this._draining
|
|
142
164
|
|
|
143
165
|
if (this._handlers.close) await this._handlers.close(this.view)
|
|
144
166
|
|
|
@@ -254,8 +276,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
254
276
|
this.bumping++
|
|
255
277
|
|
|
256
278
|
if (!this._draining) {
|
|
257
|
-
this._draining = this._drain()
|
|
258
|
-
this._draining.catch(safetyCatch)
|
|
279
|
+
this._draining = this._drain().catch(this._onErrorBound)
|
|
259
280
|
}
|
|
260
281
|
|
|
261
282
|
return this._draining
|
|
@@ -265,11 +286,46 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
265
286
|
return this._bump()
|
|
266
287
|
}
|
|
267
288
|
|
|
268
|
-
updated() {
|
|
289
|
+
async updated() {
|
|
290
|
+
if (this.opened === false) await this.ready()
|
|
269
291
|
if (this._draining) return this._draining
|
|
270
292
|
return Promise.resolve()
|
|
271
293
|
}
|
|
272
294
|
|
|
295
|
+
interrupt(reason) {
|
|
296
|
+
asserts.assert(!!this._host.applying, 'Interrupt is only allowed in apply')
|
|
297
|
+
this._interrupting = true
|
|
298
|
+
if (reason) this.interrupted = reason
|
|
299
|
+
throw INTERRUPT
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
getLastError() {
|
|
303
|
+
return this._lastError
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
_onError(err) {
|
|
307
|
+
if (this.closing) return
|
|
308
|
+
|
|
309
|
+
this._lastError = err
|
|
310
|
+
|
|
311
|
+
if (err === INTERRUPT) {
|
|
312
|
+
this.emit('interrupt', this.interrupted)
|
|
313
|
+
this.emit('update')
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this.close().catch(safetyCatch)
|
|
318
|
+
|
|
319
|
+
// if no one is listening we should crash! we cannot rely on the EE here
|
|
320
|
+
// as this is wrapped in a promise so instead of nextTick throw it
|
|
321
|
+
if (ReadyResource.listenerCount(this, 'error') === 0) {
|
|
322
|
+
crashSoon(err)
|
|
323
|
+
return
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
this.emit('error', err)
|
|
327
|
+
}
|
|
328
|
+
|
|
273
329
|
async _drain() {
|
|
274
330
|
if (this._updateLocalCore !== null) {
|
|
275
331
|
await this._rotateLocalWriter(this._updateLocalCore)
|
|
@@ -376,11 +432,6 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
376
432
|
this.emit('rotate-local-writer')
|
|
377
433
|
}
|
|
378
434
|
|
|
379
|
-
interrupt() {
|
|
380
|
-
this._interrupting = true
|
|
381
|
-
if (this._draining) return this._draining
|
|
382
|
-
}
|
|
383
|
-
|
|
384
435
|
async createAnchor() {
|
|
385
436
|
const node = this._host.applying[this._host.applying.length - 1]
|
|
386
437
|
|
|
@@ -424,7 +475,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
424
475
|
await core.append(block, { writable: true, maxLength: 1 })
|
|
425
476
|
}
|
|
426
477
|
|
|
427
|
-
await this.system.addWriter(core.key)
|
|
478
|
+
await this.system.addWriter(core.key, { weight: 1 })
|
|
428
479
|
|
|
429
480
|
const anchor = { key: core.key, length: core.length }
|
|
430
481
|
|
|
@@ -475,8 +526,6 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
475
526
|
this._workingBee.move(t.view)
|
|
476
527
|
}
|
|
477
528
|
|
|
478
|
-
asserts.assert(batch === t.tip[0], 'Batch must be first part of tip')
|
|
479
|
-
|
|
480
529
|
let failed = true
|
|
481
530
|
|
|
482
531
|
try {
|
|
@@ -594,9 +643,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
594
643
|
const value = values[i]
|
|
595
644
|
const buffer = typeof value === 'string' ? b4a.from(value) : value
|
|
596
645
|
const lnk = i === 0 ? links : []
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
const node = this.writers.appendLocal(buffer, t, b, lnk, optimistic)
|
|
646
|
+
const node = this.writers.appendLocal(buffer, t, null, lnk, optimistic)
|
|
600
647
|
batch.push(node)
|
|
601
648
|
}
|
|
602
649
|
|
|
@@ -607,6 +654,10 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
607
654
|
// analyze is worth the trade off adding the view here also (technically not needed)
|
|
608
655
|
await this.writers.flushLocal(this._workingBee.head())
|
|
609
656
|
}
|
|
657
|
+
|
|
658
|
+
async replay() {
|
|
659
|
+
return topo.replay(this)
|
|
660
|
+
}
|
|
610
661
|
}
|
|
611
662
|
|
|
612
663
|
function isObject(o) {
|
|
@@ -634,3 +685,10 @@ function createAnchorCore(store, prologue, manifestData) {
|
|
|
634
685
|
|
|
635
686
|
return core
|
|
636
687
|
}
|
|
688
|
+
|
|
689
|
+
function crashSoon(err) {
|
|
690
|
+
queueMicrotask(() => {
|
|
691
|
+
throw err
|
|
692
|
+
})
|
|
693
|
+
throw err
|
|
694
|
+
}
|
package/lib/apply-calls.js
CHANGED
|
@@ -22,13 +22,17 @@ class ApplyCalls {
|
|
|
22
22
|
return this.auto.name
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
get clock() {
|
|
26
|
+
return this.auto.system.flushes
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
get genesis() {
|
|
26
30
|
return this.auto.system.isGenesis()
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
addWriter(key, { isIndexer = true } = {}) {
|
|
33
|
+
addWriter(key, { isIndexer = true, weight = isIndexer ? 2 : 1 } = {}) {
|
|
30
34
|
if (typeof key === 'string') key = ID.decode(key)
|
|
31
|
-
return this.auto.system.addWriter(key, {
|
|
35
|
+
return this.auto.system.addWriter(key, { weight })
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
ackWriter(key) {
|
|
@@ -46,8 +50,7 @@ class ApplyCalls {
|
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
interrupt(reason) {
|
|
49
|
-
|
|
50
|
-
// this.auto._interrupt(reason)
|
|
53
|
+
this.auto.interrupt(reason)
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
removeable(key) {
|
package/lib/encoding.js
CHANGED
|
@@ -3,7 +3,7 @@ const c = require('compact-encoding')
|
|
|
3
3
|
const crypto = require('hypercore-crypto')
|
|
4
4
|
const { AutobeeEncryption } = require('autobee-encryption')
|
|
5
5
|
|
|
6
|
-
const { getEncoding } = require('../spec/
|
|
6
|
+
const { getEncoding } = require('../encoding/spec/autobee')
|
|
7
7
|
const { LEGACY_OPLOG_VERSION, OPLOG_VERSION } = require('./constants')
|
|
8
8
|
|
|
9
9
|
const Oplog = getEncoding('@autobee/oplog')
|
package/lib/system.js
CHANGED
|
@@ -28,12 +28,12 @@ module.exports = class Systembee {
|
|
|
28
28
|
this.encrypted = opts.encrypted === true
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
async addWriter(key, { length = 0,
|
|
31
|
+
async addWriter(key, { length = 0, weight = 1 } = {}) {
|
|
32
32
|
if (length === 0) {
|
|
33
33
|
const info = await this.get(key, { unflushed: false })
|
|
34
34
|
length = info ? info.length : 0
|
|
35
35
|
}
|
|
36
|
-
this.update(key, length,
|
|
36
|
+
this.update(key, length, weight, false, true, false)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
async ackWriter(key, { length = 0 } = {}) {
|
|
@@ -41,7 +41,7 @@ module.exports = class Systembee {
|
|
|
41
41
|
const info = await this.get(key, { unflushed: false })
|
|
42
42
|
length = info ? info.length : 0
|
|
43
43
|
}
|
|
44
|
-
this.update(key, length,
|
|
44
|
+
this.update(key, length, 0, false, false, true)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
async removeWriter(key, { length = 0 } = {}) {
|
|
@@ -49,7 +49,7 @@ module.exports = class Systembee {
|
|
|
49
49
|
const info = await this.get(key, { unflushed: true })
|
|
50
50
|
length = info ? info.length : 0
|
|
51
51
|
}
|
|
52
|
-
this.update(key, length,
|
|
52
|
+
this.update(key, length, 0, true, false, false)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
isGenesis() {
|
|
@@ -133,7 +133,7 @@ module.exports = class Systembee {
|
|
|
133
133
|
this.heads.push({ key: node.key, length: node.length })
|
|
134
134
|
if (node.timestamp > this.timestamp) this.timestamp = node.timestamp // TODO: support smoothing
|
|
135
135
|
|
|
136
|
-
this.update(node.key, node.length,
|
|
136
|
+
this.update(node.key, node.length, 0, false, false, false)
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
async canApply(key, optimistic) {
|
|
@@ -151,6 +151,7 @@ module.exports = class Systembee {
|
|
|
151
151
|
|
|
152
152
|
const upd = this.updates.get(b4a.toString(key, 'hex'))
|
|
153
153
|
if (!upd) return info
|
|
154
|
+
if (!info) return upd
|
|
154
155
|
|
|
155
156
|
if (upd.isAdded) info.isAdded = true
|
|
156
157
|
if (upd.isRemoved) info.isRemoved = true
|
|
@@ -183,7 +184,7 @@ module.exports = class Systembee {
|
|
|
183
184
|
return true
|
|
184
185
|
}
|
|
185
186
|
|
|
186
|
-
update(key, length,
|
|
187
|
+
update(key, length, weight, isRemoved, isAdded, isAcked) {
|
|
187
188
|
const id = b4a.toString(key, 'hex')
|
|
188
189
|
|
|
189
190
|
let upd = this.updates.get(id)
|
|
@@ -195,17 +196,27 @@ module.exports = class Systembee {
|
|
|
195
196
|
}
|
|
196
197
|
|
|
197
198
|
if (!upd) {
|
|
198
|
-
upd = {
|
|
199
|
+
upd = {
|
|
200
|
+
version: 4,
|
|
201
|
+
key,
|
|
202
|
+
length,
|
|
203
|
+
weight,
|
|
204
|
+
clock: 0,
|
|
205
|
+
isRemoved,
|
|
206
|
+
isAdded,
|
|
207
|
+
isAcked,
|
|
208
|
+
isOplog: false
|
|
209
|
+
}
|
|
199
210
|
this.updates.set(id, upd)
|
|
200
211
|
return
|
|
201
212
|
}
|
|
202
213
|
|
|
203
214
|
if (isAdded) {
|
|
204
|
-
upd.
|
|
215
|
+
upd.weight = weight
|
|
205
216
|
upd.isRemoved = false
|
|
206
217
|
}
|
|
207
218
|
if (isRemoved) {
|
|
208
|
-
upd.
|
|
219
|
+
upd.weight = 0
|
|
209
220
|
upd.isRemoved = true
|
|
210
221
|
}
|
|
211
222
|
if (isAcked) {
|
|
@@ -226,7 +237,7 @@ module.exports = class Systembee {
|
|
|
226
237
|
|
|
227
238
|
if (v) {
|
|
228
239
|
if (!changed) {
|
|
229
|
-
upd.
|
|
240
|
+
upd.weight = v.weight
|
|
230
241
|
upd.isRemoved = v.isRemoved
|
|
231
242
|
}
|
|
232
243
|
|
|
@@ -234,6 +245,8 @@ module.exports = class Systembee {
|
|
|
234
245
|
}
|
|
235
246
|
}
|
|
236
247
|
|
|
248
|
+
upd.clock = this.flushes
|
|
249
|
+
|
|
237
250
|
// TODO: we can optimise this a bit, if the above node hasnt changed, do not set this
|
|
238
251
|
// less writes, but future thing
|
|
239
252
|
upd.isOplog = b4a.equals(upd.key, oplog)
|
package/lib/topo.js
CHANGED
|
@@ -5,11 +5,43 @@ const asserts = require('./asserts.js')
|
|
|
5
5
|
|
|
6
6
|
const EMPTY_HEAD = { length: 0, key: null }
|
|
7
7
|
|
|
8
|
+
exports.replay = replay
|
|
8
9
|
exports.sort = sort
|
|
9
10
|
|
|
10
11
|
exports.isLinking = isLinking
|
|
11
12
|
exports.isLinkingAll = isLinkingAll
|
|
12
13
|
|
|
14
|
+
class Clock {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.map = new Map()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
add(link) {
|
|
20
|
+
const hex = b4a.toString(link.key, 'hex')
|
|
21
|
+
const p = this.map.get(hex)
|
|
22
|
+
if (p < link.length) this.map.set(hex, link.length)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
has(link) {
|
|
26
|
+
const hex = b4a.toString(link.key, 'hex')
|
|
27
|
+
const p = this.map.get(hex)
|
|
28
|
+
return p >= link.length
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function replay(auto) {
|
|
33
|
+
const ch = auto.system.bee.createChangesStream()
|
|
34
|
+
const replay = []
|
|
35
|
+
|
|
36
|
+
for await (const data of ch) {
|
|
37
|
+
const { ref, info } = getOplog(data)
|
|
38
|
+
replay.push(ref)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const inflated = await inflate(auto, replay.reverse())
|
|
42
|
+
return inflated.flatMap((b) => b.batch)
|
|
43
|
+
}
|
|
44
|
+
|
|
13
45
|
async function sort(auto, batch) {
|
|
14
46
|
const node = batch[0]
|
|
15
47
|
const ch = auto.system.bee.createChangesStream()
|
|
@@ -17,52 +49,98 @@ async function sort(auto, batch) {
|
|
|
17
49
|
|
|
18
50
|
for await (const data of ch) {
|
|
19
51
|
const { ref, info } = getOplog(data)
|
|
20
|
-
const link = {
|
|
52
|
+
const link = {
|
|
53
|
+
key: ref.oplog.key,
|
|
54
|
+
length: ref.oplog.length,
|
|
55
|
+
weight: ref.oplog.weight,
|
|
56
|
+
timestamp: info.timestamp
|
|
57
|
+
}
|
|
21
58
|
|
|
22
|
-
if (
|
|
59
|
+
if (!isOrderedBefore(node, link)) break
|
|
23
60
|
reorder.push(ref)
|
|
24
61
|
}
|
|
25
62
|
|
|
26
63
|
const inflated = await inflate(auto, reorder.reverse())
|
|
27
64
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const c = cmp(op, node)
|
|
65
|
+
const { undo, shared } = addSorted(inflated, batch)
|
|
66
|
+
|
|
67
|
+
const tip = inflated.slice(shared).map((b) => b.batch)
|
|
32
68
|
|
|
33
|
-
|
|
69
|
+
return {
|
|
70
|
+
undo,
|
|
71
|
+
view: null,
|
|
72
|
+
tip
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isOrderedBefore(node, oplog) {
|
|
77
|
+
const { version, weight, timestamp } = oplog
|
|
78
|
+
if (version === 0) return false
|
|
79
|
+
if (node.weight < weight) return false
|
|
80
|
+
if (isLinking(node, oplog)) return false
|
|
81
|
+
return node.timestamp <= timestamp
|
|
82
|
+
}
|
|
34
83
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
84
|
+
function addSorted(list, batch) {
|
|
85
|
+
const node = batch[0]
|
|
86
|
+
const clock = new Clock()
|
|
87
|
+
for (const link of node.links) {
|
|
88
|
+
clock.add(link)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const tip = []
|
|
92
|
+
const linked = []
|
|
93
|
+
|
|
94
|
+
let undo = null
|
|
95
|
+
let shared = list.length
|
|
96
|
+
|
|
97
|
+
while (list.length) {
|
|
98
|
+
// reached a stable sorting point
|
|
99
|
+
if (cmp(node, list[list.length - 1].batch[0]) > 0) {
|
|
100
|
+
break
|
|
39
101
|
}
|
|
40
102
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
103
|
+
const b = list.pop()
|
|
104
|
+
const target = b.batch[0]
|
|
105
|
+
|
|
106
|
+
if (list.length < shared) {
|
|
107
|
+
undo = b.undo
|
|
108
|
+
shared = list.length
|
|
45
109
|
}
|
|
46
|
-
}
|
|
47
110
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
111
|
+
// move past this node
|
|
112
|
+
if (!clock.has(target)) {
|
|
113
|
+
tip.push(b)
|
|
114
|
+
continue
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// remove node
|
|
118
|
+
linked.push(b)
|
|
119
|
+
|
|
120
|
+
// update the clock to catch linked nodes
|
|
121
|
+
for (const link of target.links) {
|
|
122
|
+
clock.add(link)
|
|
123
|
+
}
|
|
52
124
|
}
|
|
125
|
+
|
|
126
|
+
while (linked.length) addSorted(list, linked.pop())
|
|
127
|
+
list.push({ undo: null, batch })
|
|
128
|
+
while (tip.length) list.push(tip.pop())
|
|
129
|
+
|
|
130
|
+
return { undo, shared }
|
|
53
131
|
}
|
|
54
132
|
|
|
55
133
|
function cmp(a, b) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
if (c === 0) {
|
|
59
|
-
return a.length - b.length
|
|
60
|
-
}
|
|
134
|
+
const w = a.weight - b.weight
|
|
135
|
+
if (w) return w > 0 ? -1 : 1
|
|
61
136
|
|
|
62
137
|
const t = a.timestamp - b.timestamp
|
|
138
|
+
if (t) return t < 0 ? -1 : 1
|
|
63
139
|
|
|
64
|
-
|
|
65
|
-
|
|
140
|
+
const c = b4a.compare(a.key, b.key)
|
|
141
|
+
if (c) return c
|
|
142
|
+
|
|
143
|
+
return a.length < b.length ? -1 : 1
|
|
66
144
|
}
|
|
67
145
|
|
|
68
146
|
async function inflate(auto, reorder) {
|
|
@@ -74,7 +152,7 @@ async function inflate(auto, reorder) {
|
|
|
74
152
|
|
|
75
153
|
const local = auto.writers.localWriter
|
|
76
154
|
if (local && local.id === id) {
|
|
77
|
-
promises.push(getLocalBatch(ref.undo, local, ref.oplog.length))
|
|
155
|
+
promises.push(getLocalBatch(ref.undo, local, ref.oplog.length, ref.oplog.weight))
|
|
78
156
|
continue
|
|
79
157
|
}
|
|
80
158
|
|
|
@@ -84,7 +162,7 @@ async function inflate(auto, reorder) {
|
|
|
84
162
|
sessions.set(id, core)
|
|
85
163
|
}
|
|
86
164
|
|
|
87
|
-
promises.push(getOplogBatch(ref.undo, core, ref.oplog.length))
|
|
165
|
+
promises.push(getOplogBatch(ref.undo, core, ref.oplog.length, ref.oplog.weight))
|
|
88
166
|
}
|
|
89
167
|
|
|
90
168
|
try {
|
|
@@ -94,11 +172,11 @@ async function inflate(auto, reorder) {
|
|
|
94
172
|
}
|
|
95
173
|
}
|
|
96
174
|
|
|
97
|
-
async function getOplogBatch(undo, core, length) {
|
|
175
|
+
async function getOplogBatch(undo, core, length, weight) {
|
|
98
176
|
const seq = length - 1
|
|
99
177
|
const block = await core.get(seq)
|
|
100
178
|
const oplog = encoding.decodeOplog(block)
|
|
101
|
-
const head = createNode(core, length, oplog)
|
|
179
|
+
const head = createNode(core, length, weight, oplog)
|
|
102
180
|
|
|
103
181
|
const batch = []
|
|
104
182
|
const result = { undo, batch }
|
|
@@ -115,7 +193,7 @@ async function getOplogBatch(undo, core, length) {
|
|
|
115
193
|
const blocks = await Promise.all(remaining)
|
|
116
194
|
for (let i = 0; i < blocks.length; i++) {
|
|
117
195
|
const oplog = encoding.decodeOplog(blocks[i])
|
|
118
|
-
batch.push(createNode(core, i + start + 1, oplog))
|
|
196
|
+
batch.push(createNode(core, i + start + 1, weight, oplog))
|
|
119
197
|
}
|
|
120
198
|
}
|
|
121
199
|
|
|
@@ -123,7 +201,7 @@ async function getOplogBatch(undo, core, length) {
|
|
|
123
201
|
return result
|
|
124
202
|
}
|
|
125
203
|
|
|
126
|
-
|
|
204
|
+
function getLocalBatch(undo, writer, length, weight) {
|
|
127
205
|
if (length > writer.core.length) {
|
|
128
206
|
if (!writer.pending) throw new Error('No local nodes')
|
|
129
207
|
|
|
@@ -142,16 +220,13 @@ async function getLocalBatch(undo, writer, length) {
|
|
|
142
220
|
return { undo, batch }
|
|
143
221
|
}
|
|
144
222
|
|
|
145
|
-
return getOplogBatch(undo, writer.core, length)
|
|
223
|
+
return getOplogBatch(undo, writer.core, length, weight)
|
|
146
224
|
}
|
|
147
225
|
|
|
148
226
|
function getOplog(data) {
|
|
149
227
|
const result = { ref: null, info: null }
|
|
150
|
-
for (
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
for (let j = 0; j < keys.length; j++) {
|
|
154
|
-
const k = keys[j]
|
|
228
|
+
for (const { keys } of data.batch) {
|
|
229
|
+
for (const k of keys) {
|
|
155
230
|
const prefix = k.key[0]
|
|
156
231
|
|
|
157
232
|
if (prefix === 0) {
|