Skip to content

Commit 5a5a8db

Browse files
committed
session: prepare: introduce fallback to all shards
Before this commit, we could unnecessarily return an error from prepare: Let's say we have a 1-node cluster, and we have a broken connection, and we don't retry on another - we would retry error to the user despite possibly being able to prepare. This commit introduces fallback logic to `Session::prepare()`: if preparation on a single (random) connection to every node fails, the whole preparation is retried, this time on a single connection to every shard. I'm a bit unhappy that this requires us to clone `statement` on the happy path (i.e., if the on-all-nodes preparation attempt succeeds), but I'm quite convinced it's negligible overhead.
1 parent 1b2d3bc commit 5a5a8db

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

scylla/src/client/session.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -1375,9 +1375,25 @@ impl Session {
13751375
)))
13761376
}
13771377

1378-
let on_all_nodes_result = prepare_on_all(self, statement, cluster_state, false).await?;
1378+
// Start by attempting preparation on a single (random) connection to every node.
1379+
{
1380+
let on_all_nodes_result =
1381+
prepare_on_all(self, statement.clone(), Arc::clone(&cluster_state), false).await?;
1382+
if let Ok(prepared) = on_all_nodes_result {
1383+
// We succeeded in preparing the statement on at least one node. We're done; at the same time,
1384+
// the background tokio task attempts preparation on remaining nodes.
1385+
return Ok(prepared);
1386+
}
1387+
}
13791388

1380-
on_all_nodes_result.map_err(|err| PrepareError::AllAttemptsFailed { first_attempt: err })
1389+
// We could have been just unlucky: we could have possibly chosen random connections all of which were defunct
1390+
// (one possibility is that we targeted overloaded shards).
1391+
// Let's try again, this time on connections to every shard. This is a "last call" fallback.
1392+
{
1393+
let on_all_shards_result = prepare_on_all(self, statement, cluster_state, true).await?;
1394+
on_all_shards_result
1395+
.map_err(|err| PrepareError::AllAttemptsFailed { first_attempt: err })
1396+
}
13811397
}
13821398

13831399
fn extract_partitioner_name<'a>(

0 commit comments

Comments
 (0)