autobee 2.7.3 → 2.7.4

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 CHANGED
@@ -1032,10 +1032,9 @@ module.exports = class Autobee extends ReadyResource {
1032
1032
  return anchor
1033
1033
  }
1034
1034
 
1035
- // see CatchupOrder - sort order instead of legacy INFO order, so the catchup
1036
- // does not rebase on itself
1035
+ // apply in linearizer order so the catchup never undoes. weights are fixed,
1036
+ // legacy nodes carry no witness
1037
1037
  async _bumpMigratedWriters() {
1038
- const order = new migrations.CatchupOrder(this._catchupMigratedNodes)
1039
1038
  const opened = new Set()
1040
1039
  let updated = false
1041
1040
 
@@ -1046,16 +1045,14 @@ module.exports = class Autobee extends ReadyResource {
1046
1045
  }
1047
1046
 
1048
1047
  try {
1049
- while (order.size) {
1050
- const candidates = order.candidates()
1051
- // recomputed per step - prepareBatch does the same right after
1052
- for (const batch of candidates) batch[0].weight = await resolveWeight(this, batch[0])
1048
+ for (const batch of this._catchupMigratedNodes) {
1049
+ const weight = await resolveWeight(this, batch[0])
1050
+ for (const node of batch) node.weight = weight
1051
+ }
1053
1052
 
1054
- const best = order.pick(candidates)
1055
- await this._processBatch(best)
1053
+ for (const batch of topo.linearize(this._catchupMigratedNodes)) {
1054
+ await this._processBatch(batch)
1056
1055
  updated = true
1057
-
1058
- order.shift(best)
1059
1056
  }
1060
1057
  } finally {
1061
1058
  for (const core of opened) await core.close()
package/lib/migrations.js CHANGED
@@ -6,7 +6,6 @@ const { decodeBlock } = require('hyperbee2/lib/encoding.js')
6
6
 
7
7
  const encoding = require('./encoding.js')
8
8
  const { assert, bail } = require('./asserts.js')
9
- const { sortsBefore } = require('./writers.js')
10
9
 
11
10
  const { getEncoding } = require('../encoding/spec/autobee')
12
11
 
@@ -18,77 +17,13 @@ const INDEX_VERSION = 1
18
17
  const INFO = b4a.from([0x00, 0x00, 0x69, 0x6e, 0x66, 0x6f])
19
18
  const [NS_SIGNER_NAMESPACE] = crypto.namespace('autobase', 1)
20
19
 
21
- // hands out the catchup in sort order rather than legacy INFO order, so it
22
- // does not rebase on itself. only heads whose links are satisfied are
23
- // candidates, and the best of those by sortsBefore goes first. the caller
24
- // resolves weights on the candidates before picking
25
- class CatchupOrder {
26
- constructor(batches) {
27
- this.queues = new Map()
28
- this.applied = new Map()
29
-
30
- for (const batch of batches) {
31
- const id = b4a.toString(batch[0].key, 'hex')
32
- const q = this.queues.get(id)
33
- if (q) q.push(batch)
34
- else this.queues.set(id, [batch])
35
- }
36
-
37
- for (const [id, q] of this.queues) this.applied.set(id, q[0][0].length - 1)
38
- }
39
-
40
- get size() {
41
- return this.queues.size
42
- }
43
-
44
- candidates() {
45
- const batches = []
46
-
47
- for (const q of this.queues.values()) {
48
- if (this._isCandidate(q[0][0])) batches.push(q[0])
49
- }
50
-
51
- assert(batches.length > 0 || this.queues.size === 0, 'Migration catchup has unresolvable links')
52
-
53
- return batches
54
- }
55
-
56
- pick(candidates) {
57
- let best = null
58
- for (const batch of candidates) {
59
- if (best === null || sortsBefore(batch[0], best[0])) best = batch
60
- }
61
- return best
62
- }
63
-
64
- shift(batch) {
65
- const id = b4a.toString(batch[0].key, 'hex')
66
- const q = this.queues.get(id)
67
-
68
- assert(q && q[0] === batch, 'Catchup batch shifted out of order')
69
-
70
- q.shift()
71
- this.applied.set(id, batch[batch.length - 1].length)
72
- if (!q.length) this.queues.delete(id)
73
- }
74
-
75
- _isCandidate(node) {
76
- for (const l of node.links) {
77
- const length = this.applied.get(b4a.toString(l.key, 'hex'))
78
- if (length !== undefined && length < l.length) return false
79
- }
80
- return true
81
- }
82
- }
83
-
84
20
  module.exports = {
85
21
  getCoreManifest,
86
22
  getViewMap,
87
23
  checkAutobaseMigration,
88
24
  readLegacySystemInfo,
89
25
  inflateLegacyOplog,
90
- coreLength,
91
- CatchupOrder
26
+ coreLength
92
27
  }
93
28
 
94
29
  // a peer with a sparse copy may not hold block 0, but the recorded tail is the
package/lib/topo.js CHANGED
@@ -9,6 +9,8 @@ const INFO_LEGACY_KEY = b4a.concat([b4a.from([0, 0]), b4a.from('info')])
9
9
 
10
10
  exports.sort = sort
11
11
  exports.replay = replay
12
+ exports.linearize = linearize
13
+ exports.getOplogBatch = getOplogBatch
12
14
 
13
15
  exports.isLinking = isLinking
14
16
  exports.isLinkingAll = isLinkingAll
@@ -92,6 +94,18 @@ async function sort(auto, batch) {
92
94
  }
93
95
  }
94
96
 
97
+ // the order the batches settle in - applying them in it never undoes.
98
+ // batches must arrive after the batches they link
99
+ function linearize(batches) {
100
+ const list = []
101
+
102
+ for (const batch of batches) {
103
+ addSorted(list, { undo: null, batch, index: -1 })
104
+ }
105
+
106
+ return list.map((e) => e.batch)
107
+ }
108
+
95
109
  function addSorted(list, entry) {
96
110
  const node = entry.batch[0]
97
111
  const clock = new Clock()
@@ -215,16 +229,17 @@ async function getOplogBatch(undo, core, length, weight, index, readOpts = null)
215
229
  const head = createNode(core, length, weight, oplog)
216
230
  const legacy = oplog.version <= LEGACY_OPLOG_VERSION
217
231
 
218
- // if this is legacy the start pointer is always 0, fix
219
- if (legacy && !oplog.links.length) {
232
+ // legacy start is always 0, walk back to the previous head (end 0). links
233
+ // do not mark the start, legacy batch nodes link their own predecessor.
234
+ // only the block before the batch can be missing (legacy ff), so a miss is
235
+ // the boundary
236
+ if (legacy) {
220
237
  for (let i = length - 1; i > 0; i--) {
221
- const block = await core.get(i - 1, readOpts)
222
- if (block === null) return null // wait: false in replay helper
238
+ const block = await core.get(i - 1, { wait: false })
239
+ if (block === null) break
223
240
 
224
- const oplog = encoding.decodeOplog(block)
225
- if (oplog.batch.end === 0) break
241
+ if (encoding.decodeOplog(block).batch.end === 0) break
226
242
  head.batch.start++
227
- if (oplog.links.length > 0) break // always start of batch in legacy
228
243
  }
229
244
  }
230
245
 
package/lib/writers.js CHANGED
@@ -773,7 +773,6 @@ function sortsBefore(a, b) {
773
773
  }
774
774
 
775
775
  exports.ActiveWriters = ActiveWriters
776
- exports.sortsBefore = sortsBefore
777
776
  exports.Writer = Writer
778
777
  exports.createNode = createNode
779
778
  exports.finalizeNodeBatch = finalizeNodeBatch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autobee",
3
- "version": "2.7.3",
3
+ "version": "2.7.4",
4
4
  "description": "Bee based autobase",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Holepunch Inc.",