-
Notifications
You must be signed in to change notification settings - Fork 3k
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
[Performance] Report Actions Storage Paging #4506
Comments
Triggered auto assignment to @MonilBhavsar ( |
ATM the problem is amplified by the logic described here: #4027 (comment) Since we have a connection that loads all report action collections and they can grow as much as storage allows:
cc @marcaaron |
Thanks for creating the issue and apologies as it might be some time before I properly review this.
If the problem is that we are loading too many report actions when the app inits we can try to defer that or look into ways to stop doing it entirely. I'd really like to explore some strategies around this before trying to fix this in Onyx. |
This is a secondary problem. The primary problems:
|
OK, I think we are talking about two different problems. "secondary" and "primary" might not be a good way to think about this as it implies one is related to the other and giving this proposal a closer look I see they are not the same. Problem 1: Too Many Report Actions keys are loaded when the app inits Loading too many report actions when the app inits is a problem because it takes a long time to read all of those keys. While, not perfect, I have done a basic test here to show this. So my suggestion is to look into ways to reduce the need to read all of these keys when the app inits. Problem 2: Having a large report as the default report when the app inits causes performance issues This problem seems important and the solution is interesting - but really only affects users who scroll back on a large report or remain logged in for a very long time. I'm having a hard time evaluating the severity or urgency of this. Usually when I test performance I'm not scrolling back on chats or staying logged in for a long time - so there are likely gains to be had before we even start looking into chunking the report actions. |
Correct they are related - if there's no other way but to read the entire chat history opening any chat, then reading all the chats during init makes the problem N times worse You're skipping Problem 3: The entire chat is re-written for each new message I write or receive
The least we could do to address "Problem 3" is to use AsyncStorage.merge which would allow to merge a single action to the collection instead of rewriting the collection as Onyx.merge does. AsyncStorage.merge does not even need to read the collection while Onyx.merge does Is it really too early for this? The chunks idea is something that will work with simple storages like AsyncStorage and MMKV If a fully featured database is use, with a traditional cursor and page size api, then yes implementing the current proposal might be a waste of time |
It can be a hard question to answer, but one guiding Expensify principle that might help to remember is that we try to always think about how this will affect actual customers. Not every apparent problem requires an immediate solution and we're always thinking about the best place to put our limited energy. With that idea in mind, can we continue to optimize android boot time and switching from one chat to another? Once that stuff is reasonably fast we can revisit the less urgent things. You've done some great work and these are solid insights. But we're so close to finishing what we've started and I think we just need to focus up on the critical stuff. I think a good time to revisit this would be sometime after:
Then we can worry about what happens when the initial report has 1000 messages instead of 50 ? |
This issue has not been updated in over 15 days. eroding to Monthly issue. P.S. Is everyone reading this sure this is really a near-term priority? Be brave: if you disagree, go ahead and close it out. If someone disagrees, they'll reopen it, and if they don't: one less thing to do! |
@kidroca, this Monthly task hasn't been acted upon in 6 weeks; closing. If you disagree, feel encouraged to reopen it -- but pick your least important issue to close instead. |
If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!
Overview
The entire conversation of a single Report is stored under a single object that can grow infinitely
When a report is opened this "infinite" information is loaded at once from storage
When the conversation updates the whole conversation is rewritten to storage instead only the delta
Users with more data in storage will have degraded performance compared to users with less data in storage
What performance issue do we need to solve?
What is the impact of this on end-users?
List any benchmarks that show the severity of the issue
Steps
ReportActionView#render
props.reportActions
- they will contain the conversation to the very beginning (1000+ messages)Sample (Web)
Conversation updates
Each time the reportActions update it will cause a massive object to be rewritten to storage. Example:
Onyx#merge
reportActions_{ReportID}
1628430535421518
442
Sample Web
Onyx#merge called with a single action item
Onyx#merge reads the entire collection, merges the item and writes the merged result back to storage
The same thing would happen when new messages arrive, edits are made, or as you scroll to the past
Though we have a check that skips a write to storage if the written collection is structurally the same as the merged changes
This does not skip the merge and comparing the 1000+ messages to find there is no change
Proposed solution (if any)
Instead of storing the entire conversation under a single key/object split the actions to predictable chunks based on their reportID and sequence number
Example using a chunk size of 50 messages
Simplified code
Sequence numbers should be normalised to indexes like 1,2,3 - this already happens
Now when a message is added/edited you can find the chunk that it belongs to and update only that chunk
This also means that when a report is loaded only the most recent chunk is committed to memory. The report general data should have enough information to find the most recent chunkID.
Then as the user scrolls to the past we attempt to load a chunk (or page) of data from network and from storage as well. Changes from network would now be applied to the specific chunk and not the entire collection
Onyx.merge(
${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}, indexedData);
List any benchmarks after implementing the changes to show impacts of the proposed solution (if any)
Note: These should be the same as the benchmarks collected before any changes.
TBD
Platform:
Where is this issue occurring?
Version Number: 1.0.83-0
Logs: https://stackoverflow.com/c/expensify/questions/4856
Notes/Photos/Videos: Any additional supporting documentation
Expensify/Expensify Issue URL:
View all open jobs on Upwork
The text was updated successfully, but these errors were encountered: