From 42f2943144c0c7085e73f6ec7f97d0e2c6ae74ef Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:58:50 -0800 Subject: [PATCH] feat(datastore-fs): fast-write-atomic -> steno --- packages/datastore-fs/package.json | 2 +- packages/datastore-fs/src/index.ts | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/datastore-fs/package.json b/packages/datastore-fs/package.json index 2aa68b69..7ae47820 100644 --- a/packages/datastore-fs/package.json +++ b/packages/datastore-fs/package.json @@ -136,8 +136,8 @@ "dep-check": "aegir dep-check" }, "dependencies": { + "@sgtpooki/steno-patched": "^3.1.1", "datastore-core": "^9.0.0", - "fast-write-atomic": "^0.2.0", "interface-datastore": "^8.0.0", "interface-store": "^5.0.0", "it-glob": "^2.0.1", diff --git a/packages/datastore-fs/src/index.ts b/packages/datastore-fs/src/index.ts index bd19b657..302061b5 100644 --- a/packages/datastore-fs/src/index.ts +++ b/packages/datastore-fs/src/index.ts @@ -14,12 +14,10 @@ import fs from 'node:fs/promises' import path from 'node:path' -import { promisify } from 'util' +import { Writer as StenoWriter } from '@sgtpooki/steno-patched' import { BaseDatastore, Errors } from 'datastore-core' -// @ts-expect-error no types -import fwa from 'fast-write-atomic' import { Key, type KeyQuery, type Pair, type Query } from 'interface-datastore' @@ -28,21 +26,20 @@ import map from 'it-map' import parallel from 'it-parallel-batch' import type { AwaitIterable } from 'interface-store' -const writeAtomic = promisify(fwa) - /** * Write a file atomically */ -async function writeFile (path: string, contents: Uint8Array): Promise { +async function writeFile (writer: StenoWriter, file: string, contents: Uint8Array): Promise { try { - await writeAtomic(path, contents) + await writer.write(contents) } catch (err: any) { if (err.code === 'EPERM' && err.syscall === 'rename') { - // fast-write-atomic writes a file to a temp location before renaming it. + // steno writes a file to a temp location before renaming it. // On Windows, if the final file already exists this error is thrown. // No such error is thrown on Linux/Mac // Make sure we can read & write to this file - await fs.access(path, fs.constants.F_OK | fs.constants.W_OK) + // 2023-12-14: Is this still needed with steno? + await fs.access(file, fs.constants.F_OK | fs.constants.W_OK) // The file was created by another context - this means there were // attempts to write the same block by two different function calls @@ -76,6 +73,7 @@ export class FsDatastore extends BaseDatastore { private readonly deleteManyConcurrency: number private readonly getManyConcurrency: number private readonly putManyConcurrency: number + private readonly writers = new Map() constructor (location: string, init: FsDatastoreInit = {}) { super() @@ -156,7 +154,15 @@ export class FsDatastore extends BaseDatastore { await fs.mkdir(parts.dir, { recursive: true }) - await writeFile(parts.file, val) + const filePath = parts.file + let writer = this.writers.get(filePath) + if (writer == null) { + writer = new StenoWriter(filePath) + this.writers.set(filePath, writer) + } + + await writeFile(writer, filePath, val) + this.writers.delete(filePath) return key } catch (err: any) {