autobee 2.2.1 → 2.3.0

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/lib/updates.js CHANGED
@@ -24,7 +24,7 @@ module.exports = class UpdateChanges {
24
24
  }
25
25
  }
26
26
 
27
- finalise() {
27
+ finalise(fastForward) {
28
28
  // flush count at `to` - safe to read live, state is frozen for the hook
29
29
  const flushes = this.auto.system.flushes
30
30
 
@@ -33,6 +33,7 @@ module.exports = class UpdateChanges {
33
33
 
34
34
  tracked.to = this.tracking[k].head()
35
35
  tracked.flushes = flushes
36
+ tracked.incremental = !fastForward
36
37
  }
37
38
 
38
39
  return this.byName
package/lib/writers.js CHANGED
@@ -4,6 +4,7 @@ const Triggers = require('./triggers.js')
4
4
  const { LEGACY_OPLOG_VERSION } = require('./constants.js')
5
5
  const { resolveWeight } = require('./witness.js')
6
6
  const { WriterEncryption } = require('autobee-encryption')
7
+ const ReadWriteLock = require('read-write-mutexify')
7
8
 
8
9
  const WRITER_PREFETCH = 10
9
10
 
@@ -25,6 +26,7 @@ class ActiveWriters {
25
26
 
26
27
  this._pendingBuffer = new Map()
27
28
  this._adding = new Map()
29
+ this._lock = new ReadWriteLock()
28
30
 
29
31
  this.localWriter = new Writer(this, auto.system, true, local, b4a.toString(local.key, 'hex'))
30
32
  this.localWriter.attach()
@@ -89,14 +91,27 @@ class ActiveWriters {
89
91
  }
90
92
 
91
93
  async rotateLocalWriter(core) {
92
- this.clearLocal()
93
- await this.localWriter.detachAndClose()
94
+ await this._lock.write.lock()
94
95
 
95
- this.localWriter = new Writer(this, this.auto.system, true, core, b4a.toString(core.key, 'hex'))
96
- this.localWriter.addPending()
97
- this.auto.emit('writer', this.localWriter)
96
+ try {
97
+ this.clearLocal()
98
+ await this.localWriter.detachAndClose()
99
+
100
+ const id = b4a.toString(core.key, 'hex')
101
+
102
+ // a peer may already have announced this core (wakeup hint / link), in which
103
+ // case an external writer tracks it - drop it so only one writer owns the key
104
+ const existing = this.active.get(id)
105
+ if (existing) await existing.detachAndClose()
98
106
 
99
- await this.updateLocalState()
107
+ this.localWriter = new Writer(this, this.auto.system, true, core, id)
108
+ // register in active like the constructor does, so add() finds it
109
+ this.localWriter.attach()
110
+
111
+ await this.updateLocalState()
112
+ } finally {
113
+ this._lock.write.unlock()
114
+ }
100
115
  }
101
116
 
102
117
  clearLocal() {
@@ -178,7 +193,7 @@ class ActiveWriters {
178
193
  return !!this.active.get(id)
179
194
  }
180
195
 
181
- add(key) {
196
+ async add(key) {
182
197
  const id = b4a.toString(key, 'hex')
183
198
 
184
199
  let adding = this._adding.get(id)
@@ -187,44 +202,60 @@ class ActiveWriters {
187
202
  adding = this._add(key, id)
188
203
  this._adding.set(id, adding)
189
204
 
190
- return adding.finally(() => {
205
+ try {
206
+ return await adding
207
+ } finally {
191
208
  this._adding.delete(id)
192
- })
209
+ }
193
210
  }
194
211
 
195
- // TODO: correct fix is writer as ReadyResource
196
212
  async _add(key, id) {
197
- const local = b4a.equals(key, this.auto.local.key)
198
- if (local) await this.updateLocalState()
213
+ await this._lock.read.lock()
199
214
 
200
- let w = this.active.get(id)
201
- if (w) return w
215
+ try {
216
+ if (this.auto._interrupting) return null
217
+
218
+ // judged against the writer we own, not auto.local - that flips before the
219
+ // rotation takes the write lock. an add that beats the rotation onto its
220
+ // key just makes an external writer, which the rotation then evicts
221
+ if (b4a.equals(key, this.localWriter.core.key)) {
222
+ await this.updateLocalState()
223
+ if (this.auto._interrupting) return null
224
+ // never track the local core with a second writer - reattach it if it
225
+ // was detached (i.e. removed earlier and now re-added)
226
+ this.localWriter.attach()
227
+ return this.localWriter
228
+ }
202
229
 
203
- // no new sessions once teardown started
204
- if (this.auto._interrupting) return null
230
+ let w = this.active.get(id)
231
+ if (w) return w
205
232
 
206
- const encryption = this.auto.encryptionKey ? new WriterEncryption(this.auto) : null
233
+ const local = b4a.equals(key, this.auto.local.key)
234
+ const encryption = this.auto.encryptionKey ? new WriterEncryption(this.auto) : null
207
235
 
208
- const core = this.auto.store.get({
209
- active: false,
210
- key,
211
- encryption,
212
- group: local || !this.auto.wakeupCapability ? null : this.auto.wakeupCapability.discoveryKey
213
- })
236
+ const core = this.auto.store.get({
237
+ active: false,
238
+ key,
239
+ encryption,
240
+ group: local || !this.auto.wakeupCapability ? null : this.auto.wakeupCapability.discoveryKey
241
+ })
214
242
 
215
- await core.ready()
216
- await core.setUserData('referrer', this.auto.key)
243
+ await core.ready()
244
+ await core.setUserData('referrer', this.auto.key)
217
245
 
218
- // teardown may have started underneath us
219
- if (this.auto._interrupting) {
220
- await core.close()
221
- return null
222
- }
246
+ // teardown may have started underneath us
247
+ if (this.auto._interrupting) {
248
+ await core.close()
249
+ return null
250
+ }
223
251
 
224
- w = new Writer(this, this.auto.system, false, core, id)
225
- w.attach()
252
+ w = new Writer(this, this.auto.system, false, core, id)
253
+ w.attach()
226
254
 
227
- return w
255
+ return w
256
+ } finally {
257
+ this._lock.read.unlock()
258
+ }
228
259
  }
229
260
 
230
261
  async remove(key) {
@@ -521,15 +552,6 @@ class Writer {
521
552
  node.timestamp = timestamp = Math.max(node.timestamp, timestamp)
522
553
  node.optimistic = optimistic = optimistic || node.optimistic
523
554
 
524
- if (!this.isAdded && !node.optimistic && !genesis) {
525
- return null
526
- }
527
-
528
- // an optimistic writer cannot be genesis
529
- if (node.optimistic && genesis) {
530
- return null
531
- }
532
-
533
555
  if (node.optimistic && !this.isAdded && b.end >= BATCH_OPTIMISTIC_SANITY) {
534
556
  return null
535
557
  }
@@ -547,6 +569,15 @@ class Writer {
547
569
  return null
548
570
  }
549
571
 
572
+ // an optimistic writer cannot be genesis
573
+ if (node.optimistic && genesis) {
574
+ return null
575
+ }
576
+
577
+ if (!this.isAdded && !node.optimistic && !genesis) {
578
+ return null
579
+ }
580
+
550
581
  batch.push(node)
551
582
  if (b.end === 0) return finalizeNodeBatch(batch)
552
583
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autobee",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "description": "Bee based autobase",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Holepunch Inc.",
@@ -31,6 +31,7 @@
31
31
  "hypercore": "^11.33.2",
32
32
  "hypercore-id-encoding": "^1.3.0",
33
33
  "hyperschema": "^1.20.1",
34
+ "read-write-mutexify": "^2.1.0",
34
35
  "ready-guard": "^1.0.0",
35
36
  "ready-resource": "^1.2.0",
36
37
  "resolve-reject-promise": "^1.1.0",