Skip to content

Add a value-based lock in the CryptoStores #2049

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

Merged
merged 13 commits into from
Jun 16, 2023

Conversation

bnjbvr
Copy link
Member

@bnjbvr bnjbvr commented Jun 12, 2023

This implements a value-based lock in the crypto stores. The intent is to use that for multiple processes to be able to make writes into the store concurrently, while still cooperating on who does them. In particular, we need this for #1928, since we may have up to two different processes trying to write into the crypto store at the same time.

New methods in the CryptoStore trait

The idea is to introduce two new methods touching custom values in the crypto store:

  • one to atomically insert a value, only if it was missing (so, not following the semantics of upsert used in the set_custom_value)
  • one to atomically remove a custom value

Those two operations match the semantics we want:

  • take the lock only if it ain't taken already == insert an entry only if it was missing
  • release the lock = remove the entry

By looking at the number of lines affected by the query, we can infer whether the insert/remove happened or not, that is, if we managed to take the lock or not.

High-level APIs

I've also added an high-level API, CryptoStoreLock, that helps managing such a lock, and adds some niceties on top of that:

  • exponential backoff to retry attempts at acquiring the lock, when it was already taken
  • attempt to gracefully recover when the lock has been taken by an app that's been killed by the environment
  • full configuration of the key / value / backoff parameters

I've also attempted to make a CryptoStoreLockGuard, that would be RAII struct taking the lock upon creation and releasing it upon drop, but:

  • async Drops are not a thing yet, in native Rust
  • even if we spawn a blocking task that runs the cleanup, we cannot ensure that it will be finished before the next attempt to take a lock. Worst case: it's the same holder trying to take the lock (someone else couldn't take it, they would wait), but then we'd consider the lock as acquired (per the graceful recover semantics), and then the deletion would happen, and then we would panic when deleting it.

As a matter of fact, I think we should probably not have the CryptoStoreLockGuard at all, since it's causing more problems than it fixes. I don't know how big an ergonomic issue it will be, though.

Test program

There's also a test program in which I shamelessly show my rudimentary unix skills; I've put it in the labs/ directory but this could as well be a large integration test. A parent program initially fills a custom crypto store, then creates a pipe() for 1-way communication with a child created with fork(); then the parent sends commands to the child. These commands consist in reading and writing into the crypto store, using a lock. And while the child attempts to perform these operations, the parent tries hard to get the lock at the same time. This helps figuring out a few issues and making sure that cross-process locking would work as intended.

@bnjbvr bnjbvr requested a review from poljar June 12, 2023 13:47
@bnjbvr bnjbvr requested a review from a team as a code owner June 12, 2023 13:47
@bnjbvr
Copy link
Member Author

bnjbvr commented Jun 12, 2023

Haha, the CryptoStoreLockGuard not even building on wasm because we don't have the right primitives there, that's the cherry on top, so I'll get rid of it 👌

Copy link
Contributor

@poljar poljar left a comment

Choose a reason for hiding this comment

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

Looks mostly good, left a couple of nits and some questions.

@codecov
Copy link

codecov bot commented Jun 15, 2023

Codecov Report

Patch coverage: 36.98% and project coverage change: -0.18 ⚠️

Comparison is base (db5c9d8) 76.01% compared to head (38dfb91) 75.84%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2049      +/-   ##
==========================================
- Coverage   76.01%   75.84%   -0.18%     
==========================================
  Files         151      152       +1     
  Lines       16581    16654      +73     
==========================================
+ Hits        12604    12631      +27     
- Misses       3977     4023      +46     
Impacted Files Coverage Δ
crates/matrix-sdk-crypto/src/store/error.rs 0.00% <ø> (ø)
crates/matrix-sdk-crypto/src/store/locks.rs 0.00% <0.00%> (ø)
crates/matrix-sdk-crypto/src/store/memorystore.rs 76.85% <0.00%> (-4.02%) ⬇️
crates/matrix-sdk-crypto/src/store/mod.rs 74.68% <ø> (ø)
crates/matrix-sdk-crypto/src/store/traits.rs 60.00% <0.00%> (-3.94%) ⬇️
...s/matrix-sdk-crypto/src/store/integration_tests.rs 100.00% <100.00%> (ø)
crates/matrix-sdk-sqlite/src/crypto_store.rs 91.65% <100.00%> (+0.33%) ⬆️

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@bnjbvr bnjbvr force-pushed the insert-custom-value-if-missing branch from 9674be7 to 1a6e382 Compare June 15, 2023 16:48
@bnjbvr bnjbvr mentioned this pull request Jun 15, 2023
11 tasks
Copy link
Contributor

@poljar poljar left a comment

Choose a reason for hiding this comment

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

I think this is mostly fine, if you think the enum idea is not worth it then feel free to proceed.

bnjbvr added 2 commits June 16, 2023 14:03
Signed-off-by: Benjamin Bouvier <[email protected]>
@bnjbvr bnjbvr enabled auto-merge (squash) June 16, 2023 12:17
@bnjbvr bnjbvr merged commit 76ed351 into matrix-org:main Jun 16, 2023
@bnjbvr bnjbvr deleted the insert-custom-value-if-missing branch June 16, 2023 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants