MCPcopy
hub / github.com/colbymchenry/codegraph / tryAcquireDaemonLock

Function tryAcquireDaemonLock

src/mcp/daemon.ts:525–574  ·  view source on GitHub ↗
(projectRoot: string)

Source from the content-addressed store, hash-verified

523 * drive that's strictly better than the daemon never starting at all.
524 */
525export function tryAcquireDaemonLock(projectRoot: string): AcquireResult {
526 const pidPath = getDaemonPidPath(projectRoot);
527 // Make sure the .codegraph/ directory exists — the daemon may be the first
528 // thing to touch it on a fresh-clone-but-already-initialized checkout.
529 fs.mkdirSync(path.dirname(pidPath), { recursive: true });
530
531 const info: DaemonLockInfo = {
532 pid: process.pid,
533 version: CodeGraphPackageVersion,
534 socketPath: getDaemonSocketPath(projectRoot),
535 startedAt: Date.now(),
536 };
537
538 // Temp name is pid-scoped so racing candidates never collide on it.
539 const tmp = `${pidPath}.${process.pid}.tmp`;
540 let acquired = false;
541 try {
542 fs.writeFileSync(tmp, encodeLockInfo(info), { mode: 0o600 });
543 try {
544 fs.linkSync(tmp, pidPath); // atomic + exclusive (race-free; see must-fix 1)
545 acquired = true;
546 } catch (err: unknown) {
547 if ((err as NodeJS.ErrnoException).code === 'EEXIST') {
548 // Lost the race — another candidate already holds it. Fall through to read.
549 } else {
550 // link() failed for a non-conflict reason — nearly always "this filesystem
551 // has no hard links" (ExFAT/FAT external volumes, some network mounts),
552 // which surfaces as a DIFFERENT errno on every OS: ENOTSUP on macOS, EPERM
553 // on Linux, EISDIR on Windows (#997). Enumerating them is whack-a-mole and
554 // unnecessary: the `tmp` write above already proved this directory is
555 // writable, so an O_EXCL create is a valid atomic+exclusive substitute. If
556 // IT fails too, that's a genuine error and propagates. EEXIST ⇒ taken.
557 acquired = acquireLockViaExclusiveOpen(pidPath, info);
558 }
559 }
560 } finally {
561 try { fs.unlinkSync(tmp); } catch { /* temp already gone */ }
562 }
563
564 if (acquired) return { kind: 'acquired', pidPath, info };
565
566 // Taken. Because the pidfile was link'd atomically it always holds a complete
567 // record — `existing` is null only for a genuinely corrupt leftover, never a
568 // mid-write race.
569 let existing: DaemonLockInfo | null = null;
570 try {
571 existing = decodeLockInfo(fs.readFileSync(pidPath, 'utf8'));
572 } catch { /* unreadable lockfile — treat as malformed */ }
573 return { kind: 'taken', existing, pidPath };
574}
575
576/**
577 * Exclusive-create the pidfile (O_CREAT|O_EXCL via the `wx` flag) and write the

Calls 5

getDaemonPidPathFunction · 0.90
getDaemonSocketPathFunction · 0.90
encodeLockInfoFunction · 0.90
decodeLockInfoFunction · 0.90

Tested by

no test coverage detected