MCPcopy
hub / github.com/Fission-AI/OpenSpec / acquireFileLock

Function acquireFileLock

src/core/file-state.ts:119–162  ·  view source on GitHub ↗
(
  options: FileLockOptions
)

Source from the content-addressed store, hash-verified

117}
118
119export async function acquireFileLock(
120 options: FileLockOptions
121): Promise<nodeFs.promises.FileHandle> {
122 const { lockPath, errorFor } = options;
123 const lockDir = path.dirname(lockPath);
124 await FileSystemUtils.createDirectory(lockDir);
125 if (!(await FileSystemUtils.canWriteFile(lockDir))) {
126 throw errorFor('create-failed', { lockPath, cause: 'EACCES' });
127 }
128 const deadline = Date.now() + LOCK_DEADLINE_MS;
129
130 while (true) {
131 try {
132 return await fs.open(lockPath, 'wx');
133 } catch (error) {
134 if (!isNodeErrorCode(error, 'EEXIST')) {
135 // A permission or filesystem problem, not contention - say so.
136 throw errorFor('create-failed', { lockPath, cause: error });
137 }
138
139 // A crashed process leaves the lock behind forever; state-file
140 // writes are sub-second, so an old lock is an orphan - steal it.
141 let staleStolen = false;
142 try {
143 const lockStat = await fs.stat(lockPath);
144 if (Date.now() - lockStat.mtimeMs > STALE_LOCK_THRESHOLD_MS) {
145 await fs.rm(lockPath, { force: true });
146 staleStolen = true;
147 }
148 } catch {
149 // The holder released between open and stat - retry, but stay
150 // bounded: a persistently failing stat (EPERM, delete-pending)
151 // must hit the deadline instead of spinning forever.
152 }
153
154 if (!staleStolen) {
155 if (Date.now() >= deadline) {
156 throw errorFor('timeout', { lockPath });
157 }
158 await sleep(LOCK_POLL_MS);
159 }
160 }
161 }
162}
163
164export async function releaseFileLock(
165 lock: nodeFs.promises.FileHandle,

Callers 3

file-state.test.tsFile · 0.85
withWorksetsLockFunction · 0.85
updateStoreRegistryStateFunction · 0.85

Calls 6

errorForFunction · 0.85
isNodeErrorCodeFunction · 0.85
sleepFunction · 0.85
createDirectoryMethod · 0.80
canWriteFileMethod · 0.80
openMethod · 0.80

Tested by

no test coverage detected