-
Notifications
You must be signed in to change notification settings - Fork 74
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
Don't remove nulls in cache merge #411
Don't remove nulls in cache merge #411
Conversation
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.
I think the code is fine but i thought we were using null to clear unused onyx data to free up memory so I'm unsure if this code would cause a negative impact.
Either way I'll let @marcaaron also review since he's more familiar here.
Sorry, I am not sure what this means. Is there more context? Can you show where we are removing the |
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.
@chiragsalian maybe we can get more eyes on this one. I don't have the bandwidth to help validate this right now, but left some comments.
@@ -121,7 +121,7 @@ class OnyxCache { | |||
|
|||
// lodash adds a small overhead so we don't use it here | |||
// eslint-disable-next-line prefer-object-spread, rulesdir/prefer-underscore-method | |||
this.storageMap = Object.assign({}, utils.fastMerge(this.storageMap, data)); | |||
this.storageMap = Object.assign({}, utils.fastMerge(this.storageMap, data, false)); |
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.
Does this mean we would just leave in the storage map a bunch of keys with null
and never delete them? I think it does.
It is a bit hard to wrap one's head around what the side effects of this change would be 😄
One possible problem is here:
Lines 125 to 129 in cd54318
function get(key) { | |
// When we already have the value in cache - resolve right away | |
if (cache.hasCacheForKey(key)) { | |
return Promise.resolve(cache.getValue(key)); | |
} |
Since a value that we are setting again after deleting previously would be undefined
but now would be regarded as null
so we would not check to see if it should be read from storage.
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.
We will have more null values in cache storage yes, but this is only the in memory cache and not the persisted storage so I think it is fine to speedup lookup of values that we know do not exist in storage.
The behavior for deleted values should not change since the cache has a drop method which should be used to remove values completely. The only case I know of that we remove values from cache so they will be fetched from storage again is
react-native-onyx/lib/OnyxCache.js
Line 185 in cd54318
removeLeastRecentlyUsedKeys() { |
I hope that clears up any confusion.
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.
it is fine to speedup lookup of values that we know do not exist in storage.
That's a good point - I was thinking more along the lines of whether this could lead to anything unexpected e.g. could it somehow be possible for the value to exist in storage, but still null
in the cache? But doesn't seem likely.
at the very least I think we should do some testing for this PR against the App |
Sorry I think this PR lacked a little bit more context around this change. The idea was to improve Onyx caching by caching This PR is a bug fix since calling merge will wipe all |
@chiragsalian We have a method that clears least recently used keys from cache, but it doesn't use the merge method that is affected here, the cache has a drop method which should be used to fully remove items from cache and cause them to be fetched again from storage. Also note this is only the caching layer and doesn't affect persisted storage. |
@chiragsalian @marcaaron Thanks for having a look, lmk if there's anything I forgot to address. |
I think there is a subtle difference here. null is used to clear onyx data to free up disk space, not memory. To my knowledge, we haven't done much with optimizing memory.
I definitely always agree with this one (I have learned my own hard lessons from it). To alleviate this concern a little bit, this PR is coming immediately on the heels of doing a lot of extensive in-app testing and it fixes one of the last remaining bugs that was found which prevents Onyx from being updated in App. |
More context around the discussion and testing was in this Slack thread. |
Thanks for the thorough explanation @janicduplessis. With the additional context there are no blocking concerns from me. |
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.
Thank you for the explanation indeed
Sorry for the late reply! I also don't think there's anything wrong with this PR, as long as it's only for the cache 👍 @janicduplessis |
Details
When merging cache we should not remove null values, they are useful to know an item was fetched but doesn't exist.
Related Issues
#408 (comment)
Automated Tests
Added a unit test to assert behaviour of null values in OnyxCache.
Manual Tests
Tested in Expensify app and made sure the money request button renders at the same time as the rest of the header.
Author Checklist
### Related Issues
section aboveTests
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Web
Mobile Web - Chrome
Mobile Web - Safari
Desktop
iOS
Android