-
Notifications
You must be signed in to change notification settings - Fork 62
Reduce regions_hard_delete contention #7960
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
jmpesp
merged 3 commits into
oxidecomputer:main
from
jmpesp:regions_hard_delete_cte_contention
Apr 11, 2025
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
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 hidden or 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
This file contains hidden or 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
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| // This Source Code Form is subject to the terms of the Mozilla Public | ||
| // License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| // file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
|
||
| //! Implementation of query to update crucible_dataset size_used after | ||
| //! hard-deleting regions | ||
|
|
||
| use crate::db::datastore::RunnableQueryNoReturn; | ||
| use crate::db::raw_query_builder::QueryBuilder; | ||
| use diesel::sql_types; | ||
| use uuid::Uuid; | ||
|
|
||
| /// Update the affected Crucible dataset rows after hard-deleting regions | ||
| pub fn dataset_update_query( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could probably do with an EXPECTORATE + EXPLAIN test, to make it easier for future changes.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 done in 5522603 |
||
| dataset_ids: Vec<Uuid>, | ||
| ) -> impl RunnableQueryNoReturn { | ||
| let mut builder = QueryBuilder::new(); | ||
|
|
||
| builder.sql( | ||
| "WITH | ||
| size_used_with_reservation AS ( | ||
| SELECT | ||
| crucible_dataset.id AS crucible_dataset_id, | ||
| SUM( | ||
| CASE | ||
| WHEN block_size IS NULL THEN 0 | ||
| ELSE | ||
| CASE | ||
| WHEN reservation_percent = '25' THEN | ||
| (block_size * blocks_per_extent * extent_count) / 4 + | ||
| (block_size * blocks_per_extent * extent_count) | ||
| END | ||
| END | ||
| ) AS reserved_size | ||
| FROM crucible_dataset | ||
| LEFT JOIN region ON crucible_dataset.id = region.dataset_id | ||
| WHERE | ||
| crucible_dataset.time_deleted IS NULL AND | ||
| crucible_dataset.id = ANY (", | ||
| ); | ||
|
|
||
| builder.param().bind::<sql_types::Array<sql_types::Uuid>, _>(dataset_ids); | ||
|
|
||
| builder.sql( | ||
| ") | ||
| GROUP BY crucible_dataset.id | ||
| ) | ||
| UPDATE crucible_dataset | ||
| SET size_used = size_used_with_reservation.reserved_size | ||
| FROM size_used_with_reservation | ||
| WHERE crucible_dataset.id = size_used_with_reservation.crucible_dataset_id", | ||
| ); | ||
|
|
||
| builder.query::<()>() | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod test { | ||
| use super::*; | ||
| use crate::db::explain::ExplainableAsync; | ||
| use crate::db::pub_test_utils::TestDatabase; | ||
| use crate::db::raw_query_builder::expectorate_query_contents; | ||
| use omicron_test_utils::dev; | ||
| use uuid::Uuid; | ||
|
|
||
| // This test is a bit of a "change detector", but it's here to help with | ||
| // debugging too. If you change this query, it can be useful to see exactly | ||
| // how the output SQL has been altered. | ||
| #[tokio::test] | ||
| async fn expectorate_query() { | ||
| let query = | ||
| dataset_update_query(vec![Uuid::nil(), Uuid::nil(), Uuid::nil()]); | ||
|
|
||
| expectorate_query_contents( | ||
| &query, | ||
| "tests/output/dataset_update_query.sql", | ||
| ) | ||
| .await; | ||
| } | ||
|
|
||
| // Explain the possible forms of the SQL query to ensure that it | ||
| // creates a valid SQL string. | ||
| #[tokio::test] | ||
| async fn explainable() { | ||
| let logctx = dev::test_setup_log("explainable"); | ||
| let db = TestDatabase::new_with_pool(&logctx.log).await; | ||
| let pool = db.pool(); | ||
| let conn = pool.claim().await.unwrap(); | ||
|
|
||
| let query = | ||
| dataset_update_query(vec![Uuid::nil(), Uuid::nil(), Uuid::nil()]); | ||
|
|
||
| let _ = query | ||
| .explain_async(&conn) | ||
| .await | ||
| .expect("Failed to explain query - is it valid SQL?"); | ||
|
|
||
| db.terminate().await; | ||
| logctx.cleanup_successful(); | ||
| } | ||
| } | ||
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| WITH | ||
| size_used_with_reservation | ||
| AS ( | ||
| SELECT | ||
| crucible_dataset.id AS crucible_dataset_id, | ||
| sum( | ||
| CASE | ||
| WHEN block_size IS NULL THEN 0 | ||
| ELSE CASE | ||
| WHEN reservation_percent = '25' | ||
| THEN block_size * blocks_per_extent * extent_count / 4 | ||
| + block_size * blocks_per_extent * extent_count | ||
| END | ||
| END | ||
| ) | ||
| AS reserved_size | ||
| FROM | ||
| crucible_dataset LEFT JOIN region ON crucible_dataset.id = region.dataset_id | ||
| WHERE | ||
| crucible_dataset.time_deleted IS NULL AND crucible_dataset.id = ANY ($1) | ||
| GROUP BY | ||
| crucible_dataset.id | ||
| ) | ||
| UPDATE | ||
| crucible_dataset | ||
| SET | ||
| size_used = size_used_with_reservation.reserved_size | ||
| FROM | ||
| size_used_with_reservation | ||
| WHERE | ||
| crucible_dataset.id = size_used_with_reservation.crucible_dataset_id |
Oops, something went wrong.
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.
Yup, makes a lot of sense to have this be much more scoped!