autobee 2.4.0 → 2.5.1

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 CHANGED
@@ -279,7 +279,7 @@ Pass `{ timeout }` to bound the reads, so a head nobody can serve fails instead
279
279
 
280
280
  Peers fast-forward onto the heads of writers they trust, so a trusted writer that has nothing to say still has to stamp its view progress into its own oplog.
281
281
 
282
- Acking does that: an empty node is appended whenever the local writer falls `ackThreshold` (default `64`) flushes behind the system.
282
+ Acking does that: an empty node is appended whenever the local writer falls `ackThreshold` (default `32`) flushes behind the system.
283
283
 
284
284
  It is enabled for exactly the writers `isTrusted` accepts. The local key is judged when the db opens, after a fast-forward, and after the local writer rotates, so a writer that becomes trusted starts acking without being told to. `setAcking` overrides it until the next of those points.
285
285
 
package/index.js CHANGED
@@ -99,9 +99,9 @@ module.exports = class Autobee extends ReadyResource {
99
99
  this.bootFrom = (fastForward && fastForward.boot) || null
100
100
 
101
101
  // conservative (default on): only fast-forward onto a head someone can serve whole
102
- this._conservativeFF = !fastForward || fastForward.conservative !== false
102
+ this._conservativeFF = !fastForward || !!fastForward.conservative
103
103
 
104
- this.trusted = new TrustedPeers(handlers)
104
+ this.trusted = new TrustedPeers(this, handlers)
105
105
 
106
106
  this.ff = null
107
107
  this.fastForwarding = null
@@ -1098,6 +1098,7 @@ module.exports = class Autobee extends ReadyResource {
1098
1098
 
1099
1099
  for await (const p of this._servableRequests(standing)) {
1100
1100
  approving.push(fetchApproval.call(this, p.key, p.amount, approvals))
1101
+ if (approving.length === 32) break
1101
1102
  }
1102
1103
 
1103
1104
  if (!approving.length) return null
@@ -1179,6 +1180,10 @@ module.exports = class Autobee extends ReadyResource {
1179
1180
  return true
1180
1181
  }
1181
1182
 
1183
+ // not added and not applicable optimistically: nothing can apply this
1184
+ // batch now, so drop the writer for this drain instead of reselecting it
1185
+ // (a refresh re-adds it once it has been added or has new blocks)
1186
+ w.removePending()
1182
1187
  return true
1183
1188
  }
1184
1189
 
@@ -1190,19 +1195,19 @@ module.exports = class Autobee extends ReadyResource {
1190
1195
  if (t.view) this._workingBee.move(t.view)
1191
1196
 
1192
1197
  for (const b of t.tip) {
1193
- let failed = true
1198
+ const optimistic = b[0].optimistic
1199
+ let accepted = false
1194
1200
  try {
1195
- if (await this.system.canApply(b[0].key, true)) {
1196
- await this._applyBatch(b, true)
1197
- failed = false
1198
- }
1199
- } catch {}
1201
+ accepted = await this._applyBatch(b, optimistic)
1202
+ } catch (err) {
1203
+ if (!optimistic) throw err
1204
+ }
1200
1205
 
1201
1206
  // only check if batch was successful
1202
1207
  if (b !== batch) continue
1203
1208
 
1204
- const w = failed ? null : await this.system.get(b[0].key)
1205
- if (!w || w.length < b[0].length) {
1209
+ // declined: apply threw, or never called addWriter/ackWriter for this writer
1210
+ if (!accepted) {
1206
1211
  this._workingBee.move(rollbackView)
1207
1212
  this.system.bee.move(rollbackSystem)
1208
1213
  await this.system.reset()
@@ -1289,10 +1294,16 @@ module.exports = class Autobee extends ReadyResource {
1289
1294
  if (this._hasApply && (await this.system.canApply(batch[0].key, optimistic))) {
1290
1295
  this.stats.applies++
1291
1296
  this._host.applying = batch
1292
- await this._workingView.apply(userBatch)
1293
- this._host.applying = null
1297
+ try {
1298
+ await this._workingView.apply(userBatch)
1299
+ } finally {
1300
+ this._host.applying = null
1301
+ }
1294
1302
  }
1295
1303
 
1304
+ // read before flush clears it
1305
+ const accepted = this.system.touched(batch[0].key)
1306
+
1296
1307
  const changed = await this.system.flush(batch, this._workingBee)
1297
1308
 
1298
1309
  if (this.system.promotions.changed) this._prefetchApprovals().catch(safetyCatch)
@@ -1307,6 +1318,8 @@ module.exports = class Autobee extends ReadyResource {
1307
1318
  if (added) await this.writers.add(key)
1308
1319
  else await this.writers.remove(key)
1309
1320
  }
1321
+
1322
+ return accepted
1310
1323
  }
1311
1324
 
1312
1325
  async _storeBoot() {
package/lib/system.js CHANGED
@@ -48,6 +48,7 @@ module.exports = class Systembee {
48
48
  this.updates = new Map()
49
49
  this.writers = new Map()
50
50
  this.encrypted = opts.encrypted === true
51
+ this.indexers = null
51
52
  this.promotions = new Promotions(this.bee)
52
53
  }
53
54
 
@@ -85,11 +86,14 @@ module.exports = class Systembee {
85
86
  }
86
87
 
87
88
  async ackWriter(key, { length = 0 } = {}) {
89
+ const info = await this.get(key, { unflushed: true })
88
90
  if (length === 0) {
89
- const info = await this.get(key, { unflushed: false })
90
91
  length = info ? info.length : 0
91
92
  }
92
- this.update(key, length, -1, -1, false, false, false, -1, null)
93
+ // acked but never granted: keep the op (record its length) but record the
94
+ // writer as removed so nothing else from it is applied
95
+ const isRemoved = !info || info.isAdded === false
96
+ this.update(key, length, -1, -1, false, false, isRemoved, -1, null)
93
97
  }
94
98
 
95
99
  async removeWriter(key, { length = 0 } = {}) {
@@ -143,6 +147,9 @@ module.exports = class Systembee {
143
147
  // ~~~ good enough estimation
144
148
  this.flushes = Math.floor(this.bee.core.length / 2)
145
149
  this.view = await this._migrate(info, { timeout })
150
+ this.indexers = info ? info.indexers : null
151
+ } else {
152
+ this.indexers = null
146
153
  }
147
154
 
148
155
  this.updates.clear()
@@ -220,6 +227,11 @@ module.exports = class Systembee {
220
227
  this.update(node.key, node.length, node.weight, -1, false, false, false, node.timestamp, null)
221
228
  }
222
229
 
230
+ // did this apply add or remove (ack) the writer
231
+ touched(key) {
232
+ return this.writers.has(b4a.toString(key, 'hex'))
233
+ }
234
+
223
235
  async canApply(key, optimistic) {
224
236
  const id = b4a.toString(key, 'hex')
225
237
  const w = this.writers.get(id)
package/lib/trusted.js CHANGED
@@ -1,9 +1,10 @@
1
1
  const b4a = require('b4a')
2
2
 
3
3
  class TrustedPeers {
4
- constructor(hooks) {
4
+ constructor(auto, hooks) {
5
5
  this.trusted = new Map()
6
6
  this.pending = new Map()
7
+ this.auto = auto
7
8
  this.hooks = hooks
8
9
  }
9
10
 
@@ -11,6 +12,18 @@ class TrustedPeers {
11
12
  const hex = b4a.toString(key, 'hex')
12
13
  if (this.trusted.get(hex)) return true
13
14
 
15
+ // bootstrap
16
+ if (this.auto.system.isGenesis() && b4a.equals(key, this.auto.key)) {
17
+ return true
18
+ }
19
+
20
+ // legacy handling
21
+ if (this.auto.system.indexers) {
22
+ for (const idx of this.auto.system.indexers) {
23
+ if (b4a.equals(key, idx.key)) return true
24
+ }
25
+ }
26
+
14
27
  let promise = this.pending.get(hex)
15
28
  if (promise) return promise
16
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autobee",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "description": "Bee based autobase",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Holepunch Inc.",