This repository has been archived by the owner on Apr 26, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Optimise _update_client_ips_batch_txn
to batch together database operations.
#12252
Merged
+190
−51
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
7cf8b2e
Upsert many client IPs at once, more efficiently
reivilibre c7cfbf5
Newsfile
reivilibre 45c98e0
Add a simple update many txn
reivilibre 0646b4b
Add non-txn simple update many
reivilibre 1acd8cd
Use simple_update_many for devices
reivilibre 1e961ad
Isolate locals by splitting into two smaller functions
reivilibre 503f5c8
Make _dump_to_tuple dump the entire table without undue ceremony
reivilibre 5f29099
Rename some things to clarify
reivilibre e7c4907
Add a test for simple_update_many
reivilibre 5675a94
Add an exception for when the number of value rows and key rows don't…
reivilibre e7985d2
Antilint
reivilibre 7edf6f7
Add lock=True for the emulated many-upsert case
reivilibre 9556aae
Don't double-lock the table
reivilibre 303fba6
Inline column names
reivilibre ac4b1d5
Flatten user_ips builder
reivilibre 34403cb
Flatten devices builder
reivilibre 0f8e98b
Fix up docstring
reivilibre 481b730
Remove dead variable
reivilibre 99e6b66
Don't return for None
reivilibre 3f7f659
Update synapse/storage/database.py
reivilibre 50f2b91
Bail out when there's nothing to do
reivilibre 93e1237
Apply suggestions from code review
reivilibre c0aaec4
Antilint
reivilibre c456958
Lock only once for batch emulated upserts
reivilibre 214aacf
No need to manually lock
reivilibre File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
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 don't think this code is used on postgres though since that doesn't need the emulated support here?
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.
Well, sigh, you're absolutely right. Locking on SQLite is a no-op (apparently! I haven't fully reasoned through how that's sufficient, but the code is a no-op...?!).
Why do upserts have locking at all then? Maybe I made the mistake of assuming that there must have been a reason for it because of the code that was here before...
In one of the cases, an emulated upsert can be a
SELECT
followed by anINSERT
. In the other case, it's anUPDATE
followed by anINSERT
...The latter case (UPDATE, INSERT) doesn't sound like it would need a lock, because both of those operations need a PENDING lock. There's no way another writer can get in the middle of those two.
(Assuming traditional SQLite3 locking) The first case (SELECT, INSERT) may be problematic because
SELECT
only needs a SHARED lock. But it needs to upgrade to a PENDING lock when it begins theINSERT
. If there's another PENDING or stronger lock, it will fail and will need to retry the transaction.I can't tell whether this works properly in WAL mode or not; the WAL docs aren't particularly clear about how transactions interact like the old-style locking page is. That said, the page on transactions has this to say:
Assuming that's still true for WAL mode, then I think it's safe on SQLite.
Ah! However, there's one case where Postgres DOES need the emulated support, so I need to take back some of the things I just wrote :/.
That's when the unique index on the table is not ready yet and the table is 'unsafe to upsert'. (This is only a notable effect with Postgres, since SQLite's indices block when adding; Postgres' are added concurrently sometimes). In that case, locking does serve a useful role because Postgres' MVCC means that duplicates could be introduced (and then lead to the failure of creating the index altogether).
Aside:
user_directory_search
is an eternal exception — it's always 'unsafe to upsert' on SQLite....That turned into something more complex than I thought :/
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 tried this and it seems safe on both WAL and non-WAL mode.
The advantage of WAL mode in this case is that another transaction merely running 'select' and hanging around doesn't prevent you from committing. But that transaction will have to restart (at least if it's in conflict; not sure about generally) — it gets told the database is locked each time it tries to commit or update.
I learnt a bit about SQLite's WAL mode, so that's good at least