Skip to content
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

Perf: use idb-keyval #293

Merged
merged 5 commits into from
Aug 21, 2023
Merged

Perf: use idb-keyval #293

merged 5 commits into from
Aug 21, 2023

Conversation

hannojg
Copy link
Contributor

@hannojg hannojg commented Aug 3, 2023

Details

While investigating performance issues on large accounts we found an issue where storing large amounts of data in onyx takes a very long time (E.g. merging the data from a OpenApp command).
Largely this was due to the underlying storage provider opening a new database transaction for every operation in a multiMerge/multiSet operation.
The idb-keyval package optimises this, as it can handle multiple operations in one database transaction.
The good thing is, that idb-keyval also uses indexedDB as storage provider, so no migration is needed.

I created a performance comparison tool, and it showed how much better idb-keyval performs:

Each operation has been executed with 10,000 items (depth 1), which has a size of ~2.3MB

Operation Onyx w/ Localforage Onyx w/ idb-keyval Improvement in %
Single Set 42ms 36ms -14%
Get (collection) 26ms 11ms -58%
MergeCollection 57926ms 775ms -99%
Single Merge 48ms 30ms -38%
How to run the performance tests yourself:

  1. Hop on this branch (its on our fork, sorry)
  2. cd example
  3. npm i
  4. npm start
  5. Open in your web browser http://localhost:8080
Screenshot 2023-08-03 at 16 45 41

For the product the results can be seen in this video:

https://expensify.slack.com/archives/C035J5C9FAP/p1691063111819169

Related Issues

#281

Automated Tests

Linked PRs

@hannojg hannojg requested a review from a team as a code owner August 3, 2023 14:46
@melvin-bot melvin-bot bot requested review from MonilBhavsar and removed request for a team August 3, 2023 14:46
MonilBhavsar
MonilBhavsar previously approved these changes Aug 8, 2023
Copy link
Contributor

@MonilBhavsar MonilBhavsar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Any idea how can we test this in product? 🚀

lib/storage/WebStorage.js Show resolved Hide resolved
@MonilBhavsar MonilBhavsar requested a review from marcaaron August 8, 2023 17:34
@MonilBhavsar
Copy link
Contributor

@marcaaron could you please review, as you have better context of the issue

@marcaaron
Copy link
Contributor

Looks great! Any idea how can we test this in product?

I would try this:

  1. Run npm build from inside react-native-onyx
  2. Replace the /dist folder in App/node_modules/react-native-onyx
  3. Use the production API proxy in the .env file
  4. Sign in with an account that is completely buggered and has tons of reports + policies
  5. See if it improves performance

Copy link
Contributor

@marcaaron marcaaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should just remove all traces of localforage if nothing will use it? 🤔

import fastMerge from '../../fastMerge';

// Same config as localforage, so we can swap the providers easily
const customStore = createStore('OnyxDB', 'keyvaluepairs');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirming: This will have the existing data from the current DB previously set up by localforage?

Copy link
Contributor Author

@hannojg hannojg Aug 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes exactly 😊 It can just be replaced in place

@hannojg
Copy link
Contributor Author

hannojg commented Aug 10, 2023

@marcaaron You mean to delete the provider file?

@marcaaron
Copy link
Contributor

You mean to delete the provider file?

👍

@hannojg
Copy link
Contributor Author

hannojg commented Aug 11, 2023

Alright, I removed all traces of local forage 😊

@parasharrajat
Copy link
Member

parasharrajat commented Aug 11, 2023

Screenshot 2023-08-11 at 9 05 10 PM

Wow...

Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB @hannojg maybe we can benchmark Onyx.clear as well since I know there are some race conditions around it and it's unclear how well the localforage-removeItems plugin ever actually worked

@marcaaron
Copy link
Contributor

oh yeah great thought @roryabraham! adding to that point, I think the place where I see this slowing things down the most is when someone signs out of an account with a ton of data. so we should be sure to A/B test that flow and see if things improved.

@danieldoglas
Copy link
Contributor

maybe we can benchmark Onyx.clear as well since I know there are some race conditions around it and it's unclear how well the localforage-removeItems plugin ever actually worked

I don't think this is blocker for merging this PR since we don't know if the old one actually worked, right?

It would be great to have this merged Today so we can see the benefits for this mostly in Guides and AM accounts

@danieldoglas
Copy link
Contributor

Both of them return 0ms when running Clear

image

image

@hannojg
Copy link
Contributor Author

hannojg commented Aug 15, 2023

Let me fix the benchmark for clearing and give numbers for that 😊 With this implementation deleting / clearing should definitely work

@hannojg
Copy link
Contributor Author

hannojg commented Aug 15, 2023

Clearing seems to be a bit slower with idb-keyval, however the impact doesn't look too dramatic. I think we should be able to optimise it to be on par with local forage. However, I don't think that has too much priority at the moment / blocking this from getting merged?

localforage idb-keyval

(Note: for a lower item count there is almost no difference between the two implementations)

Copy link
Contributor

@mountiny mountiny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hannojg

The changes look good to me and seems like the concerns of Marc and Rory has been addressed as well. I think it would be great to test this one out in the App so given that @danieldoglas and @MonilBhavsar are approving of this too, it could hopefully improve the Guides open app start time masivelly so I will go ahead and merge this and Margelo can put up a PR with the bump

@mountiny mountiny merged commit 42440e1 into Expensify:main Aug 21, 2023
@marcaaron
Copy link
Contributor

While investigating performance issues on large accounts we found an issue where storing large amounts of data in onyx takes a very long time (E.g. merging the data from a OpenApp command).
Largely this was due to the underlying storage provider opening a new database transaction for every operation in a multiMerge/multiSet operation.

Are we sure this is faster than the previous solution of setting one value at a time synchronously? Did we verify that things improved on a large account? Which account did we test with?

The idb-keyval package optimises this, as it can handle multiple operations in one database transaction.

Is is possible we can ask it to do too many at once? I am seeing various weird logs like:

Error: TimeoutError: Transaction timed out due to inactivity.. onyxMethod: Ae ~~ parameters: '' userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.54'

@mountiny
Copy link
Contributor

mountiny commented Sep 3, 2023

I believe @hannojg is on vacation @Szymon20000 Would you be able to look into the above?

@Szymon20000
Copy link
Contributor

I will try but my focus this week is on improving chat switching and batching updates.

@Szymon20000
Copy link
Contributor

Added to my todo list!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

9 participants