Skip to content

Commit

Permalink
Merge pull request #5488 from Agoric/mhofman/5031-update-lmdb
Browse files Browse the repository at this point in the history
fix(swingset): update lmdb
  • Loading branch information
mergify[bot] authored Jun 6, 2022
2 parents 4c839ab + b14cdab commit 168da21
Show file tree
Hide file tree
Showing 36 changed files with 466 additions and 239 deletions.
2 changes: 1 addition & 1 deletion packages/SwingSet/docs/run-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ while(1) {
processInboundIO();
const policy = make100CrankPolicy();
await controller.run(policy);
commit();
await commit();
processOutboundIO();
}
```
Expand Down
9 changes: 6 additions & 3 deletions packages/SwingSet/misc-tools/db-delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function fail(message, printUsage) {
process.exit(1);
}

function run() {
async function run() {
const argv = process.argv.slice(2);

let range = false;
Expand Down Expand Up @@ -56,7 +56,10 @@ function run() {
} else {
kvStore.delete(key);
}
commit();
await commit();
}

run();
run().then(
() => 0,
e => console.error(`${e}`, e),
);
9 changes: 6 additions & 3 deletions packages/SwingSet/misc-tools/db-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function fail(message, printUsage) {
process.exit(1);
}

function run() {
async function run() {
const argv = process.argv.slice(2);

if (argv.length !== 3) {
Expand All @@ -36,7 +36,10 @@ function run() {
const { kvStore, commit } = openSwingStore(stateDBDir);

kvStore.set(key, value);
commit();
await commit();
}

run();
run().then(
() => 0,
e => console.error(`${e}`, e),
);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// XXX this is wrong; it needs to use the swingstore instead of opening the LMDB
// file directly, then use stream store reads to get the transcript entries.
import lmdb from 'node-lmdb';
import lmdb from 'lmdb';
import process from 'process';
import fs from 'fs';

Expand Down
6 changes: 3 additions & 3 deletions packages/SwingSet/misc-tools/rekernelize.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node

import '@endo/init/pre-bundle-source.js';
import 'node-lmdb';
import 'lmdb';
import '@endo/init';

import fs from 'fs';
Expand Down Expand Up @@ -65,8 +65,8 @@ async function main() {
);

kvStore.set('kernelBundle', JSON.stringify(kernelBundle));
swingStore.commit();
swingStore.close();
await swingStore.commit();
await swingStore.close();
}

main().then(
Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/misc-tools/replace-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async function run() {
const newBundleStr = JSON.stringify(bundle);
log(`new bundle is ${newBundleStr.length} bytes`);
kvStore.set(bundleName, newBundleStr);
commit();
await commit();
log(`bundle ${bundleName} replaced`);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"@endo/zip": "^0.2.25",
"anylogger": "^0.21.0",
"import-meta-resolve": "^1.1.1",
"node-lmdb": "^0.9.5",
"lmdb": "^2.4.5",
"semver": "^6.3.0"
},
"peerDependencies": {
Expand Down
31 changes: 23 additions & 8 deletions packages/SwingSet/src/kernel/kernelSyscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function makeKernelSyscallHandler(tools) {
deviceHooks,
} = tools;

/** @type {{kvStore: KVStore}} */
const { kvStore } = kernelKeeper;

function send(target, msg) {
Expand Down Expand Up @@ -46,13 +47,25 @@ export function makeKernelSyscallHandler(tools) {
let workingPriorKey;
let workingLowerBound;
let workingUpperBound;
/** @type {IterableIterator<string> | undefined} */
let workingKeyIterator;

function clearVatStoreIteration() {
workingPriorKey = undefined;
workingLowerBound = undefined;
workingUpperBound = undefined;
workingKeyIterator = undefined;
/** @param {boolean} [done] */
function clearVatStoreIteration(done = false) {
try {
if (
!done &&
workingKeyIterator &&
typeof workingKeyIterator.return === 'function'
) {
workingKeyIterator.return();
}
} finally {
workingKeyIterator = undefined;
workingPriorKey = undefined;
workingLowerBound = undefined;
workingUpperBound = undefined;
}
}

/**
Expand Down Expand Up @@ -80,8 +93,8 @@ export function makeKernelSyscallHandler(tools) {
const actualKey = vatstoreKeyKey(vatID, key);
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallVatstoreSet');
kvStore.set(actualKey, value);
clearVatStoreIteration();
kvStore.set(actualKey, value);
return OKNULL;
}

Expand Down Expand Up @@ -160,6 +173,7 @@ export function makeKernelSyscallHandler(tools) {
}
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallVatstoreGetAfter');
/** @type {IteratorResult<string>} */
let nextIter;
// Note that the working key iterator will be invalidated if the parameters
// to `vatstoreGetAfter` don't correspond to the working key iterator's
Expand All @@ -180,6 +194,7 @@ export function makeKernelSyscallHandler(tools) {
) {
nextIter = workingKeyIterator.next();
} else {
clearVatStoreIteration();
let startKey;
if (priorKey === '') {
startKey = actualLowerBound;
Expand All @@ -198,7 +213,7 @@ export function makeKernelSyscallHandler(tools) {
}
}
if (nextIter.done) {
clearVatStoreIteration();
clearVatStoreIteration(true);
return harden(['ok', [undefined, undefined]]);
} else {
const nextKey = nextIter.value;
Expand All @@ -220,8 +235,8 @@ export function makeKernelSyscallHandler(tools) {
const actualKey = vatstoreKeyKey(vatID, key);
kernelKeeper.incStat('syscalls');
kernelKeeper.incStat('syscallVatstoreDelete');
kvStore.delete(actualKey);
clearVatStoreIteration();
kvStore.delete(actualKey);
return OKNULL;
}

Expand Down
94 changes: 70 additions & 24 deletions packages/SwingSet/src/kernel/state/storageWrapper.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { assert } from '@agoric/assert';
// @ts-check

import { assert, details as X } from '@agoric/assert';
import { insistStorageAPI } from '../../lib/storageAPI.js';

// We wrap a provided object implementing StorageAPI methods { has, getKeys,
Expand All @@ -24,30 +26,74 @@ import { insistStorageAPI } from '../../lib/storageAPI.js';
* @yields any
*/
function* mergeUtf16SortedIterators(it1, it2) {
let v1 = it1.next();
let v2 = it2.next();
while (!v1.done && !v2.done) {
if (v1.value < v2.value) {
const result = v1.value;
v1 = it1.next();
yield result;
} else if (v1.value === v2.value) {
const result = v1.value;
v1 = it1.next();
v2 = it2.next();
yield result;
} else {
const result = v2.value;
v2 = it2.next();
/** @type {IteratorResult<any> | null} */
let v1 = null;
/** @type {IteratorResult<any> | null} */
let v2 = null;
/** @type {IteratorResult<any> | null} */
let vrest = null;
/** @type {Iterator<any> | null} */
let itrest = null;

try {
v1 = it1.next();
v2 = it2.next();
while (!v1.done && !v2.done) {
if (v1.value < v2.value) {
const result = v1.value;
v1 = it1.next();
yield result;
} else if (v1.value === v2.value) {
const result = v1.value;
v1 = it1.next();
v2 = it2.next();
yield result;
} else {
const result = v2.value;
v2 = it2.next();
yield result;
}
}

itrest = v1.done ? it2 : it1;
vrest = v1.done ? v2 : v1;
v1 = null;
v2 = null;

while (!vrest.done) {
const result = vrest.value;
vrest = itrest.next();
yield result;
}
}
const itrest = v1.done ? it2 : it1;
let v = v1.done ? v2 : v1;
while (!v.done) {
const result = v.value;
v = itrest.next();
yield result;
} finally {
const errors = [];
try {
if (vrest && !vrest.done && itrest && itrest.return) {
itrest.return();
}
} catch (e) {
errors.push(e);
}
try {
if (v1 && !v1.done && it1.return) {
it1.return();
}
} catch (e) {
errors.push(e);
}
try {
if (v2 && !v2.done && it2.return) {
it2.return();
}
} catch (e) {
errors.push(e);
}
if (errors.length) {
const err = assert.error(X`Merged iterator failed to close cleanly`);
for (const e of errors) {
assert.note(err, X`Caused by ${e}`);
}
}
}
}

Expand All @@ -56,7 +102,7 @@ function* mergeUtf16SortedIterators(it1, it2) {
* that buffers any mutations until told to commit them.
*
* @param {KVStore} kvStore The StorageAPI object that this crank buffer will be based on.
* @param {CreateSHA256} createSHA256
* @param {import('../../lib-nodejs/hasher.js').CreateSHA256} createSHA256
* @param { (key: string) => 'consensus' | 'local' | 'invalid' } getKeyType
* @returns {*} an object {
* crankBuffer, // crank buffer as described, wrapping `kvStore`
Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/src/lib-nodejs/hasher.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { assert } from '@agoric/assert';
import { createHash } from 'crypto';

/**
* @typedef { (initial: string?) => {
* @typedef { (initial?: string) => {
* add: (more: string) => void,
* finish: () => string,
* }
Expand Down
7 changes: 5 additions & 2 deletions packages/SwingSet/src/liveslots/collectionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import { Far, passStyleOf } from '@endo/marshal';
import { decodeToJustin } from '@endo/marshal/src/marshal-justin.js';
import { parseVatSlot } from '../lib/parseVatSlots.js';

// The maximum length of an LMDB key is 254 characters, which puts an upper
// bound on the post-encoding size of keys than can be used to index entries in
// The maximum length of an LMDB key used to be 511 bytes which corresponded to
// 254 UTF-16 code units when using JS strings directly as keys. While we now
// have larger key sizes and use a different unicode encoding, the prior
// collections key constraints remain the same. They put an upper bound on the
// post-encoding (stringified) size of keys than can be used to index entries in
// collections. In addition to the encoding of the collection entry key, the
// storage key will also be prefixed with additional indexing information that
// includes the collection ID (an integer that will grow over time as more
Expand Down
17 changes: 11 additions & 6 deletions packages/SwingSet/test/test-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function checkState(t, getState, expected) {
t.deepEqual(got.sort(compareStrings), expected.sort(compareStrings));
}

function testStorage(t, s, getState, commit) {
async function testStorage(t, s, getState, commit) {
t.falsy(s.has('missing'));
t.is(s.get('missing'), undefined);

Expand All @@ -60,7 +60,7 @@ function testStorage(t, s, getState, commit) {

if (commit) {
checkState(t, getState, []);
commit();
await commit();
}
checkState(t, getState, [
['foo', 'f'],
Expand All @@ -69,18 +69,23 @@ function testStorage(t, s, getState, commit) {
]);
}

test('storageInMemory', t => {
test('storageInMemory', async t => {
const store = initSwingStore(null);
testStorage(t, store.kvStore, () => getAllState(store).kvStuff, null);
await testStorage(t, store.kvStore, () => getAllState(store).kvStuff, null);
});

test('crankBuffer fulfills storage API', t => {
test('crankBuffer fulfills storage API', async t => {
const store = initSwingStore(null);
const { crankBuffer, commitCrank } = buildCrankBuffer(
store.kvStore,
createSHA256,
);
testStorage(t, crankBuffer, () => getAllState(store).kvStuff, commitCrank);
await testStorage(
t,
crankBuffer,
() => getAllState(store).kvStuff,
commitCrank,
);
});

test('crankBuffer handles key iteration properly even with intra-crank data changes', t => {
Expand Down
7 changes: 6 additions & 1 deletion packages/SwingSet/test/vat-warehouse/test-warehouse.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// @ts-check

import '@endo/init/pre-bundle-source.js';

// import lmdb early to work around SES incompatibility
import 'lmdb';

// eslint-disable-next-line import/order
import { test } from '../../tools/prepare-test-env-ava.js';
import fs from 'fs';
Expand Down Expand Up @@ -124,7 +129,7 @@ test('snapshot after deliveries', async t => {
t.teardown(c.shutdown);

await runSteps(c, t);
commit();
await commit();

const { inUse, onDisk, extra } = unusedSnapshotsOnDisk(
kvStore,
Expand Down
3 changes: 2 additions & 1 deletion packages/access-token/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
},
"dependencies": {
"@agoric/assert": "^0.4.0",
"n-readlines": "^1.0.0"
"n-readlines": "^1.0.0",
"tmp": "^0.2.1"
},
"devDependencies": {
"ava": "^3.12.1",
Expand Down
Loading

0 comments on commit 168da21

Please sign in to comment.