mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Add auxiliary support to LockingResourceStore
This way locks are always on the associated resource if there is a request on an auxiliary resource.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { Readable } from 'stream';
|
||||
import { promisify } from 'util';
|
||||
import eos from 'end-of-stream';
|
||||
import type { AuxiliaryIdentifierStrategy } from '../ldp/auxiliary/AuxiliaryIdentifierStrategy';
|
||||
import type { Patch } from '../ldp/http/Patch';
|
||||
import { BasicRepresentation } from '../ldp/representation/BasicRepresentation';
|
||||
import type { Representation } from '../ldp/representation/Representation';
|
||||
@@ -17,46 +18,61 @@ const endOfStream = promisify(eos);
|
||||
* Store that for every call acquires a lock before executing it on the requested resource,
|
||||
* and releases it afterwards.
|
||||
* In case the request returns a Representation the lock will only be released when the data stream is finished.
|
||||
*
|
||||
* For auxiliary resources the lock will be applied to the associated resource.
|
||||
* The actual operation is still executed on the auxiliary resource.
|
||||
*/
|
||||
export class LockingResourceStore implements AtomicResourceStore {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
|
||||
private readonly source: ResourceStore;
|
||||
private readonly locks: ExpiringReadWriteLocker;
|
||||
private readonly strategy: AuxiliaryIdentifierStrategy;
|
||||
|
||||
public constructor(source: ResourceStore, locks: ExpiringReadWriteLocker) {
|
||||
public constructor(source: ResourceStore, locks: ExpiringReadWriteLocker, strategy: AuxiliaryIdentifierStrategy) {
|
||||
this.source = source;
|
||||
this.locks = locks;
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
public async getRepresentation(identifier: ResourceIdentifier, preferences: RepresentationPreferences,
|
||||
conditions?: Conditions): Promise<Representation> {
|
||||
return this.lockedRepresentationRun(identifier,
|
||||
return this.lockedRepresentationRun(this.getLockIdentifier(identifier),
|
||||
async(): Promise<Representation> => this.source.getRepresentation(identifier, preferences, conditions));
|
||||
}
|
||||
|
||||
public async addResource(container: ResourceIdentifier, representation: Representation,
|
||||
conditions?: Conditions): Promise<ResourceIdentifier> {
|
||||
return this.locks.withWriteLock(container,
|
||||
return this.locks.withWriteLock(this.getLockIdentifier(container),
|
||||
async(): Promise<ResourceIdentifier> => this.source.addResource(container, representation, conditions));
|
||||
}
|
||||
|
||||
public async setRepresentation(identifier: ResourceIdentifier, representation: Representation,
|
||||
conditions?: Conditions): Promise<void> {
|
||||
return this.locks.withWriteLock(identifier,
|
||||
return this.locks.withWriteLock(this.getLockIdentifier(identifier),
|
||||
async(): Promise<void> => this.source.setRepresentation(identifier, representation, conditions));
|
||||
}
|
||||
|
||||
public async deleteResource(identifier: ResourceIdentifier, conditions?: Conditions): Promise<void> {
|
||||
return this.locks.withWriteLock(identifier,
|
||||
return this.locks.withWriteLock(this.getLockIdentifier(identifier),
|
||||
async(): Promise<void> => this.source.deleteResource(identifier, conditions));
|
||||
}
|
||||
|
||||
public async modifyResource(identifier: ResourceIdentifier, patch: Patch, conditions?: Conditions): Promise<void> {
|
||||
return this.locks.withWriteLock(identifier,
|
||||
return this.locks.withWriteLock(this.getLockIdentifier(identifier),
|
||||
async(): Promise<void> => this.source.modifyResource(identifier, patch, conditions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires the correct identifier to lock this resource.
|
||||
* For auxiliary resources this means the associated identifier.
|
||||
*/
|
||||
protected getLockIdentifier(identifier: ResourceIdentifier): ResourceIdentifier {
|
||||
return this.strategy.isAuxiliaryIdentifier(identifier) ?
|
||||
this.strategy.getAssociatedIdentifier(identifier) :
|
||||
identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires a lock that is only released when all data of the resulting representation data has been read,
|
||||
* an error occurs, or the timeout has been triggered.
|
||||
|
||||
Reference in New Issue
Block a user