Skip to content

Commit

Permalink
Improve locking
Browse files Browse the repository at this point in the history
  • Loading branch information
Hexagon committed May 7, 2024
1 parent b533204 commit 6d499c7
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 9 deletions.
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cross/kv",
"version": "0.0.6",
"version": "0.0.7",
"exports": {
".": "./mod.ts"
},
Expand Down
3 changes: 0 additions & 3 deletions src/kv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ export class CrossKV {
key: KVKeyRepresentation,
limit?: number,
): Promise<KVDataEntry[]> {
this.ensureOpen();
const validatedKey = new KVKey(key, true);
const offsets = this.index!.get(validatedKey)!;

Expand All @@ -188,7 +187,6 @@ export class CrossKV {
const results: any[] = [];
let count = 0;

await lock(this.dataPath!);
for (const offset of offsets) {
count++;
const lengthPrefixBuffer = await readAtPosition(
Expand All @@ -208,7 +206,6 @@ export class CrossKV {
results.push(extDecoder.decode(dataBuffer));
if (limit && count >= limit) return results;
}
await unlock(this.dataPath!);
return results;
}

Expand Down
25 changes: 20 additions & 5 deletions src/utils/file.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { open, writeFile } from "node:fs/promises";
import { CurrentRuntime, Runtime } from "@cross/runtime";
import { cwd, isDir, isFile, mkdir, unlink } from "@cross/fs";
import { cwd, isDir, isFile, mkdir, stat, unlink } from "@cross/fs";
import { dirname, isAbsolute, join, resolve } from "@std/path";

export async function writeAtPosition(
Expand Down Expand Up @@ -99,15 +99,30 @@ export async function lock(filename: string): Promise<boolean> {
filePath = resolve(join(cwd(), filename));
}

const lockFile = filePath + ".lock";
const maxRetries = 100; // Adjust as needed
const maxRetries = 50; // Adjust as needed
const retryInterval = 100; // Wait 100ms between attempts
const staleTimeout = maxRetries * retryInterval + 10000;
const lockFile = filePath + ".lock";

// Remove stale lockfile
try {
const statResult = await stat(lockFile);
if (
statResult?.mtime &&
Date.now() - statResult.mtime.getTime() > staleTimeout
) {
await unlink(lockFile);
}
} catch (_e) { /* Ignore */ }

for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
// Attempt to create the lock file (will fail if it exists)
if (CurrentRuntime === Runtime.Deno) {
const file = await Deno.open(lockFile, { create: true, write: true });
const file = await Deno.open(lockFile, {
createNew: true,
write: true,
});
file.close();
} else { // Runtime.Node
await writeFile(lockFile, "", { flag: "wx" }); // 'wx' for exclusive creation
Expand All @@ -127,7 +142,7 @@ export async function lock(filename: string): Promise<boolean> {
}

// Could not acquire the lock after retries
return false;
throw new Error("Could not acquire database lock");
}

/**
Expand Down

0 comments on commit 6d499c7

Please sign in to comment.