hypercore 10.24.5 → 10.24.6

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
@@ -958,12 +958,8 @@ module.exports = class Hypercore extends EventEmitter {
958
958
  }
959
959
 
960
960
  async append (blocks, opts = {}) {
961
- if (this._batch && this !== this._batch.session) throw BATCH_UNFLUSHED()
962
-
963
- // if a batched append, run unlocked as it already locked...
964
- const lock = !this._batch
965
-
966
961
  if (this.opened === false) await this.opening
962
+ if (this._batch) throw BATCH_UNFLUSHED()
967
963
 
968
964
  const { keyPair = this.keyPair, signature = null } = opts
969
965
  const writable = !this._readonly && !!(signature || (keyPair && keyPair.secretKey))
@@ -982,7 +978,7 @@ module.exports = class Hypercore extends EventEmitter {
982
978
  }
983
979
  }
984
980
 
985
- return this.core.append(buffers, { lock, keyPair, signature, preappend })
981
+ return this.core.append(buffers, { keyPair, signature, preappend })
986
982
  }
987
983
 
988
984
  async treeHash (length) {
package/lib/batch.js CHANGED
@@ -1,7 +1,6 @@
1
1
  const { BLOCK_NOT_AVAILABLE, SESSION_CLOSED } = require('hypercore-errors')
2
2
  const EventEmitter = require('events')
3
3
  const c = require('compact-encoding')
4
- const b4a = require('b4a')
5
4
 
6
5
  module.exports = class HypercoreBatch extends EventEmitter {
7
6
  constructor (session, autoClose) {
@@ -76,7 +75,6 @@ module.exports = class HypercoreBatch extends EventEmitter {
76
75
  async update (opts) {
77
76
  if (this.opened === false) await this.ready()
78
77
  await this.session.update(opts)
79
- await this._catchup()
80
78
  }
81
79
 
82
80
  setUserData (key, value, opts) {
@@ -253,64 +251,26 @@ module.exports = class HypercoreBatch extends EventEmitter {
253
251
  return flushed
254
252
  }
255
253
 
256
- async _catchup () {
257
- if (this.core.tree.length === this._sessionLength) return true
258
-
259
- const batchLength = this._sessionLength + this._appends.length
260
-
261
- if (this.core.tree.length > batchLength) return false
262
-
263
- const b = this.createTreeBatch()
264
-
265
- for (const root of this.core.tree.roots) {
266
- const batchRoot = await b.get(root.index)
267
-
268
- if (batchRoot === null) continue // in the shared tree
269
- if (batchRoot.size !== root.size || !b4a.equals(batchRoot.hash, root.hash)) {
270
- // TODO: type this error
271
- throw new Error('Batch is uncommitable due to a conflict at ' + root.index)
272
- }
273
- }
274
-
275
- const offset = this.core.tree.length - this._sessionLength
276
- for (let i = 0; i < offset; i++) this._byteLength -= this._appends[i].byteLength
277
-
278
- await this.core.insertValuesUnsafe(this._appends.slice(0, offset), this._sessionLength, this._sessionByteLength, b.nodes)
279
-
280
- this._sessionLength = this.session.length
281
- this._sessionByteLength = this.session.byteLength
282
- this._sessionBatch = this.session.createTreeBatch()
283
- this._appends = this._appends.slice(offset)
284
-
285
- return true
286
- }
287
-
288
254
  async _flush (length, keyPair, signature) { // TODO: make this safe to interact with a parallel truncate...
289
- if (this._appends.length === 0) return true
290
- if (!(await this._catchup())) return false
255
+ const flushingLength = Math.min(length - this._sessionLength, this._appends.length)
256
+ if (flushingLength <= 0) return true
291
257
 
292
- await this.core._mutex.lock()
258
+ const batch = this.createTreeBatch(this._sessionLength + flushingLength)
259
+ if (batch === null) return false
293
260
 
294
- try {
295
- const flushingLength = Math.min(length - this._sessionLength, this._appends.length)
296
- if (flushingLength <= 0) return true
261
+ const info = await this.core.insertBatch(batch, this._appends, { keyPair, signature })
262
+ if (info === null) return false
297
263
 
298
- const blocks = flushingLength < this._appends.length ? this._appends.slice(0, flushingLength) : this._appends
264
+ const delta = info.byteLength - this._sessionByteLength
299
265
 
300
- const info = await this.session.append(blocks, { keyPair, signature })
301
- const delta = info.byteLength - this._sessionByteLength
302
-
303
- this._sessionLength = info.length
304
- this._sessionByteLength = info.byteLength
305
- this._sessionBatch = this.session.createTreeBatch()
266
+ this._sessionLength = info.length
267
+ this._sessionByteLength = info.byteLength
268
+ this._sessionBatch = this.session.createTreeBatch()
306
269
 
307
- this._appends = this._appends.slice(flushingLength)
308
- this._byteLength -= delta
270
+ this._appends = this._appends.slice(flushingLength)
271
+ this._byteLength -= delta
309
272
 
310
- this.emit('flush')
311
- } finally {
312
- this.core._mutex.unlock()
313
- }
273
+ this.emit('flush')
314
274
 
315
275
  return true
316
276
  }
package/lib/core.js CHANGED
@@ -432,40 +432,71 @@ module.exports = class Core {
432
432
  })
433
433
  }
434
434
 
435
- // assumes mutex is already acquried
436
- async insertValuesUnsafe (values, offset, byteOffset, treeNodes) {
437
- if (!values.length) return
435
+ async insertBatch (batch, values, { signature, keyPair = this.header.keyPair } = {}) {
436
+ await this._mutex.lock()
438
437
 
439
- const bitfield = {
440
- drop: false,
441
- start: offset,
442
- end: offset + values.length
443
- }
438
+ try {
439
+ // upsert compat manifest
440
+ if (this.verifier === null && keyPair) this.setManifest(null, keyPair)
444
441
 
445
- await this.blocks.putBatch(offset, values, byteOffset)
446
- await this.oplog.append({
447
- userData: null,
448
- treeNodes,
449
- treeUpgrade: null,
450
- bitfield
451
- }, false)
442
+ if (this.tree.fork !== batch.fork) return null
452
443
 
453
- this.bitfield.setRange(bitfield.start, values.length, true)
454
- for (const node of treeNodes) this.tree.unflushed.set(node.index, node)
444
+ if (this.tree.length > batch.treeLength) {
445
+ if (this.tree.length > batch.length) return null // TODO: partial commit in the future if possible
455
446
 
456
- const status = updateContig(this.header, bitfield, this.bitfield)
457
- this.onupdate(status, bitfield, null, null)
447
+ for (const root of this.tree.roots) {
448
+ const batchRoot = await batch.get(root.index)
449
+ if (batchRoot.size !== root.size || !b4a.equals(batchRoot.hash, root.hash)) {
450
+ return null
451
+ }
452
+ }
453
+ }
458
454
 
459
- if (this._shouldFlush()) await this._flushOplog()
460
- }
455
+ const offset = batch.treeLength
456
+ const adding = batch.length - batch.treeLength
461
457
 
462
- async append (values, { lock, signature, keyPair = this.header.keyPair, preappend } = {}) {
463
- if (lock) await this._mutex.lock()
458
+ batch.upgraded = batch.length > this.tree.length
459
+ batch.treeLength = this.tree.length
460
+ if (batch.upgraded) batch.signature = signature || this.verifier.sign(batch, keyPair)
464
461
 
465
- // upsert compat manifest
466
- if (this.verifier === null && keyPair) this.setManifest(null, keyPair)
462
+ let byteOffset = batch.byteLength
463
+ for (let i = 0; i < adding; i++) byteOffset -= values[i].byteLength
464
+
465
+ const entry = {
466
+ userData: null,
467
+ treeNodes: batch.nodes,
468
+ treeUpgrade: batch.upgraded ? batch : null,
469
+ bitfield: {
470
+ drop: false,
471
+ start: offset,
472
+ length: adding
473
+ }
474
+ }
475
+
476
+ await this.blocks.putBatch(offset, adding > values.length ? values.slice(0, adding) : values, byteOffset)
477
+ await this.oplog.append([entry], false)
478
+
479
+ this.bitfield.setRange(entry.bitfield.start, entry.bitfield.length, true)
480
+ batch.commit()
481
+
482
+ const status = (batch.upgraded ? 0b0001 : 0) | updateContig(this.header, entry.bitfield, this.bitfield)
483
+ this.onupdate(status, entry.bitfield, null, null)
484
+
485
+ if (this._shouldFlush()) await this._flushOplog()
486
+ } finally {
487
+ this._mutex.unlock()
488
+ }
489
+
490
+ return { length: batch.length, byteLength: batch.byteLength }
491
+ }
492
+
493
+ async append (values, { signature, keyPair = this.header.keyPair, preappend } = {}) {
494
+ await this._mutex.lock()
467
495
 
468
496
  try {
497
+ // upsert compat manifest
498
+ if (this.verifier === null && keyPair) this.setManifest(null, keyPair)
499
+
469
500
  if (preappend) await preappend(values)
470
501
 
471
502
  if (!values.length) {
@@ -506,7 +537,7 @@ module.exports = class Core {
506
537
 
507
538
  return { length: batch.length, byteLength }
508
539
  } finally {
509
- if (lock) this._mutex.unlock()
540
+ this._mutex.unlock()
510
541
  }
511
542
  }
512
543
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.24.5",
3
+ "version": "10.24.6",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {