autobee 2.0.0-rc.31 → 2.0.0-rc.32
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 +47 -72
- package/lib/apply-calls.js +0 -5
- package/lib/fast-forward.js +3 -16
- package/lib/migrations.js +3 -1
- package/lib/system.js +14 -25
- package/lib/witness.js +1 -2
- package/lib/writers.js +39 -12
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -129,12 +129,10 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
129
129
|
this._hasApply = !!handlers.apply
|
|
130
130
|
this._hasUpdate = !!handlers.update
|
|
131
131
|
this._needsUpdate = false
|
|
132
|
-
this._ackRequired = false
|
|
133
132
|
this._approvalCheck = true
|
|
134
133
|
this._approvedPending = new Map()
|
|
135
134
|
this._approvalRequests = []
|
|
136
135
|
this._prefetchingApprovals = false
|
|
137
|
-
this._ackedHeads = new Map()
|
|
138
136
|
this._updateLocalCore = null
|
|
139
137
|
this._host = new ApplyCalls(this)
|
|
140
138
|
this._notifyHandler = null
|
|
@@ -385,7 +383,6 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
385
383
|
}
|
|
386
384
|
|
|
387
385
|
this.local.setEncryption(this._getEncryptionProvider())
|
|
388
|
-
this.local.setActive(true)
|
|
389
386
|
|
|
390
387
|
this.writers = new ActiveWriters(this)
|
|
391
388
|
|
|
@@ -554,8 +551,6 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
554
551
|
else if (head) await this._bootFromHead(head, bootCondition, wait)
|
|
555
552
|
}
|
|
556
553
|
|
|
557
|
-
this._ackRequired = false
|
|
558
|
-
|
|
559
554
|
const changes = this._hasUpdate ? new UpdateChanges(this) : null
|
|
560
555
|
if (changes) changes.track()
|
|
561
556
|
|
|
@@ -578,16 +573,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
578
573
|
break // revaluate conditions...
|
|
579
574
|
}
|
|
580
575
|
|
|
581
|
-
if (await this._bumpPendingWriters())
|
|
582
|
-
this._needsUpdate = true
|
|
583
|
-
continue
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
if (!this._appendAck()) break
|
|
587
|
-
this._needsUpdate = true
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (!this._interrupting && (await this._appendApprovals())) {
|
|
576
|
+
if (!(await this._bumpPendingWriters())) break
|
|
591
577
|
this._needsUpdate = true
|
|
592
578
|
}
|
|
593
579
|
|
|
@@ -647,24 +633,44 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
647
633
|
// wakeup hints keep arriving asynchronously
|
|
648
634
|
async _applyWakeupHints() {
|
|
649
635
|
const hints = this._wakeup.flush()
|
|
650
|
-
if (!hints.size) return
|
|
636
|
+
if (!hints.size) return []
|
|
651
637
|
|
|
652
638
|
this.previousDrain = Date.now()
|
|
639
|
+
const results = await this._filterHints(hints)
|
|
653
640
|
|
|
654
|
-
for (const
|
|
655
|
-
const key = b4a.from(hex, 'hex')
|
|
641
|
+
for (const { key, length } of results) {
|
|
656
642
|
// wakeup() itself no-ops the add for an already-active writer, but still
|
|
657
643
|
// needs to run so it can hint() the announced length - skipping it here
|
|
658
644
|
// for active writers left gc with no hint to protect them
|
|
659
645
|
await this.writers.wakeup(key, length)
|
|
660
646
|
}
|
|
661
647
|
|
|
662
|
-
return
|
|
648
|
+
return results
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
async _filterHints(hints) {
|
|
652
|
+
const results = []
|
|
653
|
+
const promises = []
|
|
654
|
+
for (const [hex, length] of hints) {
|
|
655
|
+
const key = b4a.from(hex, 'hex')
|
|
656
|
+
promises.push(this._filterTracked(key, length, results))
|
|
657
|
+
}
|
|
658
|
+
await Promise.all(promises)
|
|
659
|
+
return results
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
async _filterTracked(key, length, results) {
|
|
663
|
+
if (length) {
|
|
664
|
+
const info = await this.system.get(key)
|
|
665
|
+
// if we've seen this already, ignore
|
|
666
|
+
if (info && info.length >= length) return
|
|
667
|
+
}
|
|
668
|
+
results.push({ key, length })
|
|
663
669
|
}
|
|
664
670
|
|
|
665
671
|
async _flushWakeup() {
|
|
666
672
|
const hints = await this._applyWakeupHints()
|
|
667
|
-
if (!hints.
|
|
673
|
+
if (!hints.length) return
|
|
668
674
|
|
|
669
675
|
if (!this._ffEnabled) return
|
|
670
676
|
|
|
@@ -688,10 +694,9 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
688
694
|
async _readCandidateHeads(hints, timeout) {
|
|
689
695
|
const promises = []
|
|
690
696
|
|
|
691
|
-
for (const
|
|
697
|
+
for (const { key, length } of hints) {
|
|
692
698
|
if (length === 0) continue
|
|
693
|
-
|
|
694
|
-
promises.push(this._getOplog(key, length, timeout ? { timeout } : null))
|
|
699
|
+
promises.push(this._resolveOplogHint(key, length, timeout ? { timeout } : null))
|
|
695
700
|
}
|
|
696
701
|
|
|
697
702
|
const ops = await Promise.all(promises)
|
|
@@ -714,6 +719,22 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
714
719
|
return heads
|
|
715
720
|
}
|
|
716
721
|
|
|
722
|
+
async _resolveOplogHint(key, length, opts) {
|
|
723
|
+
const core = this.openCore(key)
|
|
724
|
+
|
|
725
|
+
try {
|
|
726
|
+
await core.ready()
|
|
727
|
+
const max = Math.max(length, core.length)
|
|
728
|
+
|
|
729
|
+
const block = await this.readOplog(core, max, opts)
|
|
730
|
+
if (max >= core.length) return block // best one
|
|
731
|
+
|
|
732
|
+
return await this.readOplog(core, core.length, opts)
|
|
733
|
+
} finally {
|
|
734
|
+
await core.close()
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
717
738
|
async _getOplog(key, length, opts = null) {
|
|
718
739
|
const core = this.openCore(key)
|
|
719
740
|
|
|
@@ -987,51 +1008,6 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
987
1008
|
}
|
|
988
1009
|
}
|
|
989
1010
|
|
|
990
|
-
async _appendApprovals() {
|
|
991
|
-
if (!this.writers.writable) return false
|
|
992
|
-
|
|
993
|
-
const approvals = await this._collectApprovals()
|
|
994
|
-
if (!approvals) return false
|
|
995
|
-
|
|
996
|
-
const links = this.system.getLinks(this.local.key)
|
|
997
|
-
const t = Math.max(this._now(), this.system.timestamp)
|
|
998
|
-
this.writers.appendLocal(null, t, { start: 0, end: 0 }, links, false, null, approvals)
|
|
999
|
-
return true
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
// append a null value node to ack writer
|
|
1003
|
-
_appendAck() {
|
|
1004
|
-
if (!this._ackRequired) return false
|
|
1005
|
-
if (!this.writers.writable) return false
|
|
1006
|
-
|
|
1007
|
-
if (this.writers.localWriter.pending !== null) return false
|
|
1008
|
-
|
|
1009
|
-
const links = this.system.getLinks(this.local.key)
|
|
1010
|
-
const t = Math.max(this._now(), this.system.timestamp)
|
|
1011
|
-
|
|
1012
|
-
let unlinked = false
|
|
1013
|
-
for (const { key, length } of links) {
|
|
1014
|
-
const hex = b4a.toString(key, 'hex')
|
|
1015
|
-
const acked = this._ackedHeads.get(hex) || 0
|
|
1016
|
-
if (length > acked) {
|
|
1017
|
-
unlinked = true
|
|
1018
|
-
break
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
if (!unlinked) {
|
|
1022
|
-
this._ackRequired = false
|
|
1023
|
-
return false
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
for (const { key, length } of links) {
|
|
1027
|
-
this._ackedHeads.set(b4a.toString(key, 'hex'), length)
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
this.writers.appendLocal(null, t, { start: 0, end: 0 }, links, false, null)
|
|
1031
|
-
this._ackRequired = false
|
|
1032
|
-
return true
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
1011
|
async _bumpPendingWriters({ local = false } = {}) {
|
|
1036
1012
|
if (!local && this._catchupMigratedNodes !== null) {
|
|
1037
1013
|
const updated = await this._bumpMigratedWriters()
|
|
@@ -1398,10 +1374,9 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
1398
1374
|
|
|
1399
1375
|
async _bootAttempt(head, bootCondition, reference) {
|
|
1400
1376
|
// peek, so the hints are still there for the drain once we have booted
|
|
1401
|
-
const
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
)
|
|
1377
|
+
const result = await this._filterHints(this._wakeup.hints)
|
|
1378
|
+
|
|
1379
|
+
const candidates = await this._readCandidateHeads(result, FastForward.DEFAULT_TIMEOUT)
|
|
1405
1380
|
|
|
1406
1381
|
const ff = await FastForward.fromHeads(this, [head, ...candidates], {
|
|
1407
1382
|
force: true,
|
package/lib/apply-calls.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const ID = require('hypercore-id-encoding')
|
|
2
|
-
const b4a = require('b4a')
|
|
3
2
|
|
|
4
3
|
class ApplyCalls {
|
|
5
4
|
constructor(auto) {
|
|
@@ -44,10 +43,6 @@ class ApplyCalls {
|
|
|
44
43
|
|
|
45
44
|
ackWriter(key) {
|
|
46
45
|
if (typeof key === 'string') key = ID.decode(key)
|
|
47
|
-
// acking an optimistic node means we owe it a linking node
|
|
48
|
-
if (this.applying && this.applying[0].optimistic && !b4a.equals(key, this.auto.local.key)) {
|
|
49
|
-
this.auto._ackRequired = true
|
|
50
|
-
}
|
|
51
46
|
return this.auto.system.ackWriter(key)
|
|
52
47
|
}
|
|
53
48
|
|
package/lib/fast-forward.js
CHANGED
|
@@ -9,10 +9,6 @@ const { LEGACY_AUTOBASE_VERSION } = require('./constants.js')
|
|
|
9
9
|
const DEFAULT_OP_TIMEOUT = 5_000
|
|
10
10
|
const MIN_FF_GAP = 32
|
|
11
11
|
|
|
12
|
-
// views are only stamped on the last node of a flush, so a head may sit above
|
|
13
|
-
// the most recent one - how far back we look for it
|
|
14
|
-
const MAX_FLUSH_SEARCH = 64
|
|
15
|
-
|
|
16
12
|
module.exports = class FastForward {
|
|
17
13
|
constructor(auto, head, { timeout = DEFAULT_OP_TIMEOUT } = {}) {
|
|
18
14
|
this.auto = auto
|
|
@@ -147,18 +143,9 @@ module.exports = class FastForward {
|
|
|
147
143
|
const core = auto.openCore(head.key)
|
|
148
144
|
|
|
149
145
|
try {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const oplog = await auto.readOplog(core, length, opts)
|
|
154
|
-
if (oplog === null) return null
|
|
155
|
-
if (oplog.op.views) return oplog
|
|
156
|
-
|
|
157
|
-
length = oplog.length - 1
|
|
158
|
-
if (length <= 0) return null
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return null
|
|
146
|
+
const oplog = await auto.readOplog(core, head.length, opts)
|
|
147
|
+
if (oplog === null) return null
|
|
148
|
+
return oplog.op.views ? oplog : null
|
|
162
149
|
} finally {
|
|
163
150
|
await core.close()
|
|
164
151
|
}
|
package/lib/migrations.js
CHANGED
|
@@ -223,7 +223,9 @@ async function inflateLegacyOplog(buf, core, seq, timeout) {
|
|
|
223
223
|
|
|
224
224
|
fetches.push(m.digest.pointer ? core.get(seq - m.digest.pointer, { timeout }) : buf)
|
|
225
225
|
fetches.push(
|
|
226
|
-
m.checkpoint.
|
|
226
|
+
m.checkpoint.system.checkpointer
|
|
227
|
+
? core.get(seq - m.checkpoint.system.checkpointer, { timeout })
|
|
228
|
+
: buf
|
|
227
229
|
)
|
|
228
230
|
|
|
229
231
|
const [digestNode, checkpointNode] = await Promise.all(fetches)
|
package/lib/system.js
CHANGED
|
@@ -71,12 +71,12 @@ module.exports = class Systembee {
|
|
|
71
71
|
const added = info && info.isAdded !== false
|
|
72
72
|
if (added && !info.isRemoved && length <= info.length && !hint && pending === -1) return
|
|
73
73
|
|
|
74
|
-
this.update(key, length, -1, -1, false, true, false,
|
|
74
|
+
this.update(key, length, -1, -1, false, true, false, -1, hint, pending)
|
|
75
75
|
return
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
const w = isGenesis ? effective : -1
|
|
79
|
-
this.update(key, length, w, effective, isGenesis, true, false,
|
|
79
|
+
this.update(key, length, w, effective, isGenesis, true, false, -1, hint, pending)
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
async ackWriter(key, { length = 0 } = {}) {
|
|
@@ -84,7 +84,7 @@ module.exports = class Systembee {
|
|
|
84
84
|
const info = await this.get(key, { unflushed: false })
|
|
85
85
|
length = info ? info.length : 0
|
|
86
86
|
}
|
|
87
|
-
this.update(key, length, -1, -1, false, false, false,
|
|
87
|
+
this.update(key, length, -1, -1, false, false, false, -1, null)
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
async removeWriter(key, { length = 0 } = {}) {
|
|
@@ -92,17 +92,24 @@ module.exports = class Systembee {
|
|
|
92
92
|
const info = await this.get(key, { unflushed: true })
|
|
93
93
|
length = info ? info.length : 0
|
|
94
94
|
}
|
|
95
|
-
this.update(key, length, -1, 0, false, false, true,
|
|
95
|
+
this.update(key, length, -1, 0, false, false, true, -1, null)
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
addAnchor(key) {
|
|
99
|
-
this.update(key, 0, -1, -1, false, true, false,
|
|
99
|
+
this.update(key, 0, -1, -1, false, true, false, -1, null)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
isGenesis() {
|
|
103
103
|
return this.bee.head() === null || this.bee.head().length === 0
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
isHead(key) {
|
|
107
|
+
for (const head of this.heads) {
|
|
108
|
+
if (b4a.equals(head.key, key)) return true
|
|
109
|
+
}
|
|
110
|
+
return false
|
|
111
|
+
}
|
|
112
|
+
|
|
106
113
|
async boot(view, { timeout } = {}) {
|
|
107
114
|
await this.bee.ready()
|
|
108
115
|
this.bee.move(view)
|
|
@@ -184,18 +191,7 @@ module.exports = class Systembee {
|
|
|
184
191
|
|
|
185
192
|
// resolved sort weight, re-stamped on every reapplication - this is what
|
|
186
193
|
// topo reads back out of the changes stream
|
|
187
|
-
this.update(
|
|
188
|
-
node.key,
|
|
189
|
-
node.length,
|
|
190
|
-
node.weight,
|
|
191
|
-
-1,
|
|
192
|
-
false,
|
|
193
|
-
false,
|
|
194
|
-
false,
|
|
195
|
-
false,
|
|
196
|
-
node.timestamp,
|
|
197
|
-
null
|
|
198
|
-
)
|
|
194
|
+
this.update(node.key, node.length, node.weight, -1, false, false, false, node.timestamp, null)
|
|
199
195
|
}
|
|
200
196
|
|
|
201
197
|
async canApply(key, optimistic) {
|
|
@@ -236,14 +232,12 @@ module.exports = class Systembee {
|
|
|
236
232
|
isGenesis: upd.maxWeight !== -1 && !!upd.isGenesis,
|
|
237
233
|
length: upd.length,
|
|
238
234
|
clock: 0,
|
|
239
|
-
isAdded: upd.isAdded
|
|
240
|
-
isAcked: upd.isAcked
|
|
235
|
+
isAdded: upd.isAdded
|
|
241
236
|
}
|
|
242
237
|
}
|
|
243
238
|
|
|
244
239
|
if (upd.isAdded) info.isAdded = true
|
|
245
240
|
if (upd.isRemoved) info.isRemoved = true
|
|
246
|
-
if (upd.isAcked) info.isAcked = true
|
|
247
241
|
if (upd.maxWeight !== -1) {
|
|
248
242
|
info.isGenesis = upd.isGenesis
|
|
249
243
|
info.maxWeight = upd.maxWeight
|
|
@@ -284,7 +278,6 @@ module.exports = class Systembee {
|
|
|
284
278
|
isGenesis,
|
|
285
279
|
isAdded,
|
|
286
280
|
isRemoved,
|
|
287
|
-
isAcked,
|
|
288
281
|
timestamp,
|
|
289
282
|
grant,
|
|
290
283
|
pending = -1
|
|
@@ -308,7 +301,6 @@ module.exports = class Systembee {
|
|
|
308
301
|
isGenesis: false,
|
|
309
302
|
isRemoved: false,
|
|
310
303
|
isAdded: false,
|
|
311
|
-
isAcked: false,
|
|
312
304
|
timestamp: 0,
|
|
313
305
|
grant: null,
|
|
314
306
|
pending: -1
|
|
@@ -330,9 +322,6 @@ module.exports = class Systembee {
|
|
|
330
322
|
upd.isRemoved = true
|
|
331
323
|
upd.isAdded = false
|
|
332
324
|
}
|
|
333
|
-
if (isAcked) {
|
|
334
|
-
upd.isAcked = true
|
|
335
|
-
}
|
|
336
325
|
if (length > upd.length) {
|
|
337
326
|
upd.length = length
|
|
338
327
|
}
|
package/lib/witness.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const b4a = require('b4a')
|
|
2
2
|
const encoding = require('./encoding.js')
|
|
3
|
-
const { DEFAULT_OP_TIMEOUT } = require('./constants.js')
|
|
4
3
|
|
|
5
4
|
exports.currentWeight = currentWeight
|
|
6
5
|
exports.resolveWeight = resolveWeight
|
|
@@ -56,7 +55,7 @@ async function readOplogNode(auto, key, length) {
|
|
|
56
55
|
|
|
57
56
|
try {
|
|
58
57
|
await core.ready()
|
|
59
|
-
const block = await core.get(length - 1
|
|
58
|
+
const block = await core.get(length - 1)
|
|
60
59
|
return encoding.decodeOplog(block)
|
|
61
60
|
} finally {
|
|
62
61
|
await core.close()
|
package/lib/writers.js
CHANGED
|
@@ -18,19 +18,24 @@ class ActiveWriters {
|
|
|
18
18
|
|
|
19
19
|
this.auto = auto
|
|
20
20
|
this.active = new Map()
|
|
21
|
-
this._adding = new Map()
|
|
22
21
|
this.triggers = new Triggers()
|
|
23
|
-
this.localWriter =
|
|
22
|
+
this.localWriter = null
|
|
24
23
|
this.writable = false
|
|
25
24
|
this.pending = []
|
|
26
25
|
|
|
27
26
|
this._pendingBuffer = new Map()
|
|
27
|
+
this._adding = new Map()
|
|
28
28
|
|
|
29
|
+
this.localWriter = new Writer(this, auto.system, true, local, b4a.toString(local.key, 'hex'))
|
|
29
30
|
this.localWriter.attach()
|
|
30
31
|
|
|
31
32
|
this._bootstrap()
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
get size() {
|
|
36
|
+
return this.active.size
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
[Symbol.iterator]() {
|
|
35
40
|
return this.active.values()
|
|
36
41
|
}
|
|
@@ -195,10 +200,7 @@ class ActiveWriters {
|
|
|
195
200
|
if (local) await this.updateLocalState()
|
|
196
201
|
|
|
197
202
|
let w = this.active.get(id)
|
|
198
|
-
if (w)
|
|
199
|
-
w.couple() // couple if we weren't ready first time
|
|
200
|
-
return w
|
|
201
|
-
}
|
|
203
|
+
if (w) return w
|
|
202
204
|
|
|
203
205
|
// no new sessions once teardown started
|
|
204
206
|
if (this.auto._interrupting) return null
|
|
@@ -222,7 +224,6 @@ class ActiveWriters {
|
|
|
222
224
|
|
|
223
225
|
w = new Writer(this, this.auto.system, false, core, id)
|
|
224
226
|
w.attach()
|
|
225
|
-
w.couple()
|
|
226
227
|
|
|
227
228
|
return w
|
|
228
229
|
}
|
|
@@ -260,7 +261,7 @@ class ActiveWriters {
|
|
|
260
261
|
const id = b4a.toString(bootstrap.key, 'hex')
|
|
261
262
|
let w = this.active.get(id)
|
|
262
263
|
if (w) {
|
|
263
|
-
w.
|
|
264
|
+
w.isHead = true
|
|
264
265
|
w.couple() // couple if we weren't ready first time
|
|
265
266
|
return
|
|
266
267
|
}
|
|
@@ -269,7 +270,7 @@ class ActiveWriters {
|
|
|
269
270
|
session.setEncryption(this.auto._getEncryptionProvider())
|
|
270
271
|
|
|
271
272
|
w = new Writer(this, this.auto.system, false, session, id)
|
|
272
|
-
w.
|
|
273
|
+
w.isHead = true // the root of the autobase, never gc'd
|
|
273
274
|
w.attach()
|
|
274
275
|
w.couple()
|
|
275
276
|
}
|
|
@@ -298,7 +299,7 @@ class Writer {
|
|
|
298
299
|
this.isRemoved = false
|
|
299
300
|
this.isCoupled = false
|
|
300
301
|
this.isFrozen = false
|
|
301
|
-
this.
|
|
302
|
+
this.isHead = false
|
|
302
303
|
|
|
303
304
|
this._onchangeBound = this._onchange.bind(this)
|
|
304
305
|
|
|
@@ -312,6 +313,10 @@ class Writer {
|
|
|
312
313
|
return this.weight >= 2
|
|
313
314
|
}
|
|
314
315
|
|
|
316
|
+
isSystemHead() {
|
|
317
|
+
return this.system.isHead(this.core.key)
|
|
318
|
+
}
|
|
319
|
+
|
|
315
320
|
couple() {
|
|
316
321
|
if (this.isCoupled) return
|
|
317
322
|
// if we don't have coupler yet we can't add
|
|
@@ -357,7 +362,10 @@ class Writer {
|
|
|
357
362
|
|
|
358
363
|
// a peer announced this length for us, so we're not caught up until we've seen it
|
|
359
364
|
hint(length) {
|
|
360
|
-
if (length > this.hintedLength)
|
|
365
|
+
if (length > this.hintedLength) {
|
|
366
|
+
this.hintedLength = length
|
|
367
|
+
this.core.setActive(true)
|
|
368
|
+
}
|
|
361
369
|
}
|
|
362
370
|
|
|
363
371
|
_onchange() {
|
|
@@ -395,12 +403,31 @@ class Writer {
|
|
|
395
403
|
this.waiting = null
|
|
396
404
|
}
|
|
397
405
|
|
|
406
|
+
const isHead = this.isSystemHead()
|
|
407
|
+
|
|
408
|
+
if (isHead && !this.isHead) {
|
|
409
|
+
this.isHead = true
|
|
410
|
+
this.couple()
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (!isHead && this.isHead) {
|
|
414
|
+
this.isHead = false
|
|
415
|
+
this.decouple()
|
|
416
|
+
}
|
|
417
|
+
|
|
398
418
|
const length = await this.update()
|
|
419
|
+
const active = length < this.core.length || length < this.hintedLength
|
|
420
|
+
|
|
421
|
+
if (this.isHead || active) {
|
|
422
|
+
this.core.setActive(true)
|
|
423
|
+
} else {
|
|
424
|
+
this.core.setActive(false)
|
|
425
|
+
}
|
|
399
426
|
|
|
400
427
|
// don't drop any local nodes left in buffer, or work a peer told us about
|
|
401
428
|
if (length < this.core.length || length < this.hintedLength || this.appending) {
|
|
402
429
|
this.addPending()
|
|
403
|
-
} else if (this !== this.writers.localWriter && !this.
|
|
430
|
+
} else if (this !== this.writers.localWriter && !this.isHead) {
|
|
404
431
|
await this.detachAndClose()
|
|
405
432
|
}
|
|
406
433
|
}
|