From 9cb0409cfdb0d841a65129ac82e730be7e6d6efe Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 6 Sep 2020 16:26:27 +0530 Subject: make db file writes atomic --- packages/taler-wallet-core/src/headless/helpers.ts | 29 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/taler-wallet-core/src/headless/helpers.ts b/packages/taler-wallet-core/src/headless/helpers.ts index 1141ad25e..09f0ca906 100644 --- a/packages/taler-wallet-core/src/headless/helpers.ts +++ b/packages/taler-wallet-core/src/headless/helpers.ts @@ -58,6 +58,20 @@ export interface DefaultNodeWalletArgs { httpLib?: HttpRequestLibrary; } +/** + * Generate a random alphanumeric ID. Does *not* use cryptographically + * secure randomness. + */ +function makeId(length: number): string { + let result = ""; + const characters = + "abcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)); + } + return result; +} + /** * Get a wallet instance with default settings for node. */ @@ -77,7 +91,13 @@ export async function getDefaultNodeWallet( const dbContent = JSON.parse(dbContentStr); myBackend.importDump(dbContent); } catch (e) { - logger.warn("could not read wallet file"); + const code: string = e.code; + if (code === "ENOENT") { + logger.trace("wallet file doesn't exist yet"); + } else { + logger.error("could not open wallet database file"); + throw e; + } } myBackend.afterCommitCallback = async () => { @@ -85,10 +105,13 @@ export async function getDefaultNodeWallet( if (args.persistentStoragePath === undefined) { return; } + const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`; const dbContent = myBackend.exportDump(); - fs.writeFileSync(storagePath, JSON.stringify(dbContent, undefined, 2), { + fs.writeFileSync(tmpPath, JSON.stringify(dbContent, undefined, 2), { encoding: "utf-8", }); + // Atomically move the temporary file onto the DB path. + fs.renameSync(tmpPath, args.persistentStoragePath); }; } @@ -106,7 +129,7 @@ export async function getDefaultNodeWallet( const myVersionChange = (): Promise => { logger.error("version change requested, should not happen"); - throw Error(); + throw Error("BUG: wallet DB version change event can't happen with memory IDB"); }; shimIndexedDB(myBridgeIdbFactory); -- cgit v1.2.3