gitoriaLog in with ident

mpackdb

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit8788872587888725release 1.0.7caramboleyo87888725/tests/stale-lock.test.js

2.4 KB

  1. import MPackDB from '../src/MPackDB.js';
  2. import { rm, writeFile, utimes, stat } from 'fs/promises';
  3. import { mkdir } from 'fs/promises';
  4. const TEST_DB_PATH = 'db/stale-lock';
  5. console.log('--- Stale Lock Recovery Test ---');
  6. console.log('A crashed process leaves its lock file behind. Waiters must take it');
  7. console.log('over after staleLockTimeout instead of hanging forever.\n');
  8. await rm(TEST_DB_PATH, { recursive: true, force: true });
  9. await mkdir(TEST_DB_PATH, { recursive: true });
  10. // TEST 1: stale lock (old mtime) is removed and the operation proceeds
  11. const lockPath = `${TEST_DB_PATH}/users.lock`;
  12. await writeFile(lockPath, '99999'); // pretend PID of a dead process
  13. const old = (Date.now() - 60000) / 1000; // 60s ago
  14. await utimes(lockPath, old, old);
  15. const db = new MPackDB(`${TEST_DB_PATH}/users`, { primaryKey: '*id', staleLockTimeout: 1000 });
  16. const start = Date.now();
  17. const id = await Promise.race([
  18. db.insert({ name: 'survivor' }),
  19. new Promise(r => setTimeout(() => r('TIMEOUT'), 10000)),
  20. ]);
  21. const took = Date.now() - start;
  22. const test1Pass = id !== 'TIMEOUT';
  23. console.log(`TEST 1: insert with stale lock present: ${test1Pass ? `succeeded in ${took}ms` : 'TIMED OUT'}`);
  24. console.log(` ${test1Pass ? '✓ PASS' : '✗ FAIL — waiter hung on a dead process lock'}\n`);
  25. // TEST 2: a FRESH lock is respected (no premature takeover)
  26. const lockPath2 = `${TEST_DB_PATH}/users.lock`;
  27. await writeFile(lockPath2, String(process.pid));
  28. const start2 = Date.now();
  29. const insert2 = db.insert({ name: 'patient' });
  30. // While the fresh lock exists the insert must wait; release it after 400ms
  31. let insert2Done = false;
  32. insert2.then(() => insert2Done = true);
  33. await new Promise(r => setTimeout(r, 400));
  34. const stillWaiting = !insert2Done;
  35. await rm(lockPath2, { force: true });
  36. const id2 = await Promise.race([
  37. insert2,
  38. new Promise(r => setTimeout(() => r('TIMEOUT'), 10000)),
  39. ]);
  40. const test2Pass = stillWaiting && id2 !== 'TIMEOUT';
  41. console.log(`TEST 2: fresh lock respected (waited: ${stillWaiting}), then acquired in ${Date.now() - start2}ms`);
  42. console.log(` ${test2Pass ? '✓ PASS' : '✗ FAIL'}\n`);
  43. await db.close();
  44. // no lock file left behind
  45. const lockLeft = await stat(lockPath).then(() => true).catch(() => false);
  46. console.log(`Lock file cleaned up: ${!lockLeft ? '✓ PASS' : '✗ FAIL'}`);
  47. const allPass = test1Pass && test2Pass && !lockLeft;
  48. console.log(`\n${allPass ? '✓ All stale lock tests passed!' : '✗ Some stale lock tests FAILED'}`);
  49. if (!allPass) throw new Error('stale-lock tests FAILED');

Branches

Latest commits

  • 87888725release 1.0.7caramboleyo
  • c4cdb9b6node: import prefixes (Deno compat) + pre-existing index-state WIPcaramboleyo
  • 0afb8f4bupdate now must be a callbackcaramboleyo
  • cde73eb4release 1.0.6caramboleyo
  • d01dda02add index hints, intersection, boundingBox; remove findByIndexcaramboleyo
  • b8ffc1a0release 1.0.5caramboleyo
  • d47876a1reimplemented lost features like indexed find and more testscaramboleyo
  • 7f08da9afixed insert ignoring model definitioncaramboleyo
  • 705774a9added flush before findcaramboleyo
  • b4db6391initial commitcaramboleyo