Fix main & improve cursor sync (#101)
This commit is contained in:
parent
81b81e30ff
commit
a36a24effc
36 changed files with 926 additions and 686 deletions
|
|
@ -31,16 +31,17 @@ export class SafeFileSystemOperations implements FileSystemOperations {
|
|||
this.logger.debug(`Reading file '${path}'`);
|
||||
return this.safeOperation(
|
||||
path,
|
||||
this.decorateToHoldLock(path, async () => this.fs.read(path)),
|
||||
async () =>
|
||||
this.locks.withLock(path, async () => this.fs.read(path)),
|
||||
"read"
|
||||
);
|
||||
}
|
||||
|
||||
public async write(path: RelativePath, content: Uint8Array): Promise<void> {
|
||||
this.logger.debug(`Writing to file '${path}'`);
|
||||
return this.decorateToHoldLock(path, async () =>
|
||||
return this.locks.withLock(path, async () =>
|
||||
this.fs.write(path, content)
|
||||
)();
|
||||
);
|
||||
}
|
||||
|
||||
public async atomicUpdateText(
|
||||
|
|
@ -50,9 +51,10 @@ export class SafeFileSystemOperations implements FileSystemOperations {
|
|||
this.logger.debug(`Atomically updating file '${path}'`);
|
||||
return this.safeOperation(
|
||||
path,
|
||||
this.decorateToHoldLock(path, async () =>
|
||||
this.fs.atomicUpdateText(path, updater)
|
||||
),
|
||||
async () =>
|
||||
this.locks.withLock(path, async () =>
|
||||
this.fs.atomicUpdateText(path, updater)
|
||||
),
|
||||
"atomicUpdateText"
|
||||
);
|
||||
}
|
||||
|
|
@ -61,32 +63,29 @@ export class SafeFileSystemOperations implements FileSystemOperations {
|
|||
// Logging this would be too noisy
|
||||
return this.safeOperation(
|
||||
path,
|
||||
this.decorateToHoldLock(path, async () =>
|
||||
this.fs.getFileSize(path)
|
||||
),
|
||||
async () =>
|
||||
this.locks.withLock(path, async () =>
|
||||
this.fs.getFileSize(path)
|
||||
),
|
||||
"getFileSize"
|
||||
);
|
||||
}
|
||||
|
||||
public async exists(path: RelativePath): Promise<boolean> {
|
||||
this.logger.debug(`Checking if file '${path}' exists`);
|
||||
return this.decorateToHoldLock(path, async () =>
|
||||
this.fs.exists(path)
|
||||
)();
|
||||
return this.locks.withLock(path, async () => this.fs.exists(path));
|
||||
}
|
||||
|
||||
public async createDirectory(path: RelativePath): Promise<void> {
|
||||
this.logger.debug(`Creating directory '${path}'`);
|
||||
return this.decorateToHoldLock(path, async () =>
|
||||
return this.locks.withLock(path, async () =>
|
||||
this.fs.createDirectory(path)
|
||||
)();
|
||||
);
|
||||
}
|
||||
|
||||
public async delete(path: RelativePath): Promise<void> {
|
||||
this.logger.debug(`Deleting file '${path}'`);
|
||||
return this.decorateToHoldLock(path, async () =>
|
||||
this.fs.delete(path)
|
||||
)();
|
||||
return this.locks.withLock(path, async () => this.fs.delete(path));
|
||||
}
|
||||
|
||||
public async rename(
|
||||
|
|
@ -96,43 +95,14 @@ export class SafeFileSystemOperations implements FileSystemOperations {
|
|||
this.logger.debug(`Renaming file '${oldPath}' to '${newPath}'`);
|
||||
return this.safeOperation(
|
||||
oldPath,
|
||||
this.decorateToHoldLock([oldPath, newPath], async () =>
|
||||
this.fs.rename(oldPath, newPath)
|
||||
),
|
||||
async () =>
|
||||
this.locks.withLock([oldPath, newPath], async () =>
|
||||
this.fs.rename(oldPath, newPath)
|
||||
),
|
||||
"rename"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorate an operation to ensure that the file is locked before running it
|
||||
* and that the lock is released afterwards. This results in at-most one
|
||||
* concurrent operation running per file.
|
||||
*/
|
||||
private decorateToHoldLock<T>(
|
||||
pathOrPaths: RelativePath | RelativePath[],
|
||||
operation: () => Promise<T>
|
||||
): () => Promise<T> {
|
||||
return async () => {
|
||||
const paths = Array.isArray(pathOrPaths)
|
||||
? pathOrPaths
|
||||
: [pathOrPaths];
|
||||
|
||||
await Promise.all(
|
||||
paths.map(async (path) => this.locks.waitForLock(path))
|
||||
);
|
||||
|
||||
try {
|
||||
return await operation();
|
||||
} finally {
|
||||
await Promise.all(
|
||||
paths.map((path) => {
|
||||
this.locks.unlock(path);
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorate an operation to ensure that the file exists before running it.
|
||||
* If the operation fails, it will check if the file still exists and throw
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue