akita icon indicating copy to clipboard operation
akita copied to clipboard

EntityDirtyCheckPlugin is extremely slow in larger (>1000 entities) stores

Open zozo8 opened this issue 4 years ago • 3 comments

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ x ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:

Current behavior

If you try to execute EntityDirtyCheckPlugin.reset() (no params!) method with store having larger (>1000) amount of entries, procedure is very slow, and grows exponentially.

Expected behavior

EntityDirtyCheckPlugin should be tracking dirty state of each entry (can do it on demand) and revert value only for dirty elements. Otherwise, it could execute diff function first, then update values (it looks it updates all values, no matter if they were dirty or not). It would be nice to get something like "selectDirty()" as side effect, what gives array of currently dirty IDs.

Minimal reproduction of the problem with instructions

https://stackblitz.com/edit/akita-store-tuvxrd Please press edit, then reset buttons. Enter todo.service.ts and play with for loop value

What is the motivation / use case for changing the behavior?

I have bigger table of data on UI side, with few editable columns and commit/cancel buttons. Commit should get diff and commit changes, cancel should revert changes before editing. The table allows edit in multiple rows and value is commited once when user decides to (it could be after editing single record or multiple records).

Environment


Angular version: X.Y.Z


Browser:
- [ x ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: XX  
- Platform:  

Others:

zozo8 avatar Oct 07 '21 19:10 zozo8

EntityDirtyCheckPlugin maintains a DirtyCheckPlugin for every entity.
EntityDirtyCheckPlugin.reset() calls DirtyCheckPlugin.reset() for each DirtyCheckPlugin. each DirtyCheckPlugin.reset() calls AkitaPlugin.updateStore() AkitaPlugin.updateStore() calls EntityStore.update() EntityStore.update() calls updateEntities(), which iterates over every entity AGAIN in this segment: entities: { ...stateEntities, ...updatedEntities }

This is O(n^2). We may be able improve this to O(n) if we used upsertMany() inside EntityDirtyCheckPlugin.reset().

TreyVigus avatar Nov 06 '21 21:11 TreyVigus

You are welcome to submit a PR

NetanelBasal avatar Nov 07 '21 09:11 NetanelBasal

will do once I get some free time

TreyVigus avatar Nov 08 '21 13:11 TreyVigus