From 3362eee2c2a6215afc05d4f5b072e7b23be642ab Mon Sep 17 00:00:00 2001 From: Joachim Van Herwegen Date: Tue, 1 Dec 2020 16:53:25 +0100 Subject: [PATCH] fix: Always release lock when patching --- src/storage/patch/SparqlUpdatePatchHandler.ts | 27 ++++++++++++------- .../patch/SparqlUpdatePatchHandler.test.ts | 16 +++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/storage/patch/SparqlUpdatePatchHandler.ts b/src/storage/patch/SparqlUpdatePatchHandler.ts index bf85e4af9..470dfe131 100644 --- a/src/storage/patch/SparqlUpdatePatchHandler.ts +++ b/src/storage/patch/SparqlUpdatePatchHandler.ts @@ -65,10 +65,25 @@ export class SparqlUpdatePatchHandler extends PatchHandler { throw new NotImplementedHttpError('WHERE statements are not supported'); } - // Read the quads of the current representation const lock = await this.locker.acquire(identifier); - const quads = await this.source.getRepresentation(identifier, - { type: [{ value: INTERNAL_QUADS, weight: 1 }]}); + try { + await this.applyPatch(identifier, deletes, inserts); + } finally { + await lock.release(); + } + } + + private isDeleteInsert(op: Algebra.Operation): op is Algebra.DeleteInsert { + return op.type === Algebra.types.DELETE_INSERT; + } + + /** + * Applies the given deletes and inserts to the resource. + */ + private async applyPatch(identifier: ResourceIdentifier, deletes: Algebra.Pattern[], inserts: Algebra.Pattern[]): + Promise { + // Read the quads of the current representation + const quads = await this.source.getRepresentation(identifier, { type: [{ value: INTERNAL_QUADS, weight: 1 }]}); const store = new Store(); const importEmitter = store.import(quads.data); await new Promise((resolve, reject): void => { @@ -91,11 +106,5 @@ export class SparqlUpdatePatchHandler extends PatchHandler { metadata, }; await this.source.setRepresentation(identifier, representation); - - await lock.release(); - } - - private isDeleteInsert(op: Algebra.Operation): op is Algebra.DeleteInsert { - return op.type === Algebra.types.DELETE_INSERT; } } diff --git a/test/unit/storage/patch/SparqlUpdatePatchHandler.test.ts b/test/unit/storage/patch/SparqlUpdatePatchHandler.test.ts index 20bb3ecab..8180edf44 100644 --- a/test/unit/storage/patch/SparqlUpdatePatchHandler.test.ts +++ b/test/unit/storage/patch/SparqlUpdatePatchHandler.test.ts @@ -199,4 +199,20 @@ describe('A SparqlUpdatePatchHandler', (): void => { await expect(handle).rejects.toThrow('Only DELETE/INSERT SPARQL update operations are supported'); expect(order).toEqual([]); }); + + it('releases the lock if an error occurs while patching.', async(): Promise => { + source.getRepresentation = jest.fn(async(): Promise => { + order.push('getRepresentation'); + throw new Error('error'); + }); + + const input = { identifier: { path: 'path' }, + patch: { algebra: translate( + 'INSERT DATA { . ' + + ' }', + { quads: true }, + ) } as SparqlUpdatePatch }; + await expect(handler.handle(input)).rejects.toThrow('error'); + expect(order).toEqual([ 'acquire', 'getRepresentation', 'release' ]); + }); });