From 6e61015876de8e4386005311fe68a0919ba47796 Mon Sep 17 00:00:00 2001 From: Evert Pot Date: Sun, 20 Mar 2022 16:58:50 -0400 Subject: [PATCH] Only emit 'update' events after the entire state cache has been updated. Currently Ketting has a race condition for updates with embedded items. If items are embedded, we were sending out 'update' events even if the entire request wasn't processed yet. This can make it unpredictable to know whether a resource's parent or child is updated. This change processes an entire _embedded tree with sub-dependencies, and only after the entire tree is cached it will start sending out 'update' events. Now, when you receive an 'update' event the entire cache state is consistent. --- src/client.ts | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/client.ts b/src/client.ts index f9a7533..9396b40 100644 --- a/src/client.ts +++ b/src/client.ts @@ -155,20 +155,28 @@ export default class Client { */ cacheState(state: State) { - this.cache.store(state); - for(const invByLink of state.links.getMany('inv-by')) { - this.addCacheDependency(resolve(invByLink), state.uri); + // Flatten the list of state objects. + const newStates = flattenState(state); + + // Register all cache dependencies. + for(const nState of newStates) { + for(const invByLink of nState.links.getMany('inv-by')) { + this.addCacheDependency(resolve(invByLink), state.uri); + } } - const resource = this.resources.get(state.uri); - if (resource) { - // We have a resource for this object, notify it as well. - resource.emit('update', state); + // Store all new caches + for(const nState of newStates) { + this.cache.store(nState); } - for(const embeddedState of state.getEmbedded()) { - // Recursion. MADNESS - this.cacheState(embeddedState); + // Emit 'update' events + for(const nState of newStates) { + const resource = this.resources.get(nState.uri); + if (resource) { + // We have a resource for this object, notify it as well. + resource.emit('update', nState); + } } } @@ -307,3 +315,17 @@ function expandCacheDependencies(uris: Set, dependencies: Map = new Set()): Set { + + result.add(state); + for(const embedded of state.getEmbedded()) { + flattenState(embedded, result); + } + return result; + +}