Skip to content

Commit 3bd7799

Browse files
committed
Move bookmarks handling into session
1 parent da6b21c commit 3bd7799

11 files changed

Lines changed: 484 additions & 585 deletions

File tree

ci/Cargo.lock.min

Lines changed: 181 additions & 249 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ci/Cargo.lock.msrv

Lines changed: 155 additions & 223 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,10 @@ pastey = "0.1.0"
4242
pin-project-lite = "0.2.9"
4343
rustls-native-certs = "0.7.3"
4444
rustls-pemfile = "2.1.2"
45-
scc = "3.0.2"
4645
serde = { version = "1.0.185", features = ["derive"] } # TODO: eliminate derive
4746
serde_json = { version = "1.0.0", optional = true }
4847
thiserror = "1.0.7"
49-
time = { version = "0.3.22", optional = true }
48+
time = { version = "=0.3.22", optional = true }
5049
tokio = { version = "1.5.0", features = ["full"] }
5150
url = "2.0.0"
5251

lib/src/graph.rs

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
22
use {
33
crate::connection::{ConnectionInfo, Routing},
4-
crate::graph::ConnectionPoolManager::Routed,
54
crate::routing::{ClusterRoutingTableProvider, RoutedConnectionManager},
65
crate::summary::ResultSummary,
76
log::debug,
87
std::sync::Arc,
98
};
109

1110
use crate::config::ImpersonateUser;
12-
use crate::graph::ConnectionPoolManager::Direct;
1311
use crate::pool::ManagedConnection;
1412
use crate::query::RetryableQuery;
1513
use crate::retry::Retry;
1614
use crate::RunResult;
17-
use crate::{config::{Config, ConfigBuilder, Database, LiveConfig}, errors::Result, pool::{create_pool, ConnectionPool}, query::Query, stream::DetachedRowStream, txn::Txn, Operation};
15+
use crate::{
16+
config::{Config, ConfigBuilder, Database, LiveConfig},
17+
errors::Result,
18+
pool::{create_pool, ConnectionPool},
19+
query::Query,
20+
stream::DetachedRowStream,
21+
txn::Txn,
22+
Operation,
23+
};
1824
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
1925
use crate::{
2026
session::{Session, SessionConfig},
@@ -41,16 +47,18 @@ impl ConnectionPoolManager {
4147
) -> Result<ManagedConnection> {
4248
match self {
4349
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
44-
Routed(manager) => manager.get(operation, db, imp_user, bookmarks).await,
45-
Direct(pool) => pool.get().await.map_err(crate::Error::from),
50+
ConnectionPoolManager::Routed(manager) => {
51+
manager.get(operation, db, imp_user, bookmarks).await
52+
}
53+
ConnectionPoolManager::Direct(pool) => pool.get().await.map_err(crate::Error::from),
4654
}
4755
}
4856

4957
fn backoff(&self) -> ExponentialBuilder {
5058
match self {
5159
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
52-
Routed(manager) => manager.backoff(),
53-
Direct(pool) => pool.manager().backoff(),
60+
ConnectionPoolManager::Routed(manager) => manager.backoff(),
61+
ConnectionPoolManager::Direct(pool) => pool.manager().backoff(),
5462
}
5563
}
5664
}
@@ -84,7 +92,7 @@ impl Graph {
8492
)?;
8593
if matches!(info.init.routing, Routing::Yes(_)) {
8694
debug!("Routing enabled, creating a routed connection manager");
87-
let pool = Routed(RoutedConnectionManager::new(
95+
let pool = ConnectionPoolManager::Routed(RoutedConnectionManager::new(
8896
&config,
8997
Arc::new(ClusterRoutingTableProvider::new(config.clone())),
9098
)?);
@@ -93,7 +101,7 @@ impl Graph {
93101
pool,
94102
})
95103
} else {
96-
let pool = Direct(create_pool(&config)?);
104+
let pool = ConnectionPoolManager::Direct(create_pool(&config)?);
97105
Ok(Graph {
98106
config: config.into_live_config(),
99107
pool,
@@ -102,7 +110,7 @@ impl Graph {
102110
}
103111
#[cfg(not(feature = "unstable-bolt-protocol-impl-v2"))]
104112
{
105-
let pool = Direct(create_pool(&config)?);
113+
let pool = ConnectionPoolManager::Direct(create_pool(&config)?);
106114
Ok(Graph {
107115
config: config.into_live_config(),
108116
pool,
@@ -194,7 +202,7 @@ impl Graph {
194202
{
195203
Txn::new(
196204
db,
197-
fetch_size.or(Some(self.config.fetch_size)).unwrap(),
205+
fetch_size.unwrap_or(self.config.fetch_size),
198206
connection,
199207
operation,
200208
imp_user,
@@ -247,14 +255,26 @@ impl Graph {
247255
db: impl Into<Database>,
248256
q: impl Into<Query>,
249257
) -> Result<ResultSummary> {
250-
self.impl_run_on(Some(db.into()), self.config.imp_user.clone(), &[], Some(self.config.fetch_size), q.into())
251-
.await
258+
self.impl_run_on(
259+
Some(db.into()),
260+
self.config.imp_user.clone(),
261+
&[],
262+
Some(self.config.fetch_size),
263+
q.into(),
264+
)
265+
.await
252266
}
253267

254268
#[cfg(not(feature = "unstable-bolt-protocol-impl-v2"))]
255269
pub async fn run_on(&self, db: impl Into<Database>, q: impl Into<Query>) -> Result<()> {
256-
self.impl_run_on(Some(db.into()), self.config.imp_user.clone(), &[], Some(self.config.fetch_size), q.into())
257-
.await
270+
self.impl_run_on(
271+
Some(db.into()),
272+
self.config.imp_user.clone(),
273+
&[],
274+
Some(self.config.fetch_size),
275+
q.into(),
276+
)
277+
.await
258278
}
259279

260280
#[allow(unused_variables)]
@@ -284,40 +304,20 @@ impl Graph {
284304
.await;
285305

286306
match result {
287-
Ok(result) => {
288-
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
289-
{
290-
if let Some(bookmark) = result.bookmark.as_deref() {
291-
match &self.pool {
292-
Routed(routed) => {
293-
routed.add_bookmark(bookmark).await;
294-
}
295-
Direct(_) => {}
296-
}
297-
} else if query.is_read() {
298-
match &self.pool {
299-
Routed(routed) => {
300-
debug!("No bookmark received after a read operation, discarding all bookmarks");
301-
routed.clear_bookmarks().await;
302-
}
303-
Direct(_) => {}
304-
}
305-
}
306-
}
307-
Ok(result)
308-
}
307+
Ok(result) => Ok(result),
309308
Err(e) => Err(e.into_inner()),
310309
}
311310
}
312311

313-
/// Executes a READ query on the configured database and returns a [`DetachedRowStream`]
312+
/// Executes a READ|WRITE query on the configured database and returns a [`DetachedRowStream`]
314313
///
315314
/// This operation retires the query on certain failures.
316315
/// All errors with the `Transient` error class as well as a few other error classes are considered retryable.
317316
/// This includes errors during a leader election or when the transaction resources on the server (memory, handles, ...) are exhausted.
318317
/// Retries happen with an exponential backoff until a retry delay exceeds 60s, at which point the query fails with the last error as it would without any retry.
319318
pub async fn execute(&self, q: impl Into<Query>) -> Result<DetachedRowStream> {
320319
self.impl_execute_on(
320+
Operation::Write,
321321
self.config.db.clone(),
322322
self.config.imp_user.clone(),
323323
&[],
@@ -335,6 +335,7 @@ impl Graph {
335335
/// Retries happen with an exponential backoff until a retry delay exceeds 60s, at which point the query fails with the last error as it would without any retry.
336336
pub async fn execute_read(&self, q: impl Into<Query>) -> Result<DetachedRowStream> {
337337
self.impl_execute_on(
338+
Operation::Read,
338339
self.config.db.clone(),
339340
self.config.imp_user.clone(),
340341
&[],
@@ -353,11 +354,19 @@ impl Graph {
353354
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
354355
pub async fn execute_on(
355356
&self,
357+
operation: Operation,
356358
db: impl Into<Database>,
357359
q: impl Into<Query>,
358360
) -> Result<DetachedRowStream> {
359-
self.impl_execute_on(Some(db.into()), self.config.imp_user.clone(), &[], Some(self.config.fetch_size), q.into())
360-
.await
361+
self.impl_execute_on(
362+
operation,
363+
Some(db.into()),
364+
self.config.imp_user.clone(),
365+
&[],
366+
Some(self.config.fetch_size),
367+
q.into(),
368+
)
369+
.await
361370
}
362371

363372
/// Executes a query on the provided database and returns a [`DetachedRowStream`]
@@ -372,6 +381,7 @@ impl Graph {
372381
q: impl Into<Query>,
373382
) -> Result<DetachedRowStream> {
374383
self.impl_execute_on(
384+
Operation::Write,
375385
Some(db.into()),
376386
self.config.imp_user.clone(),
377387
&[],
@@ -384,6 +394,7 @@ impl Graph {
384394
#[allow(unused_variables)]
385395
pub(crate) async fn impl_execute_on(
386396
&self,
397+
operation: Operation,
387398
db: Option<Database>,
388399
imp_user: Option<ImpersonateUser>,
389400
bookmarks: &[String],
@@ -393,7 +404,7 @@ impl Graph {
393404
let query = query.into_retryable(
394405
db,
395406
imp_user,
396-
Operation::Read,
407+
operation,
397408
&self.pool,
398409
fetch_size.or(Some(self.config.fetch_size)),
399410
bookmarks,
@@ -439,7 +450,7 @@ impl Graph {
439450
.config
440451
.db
441452
.clone()
442-
.map_or(Ok(Some("".into())), |db| Ok(Some(db.into()))),
453+
.map_or(Ok(Some("".into())), |db| Ok(Some(db))),
443454
}
444455
}
445456
}

lib/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ mod version;
515515
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
516516
pub use {
517517
session::{Session, SessionConfig, SessionConfigBuilder},
518-
utils::ConcurrentHashMap
518+
utils::ConcurrentHashMap,
519519
};
520520

521521
pub use crate::auth::ClientCertificate;

lib/src/query.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,6 @@ pub(crate) struct RetryableQuery<'a> {
259259
}
260260

261261
impl<'a> RetryableQuery<'a> {
262-
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
263-
pub(crate) fn is_read(&self) -> bool {
264-
self.operation.is_read()
265-
}
266-
267262
pub(crate) async fn retry_run(self) -> (Self, QueryResult<RunResult>) {
268263
let result = self.run().await;
269264
(self, result)

lib/src/routing/connection_registry.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,19 @@ impl ConnectionRegistry {
4242

4343
/// Retrieve the pool for a specific server and database.
4444
pub(crate) fn get_server_pool(&self, server: &BoltServer) -> Option<ConnectionPool> {
45-
self.pool_registry.get(&server.to_neo_url(self.scheme.as_str()))
45+
self.pool_registry
46+
.get(&server.to_neo_url(self.scheme.as_str()))
4647
}
4748

4849
/// Mark a server as available for a specific database.
49-
pub(crate) fn mark_unavailable(&self, server: &BoltServer, db: Option<Database>) {
50-
let db_name = db.map_or(String::new(), |d| d.to_string());
51-
if self.databases.contains_key(&db_name) {
50+
pub(crate) fn mark_unavailable(&self, server: &BoltServer) {
51+
for db_name in self.databases.keys() {
5252
debug!("Marking server as available: {server:?}");
5353
let mut table = self.databases.get(&db_name).unwrap();
5454
if table.mark_server_unavailable(server) {
5555
self.databases.insert(db_name, table);
56-
self.pool_registry.remove(&server.to_neo_url(self.scheme.as_str()));
56+
self.pool_registry
57+
.remove(&server.to_neo_url(self.scheme.as_str()));
5758
} else {
5859
debug!("Server not found in the registry: {server:?}");
5960
}
@@ -128,7 +129,11 @@ impl ConnectionRegistry {
128129
}
129130

130131
pub fn all_servers(&self) -> Vec<BoltServer> {
131-
self.databases.values().iter().flat_map(|dt| dt.resolve()).collect()
132+
self.databases
133+
.values()
134+
.iter()
135+
.flat_map(|dt| dt.resolve())
136+
.collect()
132137
}
133138

134139
pub fn update(&self, config: &Config, routing_table: &RoutingTable) -> Result<(), Error> {
@@ -298,10 +303,10 @@ mod tests {
298303
assert_eq!(servers.len(), 5);
299304
assert_eq!(registry.pool_registry.keys().len(), 3);
300305
registry.mark_unavailable(&BoltServer {
301-
address:"host1".to_string(),
306+
address: "host1".to_string(),
302307
port: 7687,
303308
role: "WRITE".to_string(),
304-
}, db.clone());
309+
});
305310
let servers = registry.servers(db, None, &[]).await;
306311
assert_eq!(servers.len(), 3);
307312
assert_eq!(registry.pool_registry.keys().len(), 2);
@@ -393,7 +398,7 @@ mod tests {
393398
])),
394399
));
395400

396-
let db = None;
401+
let db = Some(Database::from(""));
397402
let db1 = Some(Database::from("db1"));
398403
let db2 = Some(Database::from("db2"));
399404

@@ -406,20 +411,20 @@ mod tests {
406411
let servers = registry.servers(db2.clone(), None, &[]).await;
407412
assert_eq!(servers.len(), 5);
408413

409-
assert_eq!(registry.pool_registry.keys().len(), 7);
414+
assert_eq!(registry.pool_registry.keys().len(), 9);
410415

411416
registry.mark_unavailable(&BoltServer {
412-
address:"host1".to_string(),
417+
address: "host1".to_string(),
413418
port: 7687,
414-
role: "WRITE".to_string(),
415-
}, db.clone());
419+
role: "READ".to_string(),
420+
});
416421

417422
let servers = registry.servers(db, None, &[]).await;
418423
assert_eq!(servers.len(), 4);
419424
let servers = registry.servers(db1, None, &[]).await;
420425
assert_eq!(servers.len(), 4);
421426
let servers = registry.servers(db2, None, &[]).await;
422427
assert_eq!(servers.len(), 5);
423-
assert_eq!(registry.pool_registry.keys().len(), 6);
428+
assert_eq!(registry.pool_registry.keys().len(), 8);
424429
}
425430
}

lib/src/routing/routed_connection_manager.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ use crate::Database;
99
#[cfg(feature = "unstable-bolt-protocol-impl-v2")]
1010
use crate::{Config, Error, Operation};
1111
use backon::ExponentialBuilder;
12-
use futures::lock::Mutex;
1312
use log::{debug, error};
1413
use std::sync::Arc;
1514

1615
#[derive(Clone)]
1716
pub struct RoutedConnectionManager {
1817
load_balancing_strategy: Arc<dyn LoadBalancingStrategy>,
1918
connection_registry: Arc<ConnectionRegistry>,
20-
bookmarks: Arc<Mutex<Vec<String>>>,
2119
backoff: ExponentialBuilder,
2220
}
2321

@@ -27,7 +25,6 @@ impl RoutedConnectionManager {
2725
let connection_registry = Arc::new(ConnectionRegistry::new(config, provider));
2826
Ok(RoutedConnectionManager {
2927
load_balancing_strategy: Arc::new(RoundRobinStrategy::new(connection_registry.clone())),
30-
bookmarks: Arc::new(Mutex::new(vec![])),
3128
connection_registry,
3229
backoff,
3330
})
@@ -78,8 +75,7 @@ impl RoutedConnectionManager {
7875
Ok(conn) => return Ok(conn),
7976
Err(e) => {
8077
error!("Failed to get connection from pool for server {selected_server:?}: {e}");
81-
self.connection_registry
82-
.mark_unavailable(&selected_server, db.clone());
78+
self.connection_registry.mark_unavailable(&selected_server);
8379
continue; // Try selecting another server
8480
}
8581
}
@@ -113,17 +109,4 @@ impl RoutedConnectionManager {
113109
fn select_writer(&self, servers: &[BoltServer]) -> Option<BoltServer> {
114110
self.load_balancing_strategy.select_writer(servers)
115111
}
116-
117-
#[allow(dead_code)]
118-
pub(crate) async fn add_bookmark(&self, bookmark: &str) {
119-
let mut guard = self.bookmarks.lock().await;
120-
if !guard.contains(&bookmark.to_string()) {
121-
guard.push(bookmark.to_string());
122-
}
123-
}
124-
125-
#[allow(dead_code)]
126-
pub(crate) async fn clear_bookmarks(&self) {
127-
self.bookmarks.lock().await.clear();
128-
}
129112
}

0 commit comments

Comments
 (0)