feat: Create VoidLocker to disable locking resources

* add: Add VoidLocker and unittest

* Update src/util/locking/VoidLocker.ts

Co-authored-by: Ruben Verborgh <ruben@verborgh.org>

* Update src/util/locking/VoidLocker.ts

Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com>

* update: noop function and add debug void config

* add: debug-void in readme

* Update RELEASE_NOTES.md

Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com>

* Update config/util/README.md

Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com>

* add: missing line

Co-authored-by: lina <lina7906@gmail.com>
Co-authored-by: Ruben Verborgh <ruben@verborgh.org>
Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com>
This commit is contained in:
Lina 2021-12-16 15:09:58 +01:00 committed by GitHub
parent 4241c5348d
commit 9a1f324685
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 0 deletions

View File

@ -3,6 +3,7 @@
## v3.0.0
### New features
- The Identity Provider now uses the `webid` scope as required for Solid-OIDC.
- The `VoidLocker` can be used to disable locking for development/testing purposes. This can be enabled by changing the `/config/util/resource-locker/` import to `debug-void.json`
### Configuration changes
You might need to make changes to your v2 configuration if you use a custom config.

View File

@ -36,6 +36,7 @@ to the ChainedConverter list.
## Resource-locker
Which locking mechanism to use to for example prevent 2 write simultaneous write requests.
* *debug-void*: No locking mechanism, does not prevent simultaneous read/writes.
* *memory*: Uses an in-memory locking mechanism.
* *redis*: Uses a Redis store for locking.

View File

@ -0,0 +1,13 @@
{
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^2.0.0/components/context.jsonld",
"@graph": [
{
"comment": [
"DO NOT USE IN PRODUCTION. ONLY FOR DEVELOPMENT, TESTING, OR DEBUGGING.",
"Allows multiple simultaneous read operations and write operations without locks."
],
"@id": "urn:solid-server:default:ResourceLocker",
"@type": "VoidLocker"
}
]
}

View File

@ -363,6 +363,7 @@ export * from './util/locking/RedisResourceLocker';
export * from './util/locking/ResourceLocker';
export * from './util/locking/SingleThreadedResourceLocker';
export * from './util/locking/WrappedExpiringReadWriteLocker';
export * from './util/locking/VoidLocker';
// Util/Templates
export * from './util/templates/ChainedTemplateEngine';

View File

@ -0,0 +1,34 @@
import type { ResourceIdentifier } from '../../http/representation/ResourceIdentifier';
import { getLoggerFor } from '../../logging/LogUtil';
import type { ExpiringReadWriteLocker } from './ExpiringReadWriteLocker';
/**
* This locker will execute the whileLocked function without any locking mechanism
*
* Do not use this locker in combination with storages that doesn't handle concurrent read/writes gracefully
*/
// eslint-disable-next-line @typescript-eslint/no-empty-function
function noop(): void {}
export class VoidLocker implements ExpiringReadWriteLocker {
protected readonly logger = getLoggerFor(this);
public constructor() {
this.logger.warn('Locking mechanism disabled; data integrity during parallel requests not guaranteed.');
}
public async withReadLock<T>(
identifier: ResourceIdentifier,
whileLocked: (maintainLock: () => void) => T | Promise<T>,
): Promise<T> {
return whileLocked(noop);
}
public async withWriteLock<T>(
identifier: ResourceIdentifier,
whileLocked: (maintainLock: () => void) => T | Promise<T>,
): Promise<T> {
return whileLocked(noop);
}
}

View File

@ -0,0 +1,27 @@
import type { ResourceIdentifier } from '../../../../src';
import { VoidLocker } from '../../../../src/util/locking/VoidLocker';
describe('A VoidLocker', (): void => {
it('invokes the whileLocked function immediately with readLock.', async(): Promise<void> => {
const locker = new VoidLocker();
const identifier: ResourceIdentifier = { path: 'http://test.com/res' };
const whileLocked = jest.fn().mockImplementation((maintainLockFn: () => void): void => {
maintainLockFn();
});
await locker.withReadLock(identifier, whileLocked);
expect(whileLocked).toHaveBeenCalledTimes(1);
});
it('invokes the whileLocked function immediately with writeLock.', async(): Promise<void> => {
const locker = new VoidLocker();
const identifier: ResourceIdentifier = { path: 'http://test.com/res' };
const whileLocked = jest.fn().mockImplementation((maintainLockFn: () => void): void => {
maintainLockFn();
});
await locker.withWriteLock(identifier, whileLocked);
expect(whileLocked).toHaveBeenCalledTimes(1);
});
});