-
Notifications
You must be signed in to change notification settings - Fork 246
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
Change the store traits so they expose a transactional API #2000
Comments
To explain a bit further, since we do use transactions for all of our writes. Currently all the changes we want to write are first collected into a struct named This was mostly done since sled has an API where you pass in a closure which gets executed as part of a transaction. In this closure you write your values to the db and everybody is happy. But most other databases have a We could change our store traits to reflect this new reality and get rid of the This way, if we need to do reads during a write, they also become part of the transaction. |
Wait, turns out that sqlite implementations for both the crypto store trait and the state store trait make use of sqlite transactions. So it's a non issue, as it's already implemented, or are you suggesting something else? |
I am. If you take a look at the
We have this method, which may or may not open a transaction behind the scenes, our current implementations do so. But we also have some other methods: matrix-rust-sdk/crates/matrix-sdk-crypto/src/store/traits.rs Lines 219 to 228 in d6d19d9
Currently we can't store two custom values in a single transaction. Any reads that may happen before a If we instead have a method in the That being said, none of this is required currently, and the faux transaction using The above change to our store traits has been previously suggested by @jplatte, so he may have even more concrete ideas. |
This adds a new `StoreTransaction` type, that wraps a `StoreCache` and a `Store`. The idea is that it will allow write access to the `Store` (and maintains the cache at the same time), while the `Store::cache` method will only give read-only access to the store's content. Another new data type is introduced, `PendingChanges`, that reflects `Changes` but for fields that are properly maintained in the `StoreCache` and that one can write in the `StoreTransaction`. In the future, it wouldn't be possible to use `save_pending_changes` from the outside of a `StoreTransaction` context. The layering is the following: - `Store` wraps the `DynCryptoStore`, contains a reference to a `StoreCache`. - When read-only access is sufficient, one can get a handle to the cache with `Store::cache()`. - When a write happens, then one can create a `StoreTransaction` (later, only one at a time will be allowed, by putting the `StoreCache` behind a `RwLock`; this has been deferred to not make the PR grow too much). - Any field in the `StoreCache` will get a method to get a reference to the cached thing: it will either load from the DB if not cached, or return the previously cached value. - Any field that can be written to will get a method to get a mutable reference in the `StoreTransaction`: it will either load from the cache into a `PendingChanges` scratch pad, or return the scratchpad temporary value. - When a `StoreTransaction::commit()` happens, fields are backpropagated into the DB *and* the cache. Then, this `StoreTransaction` is used to update a `ReadOnlyAccount` in multiple places (and usage of `ReadOnlyAccount` is minimized so as not to require a transaction or cache function call as much as possible). With this, the read-only account only exists transiently, and it's only stored long-term in the cache. Followup PRs include: - making the `ReadOnlyAccount` not cloneable - remove inner mutability from the `ReadOnlyAccount` - add a `RwLock` on the `StoreTransaction` Part of #2624 + #2000. --- * crypto: Replace some uses of `ReadOnlyAccount` with `StaticAccountData` and identify tests * crypto: introduce `StoreTransaction` to modify a `ReadOnlyAccount` * crypto: introduce `save_pending_changes`, aka `save_changes` v2 * crypto: Start using `StoreTransaction`s to save the account, get rid of `Store::save_account` + `Account::save` * crypto: use `StoreTransaction` to save an account in `keys_for_upload` * crypto: use `StoreTransaction` and the cache in more places * crypto: remove `Account` from the `Changes` \o/ * crypto: remove last (test-only) callers of `Store::account()` * crypto: move `ReadOnlyAccount` inside the cache only * crypto: use `ReadOnlyAccount` and `Account` in fewer places whenever we can use `StaticAccountData` in place. * crypto: make tests rely less on OlmMachine * crypto: Don't put the `ReadOnlyAccount` behind a RwLock just yet + clippy
You have to be careful with IndexedDB transactions: in particular you can't keep them open indefinitely; they will terminate as soon as you stop giving them work to do, so you can't do any (Indeed, IndexedDB's actual API also takes closures that you pass into IndexedDB to be executed as part of the transaction. |
We no longer believe this approach is correct. |
This would increase robustness in the case of the two sync loops, so that we're sure that there aren't any partial write to the db that the main loop consumer would try to read later.
The text was updated successfully, but these errors were encountered: