From 9d2dd3f9966940961a4c21351d256fa3615715d7 Mon Sep 17 00:00:00 2001 From: Mathieu Hofman Date: Wed, 4 Oct 2023 00:32:57 +0000 Subject: [PATCH 1/2] fix(swing-store): ensure crank savepoint is wrapped in transaction --- packages/swing-store/src/swingStore.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/swing-store/src/swingStore.js b/packages/swing-store/src/swingStore.js index 81bb70c4de5..d0f9a68b8bb 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(); } From cc742b8a4344df289abc622cfe42505c5a7bbcf5 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Tue, 3 Oct 2023 18:43:57 -0700 Subject: [PATCH 2/2] test: add test of savepoints, including no automatic transactions The second tests fails if I comment out the #8423 fix, as expected. --- packages/swing-store/test/test-state.js | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/swing-store/test/test-state.js b/packages/swing-store/test/test-state.js index d9f264270ab..11b3c7d8b76 100644 --- a/packages/swing-store/test/test-state.js +++ b/packages/swing-store/test/test-state.js @@ -314,3 +314,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')); +});