Repository navigation
Conversation
Contributor
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Details
Every
Onyx.set(andmultiSet,setCollection, new members inmergeCollection) runsremoveNestedNullValuesover the whole value before caching and storing it. The App rewrites some large values after almost every update, for example derived values that hold one entry per report, so each write walks the entire object even when only one field changed.Since #765, values built from the cached one keep the same object reference for every subtree that didn't change. This PR uses that:
Skip subtrees the cache already holds.
removeNestedNullValues(value, nullFreeReference)takes the current cached value and returns any nested object that is the same reference as in the cache as is, without walking it. The cache holds it, so it has no nulls. The returned objects are exactly the same as before (same references, same values), so subscribers get the same values and notifications.setWithRetrypasses the existing value,prepareKeyValuePairsForStoragepassescache.get(key).Close the four paths that put nested nulls into the cache today, since step 1 relies on the cache being null-free:
mergeObjectnow cleans the replacement object whenshouldRemoveNestedNullsis set (lib/utils.ts).OnyxUtils.get()cleans the value read from storage before caching it (SQLiteJSON_REPLACEcan leave nulls).multiGetnow hands out what the cache holds aftercache.merge(temp), so callers and cache agree (lib/OnyxUtils.ts).cache.set(lib/Onyx.ts).Onyx.clear(): default key states are cleaned beforecache.set. For example the App's default foraccountis{errors: null, ...}, so after a clear subscribers saw anerrorskey that every other path omits (lib/Onyx.ts).On these paths subscribers now get an omitted key instead of
{key: null}, the same as on every other path.Dev-only guard. If a skipped subtree does hold nulls, App code mutated a cached object in place, which Onyx doesn't support. In development this logs an alert, so it is caught early. In production the check is skipped, because it would need the walk this PR removes.
Prior work:
skipNullRemoval(#655, #659) was removed in #666 because the App mutated shared nested objects. This PR still removes nulls from everything that changed and only skips subtrees that are the same reference as the cache. Draft #751 removes null pruning entirely, which would change what subscribers receive. This PR doesn't.Results (release builds, heavy test account, median before vs. after, 8 runs per variant on an iOS simulator and 6 on an Android emulator):
After release, the place to look in Sentry is
StartupData.Applyfor ReconnectApp.Related Issues
GH_LINK
Linked E/App PR
Automated Tests
utilsTest.ts:removeNestedNullValueswith a reference. It returns the same output as without one for any null-free reference on randomized (seeded) inputs, returns the reference itself as is, doesn't traverse shared subtrees, still removes nulls from subtrees that differ, and ignores references that aren't plain objects. Also covers the replace branch ofmergeObjectcleaning only whenshouldRemoveNestedNullsis true.onyxTest.ts(null-free cache): the native replace branch and a batched remove-then-replace update, values read from storage,multiGethanding out the cleaned cached value,setandmultiSetkeeping cached subtrees while removing new nulls, the dev alert on a mutated shared subtree, and a randomized test that runs sequences ofset,merge,multiSet,mergeCollectionandupdatewith nested nulls and checks that every cached value stays null-free.Manual Tests
removeNestedNullValues skipped a cached subtreealert appears in the dev console.errorskey).