Skip to content

Commit

Permalink
cache the merkle batch in batches
Browse files Browse the repository at this point in the history
  • Loading branch information
mafintosh committed May 6, 2024
1 parent cd8e5e2 commit 2ae0d7f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 10 deletions.
33 changes: 25 additions & 8 deletions lib/batch.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module.exports = class HypercoreBatch extends EventEmitter {
this._sessionLength = 0
this._sessionByteLength = 0
this._sessionBatch = null
this._cachedBatch = null
this._flushing = null
this._clear = clear

Expand Down Expand Up @@ -207,20 +208,32 @@ module.exports = class HypercoreBatch extends EventEmitter {
return this.session.core.tree.restoreBatch(length)
}

createTreeBatch (length, blocks = []) {
_catchupBatch (clone) {
if (this._cachedBatch === null) this._cachedBatch = this._sessionBatch.clone()

if (this.length > this._cachedBatch.length) {
const offset = this._cachedBatch.length - this._sessionBatch.length

for (let i = offset; i < this._appendsActual.length; i++) {
this._cachedBatch.append(this._appendsActual[i])
}
}

return clone ? this._cachedBatch.clone() : this._cachedBatch
}

createTreeBatch (length, opts = {}) {
if (Array.isArray(opts)) opts = { blocks: opts }

const { blocks = [], clone = true } = opts
if (!length && length !== 0) length = this.length + blocks.length

const maxLength = this.length + blocks.length
const b = this._sessionBatch.clone()
const b = this._catchupBatch(clone || (blocks.length > 0 || length !== this.length))
const len = Math.min(length, this.length)

if (len < this._sessionLength || length > maxLength) return null

for (let i = 0; i < len - this._sessionLength; i++) {
b.append(this._appendsActual[i])
}

if (len < this.length) return b
if (len < b.length) b.checkout(len, this._sessionBatch.roots)

for (let i = 0; i < length - len; i++) {
b.append(this._appendsActual === this._appends ? blocks[i] : this._encrypt(b.length, blocks[i]))
Expand All @@ -239,6 +252,8 @@ module.exports = class HypercoreBatch extends EventEmitter {
if (typeof opts === 'number') opts = { fork: opts }
const { fork = this.fork + 1, force = false } = opts

this._cachedBatch = null

const length = this._sessionLength
if (newLength < length) {
if (!force) throw new Error('Cannot truncate committed blocks')
Expand Down Expand Up @@ -380,6 +395,8 @@ module.exports = class HypercoreBatch extends EventEmitter {
this._sessionByteLength = info.byteLength
this._sessionBatch = newBatch

if (this._cachedBatch !== null) this._cachedBatch.prune(info.length)

const same = this._appends === this._appendsActual

this._appends = this._appends.slice(flushingLength)
Expand Down
12 changes: 10 additions & 2 deletions lib/merkle-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,19 @@ class MerkleTreeBatch {
this.upgraded = false
}

checkout (length) {
checkout (length, additionalRoots) {
const roots = []
let r = 0

const head = 2 * length - 2
const gaps = new Set()
const all = new Map()

// additional roots is so the original roots can be passed (we mutate the array in appendRoot)
if (additionalRoots) {
for (const node of additionalRoots) all.set(node.index, node)
}

for (const node of this.nodes) all.set(node.index, node)

for (const index of flat.fullRoots(head + 2)) {
Expand All @@ -74,7 +80,9 @@ class MerkleTreeBatch {
roots.push(this.roots[r++])
continue
}
roots.push(all.get(index))
const node = all.get(index)
if (!node) throw new BAD_ARGUMENT('root missing for given length')
roots.push(node)
}

this.roots = roots
Expand Down

0 comments on commit 2ae0d7f

Please sign in to comment.