autobee 2.0.0-rc.10 → 2.0.0-rc.12

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.
Files changed (3) hide show
  1. package/index.js +23 -6
  2. package/lib/topo.js +25 -2
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -76,8 +76,13 @@ module.exports = class Autobee extends ReadyResource {
76
76
  this.writers = null
77
77
  this.bumping = 0
78
78
 
79
+ const fastForward = handlers.fastForward || {}
80
+
79
81
  // system head to boot from: migrates or fast-forwards depending on its version
80
- this.bootFrom = handlers.bootFrom || null
82
+ this.bootFrom = fastForward.boot || null
83
+
84
+ // conservative (default on): only fast-forward onto a head someone can serve whole
85
+ this._conservativeFF = fastForward.conservative !== false
81
86
 
82
87
  this.reboot = null
83
88
  this.rebooting = null
@@ -88,6 +93,7 @@ module.exports = class Autobee extends ReadyResource {
88
93
 
89
94
  this._localSystemStart = 0
90
95
  this._localSystemLength = 0
96
+ this._localFlushes = 0
91
97
  this._localViewStart = 0
92
98
  this._localViewLength = 0
93
99
 
@@ -163,6 +169,7 @@ module.exports = class Autobee extends ReadyResource {
163
169
 
164
170
  this._localSystemStart = this.system.bee.context.local.length
165
171
  this._localViewStart = this._workingBee.context.local.length
172
+ this._localFlushes = this.system.flushes
166
173
 
167
174
  this.bumpSoon()
168
175
  }
@@ -603,6 +610,9 @@ module.exports = class Autobee extends ReadyResource {
603
610
  const target = length >= 0 ? length : core.length
604
611
  if (target === 0) return null
605
612
 
613
+ // conservative: only proceed when a connected peer can serve the head whole
614
+ if (opts && opts.conservative && core.remoteContiguousLength < target) return null
615
+
606
616
  const buf = await core.get(target - 1, opts)
607
617
  if (buf === null) return null
608
618
 
@@ -967,6 +977,7 @@ module.exports = class Autobee extends ReadyResource {
967
977
  if (local) {
968
978
  this._localSystemLength = this.system.bee.context.local.length - this._localSystemStart
969
979
  this._localViewLength = this._workingBee.context.local.length - this._localViewStart
980
+ this._localFlushes = this.system.flushes
970
981
  }
971
982
 
972
983
  this.writers.attest(witnessed)
@@ -1081,7 +1092,7 @@ module.exports = class Autobee extends ReadyResource {
1081
1092
 
1082
1093
  async _flushLocal() {
1083
1094
  await this.writers.flushLocal({
1084
- flushes: this.system.flushes,
1095
+ flushes: this._localFlushes,
1085
1096
  system: {
1086
1097
  key: this.system.bee.context.local.key,
1087
1098
  start: this._localSystemStart,
@@ -1096,6 +1107,7 @@ module.exports = class Autobee extends ReadyResource {
1096
1107
 
1097
1108
  this._localSystemStart = this.system.bee.context.local.length
1098
1109
  this._localSystemLength = 0
1110
+ this._localFlushes = this.system.flushes
1099
1111
  this._localViewStart = this._workingBee.context.local.length
1100
1112
  this._localViewLength = 0
1101
1113
  }
@@ -1155,7 +1167,9 @@ module.exports = class Autobee extends ReadyResource {
1155
1167
  }
1156
1168
 
1157
1169
  async _rebootFromHead(head, trusted, { force = false, wait = true } = {}) {
1158
- const oplog = await this._getOplog(head.key, head.length)
1170
+ const conservative = !force && this._conservativeFF
1171
+
1172
+ const oplog = await this._getOplog(head.key, head.length, { conservative })
1159
1173
  if (!oplog) return null
1160
1174
 
1161
1175
  const verified = trusted ? await this._getOplog(trusted.key, trusted.length) : oplog
@@ -1168,13 +1182,15 @@ module.exports = class Autobee extends ReadyResource {
1168
1182
  return null
1169
1183
  }
1170
1184
 
1171
- const moved = await this._moveTo(batchToHead(verified.op.views.system), {
1185
+ const tip = {
1172
1186
  system: batchToHead(oplog.op.views.system),
1173
1187
  verified: {
1174
1188
  op: trusted || head,
1175
1189
  flushes: verified.op.views.flushes
1176
1190
  }
1177
- })
1191
+ }
1192
+
1193
+ const moved = await this._moveTo(batchToHead(verified.op.views.system), tip)
1178
1194
 
1179
1195
  if (moved && wait) return this.reboot.promise
1180
1196
 
@@ -1277,7 +1293,8 @@ module.exports = class Autobee extends ReadyResource {
1277
1293
  const t = await topo.rollback(this, sys, verified)
1278
1294
  await sys.close()
1279
1295
 
1280
- await this.applyBacklog(t.tip)
1296
+ if (t !== null) await this.applyBacklog(t.tip)
1297
+
1281
1298
  return this._update(changes)
1282
1299
  }
1283
1300
 
package/lib/topo.js CHANGED
@@ -42,20 +42,35 @@ async function getMostRecentHead(auto, system) {
42
42
  }
43
43
 
44
44
  async function rollback(auto, system, verified) {
45
+ if (!(await isApplied(system, verified.op))) return null
46
+
45
47
  const tip = []
46
48
  const ch = system.createChangesStream()
47
49
 
50
+ let found = false
51
+
48
52
  for await (const data of ch) {
49
53
  const { ref, info } = getOplog(data)
54
+
50
55
  if (sameNode(ref.oplog, verified.op)) {
51
- asserts.assert(info.flushes === verified.flushes, 'Expect tip to be continuous')
56
+ // stale views.flushes - the verified head describes a prefix this system
57
+ // does not share, so nothing above it is ours to reapply
58
+ if (info.flushes === verified.flushes) found = true
59
+ break
60
+ }
61
+
62
+ // walking back, a writer's lengths only decrease - once this writer is
63
+ // behind the verified head the marker cannot be further down
64
+ if (b4a.equals(ref.oplog.key, verified.op.key) && ref.oplog.length < verified.op.length) {
52
65
  break
53
66
  }
54
67
 
55
68
  tip.push(ref)
56
69
  }
57
70
 
58
- const inflated = await inflate(auto, tip)
71
+ if (!found) return null
72
+
73
+ const inflated = await inflate(auto, tip.reverse())
59
74
 
60
75
  // @todo: verify sort
61
76
 
@@ -86,6 +101,14 @@ async function replay(auto) {
86
101
  return inflated.flatMap((b) => (b === null ? [null] : b.batch))
87
102
  }
88
103
 
104
+ async function isApplied(system, node) {
105
+ const entry = await system.get(encoding.encodeSystemWriterKey(node.key))
106
+ if (entry === null) return false
107
+
108
+ const info = encoding.decodeSystemWriter(entry.key, entry.value)
109
+ return info.length >= node.length
110
+ }
111
+
89
112
  // tolerates legacy nodes instead of asserting
90
113
  async function* oplogIterator(bee) {
91
114
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autobee",
3
- "version": "2.0.0-rc.10",
3
+ "version": "2.0.0-rc.12",
4
4
  "description": "Bee based autobase",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Holepunch Inc.",