Skip to content

Commit

Permalink
Copy node-cache entries to reduce mem usage (#521)
Browse files Browse the repository at this point in the history
* Copy node-cache entries to reduce mem usage

* undo unneeded formatting change

* Close tree at end of test

* Only copy hash

* Rm unneeded variables

* Add clarifying comment

* One-line comment
  • Loading branch information
HDegroote authored May 27, 2024
1 parent dc60658 commit f51db0d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
11 changes: 10 additions & 1 deletion lib/merkle-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,16 @@ function getStoredNode (storage, index, cache, error) {
}

const node = { index, size, hash }
if (cache !== null) cache.set(index, node)

if (cache !== null) {
// Copy hash to a new buffer to avoid blocking gc of its original slab
const hashCopy = b4a.alloc(hash.byteLength)
hashCopy.set(hash)
node.hash = hashCopy

cache.set(index, node)
}

resolve(node)
})
})
Expand Down
25 changes: 25 additions & 0 deletions test/merkle-tree.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const path = require('path')
const test = require('brittle')
const RAM = require('random-access-memory')
const b4a = require('b4a')
const RandomAccessFile = require('random-access-file')
const createTempDir = require('test-tmp')
const Tree = require('../lib/merkle-tree')

test('nodes', async function (t) {
Expand Down Expand Up @@ -599,6 +602,28 @@ test('checkout nodes in a batch', async t => {
t.alike(nodes, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 28])
})

test('buffer of cached nodes is copied to small slab', async function (t) {
// RAM does not use slab-allocated memory,
// so we need to us random-access-file to reproduce this issue
const dir = await createTempDir(t)
const storage = new RandomAccessFile(path.join(dir, 'tree'))

const tree = await Tree.open(storage)

const b = tree.batch()
b.append(b4a.from('tree-entry'))
b.commit()

// Note: if the batch is committed but not yet flushed,
// it still uses the original slab-allocated memory
await tree.flush()

const node = await tree.get(0)
t.is(node.hash.buffer.byteLength, 32, 'created a new memory slab of the correct (small) size')

await tree.close()
})

async function audit (tree) {
const flat = require('flat-tree')
const expectedRoots = flat.fullRoots(tree.length * 2)
Expand Down

0 comments on commit f51db0d

Please sign in to comment.