From afa182609ab881ed5dfab291b15e70f2fa661005 Mon Sep 17 00:00:00 2001 From: Christophe Diederichs Date: Wed, 2 Oct 2024 17:25:57 +0100 Subject: [PATCH 1/2] commit acquires lock directly --- lib/core.js | 73 +++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/lib/core.js b/lib/core.js index 4790f3cd..f8639958 100644 --- a/lib/core.js +++ b/lib/core.js @@ -389,32 +389,6 @@ class SessionState { this.mutex.unlock() } } - - async upgrade (start, end, batch, values, keyPair) { - await this.mutex.lock() - - const update = this.createUpdate() - - try { - // upsert compat manifest - if (this.core.verifier === null && keyPair) this.core._setManifest(update, null, keyPair) - - this.blocks.putBatch(update.batch, start, values) - - update.bitfield.setRange(start, end, true) - update.flushTreeBatch(batch) - - const bitfield = { start, length: end - start, drop: false } - const status = batch.upgraded ? 0b0001 : 0 - - update.coreUpdate({ status, bitfield, value: null, from: null }) - - await this.flushUpdate(update) - } finally { - this._clearActiveBatch() - this.mutex.unlock() - } - } } module.exports = class Core { @@ -863,24 +837,47 @@ module.exports = class Core { } } - const promises = [] + await this.state.mutex.lock() - const reader = state.storage.createReadBatch() - for (let i = treeLength; i < length; i++) promises.push(reader.getBlock(i)) - reader.tryFlush() + const update = this.state.createUpdate() - const values = await Promise.all(promises) + try { + const promises = [] - const batch = await this.tree.reconcile(state.tree, length, treeLength) - if (batch.upgraded) batch.signature = signature || this.verifier.sign(batch, keyPair) + const reader = state.storage.createReadBatch() + for (let i = treeLength; i < length; i++) promises.push(reader.getBlock(i)) + reader.tryFlush() - await this.state.upgrade(treeLength, length, batch, values, keyPair) + const values = await Promise.all(promises) - state.treeLength = batch.length + const batch = await this.tree.reconcile(state.tree, length, treeLength) + if (batch.upgraded) batch.signature = signature || this.verifier.sign(batch, keyPair) - return { - length: batch.length, - byteLength: batch.byteLength + // upsert compat manifest + if (this.verifier === null && keyPair) this._setManifest(update, null, keyPair) + + this.state.blocks.putBatch(update.batch, treeLength, values) + + update.bitfield.setRange(treeLength, length, true) + update.flushTreeBatch(batch) + + const bitfield = { start: treeLength, length: length - treeLength, drop: false } + const status = batch.upgraded ? 0b0001 : 0 + + update.coreUpdate({ status, bitfield, value: null, from: null }) + + await this.state.flushUpdate(update) + + state.treeLength = batch.length + + return { + length: batch.length, + byteLength: batch.byteLength + } + } finally { + this.state._clearActiveBatch() + this.updating = false + this.state.mutex.unlock() } } From 2f590a9c791e7887dcddadeec81348e8b969e1fb Mon Sep 17 00:00:00 2001 From: Christophe Diederichs Date: Mon, 7 Oct 2024 16:44:00 +0100 Subject: [PATCH 2/2] check conditions after acquiring lock --- lib/core.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/core.js b/lib/core.js index f8639958..e2634e63 100644 --- a/lib/core.js +++ b/lib/core.js @@ -824,24 +824,24 @@ module.exports = class Core { } async commit (state, { signature, keyPair = this.header.keyPair, length = state.tree.length, treeLength = state.treeLength } = {}) { - if (this.tree.fork !== state.tree.fork) return null - - if (this.tree.length > state.tree.length) return null // TODO: partial commit in the future if possible - - if (this.tree.length > treeLength) { - for (const root of this.tree.roots) { - const batchRoot = await state.tree.get(root.index) - if (batchRoot.size !== root.size || !b4a.equals(batchRoot.hash, root.hash)) { - return null - } - } - } - await this.state.mutex.lock() const update = this.state.createUpdate() try { + if (this.tree.fork !== state.tree.fork) return null + + if (this.tree.length > state.tree.length) return null // TODO: partial commit in the future if possible + + if (this.tree.length > treeLength) { + for (const root of this.tree.roots) { + const batchRoot = await state.tree.get(root.index) + if (batchRoot.size !== root.size || !b4a.equals(batchRoot.hash, root.hash)) { + return null + } + } + } + const promises = [] const reader = state.storage.createReadBatch()