autobee 2.0.0-rc.6 → 2.0.0-rc.7

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
@@ -253,7 +253,12 @@ module.exports = class Autobee extends ReadyResource {
253
253
  view: info ? info.view : EMPTY_HEAD
254
254
  }
255
255
 
256
- const shared = await this.system.commonAncestor(system || EMPTY_HEAD)
256
+ // no common ancestor (null) -> flushes -1 never matches, forcing a full diff
257
+ const shared = (await this.system.commonAncestor(system || EMPTY_HEAD)) || {
258
+ flushes: -1,
259
+ system: EMPTY_HEAD,
260
+ view: EMPTY_HEAD
261
+ }
257
262
 
258
263
  return UpdateChanges.from(shared, current)
259
264
  }
package/lib/system.js CHANGED
@@ -2,7 +2,6 @@ const Hyperbee = require('hyperbee2')
2
2
  const b4a = require('b4a')
3
3
 
4
4
  const { AUTOBEE_VERSION } = require('./constants')
5
- const asserts = require('./asserts.js')
6
5
  const encoding = require('./encoding.js')
7
6
  const topo = require('./topo.js')
8
7
 
@@ -117,46 +116,57 @@ module.exports = class Systembee {
117
116
  }
118
117
 
119
118
  async commonAncestor(head) {
120
- const info = await this.getInfo()
121
-
122
119
  const snap = this.bee.checkout(head)
123
120
 
124
- const hist1 = this.bee.createChangesStream()[Symbol.asyncIterator]()
125
- const hist2 = snap.createChangesStream()[Symbol.asyncIterator]()
121
+ const ca = infoIterator(this.bee)
122
+ const cb = infoIterator(snap)
123
+
124
+ let l = await next(ca)
125
+ let r = await next(cb)
126
+
127
+ while (l && r) {
128
+ if (l.legacy && r.legacy) {
129
+ // legacy nodes just compare head
130
+ if (sameHead(l.node.head, r.node.head)) {
131
+ return {
132
+ flushes: l.info.flushes,
133
+ system: l.node.head,
134
+ view: l.info.view || EMPTY_HEAD
135
+ }
136
+ }
126
137
 
127
- let a = await hist1.next()
128
- let b = await hist2.next()
138
+ // different legacy cores never converge - genuinely unrelated history
139
+ if (!b4a.equals(l.node.head.key, r.node.head.key)) return null
129
140
 
130
- if (!a.value || !b.value) {
131
- return { flushes: 0, system: EMPTY_HEAD, view: EMPTY_HEAD }
132
- }
141
+ if (l.node.head.length >= r.node.head.length) l = await next(ca)
142
+ else r = await next(cb)
143
+ continue
144
+ }
133
145
 
134
- let l = getInfo(a.value)
135
- let r = getInfo(b.value)
146
+ if (l.legacy !== r.legacy) {
147
+ // current-format history sits above the legacy band: descend it
148
+ if (!l.legacy) l = await next(ca)
149
+ else r = await next(cb)
150
+ continue
151
+ }
136
152
 
137
- while (!a.done || !b.done) {
138
- if (l.flushes === r.flushes && sameHead(l.view, r.view)) {
153
+ if (l.info.flushes === r.info.flushes && sameHead(l.info.view, r.info.view)) {
139
154
  return {
140
- flushes: l.flushes,
141
- system: a.value.head,
142
- view: l.view || EMPTY_HEAD
155
+ flushes: l.info.flushes,
156
+ system: l.node.head,
157
+ view: l.info.view || EMPTY_HEAD
143
158
  }
144
159
  }
145
160
 
146
- if (l.flushes >= r.flushes) {
147
- if (a.done) break
148
- a = await hist1.next()
149
- if (a.value) l = getInfo(a.value)
150
- }
161
+ const lf = l.info.flushes
162
+ const rf = r.info.flushes
151
163
 
152
- if (r.flushes >= l.flushes) {
153
- if (b.done) break
154
- b = await hist2.next()
155
- if (b.value) r = getInfo(b.value)
156
- }
164
+ if (lf >= rf) l = await next(ca)
165
+ if (rf >= lf) r = await next(cb)
157
166
  }
158
167
 
159
- return { flushes: 0, system: EMPTY_HEAD, view: EMPTY_HEAD }
168
+ // no common ancestor
169
+ return null
160
170
  }
161
171
 
162
172
  async reset({ timeout } = {}) {
@@ -491,12 +501,16 @@ function getInfo(data) {
491
501
  const prefix = k.key[0]
492
502
 
493
503
  if (prefix === 0) {
494
- return encoding.decodeSystemInfo(k.value)
504
+ try {
505
+ return encoding.decodeSystemInfo(k.value)
506
+ } catch {
507
+ return null
508
+ }
495
509
  }
496
510
  }
497
511
  }
498
512
 
499
- asserts.bail('Bad system node')
513
+ return null
500
514
  }
501
515
 
502
516
  function sameHead(a, b) {
@@ -504,3 +518,35 @@ function sameHead(a, b) {
504
518
  if (!a.key || !b.key) return a.key === b.key
505
519
  return b4a.equals(a.key, b.key)
506
520
  }
521
+
522
+ async function* infoIterator(bee) {
523
+ try {
524
+ for await (const node of bee.createChangesStream()) {
525
+ const legacy = topo.isLegacyNode(node)
526
+ const info = legacy ? getLegacyInfo(node) : getInfo(node)
527
+ if (info) yield { node, info, legacy }
528
+ }
529
+ } catch {
530
+ // fall through
531
+ }
532
+ }
533
+
534
+ async function next(it) {
535
+ const res = await it.next()
536
+ return res.done ? null : res.value
537
+ }
538
+
539
+ function getLegacyInfo(data) {
540
+ for (const { keys } of data.batch) {
541
+ for (const k of keys) {
542
+ if (b4a.equals(k.key, INFO_LEGACY_KEY)) {
543
+ try {
544
+ return encoding.decodeSystemInfo(k.value)
545
+ } catch {
546
+ return null
547
+ }
548
+ }
549
+ }
550
+ }
551
+ return null
552
+ }
package/lib/topo.js CHANGED
@@ -13,6 +13,7 @@ exports.getMostRecentHead = getMostRecentHead
13
13
 
14
14
  exports.isLinking = isLinking
15
15
  exports.isLinkingAll = isLinkingAll
16
+ exports.isLegacyNode = isLegacyNode
16
17
 
17
18
  class Clock {
18
19
  constructor() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autobee",
3
- "version": "2.0.0-rc.6",
3
+ "version": "2.0.0-rc.7",
4
4
  "description": "Bee based autobase",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Holepunch Inc.",