Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
CMCDragonkai committed Apr 1, 2022
1 parent 1d67c83 commit 71e0008
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 113 deletions.
9 changes: 6 additions & 3 deletions src/Lock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Lock {
this,
];
};
};
}

public get count(): number {
return this._count;
Expand All @@ -47,13 +47,16 @@ class Lock {
return this._lock.waitForUnlock();
}

public async withF<T>(f: (resources: [Lock]) => Promise<T>, timeout?: number): Promise<T> {
public async withF<T>(
f: (resources: [Lock]) => Promise<T>,
timeout?: number,
): Promise<T> {
return withF([this.lock(timeout)], f);
}

public withG<T, TReturn, TNext>(
g: (resources: [Lock]) => AsyncGenerator<T, TReturn, TNext>,
timeout?: number
timeout?: number,
): AsyncGenerator<T, TReturn, TNext> {
return withG([this.lock(timeout)], g);
}
Expand Down
10 changes: 5 additions & 5 deletions src/RWLockReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class RWLockReader {
++this._writerCount;
let lock: MutexInterface = this.lock;
if (timeout != null) {
lock = withTimeout(this.lock, timeout, new ErrorAsyncLocksTimeout);
lock = withTimeout(this.lock, timeout, new ErrorAsyncLocksTimeout());
}
let release: MutexInterface.Releaser;
try {
Expand Down Expand Up @@ -89,28 +89,28 @@ class RWLockReader {

public async withReadF<T>(
f: (resources: [RWLockReader]) => Promise<T>,
timeout?: number
timeout?: number,
): Promise<T> {
return withF([this.read(timeout)], f);
}

public async withWriteF<T>(
f: (resources: [RWLockReader]) => Promise<T>,
timeout?: number
timeout?: number,
): Promise<T> {
return withF([this.write(timeout)], f);
}

public withReadG<T, TReturn, TNext>(
g: (resources: [RWLockReader]) => AsyncGenerator<T, TReturn, TNext>,
timeout?: number
timeout?: number,
): AsyncGenerator<T, TReturn, TNext> {
return withG([this.read(timeout)], g);
}

public withWriteG<T, TReturn, TNext>(
g: (resources: [RWLockReader]) => AsyncGenerator<T, TReturn, TNext>,
timeout?: number
timeout?: number,
): AsyncGenerator<T, TReturn, TNext> {
return withG([this.write(timeout)], g);
}
Expand Down
26 changes: 18 additions & 8 deletions src/RWLockWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class RWLockWriter {
let timedOut = false;
await Promise.race([
this.writersLock.waitForUnlock(),
sleep(timeout).then(() => { timedOut = true; })
sleep(timeout).then(() => {
timedOut = true;
}),
]);
if (timedOut) {
--this.readerCountBlocked;
Expand All @@ -46,7 +48,7 @@ class RWLockWriter {
readersLock = withTimeout(
this.readersLock,
timeout,
new ErrorAsyncLocksTimeout()
new ErrorAsyncLocksTimeout(),
);
}
try {
Expand Down Expand Up @@ -76,7 +78,11 @@ class RWLockWriter {
++this._writerCount;
let writersLock: MutexInterface = this.writersLock;
if (timeout != null) {
writersLock = withTimeout(this.writersLock, timeout, new ErrorAsyncLocksTimeout());
writersLock = withTimeout(
this.writersLock,
timeout,
new ErrorAsyncLocksTimeout(),
);
}
const t1 = performance.now();
let writersRelease: MutexInterface.Releaser;
Expand All @@ -89,7 +95,11 @@ class RWLockWriter {
let readersLock: MutexInterface = this.readersLock;
if (timeout != null) {
timeout = timeout - (performance.now() - t1);
readersLock = withTimeout(this.readersLock, timeout, new ErrorAsyncLocksTimeout());
readersLock = withTimeout(
this.readersLock,
timeout,
new ErrorAsyncLocksTimeout(),
);
}
try {
this.readersRelease = await readersLock.acquire();
Expand Down Expand Up @@ -135,28 +145,28 @@ class RWLockWriter {

public async withReadF<T>(
f: (resources: [RWLockWriter]) => Promise<T>,
timeout?: number
timeout?: number,
): Promise<T> {
return withF([this.read(timeout)], f);
}

public async withWriteF<T>(
f: (resources: [RWLockWriter]) => Promise<T>,
timeout?: number
timeout?: number,
): Promise<T> {
return withF([this.write(timeout)], f);
}

public withReadG<T, TReturn, TNext>(
g: (resources: [RWLockWriter]) => AsyncGenerator<T, TReturn, TNext>,
timeout?: number
timeout?: number,
): AsyncGenerator<T, TReturn, TNext> {
return withG([this.read(timeout)], g);
}

public withWriteG<T, TReturn, TNext>(
g: (resources: [RWLockWriter]) => AsyncGenerator<T, TReturn, TNext>,
timeout?: number
timeout?: number,
): AsyncGenerator<T, TReturn, TNext> {
return withG([this.write(timeout)], g);
}
Expand Down
5 changes: 1 addition & 4 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,4 @@ class ErrorAsyncLocks extends CustomError {

class ErrorAsyncLocksTimeout extends ErrorAsyncLocks {}

export {
ErrorAsyncLocks,
ErrorAsyncLocksTimeout
};
export { ErrorAsyncLocks, ErrorAsyncLocksTimeout };
10 changes: 7 additions & 3 deletions tests/Lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ describe(Lock.name, () => {
expect(lock.isLocked()).toBe(true);
expect(lock.count).toBe(1);
const f = jest.fn();
await expect(withF([lock.lock(100)], f)).rejects.toThrow(errors.ErrorAsyncLocksTimeout);
await expect(withF([lock.lock(100)], f)).rejects.toThrow(
errors.ErrorAsyncLocksTimeout,
);
expect(f).not.toBeCalled();
expect(lock.isLocked()).toBe(true);
expect(lock.count).toBe(1);
Expand All @@ -174,10 +176,12 @@ describe(Lock.name, () => {
expect(lock.count).toBe(0);
await lock.withF(async () => {
const f = jest.fn();
await expect(lock.withF(f, 100)).rejects.toThrow(errors.ErrorAsyncLocksTimeout);
await expect(lock.withF(f, 100)).rejects.toThrow(
errors.ErrorAsyncLocksTimeout,
);
expect(f).not.toBeCalled();
}, 100);
const g = lock.withG(async function *() {
const g = lock.withG(async function* () {
expect(lock.isLocked()).toBe(true);
expect(lock.count).toBe(1);
const f = jest.fn();
Expand Down
98 changes: 53 additions & 45 deletions tests/RWLockReader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,24 @@ describe(RWLockReader.name, () => {
});
test('withG on read', async () => {
const lock = new RWLockReader();
const g1 = withG(
[lock.read()],
async function* ([lock]): AsyncGenerator<string, string, void> {
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
yield 'first';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
yield 'second';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
return 'last';
},
);
const g1 = withG([lock.read()], async function* ([lock]): AsyncGenerator<
string,
string,
void
> {
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
yield 'first';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
yield 'second';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
return 'last';
});
for await (const _ of g1) {
// It should be locked during iteration
expect(lock.isLocked()).toBe(true);
Expand Down Expand Up @@ -107,23 +108,24 @@ describe(RWLockReader.name, () => {
});
test('withG on write', async () => {
const lock = new RWLockReader();
const g1 = withG(
[lock.write()],
async function* ([lock]): AsyncGenerator<string, string, void> {
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
yield 'first';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
yield 'second';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
return 'last';
},
);
const g1 = withG([lock.write()], async function* ([lock]): AsyncGenerator<
string,
string,
void
> {
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
yield 'first';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
yield 'second';
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
return 'last';
});
for await (const _ of g1) {
// It should be locked during iteration
expect(lock.isLocked()).toBe(true);
Expand Down Expand Up @@ -358,9 +360,9 @@ describe(RWLockReader.name, () => {
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
const f = jest.fn();
await expect(
withF([lock.write(100)], f)
).rejects.toThrow(errors.ErrorAsyncLocksTimeout);
await expect(withF([lock.write(100)], f)).rejects.toThrow(
errors.ErrorAsyncLocksTimeout,
);
expect(f).not.toBeCalled();
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
Expand All @@ -374,30 +376,36 @@ describe(RWLockReader.name, () => {
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
const f = jest.fn();
await expect(
withF([lock.read(100)], f)
).rejects.toThrow(errors.ErrorAsyncLocksTimeout);
await expect(withF([lock.read(100)], f)).rejects.toThrow(
errors.ErrorAsyncLocksTimeout,
);
expect(f).not.toBeCalled();
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
});
await lock.withReadF(async () => {
const f = jest.fn();
await expect(lock.withWriteF(f, 100)).rejects.toThrow(errors.ErrorAsyncLocksTimeout);
await expect(lock.withWriteF(f, 100)).rejects.toThrow(
errors.ErrorAsyncLocksTimeout,
);
expect(f).not.toBeCalled();
}, 100);
await lock.withWriteF(async () => {
const f = jest.fn();
await expect(lock.withReadF(f, 100)).rejects.toThrow(errors.ErrorAsyncLocksTimeout);
await expect(lock.withReadF(f, 100)).rejects.toThrow(
errors.ErrorAsyncLocksTimeout,
);
expect(f).not.toBeCalled();
}, 100);
await lock.withWriteF(async () => {
const f = jest.fn();
await expect(lock.withWriteF(f, 100)).rejects.toThrow(errors.ErrorAsyncLocksTimeout);
await expect(lock.withWriteF(f, 100)).rejects.toThrow(
errors.ErrorAsyncLocksTimeout,
);
expect(f).not.toBeCalled();
}, 100);
const gRead = lock.withReadG(async function *() {
const gRead = lock.withReadG(async function* () {
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(1);
expect(lock.writerCount).toBe(0);
Expand All @@ -413,7 +421,7 @@ describe(RWLockReader.name, () => {
expect(lock.isLocked()).toBe(false);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(0);
const gWrite = lock.withWriteG(async function *() {
const gWrite = lock.withWriteG(async function* () {
expect(lock.isLocked()).toBe(true);
expect(lock.readerCount).toBe(0);
expect(lock.writerCount).toBe(1);
Expand Down
Loading

0 comments on commit 71e0008

Please sign in to comment.