Skip to content

Commit

Permalink
QueryRouter: route to primary when locks exists (select for update) (#…
Browse files Browse the repository at this point in the history
…782)

Authored-by: Javier Goday <[email protected]>
  • Loading branch information
drdrsh authored Aug 30, 2024
1 parent 81933b9 commit 29a476e
Showing 1 changed file with 29 additions and 2 deletions.
31 changes: 29 additions & 2 deletions src/query_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,12 @@ impl QueryRouter {
None => (),
};

// If we already visited a write statement, we should be going to the primary.
if !visited_write_statement {
let has_locks = !query.locks.is_empty();

if has_locks {
self.active_role = Some(Role::Primary);
} else if !visited_write_statement {
// If we already visited a write statement, we should be going to the primary.
self.active_role = match self.primary_reads_enabled() {
false => Some(Role::Replica), // If primary should not be receiving reads, use a replica.
true => None, // Any server role is fine in this case.
Expand Down Expand Up @@ -1158,6 +1162,29 @@ mod test {
}
}

#[test]
fn test_select_for_update() {
QueryRouter::setup();
let mut qr = QueryRouter::new();
qr.pool_settings.query_parser_read_write_splitting = true;

let queries_in_primary_role = vec![
simple_query("BEGIN"), // Transaction start
simple_query("SELECT * FROM items WHERE id = 5 FOR UPDATE"),
simple_query("UPDATE items SET name = 'pumpkin' WHERE id = 5"),
];

for query in queries_in_primary_role {
assert!(qr.infer(&qr.parse(&query).unwrap()).is_ok());
assert_eq!(qr.role(), Some(Role::Primary));
}

// query without lock do not change role
let query = simple_query("SELECT * FROM items WHERE id = 5");
assert!(qr.infer(&qr.parse(&query).unwrap()).is_ok());
assert_eq!(qr.role(), None);
}

#[test]
fn test_infer_primary_reads_enabled() {
QueryRouter::setup();
Expand Down

0 comments on commit 29a476e

Please sign in to comment.