diff --git a/packages/swing-store/src/swingStore.js b/packages/swing-store/src/swingStore.js index 368fb1c5a548..f87ad04a917b 100644 --- a/packages/swing-store/src/swingStore.js +++ b/packages/swing-store/src/swingStore.js @@ -370,6 +370,10 @@ export function makeSwingStore(dirPath, forceReset, options = {}) { inCrank || Fail`establishCrankSavepoint outside of crank`; const savepointOrdinal = savepoints.length; savepoints.push(savepoint); + // We must be in a transaction when creating the savepoint or releasing it + // later will cause an autocommit. + // See https://github.com/Agoric/agoric-sdk/issues/8423 + ensureTxn(); const sql = db.prepare(`SAVEPOINT t${savepointOrdinal}`); sql.run(); } diff --git a/packages/swing-store/test/test-state.js b/packages/swing-store/test/test-state.js index 02b7f73e8d70..22c857a88b8b 100644 --- a/packages/swing-store/test/test-state.js +++ b/packages/swing-store/test/test-state.js @@ -316,3 +316,37 @@ test('close will abort transaction', async t => { t.is(kvStore.get('key2'), undefined); t.falsy(kvStore.has('key2')); }); + +test('savepoints', async t => { + const [dbDir, cleanup] = await tmpDir('testdb'); + t.teardown(cleanup); + const ss1 = initSwingStore(dbDir); + ss1.kernelStorage.startCrank(); + ss1.kernelStorage.kvStore.set('key', 'value1'); + ss1.kernelStorage.establishCrankSavepoint('sp1'); + ss1.kernelStorage.kvStore.set('key', 'value2'); + ss1.kernelStorage.establishCrankSavepoint('sp2'); + ss1.kernelStorage.kvStore.set('key', 'value3'); + ss1.kernelStorage.rollbackCrank('sp1'); + ss1.kernelStorage.endCrank(); + await ss1.hostStorage.commit(); + await ss1.hostStorage.close(); + + const ss2 = openSwingStore(dbDir); + t.is(ss2.kernelStorage.kvStore.get('key'), 'value1'); +}); + +test('savepoints do not automatically commit', async t => { + const [dbDir, cleanup] = await tmpDir('testdb'); + t.teardown(cleanup); + const ss1 = initSwingStore(dbDir); + ss1.kernelStorage.startCrank(); + ss1.kernelStorage.establishCrankSavepoint('sp1'); + ss1.kernelStorage.kvStore.set('key', 'value1'); + // #8423 meant this .endCrank() accidentally did a commit() + ss1.kernelStorage.endCrank(); + await ss1.hostStorage.close(); + + const ss2 = openSwingStore(dbDir); + t.false(ss2.kernelStorage.kvStore.has('key')); +});