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.
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
Degrade
IndexedDBStore
back to memory only on failure #884Degrade
IndexedDBStore
back to memory only on failure #884Changes from 4 commits
6ba7e85
dd00735
8a2f84b
3eb0c53
389fcfa
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
The idea here is that the next calls to the store still go to
func
, e.g. the idb store method and encounter a closed db, fail, and end up in the catch below degrading to the memory store?I suppose that would work, but seems a bit convoluted.
Just an idea, but have you considered using a
Proxy
(seems well supported) as a meta store to switch between two implementations of the store if one fails?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.
The first time any of the IDB methods marked
degradable
fails, we'll enter the catch block that one time and revert back to being just aMemoryStore
.Not sure if this is clear from the review, but
IndexedDBStore
already extends fromMemoryStore
, so it's not like we're totally transforming into some other unrelated object. We're basically "peeling off" the child layer ofIndexedDBStore
and becoming the parentMemoryStore
only.Future method calls to the IDB store if it degrades will then only run code from
MemoryStore
. The state of the object is already set up for this to work since it extends fromMemoryStore
.I've gotten burned by
Proxy
adding perf overhead in the past, so it didn't come to mind until now... It could work, but I am not sure it would really that much more elegant?Probably we'd need to sprinkle some async / await into the above as well... The "proxies on proxies" usually makes me avoid it.
Are there parts of the current approach I could improve through comments, etc.?
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.
Oh right, I see now. Sorry for being slow on this.
One more thing then: the only method in IndexedDBStore that seems to forward the call to MemoryStore seems to be
deleteAllData
, so the memory store state would be empty for the part that the idb store overrides? The first example I can think of would begetSavedSyncToken
, but feels like there would be more code that calls the store and assume once the app is syncing, the store is not empty? Maybe I'm missing something and the memory store is being updated from somewhere else...W.r.t. commenting, maybe just briefly mentioning above
Object.setPrototypeOf(this, MemoryStore.prototype);
that we're changing the class of this instance to the parent class so future calls get permanently redirected would have helped understand the code faster.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.
Right, after looking at the store code again, I still can't spot where we're updating the memory store from the indexeddbstore mutators. But it doesn't seem like it matters as all the read methods overriden (like you mention) in indexeddbstore only seem to be called during startup, initial sync, ... so they shouldn't be called again while the app is running.
So I guess this is fine. Maybe adjust your comment where it says that the mutators update the memory state if you agree with the above assessment, as it could be a bit misleading...
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 added a comment to explain why it should be safe to fallback to the parent store type.
IndexedDBStore
actually leaves many of the methods fromMemoryStore
as-is without overriding them at all. For basic sync data like rooms and users, the memory state is used to answer things likegetRoom
even in the IDB store. When saving, the IDB callssyncToDatabase
on the backend which uses the sync accumulator to save and totally ignores the data in the store itself.You asked about
getSavedSyncToken
. This one is only used on startup when loading a sync from IDB. Since we are degrading to a memory store, this would returnnull
after degrading, which seems fine. Let's say we managed to read an old cached sync from IDB, but then it degrades at some later time.SyncApi.prototype._syncFromCache
is given the saved sync data, which calls_processSyncResponse
which write to the in-memory part of the store viastoreUser
etc. The in-memory side ofIndexedDBStore
is always being updated even when IDB fully operational. If IDB fails later, we'll just continue with this state we have, so the store won't be empty.However, the extra methods for things like OOB members, etc. don't currently maintain memory state. Let's examine all the mutator methods:
setSyncToken
storeGroup
storeRoom
removeRoom
storeUser
storeEvents
storeFilter
setFilterIdByName
storeAccountDataEvents
setSyncData
setOutOfBandMembers
clearOutOfBandMembers
storeClientOptions
So, it's good that we examined each method here, as it reveals a few to fix! (
clearOutOfBandMembers
was I guess never implemented forMemoryStore
, so that's an extra bug I guess).I have now fixed these new bugs.
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.
Great, thanks for your detailed look! I must indeed have forgotten to implement clearOutOfBandMembers for MemoryStore when working on LL.
Looks good now!