WIP: Smart create call #184
6 changed files with 18 additions and 16 deletions
|
|
@ -17,7 +17,7 @@ export class SafeFileSystemOperations implements FileSystemOperations {
|
|||
private readonly fs: FileSystemOperations,
|
||||
private readonly logger: Logger
|
||||
) {
|
||||
this.locks = new Locks(logger);
|
||||
this.locks = new Locks(SafeFileSystemOperations.name, logger);
|
||||
}
|
||||
|
||||
public async listFilesRecursively(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export class Settings {
|
|||
>();
|
||||
|
||||
private settings: SyncSettings;
|
||||
private readonly lock: Lock = new Lock();
|
||||
private readonly lock: Lock;
|
||||
|
||||
public constructor(
|
||||
private readonly logger: Logger,
|
||||
|
|
@ -50,6 +50,8 @@ export class Settings {
|
|||
...(initialState ?? {})
|
||||
};
|
||||
|
||||
this.lock = new Lock(Settings.name, this.logger);
|
||||
|
||||
this.logger.debug(
|
||||
`Loaded settings: ${JSON.stringify(this.settings, null, 2)}`
|
||||
);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export class CursorTracker {
|
|||
(cursors: MaybeOutdatedClientCursors[]) => unknown
|
||||
>();
|
||||
|
||||
private readonly updateLock = new Lock();
|
||||
private readonly updateLock = new Lock(CursorTracker.name);
|
||||
|
||||
private knownRemoteCursors: (ClientCursors & {
|
||||
upToDateness: DocumentUpToDateness;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ describe("withLock", () => {
|
|||
let locks: Locks<RelativePath>;
|
||||
|
||||
beforeEach(() => {
|
||||
locks = new Locks<RelativePath>(logger);
|
||||
locks = new Locks<RelativePath>("locks-test", logger);
|
||||
});
|
||||
|
||||
it("should execute function with single key lock", async () => {
|
||||
|
|
@ -253,7 +253,7 @@ describe("reset", () => {
|
|||
let locks: Locks<RelativePath>;
|
||||
|
||||
beforeEach(() => {
|
||||
locks = new Locks<RelativePath>(logger);
|
||||
locks = new Locks<RelativePath>("locks-test", logger);
|
||||
});
|
||||
|
||||
it("should reject pending waiters with SyncResetError while running operation completes", async () => {
|
||||
|
|
@ -265,7 +265,7 @@ describe("reset", () => {
|
|||
await sleep(1);
|
||||
|
||||
const secondPromise = locks.withLock(testPath, async () => "second");
|
||||
void secondPromise.catch(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
void secondPromise.catch(() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
|
||||
locks.reset();
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ describe("reset", () => {
|
|||
await sleep(1);
|
||||
|
||||
const secondPromise = locks.withLock(testPath, async () => "second");
|
||||
void secondPromise.catch(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
void secondPromise.catch(() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
|
||||
locks.reset();
|
||||
|
||||
|
|
@ -312,7 +312,7 @@ describe("reset", () => {
|
|||
[testPath, testPath2],
|
||||
async () => "multi"
|
||||
);
|
||||
void multiKeyPromise.catch(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
void multiKeyPromise.catch(() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
|
||||
// Wait for the multi-key operation to acquire testPath and start waiting on testPath2
|
||||
await sleep(10);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export class Locks<T> {
|
|||
/** Queue of waiters for each key */
|
||||
private readonly waiters = new Map<T, WaiterEntry<T>[]>();
|
||||
|
||||
public constructor(private readonly logger?: Logger) { }
|
||||
public constructor(private readonly name: string, private readonly logger?: Logger) { }
|
||||
|
||||
/**
|
||||
* Executes a function while holding exclusive locks on one or more keys.
|
||||
|
|
@ -122,7 +122,7 @@ export class Locks<T> {
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.logger?.debug(`Waiting for lock on ${key}`);
|
||||
this.logger?.debug(`Waiting for lock '${this.name}' on '${key}'`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// DefaultDict behavior
|
||||
|
|
@ -149,18 +149,18 @@ export class Locks<T> {
|
|||
public unlock(key: T): void {
|
||||
if (!this.locked.has(key)) {
|
||||
this.logger?.debug(
|
||||
`Attempted to unlock ${key} which is not locked`
|
||||
`Attempted to unlock '${this.name}' on '${key}' which is not locked`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger?.debug(`Releasing lock on ${key}`);
|
||||
this.logger?.debug(`Releasing lock '${this.name}' on '${key}'`);
|
||||
|
||||
// Remove first waiter to ensure FIFO order
|
||||
const nextWaiter = this.waiters.get(key)?.shift();
|
||||
|
||||
if (nextWaiter) {
|
||||
this.logger?.debug(`Granted lock on ${key}`);
|
||||
this.logger?.debug(`Granted lock '${this.name}' on '${key}'`);
|
||||
nextWaiter.resolve();
|
||||
} else {
|
||||
this.locked.delete(key);
|
||||
|
|
@ -171,8 +171,8 @@ export class Locks<T> {
|
|||
export class Lock {
|
||||
private readonly locks: Locks<boolean>;
|
||||
|
||||
public constructor(logger?: Logger) {
|
||||
this.locks = new Locks(logger);
|
||||
public constructor(name: string, logger?: Logger) {
|
||||
this.locks = new Locks(name, logger);
|
||||
}
|
||||
|
||||
public async withLock<R>(fn: () => R | Promise<R>): Promise<R> {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export function slowWebSocketFactory(
|
|||
private static readonly RECEIVE_KEY = "websocket-receive";
|
||||
private static readonly SEND_KEY = "websocket-send";
|
||||
|
||||
private readonly locks = new Locks(logger);
|
||||
private readonly locks = new Locks(FlakyWebSocket.name, logger);
|
||||
|
||||
public set onopen(callback: ((event: Event) => void) | null) {
|
||||
super.onopen = async (event: Event): Promise<void> => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue