-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Depend on existence of enclosing entity object when reading from cache. #8147
Depend on existence of enclosing entity object when reading from cache. #8147
Conversation
export function maybeDependOnExistenceOfEntity( | ||
store: NormalizedCache, | ||
entityId: string, | ||
) { | ||
if (supportsResultCaching(store)) { | ||
// We use this pseudo-field __exists elsewhere in the EntityStore code to | ||
// represent changes in the existence of the entity object identified by | ||
// entityId. This dependency gets reliably dirtied whenever an object with | ||
// this ID is deleted (or newly created) within this group, so any result | ||
// cache entries (for example, StoreReader#executeSelectionSet results) that | ||
// depend on __exists for this entityId will get dirtied as well, leading to | ||
// the eventual recomputation (instead of reuse) of those result objects the | ||
// next time someone reads them from the cache. | ||
store.group.depend(entityId, "__exists"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, the EntityStore
tries to track dependencies at the field level, so cached result objects don't have to be invalidated if none of their fields have been invalidated, but when the entire object is removed (or added for the first time), that's a more significant event than the removal/addition/modification of individual fields, so maybeDependOnExistenceOfEntity
enables consumers to listen specifically for __exists
invalidations.
ok, I see now how the this change comes together with benjamn/optimism#195. I was under the impression that I need to add a separate I am going to pull all of this down and test it locally and will get back to you tomorrow. Thanks for spending time on this, this looks great! |
src/cache/inmemory/readFromStore.ts
Outdated
this.executeSelectionSet = wrap(options => this.execSelectionSetImpl(options), { | ||
this.executeSelectionSet = wrap(options => { | ||
maybeDependOnExistenceOfEntity( | ||
options.context.store, | ||
options.enclosingRef.__ref, | ||
); | ||
return this.execSelectionSetImpl(options); | ||
}, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's an example of calling maybeDependOnExistenceOfEntity
to make executeSelectionSet
sensitive to the eviction of the enclosing entity object.
Note that options.objectOrReference
(the current object we're executing against) may be an object without an ID, but every object in the cache has some enclosing entity object that does have an ID, which is what options.enclosingRef
refers to.
If that whole enclosing entity object gets evicted, then this particular invocation of executeSelectionSet
will be invalidated, allowing its cached result to be garbage collected.
I ported this to my test app, and I definitely see the effect, but I am not seeing all the entries being evicted. The assumption I have is all once the cache data is fully empty then all created entries should be evicted. A couple of notes:
I realized I should share that test so you can try it yourself. That app was based on |
@sofianhn Just to make sure, did you also apply benjamn/optimism#195 when you were testing? That PR is necessary for the |
Yes, I applied both. That's why I actually saw some entries getting cleaned. Working on a test now that hopefully will capture what I am seeing. |
I updated the testing PR to contain the latest changes from optimism 0.16 |
@sofianhn I think I see what's wrong. This comment is not the full solution, but I wanted to share the news. When dirtied, I would say this behavior is a bug in the (recently added) benjamn/optimism#195 functionality. I'm still thinking through the consequences, and I think there may be a quick/easy solution, but of course we could always switch back to the externally-managed |
605256b
to
86ae9a6
Compare
cda7576
to
457dc65
Compare
Since the Netlify previews don't run for PRs not targeting |
I asked @sofianhn to split up PR #8107 in #8107 (comment), promising a simpler approach to the part unrelated to
resultCacheMaxSize
(the part about invalidating theexecuteSelectionSet
result cache when entities are evicted).After some investigation, I believe we can implement most of this functionality in terms of our existing dependency system, as long as cached methods like
executeSelectionSet
andexecuteSubSelectedArray
register appropriate dependencies.As luck would have it, we were already tracking an internal
__exists
dependency for every normalized object in theEntityStore
(see #5828), so I believe we can reuse that machinery, which will save us from having to guess (at the end of thecache.evict
method) whether or not the whole object was evicted.I believe what's already implemented here will be enough to release the invalidated cache results to be garbage collected, but we do have some additional options to improve memory management even further:
TODO
below)