Skip to content

Commit f290c8d

Browse files
committed
Maintain the global ttl for refreshing routing tables, even if we ask for routing tables different from the one used in the connect configuration
1 parent 97b71be commit f290c8d

File tree

2 files changed

+23
-14
lines changed

2 files changed

+23
-14
lines changed

lib/src/routing/connection_registry.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl Default for ConnectionRegistry {
7171
}
7272
}
7373

74-
async fn refresh_routing_tables(
74+
async fn refresh_all_routing_tables(
7575
config: Config,
7676
connection_registry: Arc<ConnectionRegistry>,
7777
provider: Arc<dyn RoutingTableProvider>,
@@ -200,7 +200,7 @@ pub(crate) fn start_background_updater(
200200
// This thread is in charge of refreshing the routing table periodically
201201
tokio::spawn(async move {
202202
let mut bookmarks = vec![];
203-
let mut ttl = refresh_routing_tables(
203+
let mut ttl = refresh_all_routing_tables(
204204
config_clone.clone(),
205205
registry.clone(),
206206
provider.clone(),
@@ -210,12 +210,14 @@ pub(crate) fn start_background_updater(
210210
.expect("Failed to get routing table. Exiting...");
211211
debug!("Starting background updater with TTL: {}", ttl);
212212
let mut interval = tokio::time::interval(Duration::from_secs(ttl));
213+
let now = std::time::Instant::now();
213214
interval.tick().await; // first tick is immediate
214215
loop {
215216
tokio::select! {
216217
// Trigger periodic updates
217218
_ = interval.tick() => {
218-
ttl = match refresh_routing_tables(config_clone.clone(), registry.clone(), provider.clone(), bookmarks.as_slice()).await {
219+
debug!("Refreshing all routing tables ({})", registry.databases.len());
220+
ttl = match refresh_all_routing_tables(config_clone.clone(), registry.clone(), provider.clone(), bookmarks.as_slice()).await {
219221
Ok(ttl) => ttl,
220222
Err(e) => {
221223
debug!("Failed to refresh routing table: {}", e);
@@ -228,16 +230,24 @@ pub(crate) fn start_background_updater(
228230
match cmd {
229231
Some(RegistryCommand::RefreshSingleTable((db, new_bookmarks))) => {
230232
let db_name = db.as_ref().map(|d| d.to_string()).unwrap_or_default();
233+
debug!("Forcing refresh of routing table for database: {}", db_name);
231234
bookmarks = new_bookmarks;
232235
ttl = match refresh_routing_table(&config_clone, &registry.pool_registry, provider.clone(), bookmarks.as_slice(), db).await {
233236
Ok(table) => {
234237
registry.databases.insert(db_name.clone(), table.resolve());
235-
debug!("Successfully refreshed routing table for database {}", db_name);
236-
table.ttl
238+
// we don't want to lose the initial TTL synchronization: if the forced update is triggered,
239+
// we derive the TTL from the initial time. Example:
240+
// if the TTL is 60 seconds and the forced update is triggered after 10 seconds,
241+
// we want to set the TTL to 50 seconds, so that the next update will be in 50 seconds
242+
ttl - (now.elapsed().as_secs() % table.ttl)
237243
}
238244
Err(e) => {
239245
debug!("Failed to refresh routing table: {}", e);
240-
ttl
246+
// we don't want to lose the initial TTL synchronization: if the forced update is triggered,
247+
// we derive the TTL from the initial time. Example:
248+
// if the TTL is 60 seconds and the forced update is triggered after 10 seconds,
249+
// we want to set the TTL to 50 seconds, so that the next update will be in 50 seconds
250+
ttl - (now.elapsed().as_secs() % ttl)
241251
}
242252
};
243253
}
@@ -250,7 +260,8 @@ pub(crate) fn start_background_updater(
250260
}
251261

252262
debug!("Resetting interval with TTL: {}", ttl);
253-
interval = tokio::time::interval(Duration::from_secs(ttl)); // recreate interval with the new TTL
263+
// recreate interval with the new TTL or the derived one in case of a forced update
264+
interval = tokio::time::interval(Duration::from_secs(ttl));
254265
interval.tick().await;
255266
}
256267
});
@@ -295,8 +306,6 @@ impl ConnectionRegistry {
295306
.map(|entry| entry.value().clone())
296307
.unwrap_or_default()
297308
} else {
298-
debug!("Creating new registry for database: {}", db_name);
299-
self.databases.insert(db_name.clone(), Vec::new());
300309
vec![]
301310
}
302311
}
@@ -409,7 +418,7 @@ mod tests {
409418
tls_config: ConnectionTLSConfig::None,
410419
};
411420
let registry = Arc::new(ConnectionRegistry::default());
412-
let ttl = refresh_routing_tables(
421+
let ttl = refresh_all_routing_tables(
413422
config.clone(),
414423
registry.clone(),
415424
Arc::new(TestRoutingTableProvider::new(&[cluster_routing_table])),
@@ -525,7 +534,7 @@ mod tests {
525534
cluster_routing_table_1,
526535
cluster_routing_table_2,
527536
]));
528-
refresh_routing_tables(config.clone(), registry.clone(), provider.clone(), &[])
537+
refresh_all_routing_tables(config.clone(), registry.clone(), provider.clone(), &[])
529538
.await
530539
.unwrap();
531540

@@ -535,7 +544,7 @@ mod tests {
535544

536545
let _ = registry.servers(Some("db1".into())); // ensure db1 is initialized
537546
let _ = registry.servers(Some("db2".into())); // ensure db2 is initialized
538-
let ttl = refresh_routing_tables(config.clone(), registry.clone(), provider.clone(), &[])
547+
let ttl = refresh_all_routing_tables(config.clone(), registry.clone(), provider.clone(), &[])
539548
.await
540549
.unwrap();
541550

lib/src/routing/routed_connection_manager.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl RoutedConnectionManager {
5454
) -> Result<ManagedConnection, Error> {
5555
let op = operation.unwrap_or(Operation::Write);
5656
let registry = self.connection_registry.servers(db.clone());
57-
// If the registry is empty, we need to refresh the routing table
57+
// If the registry is empty, we need to refresh the routing table immediately
5858
if registry.is_empty() {
5959
debug!("Routing table is empty, refreshing");
6060
if let Err(error) = self
@@ -80,7 +80,7 @@ impl RoutedConnectionManager {
8080
tokio::time::sleep(Duration::from_millis(10)).await;
8181
attempts += 10;
8282
if attempts > ROUTING_TABLE_MAX_WAIT_TIME_MS {
83-
// 5 seconds max wait time by default
83+
// 5 seconds max wait time by default (we don't want to block forever)
8484
error!(
8585
"Failed to get a connection after {} seconds, routing table is still empty",
8686
ROUTING_TABLE_MAX_WAIT_TIME_MS / 1000

0 commit comments

Comments
 (0)