Skip to content

Commit

Permalink
Add options.preserveCanon to cache.gc method.
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamn committed Jun 23, 2021
1 parent 44a4955 commit f7d7413
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
17 changes: 15 additions & 2 deletions src/cache/inmemory/__tests__/entityStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,19 +200,32 @@ describe('EntityStore', () => {
},
});

// Nothing left to garbage collect, but let's also reset the result cache to
// Nothing left to collect, but let's also reset the result cache to
// demonstrate that the recomputed cache results are unchanged.
const originalReader = cache["storeReader"];
expect(cache.gc({
resetResultCache: true,
})).toEqual([]);
expect(cache["storeReader"]).not.toBe(originalReader);
const resultAfterResetResultCache = cache.readQuery({ query });
expect(resultAfterResetResultCache).toBe(resultBeforeGC);
expect(resultAfterResetResultCache).toBe(resultAfterGC);

// Now discard cache.storeReader.canon as well.
expect(cache.gc({
resetResultCache: true,
preserveCanon: false,
})).toEqual([]);

const resultAfterFullGC = cache.readQuery({ query });
expect(resultAfterFullGC).toEqual(resultBeforeGC);
expect(resultAfterFullGC).toEqual(resultAfterGC);
// These !== relations are triggered by the resetResultCache:true option
// These !== relations are triggered by the preserveCanon:false option
// passed to cache.gc, above.
expect(resultAfterFullGC).not.toBe(resultBeforeGC);
expect(resultAfterFullGC).not.toBe(resultAfterGC);
// Result caching immediately begins working again after the intial reset.
expect(cache.readQuery({ query })).toBe(resultAfterFullGC);

// Go back to the pre-GC snapshot.
cache.restore(snapshot);
Expand Down
20 changes: 16 additions & 4 deletions src/cache/inmemory/inMemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
this.resetResultCache();
}

private resetResultCache() {
private resetResultCache(preserveCanon = true) {
const previousReader = this.storeReader;

// The StoreWriter is mostly stateless and so doesn't really need to be
// reset, but it does need to have its writer.storeReader reference updated,
// so it's simpler to update this.storeWriter as well.
Expand All @@ -119,6 +121,11 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
cache: this,
addTypename: this.addTypename,
resultCacheMaxSize: this.config.resultCacheMaxSize,
canon: (
preserveCanon &&
previousReader &&
previousReader["canon"]
) || void 0,
}),
);

Expand Down Expand Up @@ -269,14 +276,19 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
};
}

// Request garbage collection of unreachable normalized entities.
public gc(options?: {
// If true, also free non-essential result cache memory by bulk-releasing
// this.{store{Reader,Writer},maybeBroadcastWatch}. Defaults to false.
resetResultCache?: boolean;
// If resetResultCache is true, this.storeReader.canon will be preserved by
// default, but can also be discarded by passing false for preserveCanon.
// Defaults to true, but has no effect if resetResultCache is false.
preserveCanon?: boolean;
}) {
canonicalStringify.reset();
const ids = this.optimisticData.gc();
if (options && options.resetResultCache) {
this.resetResultCache();
if (options && options.resetResultCache && !this.txCount) {
this.resetResultCache(options.preserveCanon);
}
return ids;
}
Expand Down

0 comments on commit f7d7413

Please sign in to comment.