diff --git a/docs/source/connecting/authentication.md b/docs/source/connecting/authentication.md index 8b60cfecfd..da4a224a6a 100644 --- a/docs/source/connecting/authentication.md +++ b/docs/source/connecting/authentication.md @@ -10,7 +10,8 @@ To use the default authentication, specify credentials using the `user` method i # extern crate tokio; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; let session: Session = SessionBuilder::new() .known_node("127.0.0.1:9042") @@ -21,7 +22,8 @@ let session: Session = SessionBuilder::new() # Ok(()) # } ``` - ### Custom Authentication + +### Custom Authentication A custom authentication is defined by implementing the `AuthenticatorSession`. An `AuthenticatorSession` instance is created per session, so it is also necessary to define a `AuthenticatorProvider` for it. @@ -79,7 +81,8 @@ impl AuthenticatorProvider for CustomAuthenticatorProvider { } async fn authentication_example() -> Result<(), Box> { - use scylla::{Session, SessionBuilder}; + use scylla::client::session::Session; + use scylla::client::session_builder::SessionBuilder; let _session: Session = SessionBuilder::new() .known_node("127.0.0.1:9042") diff --git a/docs/source/connecting/compression.md b/docs/source/connecting/compression.md index 018c4cffc2..59390ecf84 100644 --- a/docs/source/connecting/compression.md +++ b/docs/source/connecting/compression.md @@ -12,8 +12,9 @@ An example enabling `Snappy` compression algorithm: ```rust # extern crate scylla; # extern crate tokio; -use scylla::{Session, SessionBuilder}; -use scylla::transport::Compression; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::client::Compression; use std::error::Error; #[tokio::main] diff --git a/docs/source/connecting/connecting.md b/docs/source/connecting/connecting.md index 7a1f07ec0a..5e27198657 100644 --- a/docs/source/connecting/connecting.md +++ b/docs/source/connecting/connecting.md @@ -5,7 +5,8 @@ When creating a `Session` you can specify a few known nodes to which the driver ```rust # extern crate scylla; # extern crate tokio; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::error::Error; use std::time::Duration; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; @@ -66,7 +67,7 @@ specify the secure connection bundle as follows: # fn check_only_compiles() { use std::path::Path; use std::error::Error; -use scylla::CloudSessionBuilder; +use scylla::client::session_builder::CloudSessionBuilder; #[tokio::main] async fn main() -> Result<(), Box> { diff --git a/docs/source/connecting/tls.md b/docs/source/connecting/tls.md index 22379b1fe5..88e472315b 100644 --- a/docs/source/connecting/tls.md +++ b/docs/source/connecting/tls.md @@ -46,7 +46,8 @@ For example, if database certificate is in the file `ca.crt`: ```rust # extern crate scylla; # extern crate openssl; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use openssl::ssl::{SslContextBuilder, SslMethod, SslVerifyMode}; use std::path::PathBuf; diff --git a/docs/source/data-types/blob.md b/docs/source/data-types/blob.md index 4c445172c0..668928f8d2 100644 --- a/docs/source/data-types/blob.md +++ b/docs/source/data-types/blob.md @@ -5,7 +5,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/collections.md b/docs/source/data-types/collections.md index 645164736a..3d44073b09 100644 --- a/docs/source/data-types/collections.md +++ b/docs/source/data-types/collections.md @@ -6,7 +6,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -34,7 +34,7 @@ while let Some((list_value,)) = stream.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -59,7 +59,7 @@ while let Some((set_value,)) = stream.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -85,7 +85,7 @@ while let Some((set_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -114,7 +114,7 @@ while let Some((set_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -142,7 +142,7 @@ while let Some((map_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/counter.md b/docs/source/data-types/counter.md index 2968701501..8da841277e 100644 --- a/docs/source/data-types/counter.md +++ b/docs/source/data-types/counter.md @@ -5,7 +5,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/date.md b/docs/source/data-types/date.md index cebbcb4803..f10bfb8be9 100644 --- a/docs/source/data-types/date.md +++ b/docs/source/data-types/date.md @@ -15,7 +15,7 @@ However, for most use cases other types are more practical. See following sectio ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::frame::value::CqlDate; @@ -51,7 +51,7 @@ If full range is not required and `chrono-04` feature is enabled, # extern crate chrono; # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use chrono::NaiveDate; @@ -87,7 +87,7 @@ documentation to get more info. # extern crate scylla; # extern crate time; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/decimal.md b/docs/source/data-types/decimal.md index 0845925001..415ed524f6 100644 --- a/docs/source/data-types/decimal.md +++ b/docs/source/data-types/decimal.md @@ -8,7 +8,7 @@ Without any feature flags, the user can interact with `decimal` type by making u ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -41,7 +41,7 @@ To make use of `bigdecimal::Bigdecimal` type, user should enable `bigdecimal-04` # extern crate scylla; # extern crate bigdecimal; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/duration.md b/docs/source/data-types/duration.md index ab46d8ac8a..ebe056cc0b 100644 --- a/docs/source/data-types/duration.md +++ b/docs/source/data-types/duration.md @@ -4,7 +4,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/inet.md b/docs/source/data-types/inet.md index eec39c1948..0b00fc9ca6 100644 --- a/docs/source/data-types/inet.md +++ b/docs/source/data-types/inet.md @@ -4,7 +4,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/primitive.md b/docs/source/data-types/primitive.md index ab7032e62f..bf36fc5a16 100644 --- a/docs/source/data-types/primitive.md +++ b/docs/source/data-types/primitive.md @@ -7,7 +7,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -36,7 +36,7 @@ while let Some((bool_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -65,7 +65,7 @@ while let Some((tinyint_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -94,7 +94,7 @@ while let Some((smallint_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -123,7 +123,7 @@ while let Some((int_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -152,7 +152,7 @@ while let Some((bigint_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; @@ -181,7 +181,7 @@ while let Some((float_value,)) = iter.try_next().await? { ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/text.md b/docs/source/data-types/text.md index b61ec2ba00..d18a585b18 100644 --- a/docs/source/data-types/text.md +++ b/docs/source/data-types/text.md @@ -4,7 +4,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/time.md b/docs/source/data-types/time.md index bcc1c2ddfc..3acf242340 100644 --- a/docs/source/data-types/time.md +++ b/docs/source/data-types/time.md @@ -15,7 +15,7 @@ However, for most use cases other types are more practical. See following sectio ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::frame::value::CqlTime; @@ -51,7 +51,7 @@ second to `CqlTime` or write it to the database will return an error. # extern crate chrono; # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use chrono::NaiveTime; @@ -85,7 +85,7 @@ with the database. # extern crate scylla; # extern crate time; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/timestamp.md b/docs/source/data-types/timestamp.md index d34a48058a..a50996274d 100644 --- a/docs/source/data-types/timestamp.md +++ b/docs/source/data-types/timestamp.md @@ -16,7 +16,7 @@ However, for most use cases other types are more practical. See following sectio ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::frame::value::CqlTimestamp; @@ -52,7 +52,7 @@ timezone information. Any precision finer than 1ms will be lost. # extern crate chrono; # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc}; @@ -93,7 +93,7 @@ than 1ms will also be lost. # extern crate scylla; # extern crate time; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/timeuuid.md b/docs/source/data-types/timeuuid.md index f213255017..d85ff2aa50 100644 --- a/docs/source/data-types/timeuuid.md +++ b/docs/source/data-types/timeuuid.md @@ -7,7 +7,7 @@ Also, `value::CqlTimeuuid` is a wrapper for `uuid::Uuid` with custom ordering lo ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::str::FromStr; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { @@ -47,7 +47,7 @@ and now you're gonna be able to use the `uuid::v1` features: # extern crate uuid; # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::str::FromStr; use futures::TryStreamExt; diff --git a/docs/source/data-types/tuple.md b/docs/source/data-types/tuple.md index de6a0c9bd1..cd091cda9e 100644 --- a/docs/source/data-types/tuple.md +++ b/docs/source/data-types/tuple.md @@ -5,7 +5,7 @@ ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/udt.md b/docs/source/data-types/udt.md index ddafb748e9..623b1d8a0f 100644 --- a/docs/source/data-types/udt.md +++ b/docs/source/data-types/udt.md @@ -44,7 +44,7 @@ Now it can be sent and received just like any other CQL value: ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/uuid.md b/docs/source/data-types/uuid.md index f8fa95276b..8db29385af 100644 --- a/docs/source/data-types/uuid.md +++ b/docs/source/data-types/uuid.md @@ -6,7 +6,7 @@ # extern crate scylla; # extern crate uuid; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/data-types/varint.md b/docs/source/data-types/varint.md index c2309bb1b5..4dced46507 100644 --- a/docs/source/data-types/varint.md +++ b/docs/source/data-types/varint.md @@ -15,7 +15,7 @@ Without any feature flags, the user can interact with `Varint` type by making us # extern crate scylla; # extern crate num_bigint; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::TryStreamExt; diff --git a/docs/source/execution-profiles/create-and-use.md b/docs/source/execution-profiles/create-and-use.md index 01bfa52d99..ee9553a12c 100644 --- a/docs/source/execution-profiles/create-and-use.md +++ b/docs/source/execution-profiles/create-and-use.md @@ -6,9 +6,10 @@ To create an `ExecutionProfile` and attach it as default for `Session`: # extern crate scylla; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::statement::Consistency; -use scylla::transport::ExecutionProfile; +use scylla::client::execution_profile::ExecutionProfile; let profile = ExecutionProfile::builder() .consistency(Consistency::LocalOne) @@ -34,7 +35,7 @@ To create an `ExecutionProfile` and attach it to a `Query`: # async fn check_only_compiles() -> Result<(), Box> { use scylla::query::Query; use scylla::statement::Consistency; -use scylla::transport::ExecutionProfile; +use scylla::client::execution_profile::ExecutionProfile; use std::time::Duration; let profile = ExecutionProfile::builder() @@ -60,7 +61,7 @@ To create an `ExecutionProfile` based on another profile: # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { use scylla::statement::Consistency; -use scylla::transport::ExecutionProfile; +use scylla::client::execution_profile::ExecutionProfile; use std::time::Duration; let base_profile = ExecutionProfile::builder() diff --git a/docs/source/execution-profiles/maximal-example.md b/docs/source/execution-profiles/maximal-example.md index 2e328970d6..dcbbb82f8d 100644 --- a/docs/source/execution-profiles/maximal-example.md +++ b/docs/source/execution-profiles/maximal-example.md @@ -7,11 +7,11 @@ # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { use scylla::query::Query; -use scylla::speculative_execution::SimpleSpeculativeExecutionPolicy; +use scylla::policies::speculative_execution::SimpleSpeculativeExecutionPolicy; use scylla::statement::{Consistency, SerialConsistency}; -use scylla::transport::ExecutionProfile; -use scylla::transport::load_balancing::DefaultPolicy; -use scylla::transport::retry_policy::FallthroughRetryPolicy; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::load_balancing::DefaultPolicy; +use scylla::policies::retry::FallthroughRetryPolicy; use std::{sync::Arc, time::Duration}; let profile = ExecutionProfile::builder() diff --git a/docs/source/execution-profiles/priority.md b/docs/source/execution-profiles/priority.md index ccc57b73b0..476f953c1f 100644 --- a/docs/source/execution-profiles/priority.md +++ b/docs/source/execution-profiles/priority.md @@ -13,10 +13,11 @@ Priorities of execution profiles and directly set options: # extern crate scylla; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::query::Query; use scylla::statement::Consistency; -use scylla::transport::ExecutionProfile; +use scylla::client::execution_profile::ExecutionProfile; let session_profile = ExecutionProfile::builder() .consistency(Consistency::One) diff --git a/docs/source/execution-profiles/remap.md b/docs/source/execution-profiles/remap.md index a64aee3916..b3b4c04ca8 100644 --- a/docs/source/execution-profiles/remap.md +++ b/docs/source/execution-profiles/remap.md @@ -23,10 +23,11 @@ Below, the remaps described above are followed in code. # extern crate scylla; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::query::Query; use scylla::statement::Consistency; -use scylla::transport::ExecutionProfile; +use scylla::client::execution_profile::ExecutionProfile; let profile1 = ExecutionProfile::builder() .consistency(Consistency::One) diff --git a/docs/source/load-balancing/default-policy.md b/docs/source/load-balancing/default-policy.md index 4f8310a36f..043fd6630a 100644 --- a/docs/source/load-balancing/default-policy.md +++ b/docs/source/load-balancing/default-policy.md @@ -21,7 +21,7 @@ You can use the builder methods to configure the desired settings and create a ```rust # extern crate scylla; # fn test_if_compiles() { -use scylla::load_balancing::DefaultPolicy; +use scylla::policies::load_balancing::DefaultPolicy; let default_policy = DefaultPolicy::builder() .prefer_datacenter_and_rack("dc1".to_string(), "rack1".to_string()) @@ -122,7 +122,7 @@ this mechanism may as well worsen latencies and/or throughput. ```rust # extern crate scylla; # fn example() { -use scylla::load_balancing::{ +use scylla::policies::load_balancing::{ LatencyAwarenessBuilder, DefaultPolicy }; use std::time::Duration; @@ -144,7 +144,7 @@ let policy = DefaultPolicy::builder() ```rust # extern crate scylla; # fn test_if_compiles() { -use scylla::load_balancing::DefaultPolicy; +use scylla::policies::load_balancing::DefaultPolicy; let default_policy = DefaultPolicy::builder() .prefer_datacenter("dc1".to_string()) diff --git a/docs/source/load-balancing/load-balancing.md b/docs/source/load-balancing/load-balancing.md index 3ec27dd7e1..dfa23cbca9 100644 --- a/docs/source/load-balancing/load-balancing.md +++ b/docs/source/load-balancing/load-balancing.md @@ -9,7 +9,7 @@ balancing plan based on the query information and the state of the cluster. Load balancing policies do not influence to which nodes connections are being opened. For a node connection blacklist configuration refer to -`scylla::transport::host_filter::HostFilter`, which can be set session-wide +`scylla::policies::host_filter::HostFilter`, which can be set session-wide using `SessionBuilder::host_filter` method. In this chapter, "target" will refer to a pair ``. @@ -49,10 +49,10 @@ The newly created execution profile is then converted to a handle using # extern crate scylla; # use std::error::Error; # async fn check_only_compiles(uri: &str) -> Result<(), Box> { -use scylla::SessionBuilder; -use scylla::load_balancing::DefaultPolicy; -use scylla::transport::ExecutionProfile; -use scylla::transport::session::Session; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::policies::load_balancing::DefaultPolicy; +use scylla::client::execution_profile::ExecutionProfile; use std::sync::Arc; let policy = Arc::new(DefaultPolicy::default()); diff --git a/docs/source/logging/logging.md b/docs/source/logging/logging.md index 1a946d82d1..7a43cda9ae 100644 --- a/docs/source/logging/logging.md +++ b/docs/source/logging/logging.md @@ -16,7 +16,8 @@ To print the logs you can use the default subscriber: # extern crate tracing; # extern crate tracing_subscriber; # use std::error::Error; -# use scylla::{Session, SessionBuilder}; +# use scylla::client::session::Session; +# use scylla::client::session_builder::SessionBuilder; use tracing::info; #[tokio::main] @@ -69,7 +70,8 @@ then you can setup `env_logger` os some other logger and it will output logs fro # extern crate tracing; # extern crate env_logger; # use std::error::Error; -# use scylla::{Session, SessionBuilder}; +# use scylla::client::session::Session; +# use scylla::client::session_builder::SessionBuilder; use tracing::info; #[tokio::main] diff --git a/docs/source/metrics/metrics.md b/docs/source/metrics/metrics.md index ce52615383..1393ed5879 100644 --- a/docs/source/metrics/metrics.md +++ b/docs/source/metrics/metrics.md @@ -15,7 +15,7 @@ They can be accessed at any moment using `Session::get_metrics()` ### Example ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { let metrics = session.get_metrics(); diff --git a/docs/source/migration-guides/0.15-deserialization.md b/docs/source/migration-guides/0.15-deserialization.md index 3c9d11478d..bbc198f3bf 100644 --- a/docs/source/migration-guides/0.15-deserialization.md +++ b/docs/source/migration-guides/0.15-deserialization.md @@ -108,7 +108,7 @@ Before: ```rust # extern crate scylla; -# use scylla::LegacySession; +# use scylla::client::session::LegacySession; # use std::error::Error; # async fn check_only_compiles(session: &LegacySession) -> Result<(), Box> { let iter = session @@ -127,7 +127,7 @@ After: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { // 1. Note that the result must be converted to a rows result, and only then @@ -158,9 +158,9 @@ Before: ```rust # extern crate scylla; # extern crate futures; -# use scylla::LegacySession; +# use scylla::client::session::LegacySession; +# use scylla::response::legacy_query_result::IntoTypedRows; # use std::error::Error; -# use scylla::IntoTypedRows; # use futures::stream::StreamExt; # async fn check_only_compiles(session: &LegacySession) -> Result<(), Box> { let mut rows_stream = session @@ -181,7 +181,7 @@ After: ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use futures::stream::StreamExt; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { @@ -233,14 +233,15 @@ If you intend to quickly migrate your application by using the old API, you can ```rust # extern crate scylla; -use scylla::LegacySession as Session; +use scylla::client::session::LegacySession as Session; ``` In order to create the `LegacySession` instead of the new `Session`, you need to use `SessionBuilder`'s `build_legacy()` method instead of `build()`: ```rust # extern crate scylla; -# use scylla::{LegacySession, SessionBuilder}; +# use scylla::client::session::LegacySession; +# use scylla::client::session_builder::SessionBuilder; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { let session: LegacySession = SessionBuilder::new() @@ -257,7 +258,7 @@ It is possible to use different APIs in different parts of the program. The `Ses ```rust # extern crate scylla; -# use scylla::{LegacySession, Session}; +# use scylla::client::session::{LegacySession, Session}; # use std::error::Error; # async fn check_only_compiles(new_api_session: &Session) -> Result<(), Box> { // All of the session objects below will use the same resources: connections, @@ -272,7 +273,8 @@ In addition to that, it is possible to convert a `QueryResult` to `LegacyQueryRe ```rust # extern crate scylla; -# use scylla::{QueryResult, LegacyQueryResult}; +# use scylla::response::query_result::QueryResult; +# use scylla::response::legacy_query_result::LegacyQueryResult; # use std::error::Error; # async fn check_only_compiles(result: QueryResult) -> Result<(), Box> { let result: QueryResult = result; @@ -285,7 +287,7 @@ let legacy_result: LegacyQueryResult = result.into_legacy_result()?; ```rust # extern crate scylla; -# use scylla::transport::iterator::{QueryPager, LegacyRowIterator}; +# use scylla::client::pager::{QueryPager, LegacyRowIterator}; # use std::error::Error; # async fn check_only_compiles(pager: QueryPager) -> Result<(), Box> { let pager: QueryPager = pager; diff --git a/docs/source/queries/batch.md b/docs/source/queries/batch.md index 4d9694c45e..bb11c83352 100644 --- a/docs/source/queries/batch.md +++ b/docs/source/queries/batch.md @@ -6,7 +6,7 @@ Only `INSERT`, `UPDATE` and `DELETE` statements are allowed. ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::batch::Batch; @@ -52,7 +52,7 @@ Instead of preparing each statement individually, it's possible to prepare a who ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::batch::Batch; @@ -80,7 +80,7 @@ You can set various options by operating on the `Batch` object.\ For example to change consistency: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::batch::Batch; @@ -114,7 +114,7 @@ By default this includes tuples `()` and slices `&[]` of tuples and slices which Example: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::batch::Batch; diff --git a/docs/source/queries/lwt.md b/docs/source/queries/lwt.md index 89c2831eb0..272339d2da 100644 --- a/docs/source/queries/lwt.md +++ b/docs/source/queries/lwt.md @@ -7,7 +7,7 @@ A lightweight transaction query can be expressed just like any other query, via A lightweight transaction query is not a separate type - it can be expressed just like any other queries: via `SimpleQuery`, `PreparedStatement`, batches, and so on. The difference lays in the query string itself - when it contains a condition (e.g. `IF NOT EXISTS`), it becomes a lightweight transaction. It's important to remember that CQL specification requires a separate, additional consistency level to be defined for LWT queries - `serial_consistency_level`. The serial consistency level can only be set to two values: `SerialConsistency::Serial` or `SerialConsistency::LocalSerial`. The "local" variant makes the transaction consistent only within the same datacenter. For convenience, Scylla Rust Driver sets the default consistency level to `LocalSerial`, as it's more commonly used. For cross-datacenter consistency, please remember to always override the default with `SerialConsistency::Serial`. ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; diff --git a/docs/source/queries/paged.md b/docs/source/queries/paged.md index 3944de5682..fb07208ae1 100644 --- a/docs/source/queries/paged.md +++ b/docs/source/queries/paged.md @@ -49,7 +49,7 @@ Use `query_iter` to perform a [simple query](simple.md) with paging: ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use futures::stream::StreamExt; @@ -71,7 +71,7 @@ Use `execute_iter` to perform a [prepared query](prepared.md) with paging: ```rust # extern crate scylla; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; @@ -102,7 +102,7 @@ It's possible to configure the size of a single page. On a `Query`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; @@ -118,7 +118,7 @@ let _ = session.query_iter(query, &[]).await?; // ... On a `PreparedStatement`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; @@ -142,11 +142,11 @@ from where the previous one left off. On a `Query`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::statement::{PagingState, PagingStateResponse}; +use scylla::response::{PagingState, PagingStateResponse}; use std::ops::ControlFlow; let paged_query = Query::new("SELECT a, b, c FROM ks.t").with_page_size(6); @@ -185,11 +185,11 @@ loop { On a `PreparedStatement`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::statement::{PagingState, PagingStateResponse}; +use scylla::response::{PagingState, PagingStateResponse}; use std::ops::ControlFlow; let paged_prepared = session diff --git a/docs/source/queries/prepared.md b/docs/source/queries/prepared.md index d362d00d9f..53be24e1c5 100644 --- a/docs/source/queries/prepared.md +++ b/docs/source/queries/prepared.md @@ -11,7 +11,7 @@ prepares the statement before execution. The reason for this is to provide type ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; @@ -54,7 +54,7 @@ For example to change the consistency: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; @@ -106,7 +106,7 @@ TABLE ks.prepare_table ( ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; diff --git a/docs/source/queries/result.md b/docs/source/queries/result.md index db63637e7b..3557940610 100644 --- a/docs/source/queries/result.md +++ b/docs/source/queries/result.md @@ -21,8 +21,8 @@ return a `QueryResult` with rows represented as `Option>`. ## Parsing using convenience methods -By calling [`QueryResult::into_rows_result`](https://docs.rs/scylla/latest/scylla/transport/query_result/struct.QueryResult.html#method.into_rows_result), -one can obtain [`QueryRowsResult`](https://docs.rs/scylla/latest/scylla/transport/query_result/struct.QueryRowsResult.html). +By calling [`QueryResult::into_rows_result`](https://docs.rs/scylla/latest/scylla/response/query_result/struct.QueryResult.html#method.into_rows_result), +one can obtain [`QueryRowsResult`](https://docs.rs/scylla/latest/scylla/response/query_result/struct.QueryRowsResult.html). `QueryRowsResult` provides convenience methods for parsing rows. Here are a few of them: * `rows::()` - returns the rows parsed as the given type @@ -30,11 +30,11 @@ Here are a few of them: * `first_row::()` - returns the first received row; fails if there are no rows * `single_row::()` - same as `first_row`, but fails when there is more than one row -Additionally, [`QueryResult`](https://docs.rs/scylla/latest/scylla/transport/query_result/struct.QueryResult.html) has a method `result_not_rows()`, which ensures that query response was not `rows` and thus helps avoid bugs. +Additionally, [`QueryResult`](https://docs.rs/scylla/latest/scylla/response/query_result/struct.QueryResult.html) has a method `result_not_rows()`, which ensures that query response was not `rows` and thus helps avoid bugs. ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { // Parse row as a single column containing an int value @@ -59,18 +59,17 @@ session.query_unpaged("INSERT INTO ks.tab (a) VALUES (0)", &[]).await?.result_no # Ok(()) # } ``` -For more see [`QueryResult`](https://docs.rs/scylla/latest/scylla/transport/query_result/struct.QueryResult.html) -and [`QueryRowsResult`](https://docs.rs/scylla/latest/scylla/transport/query_result/struct.QueryRowsResult.html) +For more see [`QueryResult`](https://docs.rs/scylla/latest/scylla/response/query_result/struct.QueryResult.html) +and [`QueryRowsResult`](https://docs.rs/scylla/latest/scylla/response/query_result/struct.QueryRowsResult.html) ### `NULL` values `NULL` values will return an error when parsed as a Rust type. To properly handle `NULL` values parse column as an `Option<>`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { -use scylla::IntoTypedRows; // Parse row as two columns containing an int and text which might be null let rows_result = session @@ -95,10 +94,9 @@ The struct must: Field names don't need to match column names. ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { -use scylla::IntoTypedRows; use scylla::macros::DeserializeRow; use scylla::deserialize::DeserializeRow; diff --git a/docs/source/queries/schema-agreement.md b/docs/source/queries/schema-agreement.md index 2df38743c8..43f9692bcc 100644 --- a/docs/source/queries/schema-agreement.md +++ b/docs/source/queries/schema-agreement.md @@ -11,7 +11,7 @@ and after creating all the tables rather than after every query. Therefore, the ```rust # extern crate scylla; -# use scylla::SessionBuilder; +# use scylla::client::session_builder::SessionBuilder; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { let session = SessionBuilder::new() @@ -31,7 +31,7 @@ the return value is `Err(QueryError::RequestTimeout)`, otherwise it is `Ok(schem ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { session.await_schema_agreement().await?; @@ -46,7 +46,7 @@ but it can be changed with `SessionBuilder::schema_agreement_interval`. ```rust # extern crate scylla; -# use scylla::SessionBuilder; +# use scylla::client::session_builder::SessionBuilder; # use std::error::Error; # use std::time::Duration; # async fn check_only_compiles() -> Result<(), Box> { @@ -65,7 +65,7 @@ If you want to check if schema is in agreement now, without retrying after failu ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { if session.check_schema_agreement().await?.is_some() { diff --git a/docs/source/queries/simple.md b/docs/source/queries/simple.md index a917998593..2300f3675c 100644 --- a/docs/source/queries/simple.md +++ b/docs/source/queries/simple.md @@ -3,7 +3,7 @@ Simple query takes query text and values and simply executes them on a `Session`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn simple_query_example(session: &Session) -> Result<(), Box> { // Insert a value into the table @@ -33,7 +33,7 @@ As the first argument `Session::query_unpaged` takes anything implementing `Into You can create a query manually to set custom options. For example to change query consistency: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; @@ -59,7 +59,7 @@ Each `?` in query text will be filled with the matching value. The easiest way is to pass values using a tuple: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { // Sending an integer and a string using a tuple @@ -80,10 +80,9 @@ The result can then be operated on via helper methods which verify that the resu Here, we use the `rows` method to check that the response indeed contains rows with a single `int` column: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { -use scylla::IntoTypedRows; // NOTE: using unpaged queries for SELECTs is discouraged in general. // Query results may be so big that it is not preferable to fetch them all at once. diff --git a/docs/source/queries/timeouts.md b/docs/source/queries/timeouts.md index f99b186cab..6384a5786a 100644 --- a/docs/source/queries/timeouts.md +++ b/docs/source/queries/timeouts.md @@ -17,8 +17,10 @@ However, setting per-statement timeout to `None` results in falling back to per- # extern crate scylla; # use std::error::Error; # async fn timeouts() -> Result<(), Box> { -use scylla::{Session, SessionBuilder, query::Query}; -use scylla::transport::ExecutionProfile; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::query::Query; use std::time::Duration; let uri = std::env::var("SCYLLA_URI") diff --git a/docs/source/queries/usekeyspace.md b/docs/source/queries/usekeyspace.md index 85c92b1c8a..819da65ebf 100644 --- a/docs/source/queries/usekeyspace.md +++ b/docs/source/queries/usekeyspace.md @@ -29,7 +29,7 @@ cqlsh:my_keyspace> SELECT * FROM other_keyspace.other_table; In the driver this can be achieved using `Session::use_keyspace`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { session @@ -53,7 +53,7 @@ It is also possible to send raw use keyspace query using `Session::query_*` inst ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { session.query_unpaged("USE my_keyspace", &[]).await?; @@ -78,7 +78,7 @@ Let's see what happens when there are two keyspaces with the same name but diffe ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { // lowercase name without case sensitivity will use my_keyspace diff --git a/docs/source/queries/values.md b/docs/source/queries/values.md index e5ae36532b..9d8e1f50f1 100644 --- a/docs/source/queries/values.md +++ b/docs/source/queries/values.md @@ -12,7 +12,8 @@ or a custom struct which derives from `SerializeRow`. A few examples: ```rust # extern crate scylla; -# use scylla::{Session, SerializeRow, frame::response::result::CqlValue}; +# use scylla::{SerializeRow, frame::response::result::CqlValue}; +# use scylla::client::session::Session; # use std::error::Error; # use std::collections::HashMap; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { @@ -96,7 +97,7 @@ session Null values can be sent using `Option<>` - sending a `None` will make the value `NULL`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { let null_i32: Option = None; @@ -114,7 +115,7 @@ Using `Unset` results in better performance: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::frame::value::{MaybeUnset, Unset}; diff --git a/docs/source/quickstart/create-project.md b/docs/source/quickstart/create-project.md index bc453bfbcc..e1832220b1 100644 --- a/docs/source/quickstart/create-project.md +++ b/docs/source/quickstart/create-project.md @@ -22,7 +22,7 @@ In `main.rs` put: ```rust # extern crate scylla; # extern crate tokio; -use scylla::Session; +use scylla::client::session::Session; #[tokio::main] async fn main() { diff --git a/docs/source/quickstart/example.md b/docs/source/quickstart/example.md index 22e332b849..fe33eff9f8 100644 --- a/docs/source/quickstart/example.md +++ b/docs/source/quickstart/example.md @@ -7,7 +7,8 @@ Here is a small example: # extern crate tokio; # extern crate futures; use futures::TryStreamExt; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::error::Error; #[tokio::main] diff --git a/docs/source/retry-policy/default.md b/docs/source/retry-policy/default.md index 3b57562c29..3e10fc278b 100644 --- a/docs/source/retry-policy/default.md +++ b/docs/source/retry-policy/default.md @@ -7,13 +7,14 @@ The behaviour is the same. To use in `Session`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles() -> Result<(), Box> { -use scylla::{Session, SessionBuilder}; -use scylla::transport::ExecutionProfile; -use scylla::transport::retry_policy::DefaultRetryPolicy; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::DefaultRetryPolicy; let handle = ExecutionProfile::builder() .retry_policy(Arc::new(DefaultRetryPolicy::new())) @@ -32,13 +33,13 @@ let session: Session = SessionBuilder::new() To use in a [simple query](../queries/simple.md): ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::transport::ExecutionProfile; -use scylla::transport::retry_policy::DefaultRetryPolicy; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::DefaultRetryPolicy; // Create a Query manually and set the retry policy let mut my_query: Query = Query::new("INSERT INTO ks.tab (a) VALUES(?)"); @@ -61,13 +62,13 @@ session.query_unpaged(my_query, (to_insert,)).await?; To use in a [prepared query](../queries/prepared.md): ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; -use scylla::transport::ExecutionProfile; -use scylla::transport::retry_policy::DefaultRetryPolicy; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::DefaultRetryPolicy; // Create PreparedStatement manually and set the retry policy let mut prepared: PreparedStatement = session diff --git a/docs/source/retry-policy/downgrading-consistency.md b/docs/source/retry-policy/downgrading-consistency.md index 2e335f6e4e..7899c85a94 100644 --- a/docs/source/retry-policy/downgrading-consistency.md +++ b/docs/source/retry-policy/downgrading-consistency.md @@ -48,13 +48,14 @@ The behaviour is the same. To use in `Session`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles() -> Result<(), Box> { -use scylla::{Session, SessionBuilder}; -use scylla::transport::ExecutionProfile; -use scylla::transport::downgrading_consistency_retry_policy::DowngradingConsistencyRetryPolicy; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::DowngradingConsistencyRetryPolicy; let handle = ExecutionProfile::builder() .retry_policy(Arc::new(DowngradingConsistencyRetryPolicy::new())) @@ -73,13 +74,13 @@ let session: Session = SessionBuilder::new() To use in a [simple query](../queries/simple.md): ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::transport::ExecutionProfile; -use scylla::transport::downgrading_consistency_retry_policy::DowngradingConsistencyRetryPolicy; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::DowngradingConsistencyRetryPolicy; let handle = ExecutionProfile::builder() .retry_policy(Arc::new(DowngradingConsistencyRetryPolicy::new())) @@ -100,13 +101,13 @@ session.query_unpaged(my_query, (to_insert,)).await?; To use in a [prepared query](../queries/prepared.md): ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; -use scylla::transport::ExecutionProfile; -use scylla::transport::downgrading_consistency_retry_policy::DowngradingConsistencyRetryPolicy; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::DowngradingConsistencyRetryPolicy; let handle = ExecutionProfile::builder() .retry_policy(Arc::new(DowngradingConsistencyRetryPolicy::new())) diff --git a/docs/source/retry-policy/fallthrough.md b/docs/source/retry-policy/fallthrough.md index a2056c52ef..7a5c170075 100644 --- a/docs/source/retry-policy/fallthrough.md +++ b/docs/source/retry-policy/fallthrough.md @@ -6,13 +6,14 @@ The `FalthroughRetryPolicy` never retries, returns errors straight to the user. To use in `Session`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles() -> Result<(), Box> { -use scylla::{Session, SessionBuilder}; -use scylla::transport::ExecutionProfile; -use scylla::transport::retry_policy::FallthroughRetryPolicy; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::FallthroughRetryPolicy; let handle = ExecutionProfile::builder() .retry_policy(Arc::new(FallthroughRetryPolicy::new())) @@ -31,13 +32,13 @@ let session: Session = SessionBuilder::new() To use in a [simple query](../queries/simple.md): ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::transport::ExecutionProfile; -use scylla::transport::retry_policy::FallthroughRetryPolicy; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::FallthroughRetryPolicy; let handle = ExecutionProfile::builder() .retry_policy(Arc::new(FallthroughRetryPolicy::new())) @@ -58,13 +59,13 @@ session.query_unpaged(my_query, (to_insert,)).await?; To use in a [prepared query](../queries/prepared.md): ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # use std::sync::Arc; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; -use scylla::transport::ExecutionProfile; -use scylla::transport::retry_policy::FallthroughRetryPolicy; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::retry::FallthroughRetryPolicy; let handle = ExecutionProfile::builder() .retry_policy(Arc::new(FallthroughRetryPolicy::new())) diff --git a/docs/source/retry-policy/retry-policy.md b/docs/source/retry-policy/retry-policy.md index b4859b0c89..03e7adfb98 100644 --- a/docs/source/retry-policy/retry-policy.md +++ b/docs/source/retry-policy/retry-policy.md @@ -21,7 +21,7 @@ Idempotent queries can be retried in situations where retrying non idempotent qu Idempotence has to be specified manually, the driver is not able to figure it out by itself. ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; diff --git a/docs/source/schema/schema.md b/docs/source/schema/schema.md index a8505765ba..b44920e108 100644 --- a/docs/source/schema/schema.md +++ b/docs/source/schema/schema.md @@ -9,7 +9,8 @@ Fetching database schema occurs periodically, but it can also be done on-demand. # extern crate scylla; # extern crate tokio; # use std::error::Error; -# use scylla::{Session, SessionBuilder}; +# use scylla::client::session::Session; +# use scylla::client::session_builder::SessionBuilder; #[tokio::main] async fn main() -> Result<(), Box> { @@ -42,7 +43,8 @@ Example showing how to print obtained schema information: # extern crate scylla; # extern crate tokio; # use std::error::Error; -# use scylla::{Session, SessionBuilder}; +# use scylla::client::session::Session; +# use scylla::client::session_builder::SessionBuilder; #[tokio::main] async fn main() -> Result<(), Box> { diff --git a/docs/source/speculative-execution/percentile.md b/docs/source/speculative-execution/percentile.md index 243429d97f..093ca253f0 100644 --- a/docs/source/speculative-execution/percentile.md +++ b/docs/source/speculative-execution/percentile.md @@ -9,15 +9,15 @@ given percentile. To use this policy in `Session`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { use std::{sync::Arc, time::Duration}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::{ - Session, - SessionBuilder, - speculative_execution::PercentileSpeculativeExecutionPolicy, - transport::execution_profile::ExecutionProfile, + policies::speculative_execution::PercentileSpeculativeExecutionPolicy, + client::execution_profile::ExecutionProfile, }; let policy = PercentileSpeculativeExecutionPolicy { diff --git a/docs/source/speculative-execution/simple.md b/docs/source/speculative-execution/simple.md index ad7720e664..022bcb7727 100644 --- a/docs/source/speculative-execution/simple.md +++ b/docs/source/speculative-execution/simple.md @@ -9,15 +9,15 @@ non-speculative one). To use this policy in `Session`: ```rust # extern crate scylla; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles() -> Result<(), Box> { use std::{sync::Arc, time::Duration}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::{ - Session, - SessionBuilder, - speculative_execution::SimpleSpeculativeExecutionPolicy, - transport::execution_profile::ExecutionProfile, + policies::speculative_execution::SimpleSpeculativeExecutionPolicy, + client::execution_profile::ExecutionProfile, }; let policy = SimpleSpeculativeExecutionPolicy { diff --git a/docs/source/tracing/basic.md b/docs/source/tracing/basic.md index 08417a1e09..c6543dc71b 100644 --- a/docs/source/tracing/basic.md +++ b/docs/source/tracing/basic.md @@ -7,12 +7,12 @@ return a `QueryResult` which contains a `tracing_id` if tracing was enabled. ```rust # extern crate scylla; # extern crate uuid; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::QueryResult; -use scylla::tracing::TracingInfo; +use scylla::response::query_result::QueryResult; +use scylla::observability::tracing::TracingInfo; use uuid::Uuid; // Create a Query manually and enable tracing @@ -35,12 +35,12 @@ if let Some(id) = tracing_id { ```rust # extern crate scylla; # extern crate uuid; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; -use scylla::QueryResult; -use scylla::tracing::TracingInfo; +use scylla::response::query_result::QueryResult; +use scylla::observability::tracing::TracingInfo; use uuid::Uuid; // Prepare the query @@ -67,12 +67,12 @@ if let Some(id) = tracing_id { ```rust # extern crate scylla; # extern crate uuid; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::batch::Batch; -use scylla::QueryResult; -use scylla::tracing::TracingInfo; +use scylla::response::query_result::QueryResult; +use scylla::observability::tracing::TracingInfo; use uuid::Uuid; // Create a batch statement diff --git a/docs/source/tracing/paged.md b/docs/source/tracing/paged.md index 20975dfc3a..58f25d3351 100644 --- a/docs/source/tracing/paged.md +++ b/docs/source/tracing/paged.md @@ -9,11 +9,11 @@ If tracing is enabled the row iterator will contain a list of tracing ids for al # extern crate scylla; # extern crate uuid; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::tracing::TracingInfo; +use scylla::observability::tracing::TracingInfo; use futures::StreamExt; use uuid::Uuid; @@ -47,11 +47,11 @@ for id in tracing_ids { # extern crate scylla; # extern crate uuid; # extern crate futures; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::prepared_statement::PreparedStatement; -use scylla::tracing::TracingInfo; +use scylla::observability::tracing::TracingInfo; use futures::StreamExt; use uuid::Uuid; diff --git a/docs/source/tracing/prepare.md b/docs/source/tracing/prepare.md index 2f3850cbde..3076523d27 100644 --- a/docs/source/tracing/prepare.md +++ b/docs/source/tracing/prepare.md @@ -5,12 +5,12 @@ ```rust # extern crate scylla; # extern crate uuid; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; use scylla::prepared_statement::PreparedStatement; -use scylla::tracing::TracingInfo; +use scylla::observability::tracing::TracingInfo; use uuid::Uuid; // Prepare the query with tracing enabled diff --git a/docs/source/tracing/query-history.md b/docs/source/tracing/query-history.md index c7c0e0b3b6..d834a38ba3 100644 --- a/docs/source/tracing/query-history.md +++ b/docs/source/tracing/query-history.md @@ -8,11 +8,11 @@ This history includes all requests sent, decisions to retry and speculative exec ```rust # extern crate scylla; # extern crate uuid; -# use scylla::Session; +# use scylla::client::session::Session; # use std::error::Error; # async fn check_only_compiles(session: &Session) -> Result<(), Box> { use scylla::query::Query; -use scylla::history::{HistoryCollector, StructuredHistory}; +use scylla::observability::history::{HistoryCollector, StructuredHistory}; use std::sync::Arc; // Create a query for which we would like to trace the history of its execution diff --git a/examples/allocations.rs b/examples/allocations.rs index d10ad9771b..bdb31bae78 100644 --- a/examples/allocations.rs +++ b/examples/allocations.rs @@ -1,6 +1,7 @@ use anyhow::Result; -use scylla::transport::session::Session; -use scylla::{statement::prepared_statement::PreparedStatement, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::statement::prepared_statement::PreparedStatement; use std::io::Write; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; diff --git a/examples/auth.rs b/examples/auth.rs index 22fbee0077..6410815cb6 100644 --- a/examples/auth.rs +++ b/examples/auth.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use scylla::SessionBuilder; +use scylla::client::session_builder::SessionBuilder; #[tokio::main] async fn main() -> Result<()> { diff --git a/examples/basic.rs b/examples/basic.rs index c4fe10b8b3..df33496a1a 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -1,10 +1,10 @@ use anyhow::Result; use futures::StreamExt as _; use futures::TryStreamExt as _; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::frame::response::result::Row; -use scylla::transport::session::Session; use scylla::DeserializeRow; -use scylla::SessionBuilder; use std::env; #[tokio::main] diff --git a/examples/cloud.rs b/examples/cloud.rs index 63265e41f8..2a62067c1d 100644 --- a/examples/cloud.rs +++ b/examples/cloud.rs @@ -2,7 +2,7 @@ use std::env; use std::path::Path; use anyhow::Result; -use scylla::CloudSessionBuilder; +use scylla::client::session_builder::CloudSessionBuilder; #[tokio::main] async fn main() -> Result<()> { diff --git a/examples/compare-tokens.rs b/examples/compare-tokens.rs index ab4bbb6b16..f95a9bd978 100644 --- a/examples/compare-tokens.rs +++ b/examples/compare-tokens.rs @@ -1,7 +1,8 @@ use anyhow::Result; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::cluster::NodeAddr; use scylla::routing::Token; -use scylla::transport::NodeAddr; -use scylla::{Session, SessionBuilder}; use std::env; #[tokio::main] diff --git a/examples/cql-time-types.rs b/examples/cql-time-types.rs index 29a66349e2..04fd6ade29 100644 --- a/examples/cql-time-types.rs +++ b/examples/cql-time-types.rs @@ -4,10 +4,10 @@ use anyhow::Result; use chrono::{DateTime, NaiveDate, NaiveTime, Utc}; use futures::{StreamExt as _, TryStreamExt as _}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::frame::response::result::CqlValue; use scylla::frame::value::{CqlDate, CqlTime, CqlTimestamp}; -use scylla::transport::session::Session; -use scylla::SessionBuilder; use std::env; #[tokio::main] diff --git a/examples/cqlsh-rs.rs b/examples/cqlsh-rs.rs index 1a2941c900..11a36e3440 100644 --- a/examples/cqlsh-rs.rs +++ b/examples/cqlsh-rs.rs @@ -3,12 +3,12 @@ use rustyline::completion::{Completer, Pair}; use rustyline::error::ReadlineError; use rustyline::{CompletionType, Config, Context, Editor}; use rustyline_derive::{Helper, Highlighter, Hinter, Validator}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::frame::response::result::Row; -use scylla::transport::query_result::IntoRowsResultError; -use scylla::transport::session::Session; -use scylla::transport::Compression; -use scylla::QueryResult; -use scylla::SessionBuilder; +use scylla::frame::Compression; +use scylla::response::query_result::IntoRowsResultError; +use scylla::response::query_result::QueryResult; use std::env; #[derive(Helper, Highlighter, Validator, Hinter)] diff --git a/examples/custom_deserialization.rs b/examples/custom_deserialization.rs index 5a5991edfe..6d339b1e28 100644 --- a/examples/custom_deserialization.rs +++ b/examples/custom_deserialization.rs @@ -1,8 +1,8 @@ use anyhow::Result; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::deserialize::DeserializeValue; use scylla::frame::response::result::ColumnType; -use scylla::transport::session::Session; -use scylla::SessionBuilder; use std::env; #[tokio::main] diff --git a/examples/custom_load_balancing_policy.rs b/examples/custom_load_balancing_policy.rs index 5c279f2331..af32f8779b 100644 --- a/examples/custom_load_balancing_policy.rs +++ b/examples/custom_load_balancing_policy.rs @@ -1,18 +1,18 @@ use anyhow::Result; use rand::thread_rng; use rand::Rng; -use scylla::transport::NodeRef; -use scylla::{ - load_balancing::{LoadBalancingPolicy, RoutingInfo}, - routing::Shard, - transport::{ClusterData, ExecutionProfile}, - Session, SessionBuilder, -}; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::cluster::ClusterState; +use scylla::cluster::NodeRef; +use scylla::policies::load_balancing::{LoadBalancingPolicy, RoutingInfo}; +use scylla::routing::Shard; use std::{env, sync::Arc}; /// Example load balancing policy that prefers nodes from favorite datacenter /// This is, of course, very naive, as it is completely non token-aware. -/// For more realistic implementation, see [`DefaultPolicy`](scylla::load_balancing::DefaultPolicy). +/// For more realistic implementation, see [`DefaultPolicy`](scylla::policies::load_balancing::DefaultPolicy). #[derive(Debug)] struct CustomLoadBalancingPolicy { fav_datacenter_name: String, @@ -30,7 +30,7 @@ impl LoadBalancingPolicy for CustomLoadBalancingPolicy { fn pick<'a>( &'a self, _info: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)> { self.fallback(_info, cluster).next() } @@ -38,8 +38,8 @@ impl LoadBalancingPolicy for CustomLoadBalancingPolicy { fn fallback<'a>( &'a self, _info: &'a RoutingInfo, - cluster: &'a ClusterData, - ) -> scylla::load_balancing::FallbackPlan<'a> { + cluster: &'a ClusterState, + ) -> scylla::policies::load_balancing::FallbackPlan<'a> { let fav_dc_nodes = cluster .replica_locator() .unique_nodes_in_datacenter_ring(&self.fav_datacenter_name); diff --git a/examples/execution_profile.rs b/examples/execution_profile.rs index 3562966ac5..b634ceb51c 100644 --- a/examples/execution_profile.rs +++ b/examples/execution_profile.rs @@ -1,12 +1,12 @@ use anyhow::Result; -use scylla::load_balancing; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::{Session, SessionConfig}; +use scylla::client::session_builder::SessionBuilder; +use scylla::policies::load_balancing; +use scylla::policies::retry::{DefaultRetryPolicy, FallthroughRetryPolicy}; +use scylla::policies::speculative_execution::PercentileSpeculativeExecutionPolicy; use scylla::query::Query; -use scylla::retry_policy::{DefaultRetryPolicy, FallthroughRetryPolicy}; -use scylla::speculative_execution::PercentileSpeculativeExecutionPolicy; use scylla::statement::{Consistency, SerialConsistency}; -use scylla::transport::session::Session; -use scylla::transport::ExecutionProfile; -use scylla::{SessionBuilder, SessionConfig}; use std::env; use std::sync::Arc; use std::time::Duration; diff --git a/examples/get_by_name.rs b/examples/get_by_name.rs index 4aca66f665..436bdb6345 100644 --- a/examples/get_by_name.rs +++ b/examples/get_by_name.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::frame::response::result::Row; -use scylla::transport::session::Session; -use scylla::SessionBuilder; use std::env; #[tokio::main] diff --git a/examples/logging.rs b/examples/logging.rs index 6b090acbcb..c8ff77f730 100644 --- a/examples/logging.rs +++ b/examples/logging.rs @@ -1,6 +1,6 @@ use anyhow::Result; -use scylla::transport::session::Session; -use scylla::SessionBuilder; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::env; use tracing::info; diff --git a/examples/logging_log.rs b/examples/logging_log.rs index 19465018cc..3630b6cdb0 100644 --- a/examples/logging_log.rs +++ b/examples/logging_log.rs @@ -1,5 +1,6 @@ use anyhow::Result; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::env; use tracing::info; diff --git a/examples/parallel-prepared.rs b/examples/parallel-prepared.rs index 167b583944..c77db1390e 100644 --- a/examples/parallel-prepared.rs +++ b/examples/parallel-prepared.rs @@ -1,5 +1,6 @@ use anyhow::Result; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::env; use std::sync::Arc; diff --git a/examples/parallel.rs b/examples/parallel.rs index 716225fb77..c3ac6b0829 100644 --- a/examples/parallel.rs +++ b/examples/parallel.rs @@ -1,5 +1,6 @@ use anyhow::Result; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::env; use std::sync::Arc; diff --git a/examples/query_history.rs b/examples/query_history.rs index 04d9586481..c36ff682d1 100644 --- a/examples/query_history.rs +++ b/examples/query_history.rs @@ -2,11 +2,11 @@ use anyhow::Result; use futures::StreamExt as _; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::frame::response::result::Row; -use scylla::history::{HistoryCollector, StructuredHistory}; +use scylla::observability::history::{HistoryCollector, StructuredHistory}; use scylla::query::Query; -use scylla::transport::session::Session; -use scylla::SessionBuilder; use std::env; use std::sync::Arc; diff --git a/examples/schema_agreement.rs b/examples/schema_agreement.rs index d37cc32b72..c5106e3d62 100644 --- a/examples/schema_agreement.rs +++ b/examples/schema_agreement.rs @@ -1,8 +1,8 @@ use anyhow::{bail, Result}; use futures::TryStreamExt as _; -use scylla::transport::errors::QueryError; -use scylla::transport::session::Session; -use scylla::SessionBuilder; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::errors::QueryError; use std::env; use std::time::Duration; diff --git a/examples/select-paging.rs b/examples/select-paging.rs index 00aa961fc8..80979d06a2 100644 --- a/examples/select-paging.rs +++ b/examples/select-paging.rs @@ -1,7 +1,9 @@ use anyhow::Result; use futures::StreamExt as _; -use scylla::statement::PagingState; -use scylla::{query::Query, Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::query::Query; +use scylla::response::PagingState; use std::env; use std::ops::ControlFlow; diff --git a/examples/speculative-execution.rs b/examples/speculative-execution.rs index e6c64e3ad7..9f5ec6369d 100644 --- a/examples/speculative-execution.rs +++ b/examples/speculative-execution.rs @@ -1,7 +1,7 @@ -use scylla::{ - speculative_execution::PercentileSpeculativeExecutionPolicy, - transport::execution_profile::ExecutionProfile, Session, SessionBuilder, -}; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::policies::speculative_execution::PercentileSpeculativeExecutionPolicy; use anyhow::Result; use std::{env, sync::Arc}; diff --git a/examples/tls.rs b/examples/tls.rs index d95f14bea2..87334a2a9c 100644 --- a/examples/tls.rs +++ b/examples/tls.rs @@ -1,7 +1,7 @@ use anyhow::Result; use futures::TryStreamExt as _; -use scylla::transport::session::Session; -use scylla::SessionBuilder; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::env; use std::fs; use std::path::PathBuf; diff --git a/examples/tower.rs b/examples/tower.rs index f521b1b614..b7b94fdc6c 100644 --- a/examples/tower.rs +++ b/examples/tower.rs @@ -1,5 +1,6 @@ +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::frame::response::result::Row; -use scylla::transport::session::Session; use std::env; use std::future::Future; use std::pin::Pin; @@ -14,8 +15,8 @@ struct SessionService { // A trivial service implementation for sending parameterless simple string requests to Scylla. impl Service for SessionService { - type Response = scylla::QueryResult; - type Error = scylla::transport::errors::QueryError; + type Response = scylla::response::query_result::QueryResult; + type Error = scylla::errors::QueryError; type Future = Pin>>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { @@ -34,12 +35,7 @@ async fn main() -> anyhow::Result<()> { println!("Connecting to {} ...", uri); let mut session: SessionService = SessionService { - session: Arc::new( - scylla::SessionBuilder::new() - .known_node(uri) - .build() - .await?, - ), + session: Arc::new(SessionBuilder::new().known_node(uri).build().await?), }; let rows_result = session diff --git a/examples/tracing.rs b/examples/tracing.rs index dd035c095d..a9ab8c9d9a 100644 --- a/examples/tracing.rs +++ b/examples/tracing.rs @@ -4,12 +4,13 @@ use anyhow::{anyhow, Result}; use futures::StreamExt as _; use scylla::batch::Batch; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::observability::tracing::TracingInfo; +use scylla::response::query_result::QueryResult; use scylla::statement::{ prepared_statement::PreparedStatement, query::Query, Consistency, SerialConsistency, }; -use scylla::tracing::TracingInfo; -use scylla::QueryResult; -use scylla::{Session, SessionBuilder}; use std::env; use std::num::NonZeroU32; use std::time::Duration; diff --git a/examples/user-defined-type.rs b/examples/user-defined-type.rs index 39b3003737..e46e5851c7 100644 --- a/examples/user-defined-type.rs +++ b/examples/user-defined-type.rs @@ -1,7 +1,9 @@ use anyhow::Result; use futures::TryStreamExt as _; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::macros::DeserializeValue; -use scylla::{SerializeValue, Session, SessionBuilder}; +use scylla::SerializeValue; use std::env; #[tokio::main] diff --git a/examples/value_list.rs b/examples/value_list.rs index a8197edca1..92f915e1eb 100644 --- a/examples/value_list.rs +++ b/examples/value_list.rs @@ -1,6 +1,7 @@ use anyhow::Result; use futures::StreamExt; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use std::env; #[tokio::main] diff --git a/scylla-cql/src/types/serialize/batch.rs b/scylla-cql/src/types/serialize/batch.rs index aff43b990e..9fbfa73e66 100644 --- a/scylla-cql/src/types/serialize/batch.rs +++ b/scylla-cql/src/types/serialize/batch.rs @@ -384,7 +384,7 @@ where fn is_empty_next(&mut self) -> Option { self.0 .next_serialized() - .map(|sv| sv.map_or(false, |sv| sv.len() == 0)) + .map(|sv| sv.is_ok_and(|sv| sv.len() == 0)) } #[inline] diff --git a/scylla-cql/src/types/serialize/row.rs b/scylla-cql/src/types/serialize/row.rs index cf05398fda..a0a96f9d3d 100644 --- a/scylla-cql/src/types/serialize/row.rs +++ b/scylla-cql/src/types/serialize/row.rs @@ -740,7 +740,7 @@ pub enum ValueListToSerializeRowAdapterError { /// It is not aware of the types of contained values, /// it is basically a byte buffer in the format expected by the CQL protocol. /// Usually there is no need for a user of a driver to use this struct, it is mostly internal. -/// The exception are APIs like `ClusterData::compute_token` / `ClusterData::get_endpoints`. +/// The exception are APIs like `ClusterState::compute_token` / `ClusterState::get_endpoints`. /// Allows adding new values to the buffer and iterating over the content. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct SerializedValues { diff --git a/scylla/benches/benchmark.rs b/scylla/benches/benchmark.rs index 61d35d8f97..39075fde76 100644 --- a/scylla/benches/benchmark.rs +++ b/scylla/benches/benchmark.rs @@ -1,7 +1,7 @@ use criterion::{criterion_group, criterion_main, Criterion}; use bytes::BytesMut; -use scylla::transport::partitioner::{calculate_token_for_partition_key, Murmur3Partitioner}; +use scylla::routing::partitioner::{calculate_token_for_partition_key, Murmur3Partitioner}; use scylla_cql::{ frame::{response::result::ColumnType, types}, types::serialize::row::SerializedValues, diff --git a/scylla/src/authentication/mod.rs b/scylla/src/authentication/mod.rs index 2e43b2dee6..a39a74a103 100644 --- a/scylla/src/authentication/mod.rs +++ b/scylla/src/authentication/mod.rs @@ -1,6 +1,8 @@ use async_trait::async_trait; use bytes::{BufMut, BytesMut}; +pub use crate::frame::Authenticator; + /// Type to represent an authentication error message. pub type AuthError = String; diff --git a/scylla/src/transport/caching_session.rs b/scylla/src/client/caching_session.rs similarity index 97% rename from scylla/src/transport/caching_session.rs rename to scylla/src/client/caching_session.rs index a5b6416833..a092e3992c 100644 --- a/scylla/src/transport/caching_session.rs +++ b/scylla/src/client/caching_session.rs @@ -1,14 +1,14 @@ use crate::batch::{Batch, BatchStatement}; +#[allow(deprecated)] +use crate::client::pager::LegacyRowIterator; +use crate::errors::QueryError; use crate::prepared_statement::PreparedStatement; use crate::query::Query; -use crate::statement::{PagingState, PagingStateResponse}; -use crate::transport::errors::QueryError; -#[allow(deprecated)] -use crate::transport::iterator::LegacyRowIterator; -use crate::transport::partitioner::PartitionerName; #[allow(deprecated)] -use crate::LegacyQueryResult; -use crate::QueryResult; +use crate::response::legacy_query_result::LegacyQueryResult; +use crate::response::query_result::QueryResult; +use crate::response::{PagingState, PagingStateResponse}; +use crate::routing::partitioner::PartitionerName; use bytes::Bytes; use dashmap::DashMap; use futures::future::try_join_all; @@ -20,9 +20,9 @@ use std::fmt; use std::hash::BuildHasher; use std::sync::Arc; -use super::iterator::QueryPager; +use crate::client::pager::QueryPager; #[allow(deprecated)] -use super::session::{ +use crate::client::session::{ CurrentDeserializationApi, DeserializationApiKind, GenericSession, LegacyDeserializationApi, }; @@ -341,25 +341,24 @@ where #[cfg(test)] mod tests { + use crate::batch::{Batch, BatchStatement}; + #[allow(deprecated)] + use crate::client::caching_session::LegacyCachingSession; + use crate::client::session::Session; + use crate::prepared_statement::PreparedStatement; use crate::query::Query; - use crate::statement::PagingState; + use crate::response::PagingState; + use crate::routing::partitioner::PartitionerName; use crate::test_utils::{ create_new_session_builder, scylla_supports_tablets, setup_tracing, PerformDDL, }; - use crate::transport::partitioner::PartitionerName; - use crate::transport::session::Session; use crate::utils::test_utils::unique_keyspace_name; - #[allow(deprecated)] - use crate::LegacyCachingSession; - use crate::{ - batch::{Batch, BatchStatement}, - prepared_statement::PreparedStatement, - CachingSession, - }; use futures::TryStreamExt; use scylla_cql::frame::response::result::Row; use std::collections::BTreeSet; + use super::CachingSession; + async fn new_for_test(with_tablet_support: bool) -> Session { let session = create_new_session_builder() .build() diff --git a/scylla/src/transport/execution_profile.rs b/scylla/src/client/execution_profile.rs similarity index 91% rename from scylla/src/transport/execution_profile.rs rename to scylla/src/client/execution_profile.rs index a94addec5b..6bdbc42321 100644 --- a/scylla/src/transport/execution_profile.rs +++ b/scylla/src/client/execution_profile.rs @@ -16,9 +16,10 @@ //! # extern crate scylla; //! # use std::error::Error; //! # async fn check_only_compiles() -> Result<(), Box> { -//! use scylla::{Session, SessionBuilder}; +//! use scylla::client::session::Session; +//! use scylla::client::session_builder::SessionBuilder; //! use scylla::statement::Consistency; -//! use scylla::transport::ExecutionProfile; +//! use scylla::client::execution_profile::ExecutionProfile; //! //! let profile = ExecutionProfile::builder() //! .consistency(Consistency::LocalOne) @@ -44,7 +45,7 @@ //! # async fn check_only_compiles() -> Result<(), Box> { //! use scylla::query::Query; //! use scylla::statement::Consistency; -//! use scylla::transport::ExecutionProfile; +//! use scylla::client::execution_profile::ExecutionProfile; //! use std::time::Duration; //! //! let profile = ExecutionProfile::builder() @@ -71,7 +72,7 @@ //! # use std::error::Error; //! # async fn check_only_compiles() -> Result<(), Box> { //! use scylla::statement::Consistency; -//! use scylla::transport::ExecutionProfile; +//! use scylla::client::execution_profile::ExecutionProfile; //! use std::time::Duration; //! //! let base_profile = ExecutionProfile::builder() @@ -109,10 +110,11 @@ //! # extern crate scylla; //! # use std::error::Error; //! # async fn check_only_compiles() -> Result<(), Box> { -//! use scylla::{Session, SessionBuilder}; +//! use scylla::client::session::Session; +//! use scylla::client::session_builder::SessionBuilder; //! use scylla::query::Query; //! use scylla::statement::Consistency; -//! use scylla::transport::ExecutionProfile; +//! use scylla::client::execution_profile::ExecutionProfile; //! //! let profile1 = ExecutionProfile::builder() //! .consistency(Consistency::One) @@ -165,16 +167,15 @@ use std::{fmt::Debug, sync::Arc, time::Duration}; use arc_swap::ArcSwap; use scylla_cql::{frame::types::SerialConsistency, Consistency}; -use crate::{ - load_balancing::LoadBalancingPolicy, retry_policy::RetryPolicy, - speculative_execution::SpeculativeExecutionPolicy, -}; +use crate::policies::load_balancing::LoadBalancingPolicy; +use crate::policies::retry::RetryPolicy; +use crate::policies::speculative_execution::SpeculativeExecutionPolicy; pub(crate) mod defaults { - use crate::load_balancing::{self, LoadBalancingPolicy}; - use crate::retry_policy::{DefaultRetryPolicy, RetryPolicy}; - use crate::speculative_execution::SpeculativeExecutionPolicy; - use crate::transport::execution_profile::ExecutionProfileInner; + use super::ExecutionProfileInner; + use crate::policies::load_balancing::{self, LoadBalancingPolicy}; + use crate::policies::retry::{DefaultRetryPolicy, RetryPolicy}; + use crate::policies::speculative_execution::SpeculativeExecutionPolicy; use scylla_cql::frame::types::SerialConsistency; use scylla_cql::Consistency; use std::sync::Arc; @@ -216,7 +217,8 @@ pub(crate) mod defaults { /// # Example /// /// ``` -/// # use scylla::transport::{ExecutionProfile, retry_policy::FallthroughRetryPolicy}; +/// # use scylla::client::execution_profile::ExecutionProfile; +/// # use scylla::policies::retry::FallthroughRetryPolicy; /// # use scylla::statement::Consistency; /// # use std::sync::Arc; /// # fn example() -> Result<(), Box> { @@ -243,7 +245,7 @@ impl ExecutionProfileBuilder { /// /// # Example /// ``` - /// # use scylla::transport::ExecutionProfile; + /// # use scylla::client::execution_profile::ExecutionProfile; /// # use std::time::Duration; /// # fn example() -> Result<(), Box> { /// let profile: ExecutionProfile = ExecutionProfile::builder() @@ -277,8 +279,8 @@ impl ExecutionProfileBuilder { /// /// # Example /// ``` - /// # use scylla::transport::ExecutionProfile; - /// # use scylla::transport::load_balancing::DefaultPolicy; + /// # use scylla::client::execution_profile::ExecutionProfile; + /// # use scylla::policies::load_balancing::DefaultPolicy; /// # use std::sync::Arc; /// # fn example() -> Result<(), Box> { /// let profile: ExecutionProfile = ExecutionProfile::builder() @@ -296,13 +298,13 @@ impl ExecutionProfileBuilder { } /// Sets the [`RetryPolicy`] to use by default on queries. - /// The default is [DefaultRetryPolicy](crate::transport::retry_policy::DefaultRetryPolicy). + /// The default is [DefaultRetryPolicy](crate::policies::retry::DefaultRetryPolicy). /// It is possible to implement a custom retry policy by implementing the trait [`RetryPolicy`]. /// /// # Example /// ``` - /// use scylla::transport::retry_policy::DefaultRetryPolicy; - /// # use scylla::transport::ExecutionProfile; + /// # use scylla::client::execution_profile::ExecutionProfile; + /// # use scylla::policies::retry::DefaultRetryPolicy; /// # use std::sync::Arc; /// # fn example() -> Result<(), Box> { /// let profile: ExecutionProfile = ExecutionProfile::builder() @@ -325,8 +327,8 @@ impl ExecutionProfileBuilder { /// # fn check_only_compiles() -> Result<(), Box> { /// use std::{sync::Arc, time::Duration}; /// use scylla::{ - /// transport::ExecutionProfile, - /// transport::speculative_execution::SimpleSpeculativeExecutionPolicy, + /// client::execution_profile::ExecutionProfile, + /// policies::speculative_execution::SimpleSpeculativeExecutionPolicy, /// }; /// /// let policy = SimpleSpeculativeExecutionPolicy { @@ -352,8 +354,8 @@ impl ExecutionProfileBuilder { /// /// # Example /// ``` - /// use scylla::transport::retry_policy::DefaultRetryPolicy; - /// # use scylla::transport::ExecutionProfile; + /// # use scylla::client::execution_profile::ExecutionProfile; + /// # use scylla::policies::retry::DefaultRetryPolicy; /// # use std::sync::Arc; /// # fn example() -> Result<(), Box> { /// let profile: ExecutionProfile = ExecutionProfile::builder() diff --git a/scylla/src/client/mod.rs b/scylla/src/client/mod.rs new file mode 100644 index 0000000000..cff02aea74 --- /dev/null +++ b/scylla/src/client/mod.rs @@ -0,0 +1,36 @@ +//! This module holds entities that represent the whole configurable +//! driver's client of the cluster. +//! The following abstractions are involved: +//! - [Session](session::Session) - the main entity of the driver. It: +//! - contains and manages all driver configuration, +// - launches and communicates with [ClusterWorker] (see [cluster](crate::cluster) module for more info), +//! - enables executing CQL requests, taking all configuration into consideration. +//! - [SessionBuilder](session_builder::SessionBuilder) - just a convenient builder for a `Session`. +//! - [CachingSession](caching_session::CachingSession) - a wrapper over a [Session](session::Session) +//! that keeps and manages a cache of prepared statements, so that a user can be free of such considerations. +//! - [SelfIdentity] - configuresd driver and application self-identifying information, +//! to be sent in STARTUP message. +//! - [ExecutionProfile](execution_profile::ExecutionProfile) - a profile that groups various configuration +//! options relevant when executing a request against the DB. +//! - [QueryPager](pager::QueryPager) and [TypedRowStream](pager::TypedRowStream) - entities that provide +//! automated transparent paging of a query. + +pub mod execution_profile; + +pub mod pager; + +pub mod caching_session; + +mod self_identity; +pub use self_identity::SelfIdentity; + +pub mod session; + +pub mod session_builder; + +#[cfg(test)] +mod session_test; + +pub use scylla_cql::frame::Compression; + +pub use crate::network::PoolSize; diff --git a/scylla/src/transport/iterator.rs b/scylla/src/client/pager.rs similarity index 96% rename from scylla/src/transport/iterator.rs rename to scylla/src/client/pager.rs index f11d9dd73e..e229090c90 100644 --- a/scylla/src/transport/iterator.rs +++ b/scylla/src/client/pager.rs @@ -1,4 +1,6 @@ -//! Iterators over rows returned by paged queries +//! Entities that provide automated transparent paging of a query. +//! They enable consuming result of a paged query as a stream over rows, +//! which abstracts over page boundaries. use std::future::Future; use std::net::SocketAddr; @@ -9,37 +11,36 @@ use std::task::{Context, Poll}; use futures::Stream; use scylla_cql::frame::frame_errors::ResultMetadataAndRowsCountParseError; +use scylla_cql::frame::request::query::PagingState; use scylla_cql::frame::response::result::RawMetadataAndRawRows; use scylla_cql::frame::response::NonErrorResponse; +use scylla_cql::frame::types::SerialConsistency; use scylla_cql::types::deserialize::result::RawRowLendingIterator; use scylla_cql::types::deserialize::row::{ColumnIterator, DeserializeRow}; use scylla_cql::types::deserialize::{DeserializationError, TypeCheckError}; use scylla_cql::types::serialize::row::SerializedValues; +use scylla_cql::Consistency; use std::result::Result; use thiserror::Error; use tokio::sync::mpsc; -use super::execution_profile::ExecutionProfileInner; -use super::query_result::ColumnSpecs; -use super::session::RequestSpan; +use crate::client::execution_profile::ExecutionProfileInner; +use crate::cluster::{ClusterState, NodeRef}; #[allow(deprecated)] use crate::cql_to_rust::{FromRow, FromRowError}; - use crate::deserialize::DeserializeOwnedRow; -use crate::frame::response::{ - result, - result::{ColumnSpec, Row}, -}; -use crate::history::{self, HistoryListener}; +use crate::errors::ProtocolError; +use crate::errors::{QueryError, UserRequestError}; +use crate::frame::response::result; +use crate::network::Connection; +use crate::observability::driver_tracing::RequestSpan; +use crate::observability::history::{self, HistoryListener}; +use crate::observability::metrics::Metrics; +use crate::policies::load_balancing::{self, RoutingInfo}; +use crate::policies::retry::{QueryInfo, RetryDecision, RetrySession}; +use crate::response::query_result::ColumnSpecs; +use crate::response::{NonErrorQueryResponse, QueryResponse}; use crate::statement::{prepared_statement::PreparedStatement, query::Query}; -use crate::statement::{Consistency, PagingState, SerialConsistency}; -use crate::transport::cluster::ClusterData; -use crate::transport::connection::{Connection, NonErrorQueryResponse, QueryResponse}; -use crate::transport::errors::{ProtocolError, QueryError, UserRequestError}; -use crate::transport::load_balancing::{self, RoutingInfo}; -use crate::transport::metrics::Metrics; -use crate::transport::retry_policy::{QueryInfo, RetryDecision, RetrySession}; -use crate::transport::NodeRef; use tracing::{trace, trace_span, warn, Instrument}; use uuid::Uuid; @@ -66,7 +67,7 @@ pub(crate) struct PreparedIteratorConfig { pub(crate) prepared: PreparedStatement, pub(crate) values: SerializedValues, pub(crate) execution_profile: Arc, - pub(crate) cluster_data: Arc, + pub(crate) cluster_data: Arc, pub(crate) metrics: Arc, } @@ -78,7 +79,7 @@ mod checked_channel_sender { use tokio::sync::mpsc; use uuid::Uuid; - use crate::transport::errors::QueryError; + use crate::errors::QueryError; use super::ReceivedPage; @@ -161,7 +162,7 @@ where SpanCreator: Fn() -> RequestSpan, { // Contract: this function MUST send at least one item through self.sender - async fn work(mut self, cluster_data: Arc) -> PageSendAttemptedProof { + async fn work(mut self, cluster_data: Arc) -> PageSendAttemptedProof { let load_balancer = self.execution_profile.load_balancing_policy.clone(); let statement_info = self.statement_info.clone(); let query_plan = @@ -553,8 +554,9 @@ where /// A pre-0.15.0 interface is also available, although deprecated: /// `into_legacy()` method converts QueryPager to LegacyRowIterator, /// enabling Stream'ed operation on rows being eagerly deserialized -/// to the middle-man [Row] type. This is inefficient, especially if -/// [Row] is not the intended target type. +/// to the middle-man [Row](scylla_cql::frame::response::result::Row) type. +/// This is inefficient, especially if [Row](scylla_cql::frame::response::result::Row) +/// is not the intended target type. pub struct QueryPager { current_page: RawRowLendingIterator, page_receiver: mpsc::Receiver>, @@ -665,7 +667,7 @@ impl QueryPager { /// Converts this iterator into an iterator over rows parsed as given type, /// using the legacy deserialization framework. /// This is inefficient, because all rows are being eagerly deserialized - /// to a middle-man [Row] type. + /// to a middle-man [Row](scylla_cql::frame::response::result::Row) type. #[deprecated( since = "0.15.0", note = "Legacy deserialization API is inefficient and is going to be removed soon" @@ -679,7 +681,7 @@ impl QueryPager { pub(crate) async fn new_for_query( query: Query, execution_profile: Arc, - cluster_data: Arc, + cluster_data: Arc, metrics: Arc, ) -> Result { let (sender, receiver) = mpsc::channel(1); @@ -1072,6 +1074,8 @@ pub enum NextRowError { mod legacy { #![allow(deprecated)] + use scylla_cql::frame::response::result::{ColumnSpec, Row}; + use super::*; /// Iterator over rows returned by paged queries. diff --git a/scylla/src/client/self_identity.rs b/scylla/src/client/self_identity.rs new file mode 100644 index 0000000000..7c33e845f0 --- /dev/null +++ b/scylla/src/client/self_identity.rs @@ -0,0 +1,140 @@ +use std::borrow::Cow; + +/// Driver and application self-identifying information, +/// to be sent in STARTUP message. +#[derive(Debug, Clone, Default)] +pub struct SelfIdentity<'id> { + // Custom driver identity can be set if a custom driver build is running, + // or an entirely different driver is operating on top of Rust driver + // (e.g. cpp-rust-driver). + custom_driver_name: Option>, + custom_driver_version: Option>, + + // ### Q: Where do APPLICATION_NAME, APPLICATION_VERSION and CLIENT_ID come from? + // - there are no columns in system.clients dedicated to those attributes, + // - APPLICATION_NAME / APPLICATION_VERSION are not present in Scylla's source code at all, + // - only 2 results in Cassandra source is some example in docs: + // https://github.com/apache/cassandra/blob/d3cbf9c1f72057d2a5da9df8ed567d20cd272931/doc/modules/cassandra/pages/managing/operating/virtualtables.adoc?plain=1#L218. + // APPLICATION_NAME and APPLICATION_VERSION appears in client_options which + // is an arbitrary dict where client can send any keys. + // - driver variables are mentioned in protocol v5 + // (https://github.com/apache/cassandra/blob/d3cbf9c1f72057d2a5da9df8ed567d20cd272931/doc/native_protocol_v5.spec#L480), + // application variables are not. + // + // ### A: + // The following options are not exposed anywhere in Scylla tables. + // They come directly from CPP driver, and they are supported in Cassandra + // + // See https://github.com/scylladb/cpp-driver/blob/fa0f27069a625057984d1fa58f434ea99b86c83f/include/cassandra.h#L2916. + // As we want to support as big subset of its API as possible in cpp-rust-driver, I decided to expose API for setting + // those particular key-value pairs, similarly to what cpp-driver does, and not an API to set arbitrary key-value pairs. + // + // Allowing users to set arbitrary options could break the driver by overwriting options that bear special meaning, + // e.g. the shard-aware port. Therefore, I'm against such liberal API. OTOH, we need to expose APPLICATION_NAME, + // APPLICATION_VERSION and CLIENT_ID for cpp-rust-driver. + + // Application identity can be set to distinguish different applications + // connected to the same cluster. + application_name: Option>, + application_version: Option>, + + // A (unique) client ID can be set to distinguish different instances + // of the same application connected to the same cluster. + client_id: Option>, +} + +impl<'id> SelfIdentity<'id> { + pub fn new() -> Self { + Self::default() + } + + /// Advertises a custom driver name, which can be used if a custom driver build is running, + /// or an entirely different driver is operating on top of Rust driver + /// (e.g. cpp-rust-driver). + pub fn set_custom_driver_name(&mut self, custom_driver_name: impl Into>) { + self.custom_driver_name = Some(custom_driver_name.into()); + } + + /// Advertises a custom driver name. See [Self::set_custom_driver_name] for use cases. + pub fn with_custom_driver_name(mut self, custom_driver_name: impl Into>) -> Self { + self.custom_driver_name = Some(custom_driver_name.into()); + self + } + + /// Custom driver name to be advertised. See [Self::set_custom_driver_name] for use cases. + pub fn get_custom_driver_name(&self) -> Option<&str> { + self.custom_driver_name.as_deref() + } + + /// Advertises a custom driver version. See [Self::set_custom_driver_name] for use cases. + pub fn set_custom_driver_version(&mut self, custom_driver_version: impl Into>) { + self.custom_driver_version = Some(custom_driver_version.into()); + } + + /// Advertises a custom driver version. See [Self::set_custom_driver_name] for use cases. + pub fn with_custom_driver_version( + mut self, + custom_driver_version: impl Into>, + ) -> Self { + self.custom_driver_version = Some(custom_driver_version.into()); + self + } + + /// Custom driver version to be advertised. See [Self::set_custom_driver_version] for use cases. + pub fn get_custom_driver_version(&self) -> Option<&str> { + self.custom_driver_version.as_deref() + } + + /// Advertises an application name, which can be used to distinguish different applications + /// connected to the same cluster. + pub fn set_application_name(&mut self, application_name: impl Into>) { + self.application_name = Some(application_name.into()); + } + + /// Advertises an application name. See [Self::set_application_name] for use cases. + pub fn with_application_name(mut self, application_name: impl Into>) -> Self { + self.application_name = Some(application_name.into()); + self + } + + /// Application name to be advertised. See [Self::set_application_name] for use cases. + pub fn get_application_name(&self) -> Option<&str> { + self.application_name.as_deref() + } + + /// Advertises an application version. See [Self::set_application_name] for use cases. + pub fn set_application_version(&mut self, application_version: impl Into>) { + self.application_version = Some(application_version.into()); + } + + /// Advertises an application version. See [Self::set_application_name] for use cases. + pub fn with_application_version( + mut self, + application_version: impl Into>, + ) -> Self { + self.application_version = Some(application_version.into()); + self + } + + /// Application version to be advertised. See [Self::set_application_version] for use cases. + pub fn get_application_version(&self) -> Option<&str> { + self.application_version.as_deref() + } + + /// Advertises a client ID, which can be set to distinguish different instances + /// of the same application connected to the same cluster. + pub fn set_client_id(&mut self, client_id: impl Into>) { + self.client_id = Some(client_id.into()); + } + + /// Advertises a client ID. See [Self::set_client_id] for use cases. + pub fn with_client_id(mut self, client_id: impl Into>) -> Self { + self.client_id = Some(client_id.into()); + self + } + + /// Client ID to be advertised. See [Self::set_client_id] for use cases. + pub fn get_client_id(&self) -> Option<&str> { + self.client_id.as_deref() + } +} diff --git a/scylla/src/transport/session.rs b/scylla/src/client/session.rs similarity index 88% rename from scylla/src/transport/session.rs rename to scylla/src/client/session.rs index 9cae1d6ad1..a0a29db4d1 100644 --- a/scylla/src/transport/session.rs +++ b/scylla/src/client/session.rs @@ -1,94 +1,68 @@ //! `Session` is the main object used in the driver.\ //! It manages all connections to the cluster and allows to perform queries. +use super::execution_profile::{ExecutionProfile, ExecutionProfileHandle, ExecutionProfileInner}; +#[allow(deprecated)] +use super::pager::{LegacyRowIterator, PreparedIteratorConfig, QueryPager}; +use super::{Compression, PoolSize, SelfIdentity}; +use crate::authentication::AuthenticatorProvider; use crate::batch::batch_values; +use crate::batch::{Batch, BatchStatement}; #[cfg(feature = "cloud")] use crate::cloud::CloudConfig; -#[allow(deprecated)] -use crate::LegacyQueryResult; - -use crate::history; -use crate::history::HistoryListener; -pub use crate::transport::errors::TranslationError; -use crate::transport::errors::{ - BadQuery, NewSessionError, ProtocolError, QueryError, UserRequestError, +#[cfg(feature = "cloud")] +use crate::cluster::node::CloudEndpoint; +use crate::cluster::node::{InternalKnownNode, KnownNode, NodeRef}; +use crate::cluster::{Cluster, ClusterNeatDebug, ClusterState}; +use crate::errors::{ + BadQuery, NewSessionError, ProtocolError, QueryError, TracingProtocolError, UserRequestError, }; -use crate::utils::pretty::{CommaSeparatedDisplayer, CqlValueDisplayer}; +use crate::frame::response::result; +#[cfg(feature = "ssl")] +use crate::network::SslConfig; +use crate::network::{Connection, ConnectionConfig, PoolConfig, VerifiedKeyspaceName}; +use crate::observability::driver_tracing::RequestSpan; +use crate::observability::history::{self, HistoryListener}; +use crate::observability::metrics::Metrics; +use crate::observability::tracing::TracingInfo; +use crate::policies::address_translator::AddressTranslator; +use crate::policies::host_filter::HostFilter; +use crate::policies::load_balancing::{self, RoutingInfo}; +use crate::policies::retry::{QueryInfo, RetryDecision, RetrySession}; +use crate::policies::speculative_execution; +use crate::prepared_statement::PreparedStatement; +use crate::query::Query; +#[allow(deprecated)] +use crate::response::legacy_query_result::LegacyQueryResult; +use crate::response::query_result::{MaybeFirstRowError, QueryResult, RowsError}; +use crate::response::{NonErrorQueryResponse, PagingState, PagingStateResponse, QueryResponse}; +use crate::routing::partitioner::PartitionerName; +use crate::routing::Shard; +use crate::statement::{Consistency, PageSize, StatementConfig}; use arc_swap::ArcSwapOption; -use async_trait::async_trait; use futures::future::join_all; use futures::future::try_join_all; -use itertools::{Either, Itertools}; -use scylla_cql::frame::response::result::RawMetadataAndRawRows; -use scylla_cql::frame::response::result::{deser_cql_value, ColumnSpec}; +use itertools::Itertools; +#[cfg(feature = "ssl")] +use openssl::ssl::SslContext; use scylla_cql::frame::response::NonErrorResponse; use scylla_cql::types::serialize::batch::BatchValues; use scylla_cql::types::serialize::row::{SerializeRow, SerializedValues}; use std::borrow::Borrow; -use std::collections::HashMap; -use std::fmt::Display; use std::future::Future; use std::marker::PhantomData; use std::net::SocketAddr; use std::num::NonZeroU32; -use std::str::FromStr; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; use tokio::time::timeout; use tracing::{debug, error, trace, trace_span, Instrument}; use uuid::Uuid; -use super::connection::NonErrorQueryResponse; -use super::connection::QueryResponse; -#[cfg(feature = "ssl")] -use super::connection::SslConfig; -use super::errors::TracingProtocolError; -use super::execution_profile::{ExecutionProfile, ExecutionProfileHandle, ExecutionProfileInner}; -use super::iterator::QueryPager; -#[cfg(feature = "cloud")] -use super::node::CloudEndpoint; -use super::node::{InternalKnownNode, KnownNode}; -use super::partitioner::PartitionerName; -use super::query_result::MaybeFirstRowError; -use super::query_result::RowsError; -use super::topology::UntranslatedPeer; -use super::{NodeRef, SelfIdentity}; -use crate::frame::response::result; -use crate::prepared_statement::PreparedStatement; -use crate::query::Query; -use crate::routing::{Shard, Token}; -use crate::statement::{Consistency, PageSize, PagingState, PagingStateResponse}; -use crate::tracing::TracingInfo; -use crate::transport::cluster::{Cluster, ClusterData, ClusterNeatDebug}; -use crate::transport::connection::{Connection, ConnectionConfig, VerifiedKeyspaceName}; -use crate::transport::connection_pool::PoolConfig; -use crate::transport::host_filter::HostFilter; -#[allow(deprecated)] -use crate::transport::iterator::{LegacyRowIterator, PreparedIteratorConfig}; -use crate::transport::load_balancing::{self, RoutingInfo}; -use crate::transport::metrics::Metrics; -use crate::transport::node::Node; -use crate::transport::query_result::QueryResult; -use crate::transport::retry_policy::{QueryInfo, RetryDecision, RetrySession}; -use crate::transport::speculative_execution; -use crate::transport::Compression; -use crate::{ - batch::{Batch, BatchStatement}, - statement::StatementConfig, -}; - -pub use crate::transport::connection_pool::PoolSize; - // This re-export is to preserve backward compatibility. // Those items are no longer here not to clutter session.rs with legacy things. #[allow(deprecated)] -pub use crate::transport::legacy_query_result::{IntoTypedRows, TypedRowIter}; - -use crate::authentication::AuthenticatorProvider; -#[cfg(feature = "ssl")] -use openssl::ssl::SslContext; +pub use crate::response::legacy_query_result::{IntoTypedRows, TypedRowIter}; mod sealed { // This is a sealed trait - its whole purpose is to be unnameable. @@ -102,71 +76,6 @@ pub(crate) const TABLET_CHANNEL_SIZE: usize = 8192; const TRACING_QUERY_PAGE_SIZE: i32 = 1024; -/// Translates IP addresses received from ScyllaDB nodes into locally reachable addresses. -/// -/// The driver auto-detects new ScyllaDB nodes added to the cluster through server side pushed -/// notifications and through checking the system tables. For each node, the address the driver -/// receives corresponds to the address set as `rpc_address` in the node yaml file. In most -/// cases, this is the correct address to use by the driver and that is what is used by default. -/// However, sometimes the addresses received through this mechanism will either not be reachable -/// directly by the driver or should not be the preferred address to use to reach the node (for -/// instance, the `rpc_address` set on ScyllaDB nodes might be a private IP, but some clients -/// may have to use a public IP, or pass by a router, e.g. through NAT, to reach that node). -/// This interface allows to deal with such cases, by allowing to translate an address as sent -/// by a ScyllaDB node to another address to be used by the driver for connection. -/// -/// Please note that the "known nodes" addresses provided while creating the [`Session`] -/// instance are not translated, only IP address retrieved from or sent by Cassandra nodes -/// to the driver are. -#[async_trait] -pub trait AddressTranslator: Send + Sync { - async fn translate_address( - &self, - untranslated_peer: &UntranslatedPeer, - ) -> Result; -} - -#[async_trait] -impl AddressTranslator for HashMap { - async fn translate_address( - &self, - untranslated_peer: &UntranslatedPeer, - ) -> Result { - match self.get(&untranslated_peer.untranslated_address) { - Some(&translated_addr) => Ok(translated_addr), - None => Err(TranslationError::NoRuleForAddress( - untranslated_peer.untranslated_address, - )), - } - } -} - -#[async_trait] -// Notice: this is inefficient, but what else can we do with such poor representation as str? -// After all, the cluster size is small enough to make this irrelevant. -impl AddressTranslator for HashMap<&'static str, &'static str> { - async fn translate_address( - &self, - untranslated_peer: &UntranslatedPeer, - ) -> Result { - for (&rule_addr_str, &translated_addr_str) in self.iter() { - if let Ok(rule_addr) = SocketAddr::from_str(rule_addr_str) { - if rule_addr == untranslated_peer.untranslated_address { - return SocketAddr::from_str(translated_addr_str).map_err(|reason| { - TranslationError::InvalidAddressInRule { - translated_addr_str, - reason, - } - }); - } - } - } - Err(TranslationError::NoRuleForAddress( - untranslated_peer.untranslated_address, - )) - } -} - pub trait DeserializationApiKind: sealed::Sealed {} pub enum CurrentDeserializationApi {} @@ -363,7 +272,7 @@ impl SessionConfig { /// /// # Example /// ``` - /// # use scylla::SessionConfig; + /// # use scylla::client::session::SessionConfig; /// let config = SessionConfig::new(); /// ``` pub fn new() -> Self { @@ -407,7 +316,7 @@ impl SessionConfig { /// If the port is not explicitly specified, 9042 is used as default /// # Example /// ``` - /// # use scylla::SessionConfig; + /// # use scylla::client::session::SessionConfig; /// let mut config = SessionConfig::new(); /// config.add_known_node("127.0.0.1"); /// config.add_known_node("db1.example.com:9042"); @@ -420,7 +329,7 @@ impl SessionConfig { /// Adds a known database server with an IP address /// # Example /// ``` - /// # use scylla::SessionConfig; + /// # use scylla::client::session::SessionConfig; /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr}; /// let mut config = SessionConfig::new(); /// config.add_known_node_addr(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9042)); @@ -433,7 +342,7 @@ impl SessionConfig { /// If the port is not explicitly specified, 9042 is used as default /// # Example /// ``` - /// # use scylla::SessionConfig; + /// # use scylla::client::session::SessionConfig; /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr}; /// let mut config = SessionConfig::new(); /// config.add_known_nodes(&["127.0.0.1:9042", "db1.example.com"]); @@ -447,7 +356,7 @@ impl SessionConfig { /// Adds a list of known database servers with IP addresses /// # Example /// ``` - /// # use scylla::SessionConfig; + /// # use scylla::client::session::SessionConfig; /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr}; /// let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 17, 0, 3)), 9042); /// let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 17, 0, 4)), 9042); @@ -500,7 +409,7 @@ impl GenericSession { /// /// # Examples /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// // Insert an int and text into a table. @@ -514,10 +423,9 @@ impl GenericSession { /// # } /// ``` /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { - /// use scylla::IntoTypedRows; /// /// // Read rows containing an int and text. /// // Keep in mind that all results come in one response (no paging is done!), @@ -558,11 +466,11 @@ impl GenericSession { /// # Example /// /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// use std::ops::ControlFlow; - /// use scylla::statement::PagingState; + /// use scylla::response::PagingState; /// /// // Manual paging in a loop, unprepared statement. /// let mut paging_state = PagingState::start(); @@ -623,10 +531,9 @@ impl GenericSession { /// # Example /// /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { - /// use scylla::IntoTypedRows; /// use futures::stream::StreamExt; /// /// let mut rows_stream = session @@ -676,7 +583,7 @@ impl GenericSession { /// /// # Example /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// use scylla::prepared_statement::PreparedStatement; @@ -705,19 +612,19 @@ impl GenericSession { /// /// # Arguments /// - /// * `prepared` - a statement prepared with [prepare](crate::Session::prepare) + /// * `prepared` - a statement prepared with [prepare](crate::client::session::Session::prepare) /// * `values` - values bound to the query /// * `paging_state` - continuation based on a paging state received from a previous paged query or None /// /// # Example /// /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// use std::ops::ControlFlow; /// use scylla::query::Query; - /// use scylla::statement::{PagingState, PagingStateResponse}; + /// use scylla::response::{PagingState, PagingStateResponse}; /// /// let paged_prepared = session /// .prepare( @@ -781,12 +688,11 @@ impl GenericSession { /// # Example /// /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use futures::StreamExt as _; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// use scylla::prepared_statement::PreparedStatement; - /// use scylla::IntoTypedRows; /// /// // Prepare the query for later execution /// let prepared: PreparedStatement = session @@ -833,7 +739,7 @@ impl GenericSession { /// /// # Example /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// use scylla::batch::Batch; @@ -1017,7 +923,7 @@ where { /// Estabilishes a CQL session with the database /// - /// Usually it's easier to use [SessionBuilder](crate::transport::session_builder::SessionBuilder) + /// Usually it's easier to use [SessionBuilder](crate::client::session_builder::SessionBuilder) /// instead of calling `Session::connect` directly, because it's more convenient. /// # Arguments /// * `config` - Connection configuration - known nodes, Compression, etc. @@ -1027,8 +933,8 @@ where /// ```rust /// # use std::error::Error; /// # async fn check_only_compiles() -> Result<(), Box> { - /// use scylla::{Session, SessionConfig}; - /// use scylla::transport::KnownNode; + /// use scylla::client::session::{Session, SessionConfig}; + /// use scylla::cluster::KnownNode; /// /// let mut config = SessionConfig::new(); /// config.known_nodes.push(KnownNode::Hostname("127.0.0.1:9042".to_string())); @@ -1365,7 +1271,7 @@ where /// /// # Example /// ```rust - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// use scylla::prepared_statement::PreparedStatement; @@ -1425,7 +1331,7 @@ where fn extract_partitioner_name<'a>( &self, prepared: &PreparedStatement, - cluster_data: &'a ClusterData, + cluster_data: &'a ClusterState, ) -> Option<&'a str> { let table_spec = prepared.get_table_spec()?; cluster_data @@ -1694,7 +1600,7 @@ where /// /// # Example /// ```rust /// # extern crate scylla; - /// # use scylla::Session; + /// # use scylla::client::session::Session; /// # use std::error::Error; /// # async fn check_only_compiles(session: &Session) -> Result<(), Box> { /// use scylla::batch::Batch; @@ -1755,8 +1661,9 @@ where /// * `case_sensitive` - if set to true the generated query will put keyspace name in quotes /// # Example /// ```rust - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::Compression; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// # let session = SessionBuilder::new().known_node("127.0.0.1:9042").build().await?; /// session @@ -1810,7 +1717,7 @@ where /// Access cluster data collected by the driver\ /// Driver collects various information about network topology or schema. /// They can be read using this method - pub fn get_cluster_data(&self) -> Arc { + pub fn get_cluster_data(&self) -> Arc { self.cluster.get_data() } @@ -1858,12 +1765,14 @@ where consistency: Option, ) -> Result, QueryError> { // Query system_traces.sessions for TracingInfo - let mut traces_session_query = Query::new(crate::tracing::TRACES_SESSION_QUERY_STR); + let mut traces_session_query = + Query::new(crate::observability::tracing::TRACES_SESSION_QUERY_STR); traces_session_query.config.consistency = consistency; traces_session_query.set_page_size(TRACING_QUERY_PAGE_SIZE); // Query system_traces.events for TracingEvents - let mut traces_events_query = Query::new(crate::tracing::TRACES_EVENTS_QUERY_STR); + let mut traces_events_query = + Query::new(crate::observability::tracing::TRACES_EVENTS_QUERY_STR); traces_events_query.config.consistency = consistency; traces_events_query.set_page_size(TRACING_QUERY_PAGE_SIZE); @@ -2322,168 +2231,3 @@ impl ExecuteRequestContext<'_> { .log_attempt_error(*attempt_id, error, retry_decision); } } - -pub(crate) struct RequestSpan { - span: tracing::Span, - speculative_executions: AtomicUsize, -} - -impl RequestSpan { - pub(crate) fn new_query(contents: &str) -> Self { - use tracing::field::Empty; - - let span = trace_span!( - "Request", - kind = "unprepared", - contents = contents, - // - request_size = Empty, - result_size = Empty, - result_rows = Empty, - replicas = Empty, - shard = Empty, - speculative_executions = Empty, - ); - - Self { - span, - speculative_executions: 0.into(), - } - } - - pub(crate) fn new_prepared<'ps, 'spec: 'ps>( - partition_key: Option)> + Clone>, - token: Option, - request_size: usize, - ) -> Self { - use tracing::field::Empty; - - let span = trace_span!( - "Request", - kind = "prepared", - partition_key = Empty, - token = Empty, - // - request_size = request_size, - result_size = Empty, - result_rows = Empty, - replicas = Empty, - shard = Empty, - speculative_executions = Empty, - ); - - if let Some(partition_key) = partition_key { - span.record( - "partition_key", - tracing::field::display( - format_args!("{}", partition_key_displayer(partition_key),), - ), - ); - } - if let Some(token) = token { - span.record("token", token.value()); - } - - Self { - span, - speculative_executions: 0.into(), - } - } - - pub(crate) fn new_batch() -> Self { - use tracing::field::Empty; - - let span = trace_span!( - "Request", - kind = "batch", - // - request_size = Empty, - result_size = Empty, - result_rows = Empty, - replicas = Empty, - shard = Empty, - speculative_executions = Empty, - ); - - Self { - span, - speculative_executions: 0.into(), - } - } - - pub(crate) fn record_shard_id(&self, conn: &Connection) { - if let Some(info) = conn.get_shard_info() { - self.span.record("shard", info.shard); - } - } - - pub(crate) fn record_raw_rows_fields(&self, raw_rows: &RawMetadataAndRawRows) { - self.span - .record("raw_result_size", raw_rows.metadata_and_rows_bytes_size()); - } - - pub(crate) fn record_result_fields(&self, query_result: &QueryResult) { - if let Some(raw_metadata_and_rows) = query_result.raw_metadata_and_rows() { - self.record_raw_rows_fields(raw_metadata_and_rows); - } - } - - pub(crate) fn record_replicas<'a>(&'a self, replicas: &'a [(impl Borrow>, Shard)]) { - struct ReplicaIps<'a, N>(&'a [(N, Shard)]); - impl Display for ReplicaIps<'_, N> - where - N: Borrow>, - { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut nodes_with_shards = self.0.iter(); - if let Some((node, shard)) = nodes_with_shards.next() { - write!(f, "{}-shard{}", node.borrow().address.ip(), shard)?; - - for (node, shard) in nodes_with_shards { - write!(f, ",{}-shard{}", node.borrow().address.ip(), shard)?; - } - } - Ok(()) - } - } - self.span - .record("replicas", tracing::field::display(&ReplicaIps(replicas))); - } - - pub(crate) fn record_request_size(&self, size: usize) { - self.span.record("request_size", size); - } - - pub(crate) fn inc_speculative_executions(&self) { - self.speculative_executions.fetch_add(1, Ordering::Relaxed); - } - - pub(crate) fn span(&self) -> &tracing::Span { - &self.span - } -} - -impl Drop for RequestSpan { - fn drop(&mut self) { - self.span.record( - "speculative_executions", - self.speculative_executions.load(Ordering::Relaxed), - ); - } -} - -fn partition_key_displayer<'ps, 'res, 'spec: 'ps>( - mut pk_values_iter: impl Iterator)> + 'res + Clone, -) -> impl Display + 'res { - CommaSeparatedDisplayer( - std::iter::from_fn(move || { - pk_values_iter - .next() - .map(|(mut cell, spec)| deser_cql_value(spec.typ(), &mut cell)) - }) - .map(|c| match c { - Ok(c) => Either::Left(CqlValueDisplayer(c)), - Err(_) => Either::Right(""), - }), - ) -} diff --git a/scylla/src/transport/session_builder.rs b/scylla/src/client/session_builder.rs similarity index 87% rename from scylla/src/transport/session_builder.rs rename to scylla/src/client/session_builder.rs index 404e277335..ee68e70ea6 100644 --- a/scylla/src/transport/session_builder.rs +++ b/scylla/src/client/session_builder.rs @@ -1,23 +1,22 @@ //! SessionBuilder provides an easy way to create new Sessions -use super::connection::SelfIdentity; +#[cfg(feature = "cloud")] +use super::execution_profile::ExecutionProfile; use super::execution_profile::ExecutionProfileHandle; #[allow(deprecated)] use super::session::{ - AddressTranslator, CurrentDeserializationApi, GenericSession, LegacyDeserializationApi, - SessionConfig, + CurrentDeserializationApi, GenericSession, LegacyDeserializationApi, SessionConfig, }; -use super::Compression; - +use super::{Compression, PoolSize, SelfIdentity}; +use crate::authentication::{AuthenticatorProvider, PlainTextAuthenticator}; #[cfg(feature = "cloud")] use crate::cloud::{CloudConfig, CloudConfigError}; -use crate::transport::errors::NewSessionError; -#[cfg(feature = "cloud")] -use crate::ExecutionProfile; - +use crate::errors::NewSessionError; +use crate::policies::address_translator::AddressTranslator; +use crate::policies::host_filter::HostFilter; use crate::statement::Consistency; -use crate::transport::connection_pool::PoolSize; -use crate::transport::host_filter::HostFilter; +#[cfg(feature = "ssl")] +use openssl::ssl::SslContext; use std::borrow::Borrow; use std::marker::PhantomData; use std::net::SocketAddr; @@ -26,10 +25,6 @@ use std::num::NonZeroU32; use std::path::Path; use std::sync::Arc; use std::time::Duration; - -use crate::authentication::{AuthenticatorProvider, PlainTextAuthenticator}; -#[cfg(feature = "ssl")] -use openssl::ssl::SslContext; use tracing::warn; mod sealed { @@ -63,8 +58,9 @@ pub type CloudSessionBuilder = GenericSessionBuilder; /// # Example /// /// ``` -/// # use scylla::{Session, SessionBuilder}; -/// # use scylla::transport::Compression; +/// # use scylla::client::session::Session; +/// # use scylla::client::session_builder::SessionBuilder; +/// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -98,7 +94,8 @@ impl GenericSessionBuilder { /// Add a known node with a hostname /// # Examples /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -109,7 +106,8 @@ impl GenericSessionBuilder { /// ``` /// /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("db1.example.com") @@ -126,7 +124,8 @@ impl GenericSessionBuilder { /// Add a known node with an IP address /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr}; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() @@ -144,7 +143,8 @@ impl GenericSessionBuilder { /// Add a list of known nodes with hostnames /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_nodes(["127.0.0.1:9042", "db1.example.com"]) @@ -161,7 +161,8 @@ impl GenericSessionBuilder { /// Add a list of known nodes with IP addresses /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr}; /// # async fn example() -> Result<(), Box> { /// let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 17, 0, 3)), 9042); @@ -187,8 +188,9 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::Compression; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -213,10 +215,11 @@ impl GenericSessionBuilder { /// ``` /// # use std::sync::Arc; /// use bytes::Bytes; - /// use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// use async_trait::async_trait; /// use scylla::authentication::{AuthenticatorProvider, AuthenticatorSession, AuthError}; - /// # use scylla::transport::Compression; + /// # use scylla::client::Compression; /// /// struct CustomAuthenticator; /// @@ -267,9 +270,11 @@ impl GenericSessionBuilder { /// # use async_trait::async_trait; /// # use std::net::SocketAddr; /// # use std::sync::Arc; - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::session::{AddressTranslator, TranslationError}; - /// # use scylla::transport::topology::UntranslatedPeer; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::cluster::metadata::UntranslatedPeer; + /// # use scylla::errors::TranslationError; + /// # use scylla::policies::address_translator::AddressTranslator; /// struct IdentityTranslator; /// /// #[async_trait] @@ -297,8 +302,10 @@ impl GenericSessionBuilder { /// # use std::sync::Arc; /// # use std::collections::HashMap; /// # use std::str::FromStr; - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::session::{AddressTranslator, TranslationError}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::errors::TranslationError; + /// # use scylla::policies::address_translator::AddressTranslator; /// # /// # async fn example() -> Result<(), Box> { /// let mut translation_rules = HashMap::new(); @@ -328,7 +335,8 @@ impl GenericSessionBuilder { /// ``` /// # use std::fs; /// # use std::path::PathBuf; - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use openssl::ssl::{SslContextBuilder, SslVerifyMode, SslMethod, SslFiletype}; /// # async fn example() -> Result<(), Box> { /// let certdir = fs::canonicalize(PathBuf::from("./examples/certs/scylla.crt"))?; @@ -387,8 +395,9 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::Compression; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -408,7 +417,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use std::time::Duration; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() @@ -428,7 +438,10 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{statement::Consistency, ExecutionProfile, Session, SessionBuilder}; + /// # use scylla::statement::Consistency; + /// # use scylla::client::execution_profile::ExecutionProfile; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use std::time::Duration; /// # async fn example() -> Result<(), Box> { /// let execution_profile = ExecutionProfile::builder() @@ -456,7 +469,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -479,7 +493,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -503,12 +518,13 @@ impl GenericSessionBuilder { /// Set keyspace to be used on all connections.\ /// Each connection will send `"USE "` before sending any requests.\ - /// This can be later changed with [`crate::Session::use_keyspace`] + /// This can be later changed with [`crate::client::session::Session::use_keyspace`] /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::Compression; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -531,8 +547,9 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{LegacySession, SessionBuilder}; - /// # use scylla::transport::Compression; + /// # use scylla::client::session::LegacySession; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// let session: LegacySession = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -560,8 +577,9 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::Compression; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -583,7 +601,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use std::time::Duration; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() @@ -604,10 +623,11 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// use std::num::NonZeroUsize; - /// use scylla::transport::session::PoolSize; + /// use scylla::client::PoolSize; /// /// // This session will establish 4 connections to each node. /// // For Scylla clusters, this number will be divided across shards @@ -648,7 +668,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -668,7 +689,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -691,7 +713,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -714,7 +737,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -744,7 +768,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -771,7 +796,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -791,7 +817,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -810,7 +837,7 @@ impl GenericSessionBuilder { /// should be opened to the node or not. The driver will also avoid /// those nodes when re-establishing the control connection. /// - /// See the [host filter](crate::transport::host_filter) module for a list + /// See the [host filter](crate::policies::host_filter) module for a list /// of pre-defined filters. It is also possible to provide a custom filter /// by implementing the HostFilter trait. /// @@ -819,9 +846,11 @@ impl GenericSessionBuilder { /// # use async_trait::async_trait; /// # use std::net::SocketAddr; /// # use std::sync::Arc; - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::session::{AddressTranslator, TranslationError}; - /// # use scylla::transport::host_filter::DcHostFilter; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::errors::TranslationError; + /// # use scylla::policies::address_translator::AddressTranslator; + /// # use scylla::policies::host_filter::DcHostFilter; /// /// # async fn example() -> Result<(), Box> { /// // The session will only connect to nodes from "my-local-dc" @@ -843,7 +872,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -858,8 +888,8 @@ impl GenericSessionBuilder { self } - /// Set the number of attempts to fetch [TracingInfo](crate::tracing::TracingInfo) - /// in [`Session::get_tracing_info`](crate::Session::get_tracing_info). + /// Set the number of attempts to fetch [TracingInfo](crate::observability::tracing::TracingInfo) + /// in [`Session::get_tracing_info`](crate::client::session::Session::get_tracing_info). /// The default is 5 attempts. /// /// Tracing info might not be available immediately on queried node - that's why @@ -871,7 +901,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use std::num::NonZeroU32; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() @@ -887,8 +918,8 @@ impl GenericSessionBuilder { self } - /// Set the delay between attempts to fetch [TracingInfo](crate::tracing::TracingInfo) - /// in [`Session::get_tracing_info`](crate::Session::get_tracing_info). + /// Set the delay between attempts to fetch [TracingInfo](crate::observability::tracing::TracingInfo) + /// in [`Session::get_tracing_info`](crate::client::session::Session::get_tracing_info). /// The default is 3 milliseconds. /// /// Tracing info might not be available immediately on queried node - that's why @@ -900,7 +931,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # use std::time::Duration; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() @@ -916,13 +948,15 @@ impl GenericSessionBuilder { self } - /// Set the consistency level of fetching [TracingInfo](crate::tracing::TracingInfo) - /// in [`Session::get_tracing_info`](crate::Session::get_tracing_info). + /// Set the consistency level of fetching [TracingInfo](crate::observability::tracing::TracingInfo) + /// in [`Session::get_tracing_info`](crate::client::session::Session::get_tracing_info). /// The default is [`Consistency::One`]. /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder, statement::Consistency}; + /// # use scylla::statement::Consistency; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -952,8 +986,9 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::Compression; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::Compression; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -977,7 +1012,8 @@ impl GenericSessionBuilder { /// means that the metadata is refreshed every 20 seconds. /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; /// # async fn example() -> Result<(), Box> { /// let session: Session = SessionBuilder::new() /// .known_node("127.0.0.1:9042") @@ -1000,8 +1036,9 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use scylla::{Session, SessionBuilder}; - /// # use scylla::transport::SelfIdentity; + /// # use scylla::client::session::Session; + /// # use scylla::client::session_builder::SessionBuilder; + /// # use scylla::client::SelfIdentity; /// # async fn example() -> Result<(), Box> { /// let (app_major, app_minor, app_patch) = (2, 1, 3); /// let app_version = format!("{app_major}.{app_minor}.{app_patch}"); @@ -1037,11 +1074,11 @@ mod tests { use scylla_cql::frame::types::SerialConsistency; use scylla_cql::Consistency; + use super::super::Compression; use super::SessionBuilder; + use crate::client::execution_profile::{defaults, ExecutionProfile}; + use crate::cluster::node::KnownNode; use crate::test_utils::setup_tracing; - use crate::transport::execution_profile::{defaults, ExecutionProfile}; - use crate::transport::node::KnownNode; - use crate::transport::Compression; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::time::Duration; diff --git a/scylla/src/transport/session_test.rs b/scylla/src/client/session_test.rs similarity index 99% rename from scylla/src/transport/session_test.rs rename to scylla/src/client/session_test.rs index 318848c576..677acef49b 100644 --- a/scylla/src/transport/session_test.rs +++ b/scylla/src/client/session_test.rs @@ -1,27 +1,26 @@ +use super::caching_session::CachingSession; +use super::execution_profile::ExecutionProfile; +use super::session::Session; +use super::session_builder::SessionBuilder; +use crate as scylla; use crate::batch::{Batch, BatchStatement}; +use crate::cluster::metadata::Strategy::NetworkTopologyStrategy; +use crate::cluster::metadata::{CollectionType, ColumnKind, CqlType, NativeType, UserDefinedType}; use crate::deserialize::DeserializeOwnedValue; +use crate::errors::{BadKeyspaceName, BadQuery, DbError, QueryError}; +use crate::observability::tracing::TracingInfo; +use crate::policies::retry::{QueryInfo, RetryDecision, RetryPolicy, RetrySession}; use crate::prepared_statement::PreparedStatement; use crate::query::Query; -use crate::retry_policy::{QueryInfo, RetryDecision, RetryPolicy, RetrySession}; -use crate::routing::Token; -use crate::statement::Consistency; -use crate::tracing::TracingInfo; -use crate::transport::errors::{BadKeyspaceName, BadQuery, DbError, QueryError}; -use crate::transport::partitioner::{ +use crate::routing::partitioner::{ calculate_token_for_partition_key, Murmur3Partitioner, Partitioner, PartitionerName, }; -use crate::transport::session::Session; -use crate::transport::topology::Strategy::NetworkTopologyStrategy; -use crate::transport::topology::{ - CollectionType, ColumnKind, CqlType, NativeType, UserDefinedType, -}; +use crate::routing::Token; +use crate::statement::Consistency; use crate::utils::test_utils::{ create_new_session_builder, scylla_supports_tablets, setup_tracing, supports_feature, unique_keyspace_name, PerformDDL, }; -use crate::ExecutionProfile; -use crate::{self as scylla, QueryResult}; -use crate::{CachingSession, SessionBuilder}; use assert_matches::assert_matches; use futures::{FutureExt, StreamExt as _, TryStreamExt}; use itertools::Itertools; @@ -37,7 +36,7 @@ use std::sync::Arc; use tokio::net::TcpListener; use uuid::Uuid; -use super::query_result::QueryRowsResult; +use crate::response::query_result::{QueryResult, QueryRowsResult}; #[tokio::test] async fn test_connection_failure() { @@ -187,7 +186,7 @@ async fn test_prepared_statement() { .await .unwrap(); - // Refresh metadata as `ClusterData::compute_token` use them + // Refresh metadata as `ClusterState::compute_token` use them session.await_schema_agreement().await.unwrap(); session.refresh_metadata().await.unwrap(); @@ -588,7 +587,7 @@ async fn test_token_calculation() { .await .unwrap(); - // Refresh metadata as `ClusterData::compute_token` use them + // Refresh metadata as `ClusterState::compute_token` use them session.await_schema_agreement().await.unwrap(); session.refresh_metadata().await.unwrap(); @@ -2530,7 +2529,7 @@ async fn test_rate_limit_exceeded_exception() { } } - use crate::transport::errors::OperationType; + use crate::errors::OperationType; match maybe_err.expect("Rate limit error didn't occur") { QueryError::DbError(DbError::RateLimitReached { op_type, .. }, _) => { diff --git a/scylla/src/cloud/mod.rs b/scylla/src/cloud/mod.rs index fd991a8d45..8e773890d8 100644 --- a/scylla/src/cloud/mod.rs +++ b/scylla/src/cloud/mod.rs @@ -11,7 +11,7 @@ use openssl::{ use tracing::warn; use uuid::Uuid; -use crate::transport::connection::{ConnectionConfig, SslConfig}; +use crate::network::{ConnectionConfig, SslConfig}; pub(crate) fn set_ssl_config_for_scylla_cloud_host( host_id: Option, diff --git a/scylla/src/transport/topology.rs b/scylla/src/cluster/metadata.rs similarity index 98% rename from scylla/src/transport/topology.rs rename to scylla/src/cluster/metadata.rs index 7bbfc6b2a1..d5d4c0e091 100644 --- a/scylla/src/transport/topology.rs +++ b/scylla/src/cluster/metadata.rs @@ -1,13 +1,30 @@ +//! This module holds entities that represent the cluster metadata, +//! which includes: +//! - topology metadata: +//! - [Peer], +//! - schema metadata: +//! - [Keyspace], +//! - [Strategy] - replication strategy employed by a keyspace, +//! - [Table], +//! - [Column], +//! - [ColumnKind], +//! - [MaterializedView], +//! - CQL types: +//! - [CqlType], +//! - [NativeType], +//! - [UserDefinedType], +//! - [CollectionType], +//! + +use crate::client::pager::QueryPager; +use crate::cluster::node::resolve_contact_points; use crate::deserialize::DeserializeOwnedRow; +use crate::errors::{DbError, NewSessionError, QueryError}; use crate::frame::response::event::Event; +use crate::network::{Connection, ConnectionConfig, NodeConnectionPool, PoolConfig, PoolSize}; +use crate::policies::host_filter::HostFilter; use crate::routing::Token; use crate::statement::query::Query; -use crate::transport::connection::{Connection, ConnectionConfig}; -use crate::transport::connection_pool::{NodeConnectionPool, PoolConfig, PoolSize}; -use crate::transport::errors::{DbError, NewSessionError, QueryError}; -use crate::transport::host_filter::HostFilter; -use crate::transport::iterator::QueryPager; -use crate::transport::node::resolve_contact_points; use crate::utils::parse::{ParseErrorCause, ParseResult, ParserState}; use futures::future::{self, FutureExt}; @@ -31,11 +48,11 @@ use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error, trace, warn}; use uuid::Uuid; -use super::errors::{ +use crate::cluster::node::{InternalKnownNode, NodeAddr, ResolvedContactPoint}; +use crate::errors::{ KeyspaceStrategyError, KeyspacesMetadataError, MetadataError, PeersMetadataError, ProtocolError, TablesMetadataError, UdtMetadataError, ViewsMetadataError, }; -use super::node::{InternalKnownNode, NodeAddr, ResolvedContactPoint}; /// Allows to read current metadata from the cluster pub(crate) struct MetadataReader { @@ -977,7 +994,7 @@ where let fut = async move { let pager = make_keyspace_filtered_query_pager(conn, query_str, keyspaces_to_fetch).await?; - let stream: super::iterator::TypedRowStream = + let stream: crate::client::pager::TypedRowStream = pager.rows_stream::().map_err(convert_typecheck_error)?; Ok::<_, QueryError>(stream) }; diff --git a/scylla/src/cluster/mod.rs b/scylla/src/cluster/mod.rs new file mode 100644 index 0000000000..d45bf501cd --- /dev/null +++ b/scylla/src/cluster/mod.rs @@ -0,0 +1,25 @@ +//! This module holds entities that represent the cluster as a whole, +//! nodes in the cluster (together with a pool of connections), +//! the cluster's state, and logic for ruling out specific nodes. +//! +//! This includes: +//! - node's representation ([Node]), +//! - [metadata] representation, fetching and management, including: +//! - topology metadata, +//! - schema metadata, +// - tablet metadata, +//! - [ClusterState], which is a snapshot of the cluster's state. +//! - [ClusterState] is replaced atomically upon a metadata refresh, +//! preventing any issues arising from mutability, including races. +//! + +mod worker; +pub(crate) use worker::{use_keyspace_result, Cluster, ClusterNeatDebug}; + +mod state; +pub use state::ClusterState; + +pub(crate) mod node; +pub use node::{KnownNode, Node, NodeAddr, NodeRef}; + +pub mod metadata; diff --git a/scylla/src/transport/node.rs b/scylla/src/cluster/node.rs similarity index 96% rename from scylla/src/transport/node.rs rename to scylla/src/cluster/node.rs index ba2b3d9f4c..808902c23b 100644 --- a/scylla/src/transport/node.rs +++ b/scylla/src/cluster/node.rs @@ -3,12 +3,12 @@ use tokio::net::lookup_host; use tracing::warn; use uuid::Uuid; +use crate::errors::{ConnectionPoolError, QueryError}; +use crate::network::Connection; +use crate::network::VerifiedKeyspaceName; +use crate::network::{NodeConnectionPool, PoolConfig}; /// Node represents a cluster node along with it's data and connections use crate::routing::{Shard, Sharder}; -use crate::transport::connection::Connection; -use crate::transport::connection::VerifiedKeyspaceName; -use crate::transport::connection_pool::{NodeConnectionPool, PoolConfig}; -use crate::transport::errors::{ConnectionPoolError, QueryError}; use std::fmt::Display; use std::io; @@ -22,7 +22,7 @@ use std::{ }, }; -use super::topology::{PeerEndpoint, UntranslatedEndpoint}; +use crate::cluster::metadata::{PeerEndpoint, UntranslatedEndpoint}; /// This enum is introduced to support address translation only upon opening a connection, /// as well as to cope with a bug present in older Cassandra and Scylla releases. @@ -65,7 +65,7 @@ impl Display for NodeAddr { } } -/// Node represents a cluster node along with it's data and connections +/// Node represents a cluster node along with its data and connections /// /// Note: if a Node changes its broadcast address, then it is not longer /// represented by the same instance of Node struct, but instead diff --git a/scylla/src/cluster/state.rs b/scylla/src/cluster/state.rs new file mode 100644 index 0000000000..97b75847b1 --- /dev/null +++ b/scylla/src/cluster/state.rs @@ -0,0 +1,297 @@ +use crate::errors::{BadQuery, QueryError}; +use crate::network::{Connection, PoolConfig, VerifiedKeyspaceName}; +use crate::policies::host_filter::HostFilter; +use crate::prepared_statement::TokenCalculationError; +use crate::routing::locator::tablets::{RawTablet, Tablet, TabletsInfo}; +use crate::routing::locator::ReplicaLocator; +use crate::routing::partitioner::{calculate_token_for_partition_key, PartitionerName}; +use crate::routing::{Shard, Token}; + +use itertools::Itertools; +use scylla_cql::frame::response::result::TableSpec; +use scylla_cql::types::serialize::row::SerializedValues; +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; +use tracing::debug; +use uuid::Uuid; + +use super::metadata::{Keyspace, Metadata, Strategy}; +use super::node::{Node, NodeRef}; + +#[derive(Clone)] +pub struct ClusterState { + pub(crate) known_peers: HashMap>, // Invariant: nonempty after Cluster::new() + pub(crate) keyspaces: HashMap, + pub(crate) locator: ReplicaLocator, +} + +/// Enables printing [ClusterState] struct in a neat way, skipping the clutter involved by +/// [ClusterState::ring] being large and [Self::keyspaces] debug print being very verbose by default. +pub(crate) struct ClusterStateNeatDebug<'a>(pub(crate) &'a Arc); +impl std::fmt::Debug for ClusterStateNeatDebug<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let cluster_data = &self.0; + + f.debug_struct("ClusterState") + .field("known_peers", &cluster_data.known_peers) + .field("ring", { + struct RingSizePrinter(usize); + impl std::fmt::Debug for RingSizePrinter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "", self.0) + } + } + &RingSizePrinter(cluster_data.locator.ring().len()) + }) + .field("keyspaces", &cluster_data.keyspaces.keys()) + .finish_non_exhaustive() + } +} + +impl ClusterState { + pub(crate) async fn wait_until_all_pools_are_initialized(&self) { + for node in self.locator.unique_nodes_in_global_ring().iter() { + node.wait_until_pool_initialized().await; + } + } + + /// Creates new ClusterState using information about topology held in `metadata`. + /// Uses provided `known_peers` hashmap to recycle nodes if possible. + pub(crate) async fn new( + metadata: Metadata, + pool_config: &PoolConfig, + known_peers: &HashMap>, + used_keyspace: &Option, + host_filter: Option<&dyn HostFilter>, + mut tablets: TabletsInfo, + ) -> Self { + // Create new updated known_peers and ring + let mut new_known_peers: HashMap> = + HashMap::with_capacity(metadata.peers.len()); + let mut ring: Vec<(Token, Arc)> = Vec::new(); + + for peer in metadata.peers { + // Take existing Arc if possible, otherwise create new one + // Changing rack/datacenter but not ip address seems improbable + // so we can just create new node and connections then + let peer_host_id = peer.host_id; + let peer_address = peer.address; + let peer_tokens; + + let node: Arc = match known_peers.get(&peer_host_id) { + Some(node) if node.datacenter == peer.datacenter && node.rack == peer.rack => { + let (peer_endpoint, tokens) = peer.into_peer_endpoint_and_tokens(); + peer_tokens = tokens; + if node.address == peer_address { + node.clone() + } else { + // If IP changes, the Node struct is recreated, but the underlying pool is preserved and notified about the IP change. + Arc::new(Node::inherit_with_ip_changed(node, peer_endpoint)) + } + } + _ => { + let is_enabled = host_filter.map_or(true, |f| f.accept(&peer)); + let (peer_endpoint, tokens) = peer.into_peer_endpoint_and_tokens(); + peer_tokens = tokens; + Arc::new(Node::new( + peer_endpoint, + pool_config.clone(), + used_keyspace.clone(), + is_enabled, + )) + } + }; + + new_known_peers.insert(peer_host_id, node.clone()); + + for token in peer_tokens { + ring.push((token, node.clone())); + } + } + + { + let removed_nodes = { + let mut removed_nodes = HashSet::new(); + for old_peer in known_peers { + if !new_known_peers.contains_key(old_peer.0) { + removed_nodes.insert(*old_peer.0); + } + } + + removed_nodes + }; + + let table_predicate = |spec: &TableSpec| { + if let Some(ks) = metadata.keyspaces.get(spec.ks_name()) { + ks.tables.contains_key(spec.table_name()) + } else { + false + } + }; + + let recreated_nodes = { + let mut recreated_nodes = HashMap::new(); + for (old_peer_id, old_peer_node) in known_peers { + if let Some(new_peer_node) = new_known_peers.get(old_peer_id) { + if !Arc::ptr_eq(old_peer_node, new_peer_node) { + recreated_nodes.insert(*old_peer_id, Arc::clone(new_peer_node)); + } + } + } + + recreated_nodes + }; + + tablets.perform_maintenance( + &table_predicate, + &removed_nodes, + &new_known_peers, + &recreated_nodes, + ) + } + + let keyspaces = metadata.keyspaces; + let (locator, keyspaces) = tokio::task::spawn_blocking(move || { + let keyspace_strategies = keyspaces.values().map(|ks| &ks.strategy); + let locator = ReplicaLocator::new(ring.into_iter(), keyspace_strategies, tablets); + (locator, keyspaces) + }) + .await + .unwrap(); + + ClusterState { + known_peers: new_known_peers, + keyspaces, + locator, + } + } + + /// Access keyspaces details collected by the driver + /// Driver collects various schema details like tables, partitioners, columns, types. + /// They can be read using this method + pub fn get_keyspace_info(&self) -> &HashMap { + &self.keyspaces + } + + /// Access details about nodes known to the driver + pub fn get_nodes_info(&self) -> &[Arc] { + self.locator.unique_nodes_in_global_ring() + } + + /// Compute token of a table partition key + pub fn compute_token( + &self, + keyspace: &str, + table: &str, + partition_key: &SerializedValues, + ) -> Result { + let partitioner = self + .keyspaces + .get(keyspace) + .and_then(|k| k.tables.get(table)) + .and_then(|t| t.partitioner.as_deref()) + .and_then(PartitionerName::from_str) + .unwrap_or_default(); + + calculate_token_for_partition_key(partition_key, &partitioner).map_err(|err| match err { + TokenCalculationError::ValueTooLong(values_len) => { + BadQuery::ValuesTooLongForKey(values_len, u16::MAX.into()) + } + }) + } + + /// Access to replicas owning a given token + pub fn get_token_endpoints( + &self, + keyspace: &str, + table: &str, + token: Token, + ) -> Vec<(Arc, Shard)> { + let table_spec = TableSpec::borrowed(keyspace, table); + self.get_token_endpoints_iter(&table_spec, token) + .map(|(node, shard)| (node.clone(), shard)) + .collect() + } + + pub(crate) fn get_token_endpoints_iter( + &self, + table_spec: &TableSpec, + token: Token, + ) -> impl Iterator, Shard)> { + let keyspace = self.keyspaces.get(table_spec.ks_name()); + let strategy = keyspace + .map(|k| &k.strategy) + .unwrap_or(&Strategy::LocalStrategy); + let replica_set = self + .replica_locator() + .replicas_for_token(token, strategy, None, table_spec); + + replica_set.into_iter() + } + + /// Access to replicas owning a given partition key (similar to `nodetool getendpoints`) + pub fn get_endpoints( + &self, + keyspace: &str, + table: &str, + partition_key: &SerializedValues, + ) -> Result, Shard)>, BadQuery> { + let token = self.compute_token(keyspace, table, partition_key)?; + Ok(self.get_token_endpoints(keyspace, table, token)) + } + + /// Access replica location info + pub fn replica_locator(&self) -> &ReplicaLocator { + &self.locator + } + + /// Returns nonempty iterator of working connections to all shards. + pub(crate) fn iter_working_connections( + &self, + ) -> Result> + '_, QueryError> { + // The returned iterator is nonempty by nonemptiness invariant of `self.known_peers`. + assert!(!self.known_peers.is_empty()); + let mut peers_iter = self.known_peers.values(); + + // First we try to find the first working pool of connections. + // If none is found, return error. + let first_working_pool = peers_iter + .by_ref() + .map(|node| node.get_working_connections()) + .find_or_first(Result::is_ok) + .expect("impossible: known_peers was asserted to be nonempty")?; + + let remaining_pools_iter = peers_iter + .map(|node| node.get_working_connections()) + .flatten_ok() + .flatten(); + + Ok(first_working_pool.into_iter().chain(remaining_pools_iter)) + // By an invariant `self.known_peers` is nonempty, so the returned iterator + // is nonempty, too. + } + + pub(super) fn update_tablets(&mut self, raw_tablets: Vec<(TableSpec<'static>, RawTablet)>) { + let replica_translator = |uuid: Uuid| self.known_peers.get(&uuid).cloned(); + + for (table, raw_tablet) in raw_tablets.into_iter() { + // Should we skip tablets that belong to a keyspace not present in + // self.keyspaces? The keyspace could have been, without driver's knowledge: + // 1. Dropped - in which case we'll remove its info soon (when refreshing + // topology) anyway. + // 2. Created - no harm in storing the info now. + // + // So I think we can safely skip checking keyspace presence. + let tablet = match Tablet::from_raw_tablet(raw_tablet, replica_translator) { + Ok(t) => t, + Err((t, f)) => { + debug!("Nodes ({}) that are replicas for a tablet {{ks: {}, table: {}, range: [{}. {}]}} not present in current ClusterState.known_peers. \ + Skipping these replicas until topology refresh", + f.iter().format(", "), table.ks_name(), table.table_name(), t.range().0.value(), t.range().1.value()); + t + } + }; + self.locator.tablets.add_tablet(table, tablet); + } + } +} diff --git a/scylla/src/transport/cluster.rs b/scylla/src/cluster/worker.rs similarity index 56% rename from scylla/src/transport/cluster.rs rename to scylla/src/cluster/worker.rs index 309fe58157..11ca6a8cad 100644 --- a/scylla/src/transport/cluster.rs +++ b/scylla/src/cluster/worker.rs @@ -1,41 +1,26 @@ -/// Cluster manages up to date information and connections to database nodes +use crate::client::session::TABLET_CHANNEL_SIZE; +use crate::errors::{NewSessionError, QueryError}; use crate::frame::response::event::{Event, StatusChangeEvent}; -use crate::prepared_statement::TokenCalculationError; -use crate::routing::{Shard, Token}; -use crate::transport::errors::{BadQuery, NewSessionError, QueryError}; -use crate::transport::host_filter::HostFilter; -use crate::transport::session::TABLET_CHANNEL_SIZE; -use crate::transport::{ - connection::{Connection, VerifiedKeyspaceName}, - connection_pool::PoolConfig, - node::Node, - partitioner::PartitionerName, - topology::{Keyspace, Metadata, MetadataReader}, -}; +use crate::network::{PoolConfig, VerifiedKeyspaceName}; +use crate::policies::host_filter::HostFilter; +use crate::routing::locator::tablets::{RawTablet, TabletsInfo}; use arc_swap::ArcSwap; use futures::future::join_all; use futures::{future::RemoteHandle, FutureExt}; -use itertools::Itertools; use scylla_cql::frame::response::result::TableSpec; -use scylla_cql::types::serialize::row::SerializedValues; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; use tracing::{debug, warn}; -use uuid::Uuid; -use super::locator::tablets::{RawTablet, Tablet, TabletsInfo}; +use super::metadata::MetadataReader; use super::node::{InternalKnownNode, NodeAddr}; -use super::NodeRef; - -use super::locator::ReplicaLocator; -use super::partitioner::calculate_token_for_partition_key; -use super::topology::Strategy; +use super::state::{ClusterState, ClusterStateNeatDebug}; /// Cluster manages up to date information and connections to database nodes. -/// All data can be accessed by cloning Arc in the `data` field +/// All data can be accessed by cloning Arc in the `data` field // // NOTE: This structure was intentionally made cloneable. The reason for this // is to make it possible to use two different Session APIs in the same program @@ -43,15 +28,15 @@ use super::topology::Strategy; // // It is safe to do because the Cluster struct is just a facade for the real, // "semantic" Cluster object. Cloned instance of this struct will use the same -// ClusterData and worker and will observe the same state. +// ClusterState and worker and will observe the same state. // // TODO: revert this commit (one making Cluster clonable) once the legacy // deserialization API is removed. #[derive(Clone)] pub(crate) struct Cluster { - // `ArcSwap` is wrapped in `Arc` to support sharing cluster data + // `ArcSwap` is wrapped in `Arc` to support sharing cluster data // between `Cluster` and `ClusterWorker` - data: Arc>, + data: Arc>, refresh_channel: tokio::sync::mpsc::Sender, use_keyspace_channel: tokio::sync::mpsc::Sender, @@ -60,43 +45,13 @@ pub(crate) struct Cluster { } /// Enables printing [Cluster] struct in a neat way, by skipping the rather useless -/// print of channels state and printing [ClusterData] neatly. +/// print of channels state and printing [ClusterState] neatly. pub(crate) struct ClusterNeatDebug<'a>(pub(crate) &'a Cluster); impl std::fmt::Debug for ClusterNeatDebug<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let cluster = self.0; f.debug_struct("Cluster") - .field("data", &ClusterDataNeatDebug(&cluster.data.load())) - .finish_non_exhaustive() - } -} - -#[derive(Clone)] -pub struct ClusterData { - pub(crate) known_peers: HashMap>, // Invariant: nonempty after Cluster::new() - pub(crate) keyspaces: HashMap, - pub(crate) locator: ReplicaLocator, -} - -/// Enables printing [ClusterData] struct in a neat way, skipping the clutter involved by -/// [ClusterData::ring] being large and [Self::keyspaces] debug print being very verbose by default. -pub(crate) struct ClusterDataNeatDebug<'a>(pub(crate) &'a Arc); -impl std::fmt::Debug for ClusterDataNeatDebug<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let cluster_data = &self.0; - - f.debug_struct("ClusterData") - .field("known_peers", &cluster_data.known_peers) - .field("ring", { - struct RingSizePrinter(usize); - impl std::fmt::Debug for RingSizePrinter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "", self.0) - } - } - &RingSizePrinter(cluster_data.locator.ring().len()) - }) - .field("keyspaces", &cluster_data.keyspaces.keys()) + .field("data", &ClusterStateNeatDebug(&cluster.data.load())) .finish_non_exhaustive() } } @@ -104,7 +59,7 @@ impl std::fmt::Debug for ClusterDataNeatDebug<'_> { // Works in the background to keep the cluster updated struct ClusterWorker { // Cluster data to keep updated: - cluster_data: Arc>, + cluster_data: Arc>, // Cluster connections metadata_reader: MetadataReader, @@ -178,7 +133,7 @@ impl Cluster { .await?; let metadata = metadata_reader.read_metadata(true).await?; - let cluster_data = ClusterData::new( + let cluster_data = ClusterState::new( metadata, &pool_config, &HashMap::new(), @@ -188,7 +143,7 @@ impl Cluster { ) .await; cluster_data.wait_until_all_pools_are_initialized().await; - let cluster_data: Arc> = + let cluster_data: Arc> = Arc::new(ArcSwap::from(Arc::new(cluster_data))); let worker = ClusterWorker { @@ -222,7 +177,7 @@ impl Cluster { Ok(result) } - pub(crate) fn get_data(&self) -> Arc { + pub(crate) fn get_data(&self) -> Arc { self.data.load_full() } @@ -256,260 +211,12 @@ impl Cluster { }) .await .expect("Bug in Cluster::use_keyspace sending"); - // Other end of this channel is in ClusterWorker, can't be dropped while we have &self to Cluster with _worker_handle + // Other end of this channel is in ClusterWorkers, can't be dropped while we have &self to Cluster with _worker_handle response_receiver.await.unwrap() // ClusterWorker always responds } } -impl ClusterData { - pub(crate) async fn wait_until_all_pools_are_initialized(&self) { - for node in self.locator.unique_nodes_in_global_ring().iter() { - node.wait_until_pool_initialized().await; - } - } - - /// Creates new ClusterData using information about topology held in `metadata`. - /// Uses provided `known_peers` hashmap to recycle nodes if possible. - pub(crate) async fn new( - metadata: Metadata, - pool_config: &PoolConfig, - known_peers: &HashMap>, - used_keyspace: &Option, - host_filter: Option<&dyn HostFilter>, - mut tablets: TabletsInfo, - ) -> Self { - // Create new updated known_peers and ring - let mut new_known_peers: HashMap> = - HashMap::with_capacity(metadata.peers.len()); - let mut ring: Vec<(Token, Arc)> = Vec::new(); - - for peer in metadata.peers { - // Take existing Arc if possible, otherwise create new one - // Changing rack/datacenter but not ip address seems improbable - // so we can just create new node and connections then - let peer_host_id = peer.host_id; - let peer_address = peer.address; - let peer_tokens; - - let node: Arc = match known_peers.get(&peer_host_id) { - Some(node) if node.datacenter == peer.datacenter && node.rack == peer.rack => { - let (peer_endpoint, tokens) = peer.into_peer_endpoint_and_tokens(); - peer_tokens = tokens; - if node.address == peer_address { - node.clone() - } else { - // If IP changes, the Node struct is recreated, but the underlying pool is preserved and notified about the IP change. - Arc::new(Node::inherit_with_ip_changed(node, peer_endpoint)) - } - } - _ => { - let is_enabled = host_filter.map_or(true, |f| f.accept(&peer)); - let (peer_endpoint, tokens) = peer.into_peer_endpoint_and_tokens(); - peer_tokens = tokens; - Arc::new(Node::new( - peer_endpoint, - pool_config.clone(), - used_keyspace.clone(), - is_enabled, - )) - } - }; - - new_known_peers.insert(peer_host_id, node.clone()); - - for token in peer_tokens { - ring.push((token, node.clone())); - } - } - - { - let removed_nodes = { - let mut removed_nodes = HashSet::new(); - for old_peer in known_peers { - if !new_known_peers.contains_key(old_peer.0) { - removed_nodes.insert(*old_peer.0); - } - } - - removed_nodes - }; - - let table_predicate = |spec: &TableSpec| { - if let Some(ks) = metadata.keyspaces.get(spec.ks_name()) { - ks.tables.contains_key(spec.table_name()) - } else { - false - } - }; - - let recreated_nodes = { - let mut recreated_nodes = HashMap::new(); - for (old_peer_id, old_peer_node) in known_peers { - if let Some(new_peer_node) = new_known_peers.get(old_peer_id) { - if !Arc::ptr_eq(old_peer_node, new_peer_node) { - recreated_nodes.insert(*old_peer_id, Arc::clone(new_peer_node)); - } - } - } - - recreated_nodes - }; - - tablets.perform_maintenance( - &table_predicate, - &removed_nodes, - &new_known_peers, - &recreated_nodes, - ) - } - - let keyspaces = metadata.keyspaces; - let (locator, keyspaces) = tokio::task::spawn_blocking(move || { - let keyspace_strategies = keyspaces.values().map(|ks| &ks.strategy); - let locator = ReplicaLocator::new(ring.into_iter(), keyspace_strategies, tablets); - (locator, keyspaces) - }) - .await - .unwrap(); - - ClusterData { - known_peers: new_known_peers, - keyspaces, - locator, - } - } - - /// Access keyspaces details collected by the driver - /// Driver collects various schema details like tables, partitioners, columns, types. - /// They can be read using this method - pub fn get_keyspace_info(&self) -> &HashMap { - &self.keyspaces - } - - /// Access details about nodes known to the driver - pub fn get_nodes_info(&self) -> &[Arc] { - self.locator.unique_nodes_in_global_ring() - } - - /// Compute token of a table partition key - pub fn compute_token( - &self, - keyspace: &str, - table: &str, - partition_key: &SerializedValues, - ) -> Result { - let partitioner = self - .keyspaces - .get(keyspace) - .and_then(|k| k.tables.get(table)) - .and_then(|t| t.partitioner.as_deref()) - .and_then(PartitionerName::from_str) - .unwrap_or_default(); - - calculate_token_for_partition_key(partition_key, &partitioner).map_err(|err| match err { - TokenCalculationError::ValueTooLong(values_len) => { - BadQuery::ValuesTooLongForKey(values_len, u16::MAX.into()) - } - }) - } - - /// Access to replicas owning a given token - pub fn get_token_endpoints( - &self, - keyspace: &str, - table: &str, - token: Token, - ) -> Vec<(Arc, Shard)> { - let table_spec = TableSpec::borrowed(keyspace, table); - self.get_token_endpoints_iter(&table_spec, token) - .map(|(node, shard)| (node.clone(), shard)) - .collect() - } - - pub(crate) fn get_token_endpoints_iter( - &self, - table_spec: &TableSpec, - token: Token, - ) -> impl Iterator, Shard)> { - let keyspace = self.keyspaces.get(table_spec.ks_name()); - let strategy = keyspace - .map(|k| &k.strategy) - .unwrap_or(&Strategy::LocalStrategy); - let replica_set = self - .replica_locator() - .replicas_for_token(token, strategy, None, table_spec); - - replica_set.into_iter() - } - - /// Access to replicas owning a given partition key (similar to `nodetool getendpoints`) - pub fn get_endpoints( - &self, - keyspace: &str, - table: &str, - partition_key: &SerializedValues, - ) -> Result, Shard)>, BadQuery> { - let token = self.compute_token(keyspace, table, partition_key)?; - Ok(self.get_token_endpoints(keyspace, table, token)) - } - - /// Access replica location info - pub fn replica_locator(&self) -> &ReplicaLocator { - &self.locator - } - - /// Returns nonempty iterator of working connections to all shards. - pub(crate) fn iter_working_connections( - &self, - ) -> Result> + '_, QueryError> { - // The returned iterator is nonempty by nonemptiness invariant of `self.known_peers`. - assert!(!self.known_peers.is_empty()); - let mut peers_iter = self.known_peers.values(); - - // First we try to find the first working pool of connections. - // If none is found, return error. - let first_working_pool = peers_iter - .by_ref() - .map(|node| node.get_working_connections()) - .find_or_first(Result::is_ok) - .expect("impossible: known_peers was asserted to be nonempty")?; - - let remaining_pools_iter = peers_iter - .map(|node| node.get_working_connections()) - .flatten_ok() - .flatten(); - - Ok(first_working_pool.into_iter().chain(remaining_pools_iter)) - // By an invariant `self.known_peers` is nonempty, so the returned iterator - // is nonempty, too. - } - - fn update_tablets(&mut self, raw_tablets: Vec<(TableSpec<'static>, RawTablet)>) { - let replica_translator = |uuid: Uuid| self.known_peers.get(&uuid).cloned(); - - for (table, raw_tablet) in raw_tablets.into_iter() { - // Should we skip tablets that belong to a keyspace not present in - // self.keyspaces? The keyspace could have been, without driver's knowledge: - // 1. Dropped - in which case we'll remove its info soon (when refreshing - // topology) anyway. - // 2. Created - no harm in storing the info now. - // - // So I think we can safely skip checking keyspace presence. - let tablet = match Tablet::from_raw_tablet(raw_tablet, replica_translator) { - Ok(t) => t, - Err((t, f)) => { - debug!("Nodes ({}) that are replicas for a tablet {{ks: {}, table: {}, range: [{}. {}]}} not present in current ClusterData.known_peers. \ - Skipping these replicas until topology refresh", - f.iter().format(", "), table.ks_name(), table.table_name(), t.range().0.value(), t.range().1.value()); - t - } - }; - self.locator.tablets.add_tablet(table, tablet); - } - } -} - impl ClusterWorker { pub(crate) async fn work(mut self) { use tokio::time::Instant; @@ -550,25 +257,25 @@ impl ClusterWorker { return; } // The current tablet implementation collects tablet feedback in a channel - // and then clones the whole ClusterData, updates it with new tablets and replaces - // the old ClusterData - this update procedure happens below. - // This fits the general model of how ClusterData is handled in the driver: - // - ClusterData remains a "simple" struct - without locks etc (apart from Node). - // - Topology information update is similar to tablet update - it creates a new ClusterData + // and then clones the whole ClusterState, updates it with new tablets and replaces + // the old ClusterState - this update procedure happens below. + // This fits the general model of how ClusterState is handled in the driver: + // - ClusterState remains a "simple" struct - without locks etc (apart from Node). + // - Topology information update is similar to tablet update - it creates a new ClusterState // and replaces the old one. - // The disadvantage is that we need to have 2 copies of ClusterData, but this happens + // The disadvantage is that we need to have 2 copies of ClusterState, but this happens // anyway during topology update. // // An alternative solution would be to use some synchronization primitives to update tablet info - // in place. This solution avoids ClusterData cloning but: - // - ClusterData would be much more complicated + // in place. This solution avoids ClusterState cloning but: + // - ClusterState would be much more complicated // - Requires using locks in hot path (when sending request) // - Makes maintenance (which happens during topology update) more complicated and error-prone. // // I decided to stick with the approach that fits with the driver. // Apart from the reasons above, it is much easier to reason about concurrency etc // when reading the code in other parts of the driver. - let mut new_cluster_data: ClusterData = self.cluster_data.load().as_ref().clone(); + let mut new_cluster_data: ClusterState = self.cluster_data.load().as_ref().clone(); new_cluster_data.update_tablets(tablets); self.update_cluster_data(Arc::new(new_cluster_data)); @@ -670,7 +377,7 @@ impl ClusterWorker { } async fn handle_use_keyspace_request( - cluster_data: Arc, + cluster_data: Arc, request: UseKeyspaceRequest, ) { let result = Self::send_use_keyspace(cluster_data, &request.keyspace_name).await; @@ -680,7 +387,7 @@ impl ClusterWorker { } async fn send_use_keyspace( - cluster_data: Arc, + cluster_data: Arc, keyspace_name: &VerifiedKeyspaceName, ) -> Result<(), QueryError> { let use_keyspace_futures = cluster_data @@ -696,10 +403,10 @@ impl ClusterWorker { async fn perform_refresh(&mut self) -> Result<(), QueryError> { // Read latest Metadata let metadata = self.metadata_reader.read_metadata(false).await?; - let cluster_data: Arc = self.cluster_data.load_full(); + let cluster_data: Arc = self.cluster_data.load_full(); let new_cluster_data = Arc::new( - ClusterData::new( + ClusterState::new( metadata, &self.pool_config, &cluster_data.known_peers, @@ -719,7 +426,7 @@ impl ClusterWorker { Ok(()) } - fn update_cluster_data(&mut self, new_cluster_data: Arc) { + fn update_cluster_data(&mut self, new_cluster_data: Arc) { self.cluster_data.store(new_cluster_data); } } diff --git a/scylla/src/transport/errors.rs b/scylla/src/errors.rs similarity index 98% rename from scylla/src/transport/errors.rs rename to scylla/src/errors.rs index fdd5b9aa05..81d2977684 100644 --- a/scylla/src/transport/errors.rs +++ b/scylla/src/errors.rs @@ -1,4 +1,4 @@ -//! This module contains various errors which can be returned by [`Session`](crate::transport::session::Session). +//! This module contains various errors which can be returned by [`Session`](crate::client::session::Session). // Re-export DbError type and types that it depends on // so they can be found in `scylla::errors`. @@ -35,10 +35,11 @@ use thiserror::Error; use crate::{authentication::AuthError, frame::response}; -use super::iterator::NextRowError; #[allow(deprecated)] -use super::legacy_query_result::IntoLegacyQueryResultError; -use super::query_result::{IntoRowsResultError, SingleRowError}; +use crate::client::pager::NextRowError; +#[allow(deprecated)] +use crate::response::legacy_query_result::IntoLegacyQueryResultError; +use crate::response::query_result::{IntoRowsResultError, SingleRowError}; /// Error that occurred during query execution #[derive(Error, Debug, Clone)] @@ -114,8 +115,8 @@ pub enum QueryError { #[error("An error occurred during async iteration over rows of result: {0}")] NextRowError(#[from] NextRowError), - /// Failed to convert [`QueryResult`][crate::transport::query_result::QueryResult] - /// into [`LegacyQueryResult`][crate::transport::legacy_query_result::LegacyQueryResult]. + /// Failed to convert [`QueryResult`][crate::response::query_result::QueryResult] + /// into [`LegacyQueryResult`][crate::response::legacy_query_result::LegacyQueryResult]. #[deprecated( since = "0.15.1", note = "Legacy deserialization API is inefficient and is going to be removed soon" @@ -293,8 +294,8 @@ pub enum NewSessionError { #[error("An error occurred during async iteration over rows of result: {0}")] NextRowError(#[from] NextRowError), - /// Failed to convert [`QueryResult`][crate::transport::query_result::QueryResult] - /// into [`LegacyQueryResult`][crate::transport::legacy_query_result::LegacyQueryResult]. + /// Failed to convert [`QueryResult`][crate::response::query_result::QueryResult] + /// into [`LegacyQueryResult`][crate::response::legacy_query_result::LegacyQueryResult]. #[deprecated( since = "0.15.1", note = "Legacy deserialization API is inefficient and is going to be removed soon" @@ -780,8 +781,8 @@ pub enum ConnectionSetupRequestErrorKind { AuthFinishError(AuthError), /// User did not provide authentication while the cluster requires it. - /// See [`SessionBuilder::user`](crate::transport::session_builder::SessionBuilder::user) - /// and/or [`SessionBuilder::authenticator_provider`](crate::transport::session_builder::SessionBuilder::authenticator_provider). + /// See [`SessionBuilder::user`](crate::client::session_builder::SessionBuilder::user) + /// and/or [`SessionBuilder::authenticator_provider`](crate::client::session_builder::SessionBuilder::authenticator_provider). #[error("Authentication is required. You can use SessionBuilder::user(\"user\", \"pass\") to provide credentials or SessionBuilder::authenticator_provider to provide custom authenticator")] MissingAuthentication, } @@ -1013,7 +1014,7 @@ pub(crate) enum ResponseParseError { mod tests { use scylla_cql::Consistency; - use crate::transport::errors::{DbError, QueryError, WriteType}; + use super::{DbError, QueryError, WriteType}; #[test] fn write_type_from_str() { diff --git a/scylla/src/lib.rs b/scylla/src/lib.rs index 8dc56420a9..23d552b2e5 100644 --- a/scylla/src/lib.rs +++ b/scylla/src/lib.rs @@ -13,11 +13,12 @@ //! //! # Driver overview //! ### Connecting -//! All driver activity revolves around the [Session]\ +//! All driver activity revolves around the [Session](crate::client::session::Session)\ //! `Session` is created by specifying a few known nodes and connecting to them: //! //! ```rust,no_run -//! use scylla::{Session, SessionBuilder}; +//! use scylla::client::session::Session; +//! use scylla::client::session_builder::SessionBuilder; //! use std::error::Error; //! //! #[tokio::main] @@ -31,17 +32,17 @@ //! Ok(()) //! } //! ``` -//! `Session` is usually created using the [SessionBuilder].\ +//! `Session` is usually created using the [SessionBuilder](crate::client::session_builder::SessionBuilder).\ //! All configuration options for a `Session` can be specified while building. //! //! ### Making queries //! After successfully connecting to the cluster we can make queries.\ //! The driver supports multiple query types: -//! * [Simple](crate::Session::query_unpaged) -//! * [Simple paged](crate::Session::query_iter) -//! * [Prepared](crate::Session::execute_unpaged) (need to be [prepared](crate::Session::prepare) before use) -//! * [Prepared paged](crate::Session::execute_iter) -//! * [Batch](crate::Session::batch) +//! * [Simple](crate::client::session::Session::query_unpaged) +//! * [Simple paged](crate::client::session::Session::query_iter) +//! * [Prepared](crate::client::session::Session::execute_unpaged) (need to be [prepared](crate::client::session::Session::prepare) before use) +//! * [Prepared paged](crate::client::session::Session::execute_iter) +//! * [Batch](crate::client::session::Session::batch) //! //! To specify options for a single query create the query object and configure it: //! * For simple: [Query](crate::query::Query) @@ -50,7 +51,7 @@ //! //! The easiest way to specify bound values in a query is using a tuple: //! ```rust -//! # use scylla::Session; +//! # use scylla::client::session::Session; //! # use std::error::Error; //! # async fn check_only_compiles(session: &Session) -> Result<(), Box> { //! // Insert an int and text into the table @@ -69,7 +70,7 @@ //! The easiest way to read rows returned by a query is to cast each row to a tuple of values: //! //! ```rust -//! # use scylla::Session; +//! # use scylla::client::session::Session; //! # use std::error::Error; //! # async fn check_only_compiles(session: &Session) -> Result<(), Box> { //! @@ -252,14 +253,18 @@ pub mod deserialize { } pub mod authentication; +pub mod client; #[cfg(feature = "cloud")] pub mod cloud; -pub mod history; +pub mod cluster; +pub mod errors; +mod network; +pub mod observability; +pub mod policies; +pub mod response; pub mod routing; pub mod statement; -pub mod tracing; -pub mod transport; pub(crate) mod utils; @@ -272,24 +277,3 @@ pub use statement::query; #[allow(deprecated)] pub use frame::response::cql_to_rust::{self, FromRow}; - -#[allow(deprecated)] -pub use transport::caching_session::{CachingSession, GenericCachingSession, LegacyCachingSession}; -pub use transport::execution_profile::ExecutionProfile; -#[allow(deprecated)] -pub use transport::legacy_query_result::LegacyQueryResult; -pub use transport::query_result::{QueryResult, QueryRowsResult}; -#[allow(deprecated)] -pub use transport::session::{IntoTypedRows, LegacySession, Session, SessionConfig}; -pub use transport::session_builder::SessionBuilder; - -#[cfg(feature = "cloud")] -pub use transport::session_builder::CloudSessionBuilder; - -pub use transport::execution_profile; -pub use transport::host_filter; -pub use transport::load_balancing; -pub use transport::retry_policy; -pub use transport::speculative_execution; - -pub use transport::metrics::{Metrics, MetricsError}; diff --git a/scylla/src/transport/connection.rs b/scylla/src/network/connection.rs similarity index 87% rename from scylla/src/transport/connection.rs rename to scylla/src/network/connection.rs index 3a550ae6ae..7068cd0c0c 100644 --- a/scylla/src/transport/connection.rs +++ b/scylla/src/network/connection.rs @@ -1,8 +1,42 @@ +use crate::authentication::AuthenticatorProvider; +use crate::batch::{Batch, BatchStatement}; +use crate::client::pager::QueryPager; +use crate::client::Compression; +use crate::client::SelfIdentity; +#[cfg(feature = "cloud")] +use crate::cloud::CloudConfig; +use crate::cluster::metadata::{PeerEndpoint, UntranslatedEndpoint, UntranslatedPeer}; +use crate::cluster::NodeAddr; +use crate::errors::{ + BadKeyspaceName, BrokenConnectionError, BrokenConnectionErrorKind, ConnectionError, + ConnectionSetupRequestError, ConnectionSetupRequestErrorKind, CqlEventHandlingError, DbError, + ProtocolError, QueryError, RequestError, ResponseParseError, SchemaVersionFetchError, + TranslationError, UseKeyspaceProtocolError, UserRequestError, +}; +use crate::frame::protocol_features::ProtocolFeatures; +use crate::frame::{ + self, + request::{self, batch, execute, query, register, SerializableRequest}, + response::{event::Event, result, Response, ResponseOpcode}, + server_event_type::EventType, + FrameParams, SerializedRequest, +}; +use crate::policies::address_translator::AddressTranslator; +use crate::query::Query; +use crate::response::query_result::QueryResult; +use crate::response::{ + NonErrorAuthResponse, NonErrorStartupResponse, PagingState, PagingStateResponse, QueryResponse, +}; +use crate::routing::locator::tablets::{RawTablet, TabletParsingError}; +use crate::routing::{Shard, ShardInfo, Sharder}; +use crate::statement::prepared_statement::PreparedStatement; +use crate::statement::{Consistency, PageSize}; use bytes::Bytes; use futures::{future::RemoteHandle, FutureExt}; use scylla_cql::frame::frame_errors::CqlResponseParseError; use scylla_cql::frame::request::options::{self, Options}; use scylla_cql::frame::request::CqlRequestKind; +use scylla_cql::frame::response::authenticate::Authenticate; use scylla_cql::frame::response::result::{ResultMetadata, TableSpec}; use scylla_cql::frame::response::Error; use scylla_cql::frame::response::{self, error}; @@ -11,65 +45,30 @@ use scylla_cql::types::serialize::batch::{BatchValues, BatchValuesIterator}; use scylla_cql::types::serialize::raw_batch::RawBatchValuesAdapter; use scylla_cql::types::serialize::row::{RowSerializationContext, SerializedValues}; use socket2::{SockRef, TcpKeepalive}; -use tokio::io::{split, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter}; -use tokio::net::{TcpSocket, TcpStream}; -use tokio::sync::{mpsc, oneshot}; -use tokio::time::Instant; -use tracing::{debug, error, trace, warn}; -use uuid::Uuid; - -use std::borrow::Cow; -#[cfg(feature = "ssl")] -use std::pin::Pin; -use std::sync::atomic::AtomicU64; -use std::time::Duration; -#[cfg(feature = "ssl")] -use tokio_openssl::SslStream; - #[cfg(feature = "ssl")] pub(crate) use ssl_config::SslConfig; - -use crate::authentication::AuthenticatorProvider; -use crate::transport::errors::{ - BadKeyspaceName, BrokenConnectionError, BrokenConnectionErrorKind, ConnectionError, - ConnectionSetupRequestError, ConnectionSetupRequestErrorKind, CqlEventHandlingError, DbError, - QueryError, RequestError, ResponseParseError, TranslationError, UserRequestError, -}; -use scylla_cql::frame::response::authenticate::Authenticate; +use std::borrow::Cow; use std::collections::{BTreeSet, HashMap, HashSet}; use std::convert::TryFrom; use std::net::{IpAddr, SocketAddr}; +#[cfg(feature = "ssl")] +use std::pin::Pin; +use std::sync::atomic::AtomicU64; use std::sync::Arc; use std::sync::Mutex as StdMutex; +use std::time::Duration; use std::{ cmp::Ordering, net::{Ipv4Addr, Ipv6Addr}, }; - -use super::errors::{ProtocolError, SchemaVersionFetchError, UseKeyspaceProtocolError}; -use super::iterator::QueryPager; -use super::locator::tablets::{RawTablet, TabletParsingError}; -use super::query_result::QueryResult; -use super::session::AddressTranslator; -use super::topology::{PeerEndpoint, UntranslatedEndpoint, UntranslatedPeer}; -use super::NodeAddr; -#[cfg(feature = "cloud")] -use crate::cloud::CloudConfig; - -use crate::batch::{Batch, BatchStatement}; -use crate::frame::protocol_features::ProtocolFeatures; -use crate::frame::{ - self, - request::{self, batch, execute, query, register, SerializableRequest}, - response::{event::Event, result, NonErrorResponse, Response, ResponseOpcode}, - server_event_type::EventType, - FrameParams, SerializedRequest, -}; -use crate::query::Query; -use crate::routing::ShardInfo; -use crate::statement::prepared_statement::PreparedStatement; -use crate::statement::{Consistency, PageSize, PagingState, PagingStateResponse}; -use crate::transport::Compression; +use tokio::io::{split, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter}; +use tokio::net::{TcpSocket, TcpStream}; +use tokio::sync::{mpsc, oneshot}; +use tokio::time::Instant; +#[cfg(feature = "ssl")] +use tokio_openssl::SslStream; +use tracing::{debug, error, trace, warn}; +use uuid::Uuid; // Queries for schema agreement const LOCAL_VERSION: &str = "SELECT schema_version FROM system.local WHERE key='local'"; @@ -212,105 +211,6 @@ struct TaskResponse { body: Bytes, } -pub(crate) struct QueryResponse { - pub(crate) response: Response, - pub(crate) tracing_id: Option, - pub(crate) warnings: Vec, - #[allow(dead_code)] // This is not exposed to user (yet?) - pub(crate) custom_payload: Option>, -} - -// A QueryResponse in which response can not be Response::Error -pub(crate) struct NonErrorQueryResponse { - pub(crate) response: NonErrorResponse, - pub(crate) tracing_id: Option, - pub(crate) warnings: Vec, -} - -impl QueryResponse { - pub(crate) fn into_non_error_query_response( - self, - ) -> Result { - Ok(NonErrorQueryResponse { - response: self.response.into_non_error_response()?, - tracing_id: self.tracing_id, - warnings: self.warnings, - }) - } - - pub(crate) fn into_query_result_and_paging_state( - self, - ) -> Result<(QueryResult, PagingStateResponse), UserRequestError> { - self.into_non_error_query_response()? - .into_query_result_and_paging_state() - } - - pub(crate) fn into_query_result(self) -> Result { - self.into_non_error_query_response()?.into_query_result() - } -} - -impl NonErrorQueryResponse { - pub(crate) fn as_set_keyspace(&self) -> Option<&result::SetKeyspace> { - match &self.response { - NonErrorResponse::Result(result::Result::SetKeyspace(sk)) => Some(sk), - _ => None, - } - } - - pub(crate) fn as_schema_change(&self) -> Option<&result::SchemaChange> { - match &self.response { - NonErrorResponse::Result(result::Result::SchemaChange(sc)) => Some(sc), - _ => None, - } - } - - pub(crate) fn into_query_result_and_paging_state( - self, - ) -> Result<(QueryResult, PagingStateResponse), UserRequestError> { - let (raw_rows, paging_state_response) = match self.response { - NonErrorResponse::Result(result::Result::Rows((rs, paging_state_response))) => { - (Some(rs), paging_state_response) - } - NonErrorResponse::Result(_) => (None, PagingStateResponse::NoMorePages), - _ => { - return Err(UserRequestError::UnexpectedResponse( - self.response.to_response_kind(), - )) - } - }; - - Ok(( - QueryResult::new(raw_rows, self.tracing_id, self.warnings), - paging_state_response, - )) - } - - pub(crate) fn into_query_result(self) -> Result { - let (result, paging_state) = self.into_query_result_and_paging_state()?; - - if !paging_state.finished() { - error!( - "Internal driver API misuse or a server bug: nonfinished paging state\ - would be discarded by `NonErrorQueryResponse::into_query_result`" - ); - return Err(ProtocolError::NonfinishedPagingState.into()); - } - - Ok(result) - } -} - -pub(crate) enum NonErrorStartupResponse { - Ready, - Authenticate(response::authenticate::Authenticate), -} - -pub(crate) enum NonErrorAuthResponse { - AuthChallenge(response::authenticate::AuthChallenge), - AuthSuccess(response::authenticate::AuthSuccess), -} - #[cfg(feature = "ssl")] mod ssl_config { use openssl::{ @@ -378,151 +278,11 @@ mod ssl_config { } } -/// Driver and application self-identifying information, -/// to be sent in STARTUP message. -#[derive(Debug, Clone, Default)] -pub struct SelfIdentity<'id> { - // Custom driver identity can be set if a custom driver build is running, - // or an entirely different driver is operating on top of Rust driver - // (e.g. cpp-rust-driver). - custom_driver_name: Option>, - custom_driver_version: Option>, - - // ### Q: Where do APPLICATION_NAME, APPLICATION_VERSION and CLIENT_ID come from? - // - there are no columns in system.clients dedicated to those attributes, - // - APPLICATION_NAME / APPLICATION_VERSION are not present in Scylla's source code at all, - // - only 2 results in Cassandra source is some example in docs: - // https://github.com/apache/cassandra/blob/d3cbf9c1f72057d2a5da9df8ed567d20cd272931/doc/modules/cassandra/pages/managing/operating/virtualtables.adoc?plain=1#L218. - // APPLICATION_NAME and APPLICATION_VERSION appears in client_options which - // is an arbitrary dict where client can send any keys. - // - driver variables are mentioned in protocol v5 - // (https://github.com/apache/cassandra/blob/d3cbf9c1f72057d2a5da9df8ed567d20cd272931/doc/native_protocol_v5.spec#L480), - // application variables are not. - // - // ### A: - // The following options are not exposed anywhere in Scylla tables. - // They come directly from CPP driver, and they are supported in Cassandra - // - // See https://github.com/scylladb/cpp-driver/blob/fa0f27069a625057984d1fa58f434ea99b86c83f/include/cassandra.h#L2916. - // As we want to support as big subset of its API as possible in cpp-rust-driver, I decided to expose API for setting - // those particular key-value pairs, similarly to what cpp-driver does, and not an API to set arbitrary key-value pairs. - // - // Allowing users to set arbitrary options could break the driver by overwriting options that bear special meaning, - // e.g. the shard-aware port. Therefore, I'm against such liberal API. OTOH, we need to expose APPLICATION_NAME, - // APPLICATION_VERSION and CLIENT_ID for cpp-rust-driver. - - // Application identity can be set to distinguish different applications - // connected to the same cluster. - application_name: Option>, - application_version: Option>, - - // A (unique) client ID can be set to distinguish different instances - // of the same application connected to the same cluster. - client_id: Option>, -} - -impl<'id> SelfIdentity<'id> { - pub fn new() -> Self { - Self::default() - } - - /// Advertises a custom driver name, which can be used if a custom driver build is running, - /// or an entirely different driver is operating on top of Rust driver - /// (e.g. cpp-rust-driver). - pub fn set_custom_driver_name(&mut self, custom_driver_name: impl Into>) { - self.custom_driver_name = Some(custom_driver_name.into()); - } - - /// Advertises a custom driver name. See [Self::set_custom_driver_name] for use cases. - pub fn with_custom_driver_name(mut self, custom_driver_name: impl Into>) -> Self { - self.custom_driver_name = Some(custom_driver_name.into()); - self - } - - /// Custom driver name to be advertised. See [Self::set_custom_driver_name] for use cases. - pub fn get_custom_driver_name(&self) -> Option<&str> { - self.custom_driver_name.as_deref() - } - - /// Advertises a custom driver version. See [Self::set_custom_driver_name] for use cases. - pub fn set_custom_driver_version(&mut self, custom_driver_version: impl Into>) { - self.custom_driver_version = Some(custom_driver_version.into()); - } - - /// Advertises a custom driver version. See [Self::set_custom_driver_name] for use cases. - pub fn with_custom_driver_version( - mut self, - custom_driver_version: impl Into>, - ) -> Self { - self.custom_driver_version = Some(custom_driver_version.into()); - self - } - - /// Custom driver version to be advertised. See [Self::set_custom_driver_version] for use cases. - pub fn get_custom_driver_version(&self) -> Option<&str> { - self.custom_driver_version.as_deref() - } - - /// Advertises an application name, which can be used to distinguish different applications - /// connected to the same cluster. - pub fn set_application_name(&mut self, application_name: impl Into>) { - self.application_name = Some(application_name.into()); - } - - /// Advertises an application name. See [Self::set_application_name] for use cases. - pub fn with_application_name(mut self, application_name: impl Into>) -> Self { - self.application_name = Some(application_name.into()); - self - } - - /// Application name to be advertised. See [Self::set_application_name] for use cases. - pub fn get_application_name(&self) -> Option<&str> { - self.application_name.as_deref() - } - - /// Advertises an application version. See [Self::set_application_name] for use cases. - pub fn set_application_version(&mut self, application_version: impl Into>) { - self.application_version = Some(application_version.into()); - } - - /// Advertises an application version. See [Self::set_application_name] for use cases. - pub fn with_application_version( - mut self, - application_version: impl Into>, - ) -> Self { - self.application_version = Some(application_version.into()); - self - } - - /// Application version to be advertised. See [Self::set_application_version] for use cases. - pub fn get_application_version(&self) -> Option<&str> { - self.application_version.as_deref() - } - - /// Advertises a client ID, which can be set to distinguish different instances - /// of the same application connected to the same cluster. - pub fn set_client_id(&mut self, client_id: impl Into>) { - self.client_id = Some(client_id.into()); - } - - /// Advertises a client ID. See [Self::set_client_id] for use cases. - pub fn with_client_id(mut self, client_id: impl Into>) -> Self { - self.client_id = Some(client_id.into()); - self - } - - /// Client ID to be advertised. See [Self::set_client_id] for use cases. - pub fn get_client_id(&self) -> Option<&str> { - self.client_id.as_deref() - } -} - impl<'id: 'map, 'map> SelfIdentity<'id> { fn add_startup_options(&'id self, options: &'map mut HashMap, Cow<'id, str>>) { /* Driver identity. */ let driver_name = self - .custom_driver_name - .as_deref() + .get_custom_driver_name() .unwrap_or(options::DEFAULT_DRIVER_NAME); options.insert( Cow::Borrowed(options::DRIVER_NAME), @@ -530,8 +290,7 @@ impl<'id: 'map, 'map> SelfIdentity<'id> { ); let driver_version = self - .custom_driver_version - .as_deref() + .get_custom_driver_version() .unwrap_or(options::DEFAULT_DRIVER_VERSION); options.insert( Cow::Borrowed(options::DRIVER_VERSION), @@ -539,14 +298,14 @@ impl<'id: 'map, 'map> SelfIdentity<'id> { ); /* Application identity. */ - if let Some(application_name) = self.application_name.as_deref() { + if let Some(application_name) = self.get_application_name() { options.insert( Cow::Borrowed(options::APPLICATION_NAME), Cow::Borrowed(application_name), ); } - if let Some(application_version) = self.application_version.as_deref() { + if let Some(application_version) = self.get_application_version() { options.insert( Cow::Borrowed(options::APPLICATION_VERSION), Cow::Borrowed(application_version), @@ -554,7 +313,7 @@ impl<'id: 'map, 'map> SelfIdentity<'id> { } /* Client identity. */ - if let Some(client_id) = self.client_id.as_deref() { + if let Some(client_id) = self.get_client_id() { options.insert(Cow::Borrowed(options::CLIENT_ID), Cow::Borrowed(client_id)); } } @@ -635,7 +394,7 @@ impl Connection { // Returns new connection and ErrorReceiver which can be used to wait for a fatal error /// Opens a connection and makes it ready to send/receive CQL frames on it, /// but does not yet send any frames (no OPTIONS/STARTUP handshake nor REGISTER requests). - pub(crate) async fn new( + async fn new( addr: SocketAddr, source_port: Option, config: ConnectionConfig, @@ -745,7 +504,7 @@ impl Connection { sf.set_tcp_keepalive(&tcp_keepalive) } - pub(crate) async fn startup( + async fn startup( &self, options: HashMap, Cow<'_, str>>, ) -> Result { @@ -797,9 +556,7 @@ impl Connection { Ok(response) } - pub(crate) async fn get_options( - &self, - ) -> Result { + async fn get_options(&self) -> Result { let err = |kind: ConnectionSetupRequestErrorKind| { ConnectionSetupRequestError::new(CqlRequestKind::Options, kind) }; @@ -886,7 +643,7 @@ impl Connection { Ok(prepared_statement) } - pub(crate) async fn reprepare( + async fn reprepare( &self, query: impl Into, previous_prepared: &PreparedStatement, @@ -906,7 +663,56 @@ impl Connection { } } - pub(crate) async fn authenticate_response( + async fn perform_authenticate( + &mut self, + authenticate: &Authenticate, + ) -> Result<(), ConnectionSetupRequestError> { + let err = |kind: ConnectionSetupRequestErrorKind| { + ConnectionSetupRequestError::new(CqlRequestKind::AuthResponse, kind) + }; + + let authenticator = &authenticate.authenticator_name as &str; + + match self.config.authenticator { + Some(ref authenticator_provider) => { + let (mut response, mut auth_session) = authenticator_provider + .start_authentication_session(authenticator) + .await + .map_err(|e| err(ConnectionSetupRequestErrorKind::StartAuthSessionError(e)))?; + + loop { + match self.authenticate_response(response).await? { + NonErrorAuthResponse::AuthChallenge(challenge) => { + response = auth_session + .evaluate_challenge(challenge.authenticate_message.as_deref()) + .await + .map_err(|e| { + err( + ConnectionSetupRequestErrorKind::AuthChallengeEvaluationError( + e, + ), + ) + })?; + } + NonErrorAuthResponse::AuthSuccess(success) => { + auth_session + .success(success.success_message.as_deref()) + .await + .map_err(|e| { + err(ConnectionSetupRequestErrorKind::AuthFinishError(e)) + })?; + break; + } + } + } + } + None => return Err(err(ConnectionSetupRequestErrorKind::MissingAuthentication)), + } + + Ok(()) + } + + async fn authenticate_response( &self, response: Option>, ) -> Result { @@ -1340,7 +1146,7 @@ impl Connection { Ok(batch) } - pub(crate) async fn use_keyspace( + pub(super) async fn use_keyspace( &self, keyspace_name: &VerifiedKeyspaceName, ) -> Result<(), QueryError> { @@ -1984,7 +1790,7 @@ async fn maybe_translated_addr( /// - registers for all event types using REGISTER request (if this is control connection). /// /// At the beginning, translates node's address, if it is subject to address translation. -pub(crate) async fn open_connection( +pub(super) async fn open_connection( endpoint: UntranslatedEndpoint, source_port: Option, config: &ConnectionConfig, @@ -2069,7 +1875,7 @@ pub(crate) async fn open_connection( match startup_result { NonErrorStartupResponse::Ready => {} NonErrorStartupResponse::Authenticate(authenticate) => { - perform_authenticate(&mut connection, &authenticate).await?; + connection.perform_authenticate(&authenticate).await?; } } @@ -2086,53 +1892,26 @@ pub(crate) async fn open_connection( Ok((connection, error_receiver)) } -async fn perform_authenticate( - connection: &mut Connection, - authenticate: &Authenticate, -) -> Result<(), ConnectionSetupRequestError> { - let err = |kind: ConnectionSetupRequestErrorKind| { - ConnectionSetupRequestError::new(CqlRequestKind::AuthResponse, kind) - }; - - let authenticator = &authenticate.authenticator_name as &str; +pub(super) async fn open_connection_to_shard_aware_port( + endpoint: UntranslatedEndpoint, + shard: Shard, + sharder: Sharder, + connection_config: &ConnectionConfig, +) -> Result<(Connection, ErrorReceiver), ConnectionError> { + // Create iterator over all possible source ports for this shard + let source_port_iter = sharder.iter_source_ports_for_shard(shard); - match connection.config.authenticator { - Some(ref authenticator_provider) => { - let (mut response, mut auth_session) = authenticator_provider - .start_authentication_session(authenticator) - .await - .map_err(|e| err(ConnectionSetupRequestErrorKind::StartAuthSessionError(e)))?; + for port in source_port_iter { + let connect_result = open_connection(endpoint.clone(), Some(port), connection_config).await; - loop { - match connection.authenticate_response(response).await? { - NonErrorAuthResponse::AuthChallenge(challenge) => { - response = auth_session - .evaluate_challenge(challenge.authenticate_message.as_deref()) - .await - .map_err(|e| { - err( - ConnectionSetupRequestErrorKind::AuthChallengeEvaluationError( - e, - ), - ) - })?; - } - NonErrorAuthResponse::AuthSuccess(success) => { - auth_session - .success(success.success_message.as_deref()) - .await - .map_err(|e| { - err(ConnectionSetupRequestErrorKind::AuthFinishError(e)) - })?; - break; - } - } - } + match connect_result { + Err(err) if err.is_address_unavailable_for_use() => continue, // If we can't use this port, try the next one + result => return result, } - None => return Err(err(ConnectionSetupRequestErrorKind::MissingAuthentication)), } - Ok(()) + // Tried all source ports for that shard, give up + Err(ConnectionError::NoSourcePortForShard(shard)) } async fn connect_with_source_port( @@ -2391,14 +2170,12 @@ mod tests { use tokio::select; use tokio::sync::mpsc; - use super::ConnectionConfig; + use super::{open_connection, ConnectionConfig}; + use crate::cluster::metadata::UntranslatedEndpoint; + use crate::cluster::node::ResolvedContactPoint; use crate::query::Query; use crate::test_utils::setup_tracing; - use crate::transport::connection::open_connection; - use crate::transport::node::ResolvedContactPoint; - use crate::transport::topology::UntranslatedEndpoint; use crate::utils::test_utils::{unique_keyspace_name, PerformDDL}; - use crate::SessionBuilder; use futures::{StreamExt, TryStreamExt}; use std::collections::HashMap; use std::net::SocketAddr; @@ -2427,6 +2204,8 @@ mod tests { #[tokio::test] #[cfg(not(scylla_cloud_tests))] async fn connection_query_iter_test() { + use crate::client::session_builder::SessionBuilder; + setup_tracing(); let uri = std::env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9042".to_string()); let addr: SocketAddr = resolve_hostname(&uri).await; @@ -2528,6 +2307,8 @@ mod tests { #[tokio::test] #[cfg(not(scylla_cloud_tests))] async fn test_coalescing() { + use crate::client::session_builder::SessionBuilder; + setup_tracing(); // It's difficult to write a reliable test that checks whether coalescing // works like intended or not. Instead, this is a smoke test which is supposed @@ -2721,7 +2502,7 @@ mod tests { #[ntest::timeout(20000)] #[cfg(not(scylla_cloud_tests))] async fn connection_is_closed_on_no_response_to_keepalives() { - use crate::transport::errors::BrokenConnectionErrorKind; + use crate::errors::BrokenConnectionErrorKind; setup_tracing(); @@ -2785,9 +2566,7 @@ mod tests { // Then, the error from keepaliver will be propagated to the error receiver. let err = error_receiver.await.unwrap(); let err_inner: &BrokenConnectionErrorKind = match err { - crate::transport::connection::ConnectionError::BrokenConnection(ref e) => { - e.downcast_ref().unwrap() - } + super::ConnectionError::BrokenConnection(ref e) => e.downcast_ref().unwrap(), _ => panic!("Bad error type. Expected keepalive timeout."), }; assert_matches!(err_inner, BrokenConnectionErrorKind::KeepaliveTimeout(_)); diff --git a/scylla/src/transport/connection_pool.rs b/scylla/src/network/connection_pool.rs similarity index 96% rename from scylla/src/transport/connection_pool.rs rename to scylla/src/network/connection_pool.rs index 4b3de60c53..a750887e4a 100644 --- a/scylla/src/transport/connection_pool.rs +++ b/scylla/src/network/connection_pool.rs @@ -1,22 +1,22 @@ #[cfg(feature = "cloud")] use crate::cloud::set_ssl_config_for_scylla_cloud_host; -use crate::routing::{Shard, ShardCount, Sharder}; -use crate::transport::errors::{ - BrokenConnectionErrorKind, ConnectionError, ConnectionPoolError, QueryError, -}; -use crate::transport::{ - connection, - connection::{Connection, ConnectionConfig, ErrorReceiver, VerifiedKeyspaceName}, +use super::connection::{ + open_connection, open_connection_to_shard_aware_port, Connection, ConnectionConfig, + ErrorReceiver, VerifiedKeyspaceName, }; +use crate::errors::{BrokenConnectionErrorKind, ConnectionError, ConnectionPoolError, QueryError}; +use crate::routing::{Shard, ShardCount, Sharder}; + +use crate::cluster::metadata::{PeerEndpoint, UntranslatedEndpoint}; + #[cfg(feature = "cloud")] -use super::node::resolve_hostname; +use crate::cluster::node::resolve_hostname; #[cfg(feature = "cloud")] -use super::node::ResolvedContactPoint; -use super::topology::{PeerEndpoint, UntranslatedEndpoint}; -use super::NodeAddr; +use crate::cluster::node::ResolvedContactPoint; +use crate::cluster::NodeAddr; use arc_swap::ArcSwap; use futures::{future::RemoteHandle, stream::FuturesUnordered, Future, FutureExt, StreamExt}; @@ -947,8 +947,7 @@ impl PoolRefiller { .boxed(), _ => async move { let non_shard_aware_endpoint = endpoint_fut.await; - let result = - connection::open_connection(non_shard_aware_endpoint, None, &cfg).await; + let result = open_connection(non_shard_aware_endpoint, None, &cfg).await; OpenedConnectionEvent { result, requested_shard: None, @@ -1107,7 +1106,7 @@ impl PoolRefiller { .await .map_err(|_| QueryError::TimeoutError)?; - super::cluster::use_keyspace_result(use_keyspace_results.into_iter()) + crate::cluster::use_keyspace_result(use_keyspace_results.into_iter()) }; tokio::task::spawn(async move { @@ -1194,37 +1193,14 @@ struct OpenedConnectionEvent { keyspace_name: Option, } -async fn open_connection_to_shard_aware_port( - endpoint: UntranslatedEndpoint, - shard: Shard, - sharder: Sharder, - connection_config: &ConnectionConfig, -) -> Result<(Connection, ErrorReceiver), ConnectionError> { - // Create iterator over all possible source ports for this shard - let source_port_iter = sharder.iter_source_ports_for_shard(shard); - - for port in source_port_iter { - let connect_result = - connection::open_connection(endpoint.clone(), Some(port), connection_config).await; - - match connect_result { - Err(err) if err.is_address_unavailable_for_use() => continue, // If we can't use this port, try the next one - result => return result, - } - } - - // Tried all source ports for that shard, give up - Err(ConnectionError::NoSourcePortForShard(shard)) -} - #[cfg(test)] mod tests { - use super::open_connection_to_shard_aware_port; + use super::super::connection::open_connection_to_shard_aware_port; + use super::ConnectionConfig; + use crate::cluster::metadata::UntranslatedEndpoint; + use crate::cluster::node::ResolvedContactPoint; use crate::routing::{ShardCount, Sharder}; use crate::test_utils::setup_tracing; - use crate::transport::connection::ConnectionConfig; - use crate::transport::node::ResolvedContactPoint; - use crate::transport::topology::UntranslatedEndpoint; use std::net::{SocketAddr, ToSocketAddrs}; // Open many connections to a node diff --git a/scylla/src/network/mod.rs b/scylla/src/network/mod.rs new file mode 100644 index 0000000000..308e65a7ab --- /dev/null +++ b/scylla/src/network/mod.rs @@ -0,0 +1,15 @@ +//! This module holds entities that represent connections to the cluster +//! and management over those connections (connection pooling). +//! This includes two main abstractions: +//! - Connection - a single, possibly encrypted, connection to a Scylla node over CQL protocol, +//! - NodeConnectionPool - a manager that keeps a desired number of connections opened to each shard. + +mod connection; +#[cfg(feature = "ssl")] +pub(crate) use connection::SslConfig; +pub(crate) use connection::{Connection, ConnectionConfig, VerifiedKeyspaceName}; + +mod connection_pool; + +pub use connection_pool::PoolSize; +pub(crate) use connection_pool::{NodeConnectionPool, PoolConfig}; diff --git a/scylla/src/observability/driver_tracing.rs b/scylla/src/observability/driver_tracing.rs new file mode 100644 index 0000000000..5d4877c9f3 --- /dev/null +++ b/scylla/src/observability/driver_tracing.rs @@ -0,0 +1,179 @@ +use crate::cluster::node::Node; +use crate::network::Connection; +use crate::response::query_result::QueryResult; +use crate::routing::{Shard, Token}; +use crate::utils::pretty::{CommaSeparatedDisplayer, CqlValueDisplayer}; +use itertools::Either; +use scylla_cql::frame::response::result::RawMetadataAndRawRows; +use scylla_cql::frame::response::result::{deser_cql_value, ColumnSpec}; +use std::borrow::Borrow; +use std::fmt::Display; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use tracing::trace_span; + +pub(crate) struct RequestSpan { + span: tracing::Span, + speculative_executions: AtomicUsize, +} + +impl RequestSpan { + pub(crate) fn new_query(contents: &str) -> Self { + use tracing::field::Empty; + + let span = trace_span!( + "Request", + kind = "unprepared", + contents = contents, + // + request_size = Empty, + result_size = Empty, + result_rows = Empty, + replicas = Empty, + shard = Empty, + speculative_executions = Empty, + ); + + Self { + span, + speculative_executions: 0.into(), + } + } + + pub(crate) fn new_prepared<'ps, 'spec: 'ps>( + partition_key: Option)> + Clone>, + token: Option, + request_size: usize, + ) -> Self { + use tracing::field::Empty; + + let span = trace_span!( + "Request", + kind = "prepared", + partition_key = Empty, + token = Empty, + // + request_size = request_size, + result_size = Empty, + result_rows = Empty, + replicas = Empty, + shard = Empty, + speculative_executions = Empty, + ); + + if let Some(partition_key) = partition_key { + span.record( + "partition_key", + tracing::field::display( + format_args!("{}", partition_key_displayer(partition_key),), + ), + ); + } + if let Some(token) = token { + span.record("token", token.value()); + } + + Self { + span, + speculative_executions: 0.into(), + } + } + + pub(crate) fn new_batch() -> Self { + use tracing::field::Empty; + + let span = trace_span!( + "Request", + kind = "batch", + // + request_size = Empty, + result_size = Empty, + result_rows = Empty, + replicas = Empty, + shard = Empty, + speculative_executions = Empty, + ); + + Self { + span, + speculative_executions: 0.into(), + } + } + + pub(crate) fn record_shard_id(&self, conn: &Connection) { + if let Some(info) = conn.get_shard_info() { + self.span.record("shard", info.shard); + } + } + + pub(crate) fn record_raw_rows_fields(&self, raw_rows: &RawMetadataAndRawRows) { + self.span + .record("raw_result_size", raw_rows.metadata_and_rows_bytes_size()); + } + + pub(crate) fn record_result_fields(&self, query_result: &QueryResult) { + if let Some(raw_metadata_and_rows) = query_result.raw_metadata_and_rows() { + self.record_raw_rows_fields(raw_metadata_and_rows); + } + } + + pub(crate) fn record_replicas<'a>(&'a self, replicas: &'a [(impl Borrow>, Shard)]) { + struct ReplicaIps<'a, N>(&'a [(N, Shard)]); + impl Display for ReplicaIps<'_, N> + where + N: Borrow>, + { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut nodes_with_shards = self.0.iter(); + if let Some((node, shard)) = nodes_with_shards.next() { + write!(f, "{}-shard{}", node.borrow().address.ip(), shard)?; + + for (node, shard) in nodes_with_shards { + write!(f, ",{}-shard{}", node.borrow().address.ip(), shard)?; + } + } + Ok(()) + } + } + self.span + .record("replicas", tracing::field::display(&ReplicaIps(replicas))); + } + + pub(crate) fn record_request_size(&self, size: usize) { + self.span.record("request_size", size); + } + + pub(crate) fn inc_speculative_executions(&self) { + self.speculative_executions.fetch_add(1, Ordering::Relaxed); + } + + pub(crate) fn span(&self) -> &tracing::Span { + &self.span + } +} + +impl Drop for RequestSpan { + fn drop(&mut self) { + self.span.record( + "speculative_executions", + self.speculative_executions.load(Ordering::Relaxed), + ); + } +} + +fn partition_key_displayer<'ps, 'res, 'spec: 'ps>( + mut pk_values_iter: impl Iterator)> + 'res + Clone, +) -> impl Display + 'res { + CommaSeparatedDisplayer( + std::iter::from_fn(move || { + pk_values_iter + .next() + .map(|(mut cell, spec)| deser_cql_value(spec.typ(), &mut cell)) + }) + .map(|c| match c { + Ok(c) => Either::Left(CqlValueDisplayer(c)), + Err(_) => Either::Right(""), + }), + ) +} diff --git a/scylla/src/history.rs b/scylla/src/observability/history.rs similarity index 99% rename from scylla/src/history.rs rename to scylla/src/observability/history.rs index b80dcf15ec..6e99fbd605 100644 --- a/scylla/src/history.rs +++ b/scylla/src/observability/history.rs @@ -7,7 +7,8 @@ use std::{ time::SystemTime, }; -use crate::{retry_policy::RetryDecision, transport::errors::QueryError}; +use crate::errors::QueryError; +use crate::policies::retry::RetryDecision; use chrono::{DateTime, Utc}; use tracing::warn; @@ -452,9 +453,9 @@ mod tests { use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use crate::{ - retry_policy::RetryDecision, + errors::{DbError, QueryError}, + policies::retry::RetryDecision, test_utils::setup_tracing, - transport::errors::{DbError, QueryError}, }; use super::{ diff --git a/scylla/src/transport/metrics.rs b/scylla/src/observability/metrics.rs similarity index 100% rename from scylla/src/transport/metrics.rs rename to scylla/src/observability/metrics.rs diff --git a/scylla/src/observability/mod.rs b/scylla/src/observability/mod.rs new file mode 100644 index 0000000000..da5ba7f004 --- /dev/null +++ b/scylla/src/observability/mod.rs @@ -0,0 +1,11 @@ +//! This module holds entities that allow observing and measuring driver's and cluster's behaviour. +//! This includes: +//! - driver-side tracing, +//! - cluster-side tracing, +//! - request execution history, +//! - driver metrics. + +pub(crate) mod driver_tracing; +pub mod history; +pub mod metrics; +pub mod tracing; diff --git a/scylla/src/tracing.rs b/scylla/src/observability/tracing.rs similarity index 100% rename from scylla/src/tracing.rs rename to scylla/src/observability/tracing.rs diff --git a/scylla/src/policies/address_translator.rs b/scylla/src/policies/address_translator.rs new file mode 100644 index 0000000000..db88068092 --- /dev/null +++ b/scylla/src/policies/address_translator.rs @@ -0,0 +1,73 @@ +use std::collections::HashMap; +use std::net::SocketAddr; +use std::str::FromStr as _; + +use async_trait::async_trait; + +use crate::cluster::metadata::UntranslatedPeer; +use crate::errors::TranslationError; + +/// Translates IP addresses received from ScyllaDB nodes into locally reachable addresses. +/// +/// The driver auto-detects new ScyllaDB nodes added to the cluster through server side pushed +/// notifications and through checking the system tables. For each node, the address the driver +/// receives corresponds to the address set as `rpc_address` in the node yaml file. In most +/// cases, this is the correct address to use by the driver and that is what is used by default. +/// However, sometimes the addresses received through this mechanism will either not be reachable +/// directly by the driver or should not be the preferred address to use to reach the node (for +/// instance, the `rpc_address` set on ScyllaDB nodes might be a private IP, but some clients +/// may have to use a public IP, or pass by a router, e.g. through NAT, to reach that node). +/// This interface allows to deal with such cases, by allowing to translate an address as sent +/// by a ScyllaDB node to another address to be used by the driver for connection. +/// +/// Please note that the "known nodes" addresses provided while creating +/// the [`Session`](crate::client::session::Session) instance are not translated, +/// only IP addresses retrieved from or sent by Cassandra nodes to the driver are. +#[async_trait] +pub trait AddressTranslator: Send + Sync { + async fn translate_address( + &self, + untranslated_peer: &UntranslatedPeer, + ) -> Result; +} + +#[async_trait] +impl AddressTranslator for HashMap { + async fn translate_address( + &self, + untranslated_peer: &UntranslatedPeer, + ) -> Result { + match self.get(&untranslated_peer.untranslated_address) { + Some(&translated_addr) => Ok(translated_addr), + None => Err(TranslationError::NoRuleForAddress( + untranslated_peer.untranslated_address, + )), + } + } +} + +#[async_trait] +// Notice: this is inefficient, but what else can we do with such poor representation as str? +// After all, the cluster size is small enough to make this irrelevant. +impl AddressTranslator for HashMap<&'static str, &'static str> { + async fn translate_address( + &self, + untranslated_peer: &UntranslatedPeer, + ) -> Result { + for (&rule_addr_str, &translated_addr_str) in self.iter() { + if let Ok(rule_addr) = SocketAddr::from_str(rule_addr_str) { + if rule_addr == untranslated_peer.untranslated_address { + return SocketAddr::from_str(translated_addr_str).map_err(|reason| { + TranslationError::InvalidAddressInRule { + translated_addr_str, + reason, + } + }); + } + } + } + Err(TranslationError::NoRuleForAddress( + untranslated_peer.untranslated_address, + )) + } +} diff --git a/scylla/src/transport/host_filter.rs b/scylla/src/policies/host_filter.rs similarity index 88% rename from scylla/src/transport/host_filter.rs rename to scylla/src/policies/host_filter.rs index 2838f1733c..c271bdf490 100644 --- a/scylla/src/transport/host_filter.rs +++ b/scylla/src/policies/host_filter.rs @@ -2,14 +2,14 @@ //! //! Host filters are essentially just a predicate over //! [`Peer`]s. Currently, they are used -//! by the [`Session`](crate::transport::session::Session) to determine whether +//! by the [`Session`](crate::client::session::Session) to determine whether //! connections should be opened to a given node or not. use std::collections::HashSet; use std::io::Error; use std::net::{SocketAddr, ToSocketAddrs}; -use crate::transport::topology::Peer; +use crate::cluster::metadata::Peer; /// The `HostFilter` trait. pub trait HostFilter: Send + Sync { @@ -55,11 +55,11 @@ impl AllowListHostFilter { impl HostFilter for AllowListHostFilter { fn accept(&self, peer: &Peer) -> bool { match peer.address { - super::NodeAddr::Translatable(addr) => self.allowed.contains(&addr), + crate::cluster::NodeAddr::Translatable(addr) => self.allowed.contains(&addr), // If the address is Untranslatable, then the node either was originally // an ContactPoint, or a Translatable node for which the host filter // returned true. - super::NodeAddr::Untranslatable(_) => true, + crate::cluster::NodeAddr::Untranslatable(_) => true, } } } diff --git a/scylla/src/transport/load_balancing/default.rs b/scylla/src/policies/load_balancing/default.rs similarity index 98% rename from scylla/src/transport/load_balancing/default.rs rename to scylla/src/policies/load_balancing/default.rs index 16fd6ac9aa..600c5698f3 100644 --- a/scylla/src/transport/load_balancing/default.rs +++ b/scylla/src/policies/load_balancing/default.rs @@ -2,10 +2,13 @@ use self::latency_awareness::LatencyAwareness; pub use self::latency_awareness::LatencyAwarenessBuilder; use super::{FallbackPlan, LoadBalancingPolicy, NodeRef, RoutingInfo}; +use crate::cluster::ClusterState; use crate::{ + cluster::metadata::Strategy, + cluster::node::Node, + errors::QueryError, + routing::locator::ReplicaSet, routing::{Shard, Token}, - transport::errors::QueryError, - transport::{cluster::ClusterData, locator::ReplicaSet, node::Node, topology::Strategy}, }; use itertools::{Either, Itertools}; use rand::{prelude::SliceRandom, thread_rng, Rng}; @@ -160,7 +163,7 @@ impl LoadBalancingPolicy for DefaultPolicy { fn pick<'a>( &'a self, query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)> { /* For prepared statements, token-aware logic is available, we know what are the replicas * for the statement, so that we can pick one of them. */ @@ -333,7 +336,7 @@ or refrain from preferring datacenters (which may ban all other datacenters, if fn fallback<'a>( &'a self, query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> FallbackPlan<'a> { /* For prepared statements, token-aware logic is available, we know what are the replicas * for the statement, so that we can pick one of them. */ @@ -587,7 +590,7 @@ impl DefaultPolicy { fn routing_info<'a>( &'a self, query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> ProcessedRoutingInfo<'a> { let mut routing_info = ProcessedRoutingInfo::new(query, cluster); @@ -600,7 +603,7 @@ impl DefaultPolicy { /// Returns all nodes in the local datacenter if one is given, /// or else all nodes in the cluster. - fn preferred_node_set<'a>(&'a self, cluster: &'a ClusterData) -> &'a [Arc] { + fn preferred_node_set<'a>(&'a self, cluster: &'a ClusterState) -> &'a [Arc] { if let Some(preferred_datacenter) = self.preferences.datacenter() { if let Some(nodes) = cluster .replica_locator() @@ -626,7 +629,7 @@ impl DefaultPolicy { &'a self, ts: &TokenWithStrategy<'a>, replica_location: NodeLocationCriteria<'a>, - cluster: &'a ClusterData, + cluster: &'a ClusterState, table_spec: &TableSpec, ) -> ReplicaSet<'a> { let datacenter = replica_location.datacenter(); @@ -674,7 +677,7 @@ impl DefaultPolicy { ts: &TokenWithStrategy<'a>, replica_location: NodeLocationCriteria<'a>, predicate: impl Fn(NodeRef<'a>, Shard) -> bool + 'a, - cluster: &'a ClusterData, + cluster: &'a ClusterState, order: ReplicaOrder, table_spec: &TableSpec, ) -> impl Iterator, Shard)> { @@ -704,7 +707,7 @@ impl DefaultPolicy { ts: &TokenWithStrategy<'a>, replica_location: NodeLocationCriteria<'a>, predicate: impl Fn(NodeRef<'a>, Shard) -> bool + 'a, - cluster: &'a ClusterData, + cluster: &'a ClusterState, statement_type: StatementType, table_spec: &TableSpec, ) -> Option> { @@ -742,7 +745,7 @@ impl DefaultPolicy { ts: &TokenWithStrategy<'a>, replica_location: NodeLocationCriteria<'a>, predicate: impl Fn(NodeRef<'a>, Shard) -> bool + 'a, - cluster: &'a ClusterData, + cluster: &'a ClusterState, table_spec: &TableSpec, ) -> Option> { match replica_location { @@ -796,7 +799,7 @@ impl DefaultPolicy { ts: &TokenWithStrategy<'a>, replica_location: NodeLocationCriteria<'a>, predicate: impl Fn(NodeRef<'a>, Shard) -> bool + 'a, - cluster: &'a ClusterData, + cluster: &'a ClusterState, table_spec: &TableSpec, ) -> Option<(NodeRef<'a>, Shard)> { let predicate = Self::make_sharded_rack_predicate(predicate, replica_location); @@ -820,7 +823,7 @@ impl DefaultPolicy { ts: &TokenWithStrategy<'a>, replica_location: NodeLocationCriteria<'a>, predicate: impl Fn(NodeRef<'a>, Shard) -> bool + 'a, - cluster: &'a ClusterData, + cluster: &'a ClusterState, statement_type: StatementType, table_spec: &TableSpec, ) -> impl Iterator, Shard)> { @@ -927,7 +930,7 @@ impl Default for DefaultPolicy { /// # Example /// ``` /// # async fn example() -> Result<(), Box> { -/// use scylla::load_balancing::DefaultPolicy; +/// use scylla::policies::load_balancing::DefaultPolicy; /// /// let default_policy = DefaultPolicy::builder() /// .prefer_datacenter("dc1".to_string()) @@ -1120,7 +1123,7 @@ struct ProcessedRoutingInfo<'a> { } impl<'a> ProcessedRoutingInfo<'a> { - fn new(query: &'a RoutingInfo, cluster: &'a ClusterData) -> ProcessedRoutingInfo<'a> { + fn new(query: &'a RoutingInfo, cluster: &'a ClusterState) -> ProcessedRoutingInfo<'a> { let local_consistency = matches!( (query.consistency, query.serial_consistency), (Consistency::LocalQuorum, _) @@ -1141,7 +1144,7 @@ struct TokenWithStrategy<'a> { } impl<'a> TokenWithStrategy<'a> { - fn new(query: &'a RoutingInfo, cluster: &'a ClusterData) -> Option> { + fn new(query: &'a RoutingInfo, cluster: &'a ClusterState) -> Option> { let token = query.token?; let keyspace_name = query.table?.ks_name(); let keyspace = cluster.get_keyspace_info().get(keyspace_name)?; @@ -1161,42 +1164,43 @@ mod tests { get_plan_and_collect_node_identifiers, mock_cluster_data_for_token_unaware_tests, ExpectedGroups, ExpectedGroupsBuilder, }; - use crate::host_filter::HostFilter; - use crate::transport::locator::tablets::TabletsInfo; - use crate::transport::locator::test::{ + use crate::policies::host_filter::HostFilter; + use crate::routing::locator::tablets::TabletsInfo; + use crate::routing::locator::test::{ id_to_invalid_addr, mock_metadata_for_token_aware_tests, TABLE_NTS_RF_2, TABLE_NTS_RF_3, TABLE_SS_RF_2, }; use crate::{ - load_balancing::{ + cluster::ClusterState, + policies::load_balancing::{ default::tests::framework::mock_cluster_data_for_token_aware_tests, Plan, RoutingInfo, }, routing::Token, test_utils::setup_tracing, - transport::ClusterData, }; use super::{DefaultPolicy, NodeLocationPreference}; pub(crate) mod framework { + use crate::routing::locator::test::{ + id_to_invalid_addr, mock_metadata_for_token_aware_tests, + }; use std::collections::{HashMap, HashSet}; use uuid::Uuid; use crate::{ - load_balancing::{LoadBalancingPolicy, Plan, RoutingInfo}, + cluster::{ + metadata::{Metadata, Peer}, + ClusterState, + }, + policies::load_balancing::{LoadBalancingPolicy, Plan, RoutingInfo}, routing::Token, test_utils::setup_tracing, - transport::{ - locator::{ - tablets::TabletsInfo, - test::{id_to_invalid_addr, mock_metadata_for_token_aware_tests}, - }, - topology::{Metadata, Peer}, - ClusterData, - }, }; + use super::TabletsInfo; + #[derive(Debug)] enum ExpectedGroup { NonDeterministic(HashSet), @@ -1401,9 +1405,9 @@ mod tests { } // based on locator mock cluster - pub(crate) async fn mock_cluster_data_for_token_aware_tests() -> ClusterData { + pub(crate) async fn mock_cluster_data_for_token_aware_tests() -> ClusterState { let metadata = mock_metadata_for_token_aware_tests(); - ClusterData::new( + ClusterState::new( metadata, &Default::default(), &HashMap::new(), @@ -1414,9 +1418,9 @@ mod tests { .await } - // creates ClusterData with info about 5 nodes living in 2 different datacenters + // creates ClusterState with info about 5 nodes living in 2 different datacenters // ring field is minimal, not intended to influence the tests - pub(crate) async fn mock_cluster_data_for_token_unaware_tests() -> ClusterData { + pub(crate) async fn mock_cluster_data_for_token_unaware_tests() -> ClusterState { let peers = [("eu", 1), ("eu", 2), ("eu", 3), ("us", 4), ("us", 5)] .iter() .map(|(dc, id)| Peer { @@ -1433,7 +1437,7 @@ mod tests { keyspaces: HashMap::new(), }; - ClusterData::new( + ClusterState::new( info, &Default::default(), &HashMap::new(), @@ -1447,7 +1451,7 @@ mod tests { pub(crate) fn get_plan_and_collect_node_identifiers( policy: &impl LoadBalancingPolicy, query_info: &RoutingInfo, - cluster: &ClusterData, + cluster: &ClusterState, ) -> Vec { let plan = Plan::new(policy, query_info, cluster); plan.map(|(node, _shard)| node.address.port()) @@ -1465,7 +1469,7 @@ mod tests { pub(super) async fn test_default_policy_with_given_cluster_and_routing_info( policy: &DefaultPolicy, - cluster: &ClusterData, + cluster: &ClusterState, routing_info: &RoutingInfo<'_>, expected_groups: &ExpectedGroups, ) { @@ -1543,7 +1547,7 @@ mod tests { async fn test_default_policy_with_token_aware_statements() { setup_tracing(); - use crate::transport::locator::test::{A, B, C, D, E, F, G}; + use crate::routing::locator::test::{A, B, C, D, E, F, G}; let cluster = mock_cluster_data_for_token_aware_tests().await; #[derive(Debug)] @@ -2016,7 +2020,7 @@ mod tests { #[tokio::test] async fn test_default_policy_with_lwt_statements() { setup_tracing(); - use crate::transport::locator::test::{A, B, C, D, E, F, G}; + use crate::routing::locator::test::{A, B, C, D, E, F, G}; let cluster = mock_cluster_data_for_token_aware_tests().await; struct Test<'a> { @@ -2473,7 +2477,7 @@ mod tests { .await; } - let cluster_with_disabled_node_f = ClusterData::new( + let cluster_with_disabled_node_f = ClusterState::new( mock_metadata_for_token_aware_tests(), &Default::default(), &HashMap::new(), @@ -2481,7 +2485,7 @@ mod tests { { struct FHostFilter; impl HostFilter for FHostFilter { - fn accept(&self, peer: &crate::transport::topology::Peer) -> bool { + fn accept(&self, peer: &crate::cluster::metadata::Peer) -> bool { peer.address != id_to_invalid_addr(F) } } @@ -2549,12 +2553,10 @@ mod latency_awareness { use tracing::{trace, warn}; use uuid::Uuid; - use crate::{ - load_balancing::NodeRef, - routing::Shard, - transport::errors::{DbError, QueryError}, - transport::node::Node, - }; + use crate::cluster::node::Node; + use crate::errors::{DbError, QueryError}; + use crate::policies::load_balancing::NodeRef; + use crate::routing::Shard; use std::{ collections::HashMap, ops::Deref, @@ -2918,7 +2920,7 @@ mod latency_awareness { /// # Example /// ``` /// # fn example() { - /// use scylla::load_balancing::{ + /// use scylla::policies::load_balancing::{ /// LatencyAwarenessBuilder, DefaultPolicy /// }; /// @@ -3127,28 +3129,25 @@ mod latency_awareness { }; use crate::{ - load_balancing::default::NodeLocationPreference, - routing::Shard, - test_utils::setup_tracing, - transport::locator::test::{TABLE_INVALID, TABLE_NTS_RF_2, TABLE_NTS_RF_3}, - }; - use crate::{ - load_balancing::{ + cluster::ClusterState, + cluster::NodeAddr, + policies::load_balancing::default::NodeLocationPreference, + policies::load_balancing::{ default::tests::test_default_policy_with_given_cluster_and_routing_info, RoutingInfo, }, + routing::locator::test::{id_to_invalid_addr, A, B, C, D, E, F, G}, + routing::locator::test::{TABLE_INVALID, TABLE_NTS_RF_2, TABLE_NTS_RF_3}, + routing::Shard, routing::Token, - transport::{ - locator::test::{id_to_invalid_addr, A, B, C, D, E, F, G}, - ClusterData, NodeAddr, - }, + test_utils::setup_tracing, }; use tokio::time::Instant; trait DefaultPolicyTestExt { fn set_nodes_latency_stats( &self, - cluster: &ClusterData, + cluster: &ClusterState, averages: &[(u16, Option)], ); } @@ -3156,7 +3155,7 @@ mod latency_awareness { impl DefaultPolicyTestExt for DefaultPolicy { fn set_nodes_latency_stats( &self, - cluster: &ClusterData, + cluster: &ClusterState, averages: &[(u16, Option)], ) { let addr_to_host_id: HashMap = cluster diff --git a/scylla/src/transport/load_balancing/mod.rs b/scylla/src/policies/load_balancing/mod.rs similarity index 94% rename from scylla/src/transport/load_balancing/mod.rs rename to scylla/src/policies/load_balancing/mod.rs index 72aaa1000e..1307c156c5 100644 --- a/scylla/src/transport/load_balancing/mod.rs +++ b/scylla/src/policies/load_balancing/mod.rs @@ -2,10 +2,10 @@ //! `Session` can use any load balancing policy which implements the `LoadBalancingPolicy` trait\ //! See [the book](https://rust-driver.docs.scylladb.com/stable/load-balancing/load-balancing.html) for more information -use super::{cluster::ClusterData, NodeRef}; +use crate::cluster::{ClusterState, NodeRef}; use crate::{ + errors::QueryError, routing::{Shard, Token}, - transport::errors::QueryError, }; use scylla_cql::frame::{response::result::TableSpec, types}; @@ -72,12 +72,15 @@ pub trait LoadBalancingPolicy: Send + Sync + std::fmt::Debug { fn pick<'a>( &'a self, query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)>; /// Returns all contact-appropriate nodes for a given query. - fn fallback<'a>(&'a self, query: &'a RoutingInfo, cluster: &'a ClusterData) - -> FallbackPlan<'a>; + fn fallback<'a>( + &'a self, + query: &'a RoutingInfo, + cluster: &'a ClusterState, + ) -> FallbackPlan<'a>; /// Invoked each time a query succeeds. fn on_query_success(&self, _query: &RoutingInfo, _latency: Duration, _node: NodeRef<'_>) {} diff --git a/scylla/src/transport/load_balancing/plan.rs b/scylla/src/policies/load_balancing/plan.rs similarity index 91% rename from scylla/src/transport/load_balancing/plan.rs rename to scylla/src/policies/load_balancing/plan.rs index 7ae247ab13..aff7488ee8 100644 --- a/scylla/src/transport/load_balancing/plan.rs +++ b/scylla/src/policies/load_balancing/plan.rs @@ -2,7 +2,8 @@ use rand::{thread_rng, Rng}; use tracing::error; use super::{FallbackPlan, LoadBalancingPolicy, NodeRef, RoutingInfo}; -use crate::{routing::Shard, transport::ClusterData}; +use crate::cluster::ClusterState; +use crate::routing::Shard; enum PlanState<'a> { Created, @@ -32,12 +33,12 @@ enum PlanState<'a> { /// /// ``` /// # use std::sync::Arc; -/// # use scylla::load_balancing::LoadBalancingPolicy; -/// # use scylla::load_balancing::RoutingInfo; -/// # use scylla::transport::ClusterData; -/// # use scylla::transport::NodeRef; +/// # use scylla::cluster::NodeRef; +/// # use scylla::cluster::ClusterState; +/// # use scylla::policies::load_balancing::FallbackPlan; +/// # use scylla::policies::load_balancing::LoadBalancingPolicy; +/// # use scylla::policies::load_balancing::RoutingInfo; /// # use scylla::routing::Shard; -/// # use scylla::load_balancing::FallbackPlan; /// /// #[derive(Debug)] /// struct NonRandomLBP { @@ -47,14 +48,14 @@ enum PlanState<'a> { /// fn pick<'a>( /// &'a self, /// info: &'a RoutingInfo, -/// cluster: &'a ClusterData, +/// cluster: &'a ClusterState, /// ) -> Option<(NodeRef<'a>, Option)> { /// self.inner /// .pick(info, cluster) /// .map(|(node, shard)| (node, shard.or(Some(0)))) /// } /// -/// fn fallback<'a>(&'a self, info: &'a RoutingInfo, cluster: &'a ClusterData) -> FallbackPlan<'a> { +/// fn fallback<'a>(&'a self, info: &'a RoutingInfo, cluster: &'a ClusterState) -> FallbackPlan<'a> { /// Box::new(self.inner /// .fallback(info, cluster) /// .map(|(node, shard)| (node, shard.or(Some(0))))) @@ -68,7 +69,7 @@ enum PlanState<'a> { pub struct Plan<'a> { policy: &'a dyn LoadBalancingPolicy, routing_info: &'a RoutingInfo<'a>, - cluster: &'a ClusterData, + cluster: &'a ClusterState, state: PlanState<'a>, } @@ -77,7 +78,7 @@ impl<'a> Plan<'a> { pub fn new( policy: &'a dyn LoadBalancingPolicy, routing_info: &'a RoutingInfo<'a>, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> Self { Self { policy, @@ -166,11 +167,9 @@ mod tests { use std::{net::SocketAddr, str::FromStr, sync::Arc}; use crate::{ + cluster::{Node, NodeAddr}, + routing::locator::test::{create_locator, mock_metadata_for_token_aware_tests}, test_utils::setup_tracing, - transport::{ - locator::test::{create_locator, mock_metadata_for_token_aware_tests}, - Node, NodeAddr, - }, }; use super::*; @@ -197,7 +196,7 @@ mod tests { fn pick<'a>( &'a self, _query: &'a RoutingInfo, - _cluster: &'a ClusterData, + _cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)> { None } @@ -205,7 +204,7 @@ mod tests { fn fallback<'a>( &'a self, _query: &'a RoutingInfo, - _cluster: &'a ClusterData, + _cluster: &'a ClusterState, ) -> FallbackPlan<'a> { Box::new( self.expected_nodes @@ -226,7 +225,7 @@ mod tests { expected_nodes: expected_nodes(), }; let locator = create_locator(&mock_metadata_for_token_aware_tests()); - let cluster_data = ClusterData { + let cluster_data = ClusterState { known_peers: Default::default(), keyspaces: Default::default(), locator, diff --git a/scylla/src/policies/mod.rs b/scylla/src/policies/mod.rs new file mode 100644 index 0000000000..6e8bd3985e --- /dev/null +++ b/scylla/src/policies/mod.rs @@ -0,0 +1,22 @@ +//! This module holds policies, which are entities that allow configuring +//! the driver's behaviour in various aspects. The common feature of all policies +//! is that users can implement a policy on their own (because they simply need +//! to implement a certain trait), allowing flexible customizability of the driver. +//! +//! This includes: +//! - HostFilter, which is a way to filter out some nodes and thus +//! not contact them at all on any condition. +//! - AddressTranslator, which allows contacting a node through a different address +//! than its broadcast address (e.g., when it's behind a NAT). +//! - LoadBalancingPolicy, which decides which nodes and shards to contact for each +//! request. +//! - SpeculativeExecutionPolicy, which decides if the driver will send speculative +//! requests to the next hosts when the current host takes too long to respond. +//! - RetryPolicy, which decides whether and how to retry a request. +//! - TODO + +pub mod address_translator; +pub mod host_filter; +pub mod load_balancing; +pub mod retry; +pub mod speculative_execution; diff --git a/scylla/src/transport/retry_policy.rs b/scylla/src/policies/retry/default.rs similarity index 86% rename from scylla/src/transport/retry_policy.rs rename to scylla/src/policies/retry/default.rs index 54f87380eb..0691445a96 100644 --- a/scylla/src/transport/retry_policy.rs +++ b/scylla/src/policies/retry/default.rs @@ -1,76 +1,8 @@ -//! Query retries configurations\ -//! To decide when to retry a query the `Session` can use any object which implements -//! the `RetryPolicy` trait - -use crate::frame::types::Consistency; -use crate::transport::errors::{DbError, QueryError, WriteType}; - -/// Information about a failed query -pub struct QueryInfo<'a> { - /// The error with which the query failed - pub error: &'a QueryError, - /// A query is idempotent if it can be applied multiple times without changing the result of the initial application\ - /// If set to `true` we can be sure that it is idempotent\ - /// If set to `false` it is unknown whether it is idempotent - pub is_idempotent: bool, - /// Consistency with which the query failed - pub consistency: Consistency, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum RetryDecision { - RetrySameNode(Option), // None means that the same consistency should be used as before - RetryNextNode(Option), // ditto - DontRetry, - IgnoreWriteError, -} - -/// Specifies a policy used to decide when to retry a query -pub trait RetryPolicy: std::fmt::Debug + Send + Sync { - /// Called for each new query, starts a session of deciding about retries - fn new_session(&self) -> Box; -} - -/// Used throughout a single query to decide when to retry it -/// After this query is finished it is destroyed or reset -pub trait RetrySession: Send + Sync { - /// Called after the query failed - decide what to do next - fn decide_should_retry(&mut self, query_info: QueryInfo) -> RetryDecision; - - /// Reset before using for a new query - fn reset(&mut self); -} - -/// Forwards all errors directly to the user, never retries -#[derive(Debug)] -pub struct FallthroughRetryPolicy; -pub struct FallthroughRetrySession; - -impl FallthroughRetryPolicy { - pub fn new() -> FallthroughRetryPolicy { - FallthroughRetryPolicy - } -} +use scylla_cql::frame::response::error::{DbError, WriteType}; -impl Default for FallthroughRetryPolicy { - fn default() -> FallthroughRetryPolicy { - FallthroughRetryPolicy - } -} +use crate::errors::QueryError; -impl RetryPolicy for FallthroughRetryPolicy { - fn new_session(&self) -> Box { - Box::new(FallthroughRetrySession) - } -} - -impl RetrySession for FallthroughRetrySession { - fn decide_should_retry(&mut self, _query_info: QueryInfo) -> RetryDecision { - RetryDecision::DontRetry - } - - fn reset(&mut self) {} -} +use super::{QueryInfo, RetryDecision, RetryPolicy, RetrySession}; /// Default retry policy - retries when there is a high chance that a retry might help.\ /// Behaviour based on [DataStax Java Driver](https://docs.datastax.com/en/developer/java-driver/4.10/manual/core/retries/) @@ -203,12 +135,12 @@ impl RetrySession for DefaultRetrySession { #[cfg(test)] mod tests { use super::{DefaultRetryPolicy, QueryInfo, RetryDecision, RetryPolicy}; - use crate::statement::Consistency; - use crate::test_utils::setup_tracing; - use crate::transport::errors::{ + use crate::errors::{ BadQuery, BrokenConnectionErrorKind, ConnectionPoolError, ProtocolError, QueryError, }; - use crate::transport::errors::{DbError, WriteType}; + use crate::errors::{DbError, WriteType}; + use crate::statement::Consistency; + use crate::test_utils::setup_tracing; use bytes::Bytes; fn make_query_info(error: &QueryError, is_idempotent: bool) -> QueryInfo<'_> { diff --git a/scylla/src/transport/downgrading_consistency_retry_policy.rs b/scylla/src/policies/retry/downgrading_consistency.rs similarity index 98% rename from scylla/src/transport/downgrading_consistency_retry_policy.rs rename to scylla/src/policies/retry/downgrading_consistency.rs index e52a44cbf1..27e5eb132d 100644 --- a/scylla/src/transport/downgrading_consistency_retry_policy.rs +++ b/scylla/src/policies/retry/downgrading_consistency.rs @@ -1,13 +1,11 @@ use scylla_cql::Consistency; use tracing::debug; -use crate::{ - retry_policy::{QueryInfo, RetryDecision, RetryPolicy, RetrySession}, - transport::errors::{DbError, QueryError, WriteType}, -}; +use super::{QueryInfo, RetryDecision, RetryPolicy, RetrySession}; +use crate::errors::{DbError, QueryError, WriteType}; /// Downgrading consistency retry policy - retries with lower consistency level if it knows\ -/// that the initial CL is unreachable. Also, it behaves as [DefaultRetryPolicy](crate::retry_policy::DefaultRetryPolicy) +/// that the initial CL is unreachable. Also, it behaves as [DefaultRetryPolicy](crate::policies::retry::DefaultRetryPolicy) /// when it believes that the initial CL is reachable. /// Behaviour based on [DataStax Java Driver]\ ///() @@ -180,10 +178,8 @@ impl RetrySession for DowngradingConsistencyRetrySession { mod tests { use bytes::Bytes; + use crate::errors::{BadQuery, BrokenConnectionErrorKind, ConnectionPoolError, ProtocolError}; use crate::test_utils::setup_tracing; - use crate::transport::errors::{ - BadQuery, BrokenConnectionErrorKind, ConnectionPoolError, ProtocolError, - }; use super::*; diff --git a/scylla/src/policies/retry/fallthrough.rs b/scylla/src/policies/retry/fallthrough.rs new file mode 100644 index 0000000000..48a866e5fd --- /dev/null +++ b/scylla/src/policies/retry/fallthrough.rs @@ -0,0 +1,32 @@ +use super::{QueryInfo, RetryDecision, RetryPolicy, RetrySession}; + +/// Forwards all errors directly to the user, never retries +#[derive(Debug)] +pub struct FallthroughRetryPolicy; +pub struct FallthroughRetrySession; + +impl FallthroughRetryPolicy { + pub fn new() -> FallthroughRetryPolicy { + FallthroughRetryPolicy + } +} + +impl Default for FallthroughRetryPolicy { + fn default() -> FallthroughRetryPolicy { + FallthroughRetryPolicy + } +} + +impl RetryPolicy for FallthroughRetryPolicy { + fn new_session(&self) -> Box { + Box::new(FallthroughRetrySession) + } +} + +impl RetrySession for FallthroughRetrySession { + fn decide_should_retry(&mut self, _query_info: QueryInfo) -> RetryDecision { + RetryDecision::DontRetry + } + + fn reset(&mut self) {} +} diff --git a/scylla/src/policies/retry/mod.rs b/scylla/src/policies/retry/mod.rs new file mode 100644 index 0000000000..f065e6a881 --- /dev/null +++ b/scylla/src/policies/retry/mod.rs @@ -0,0 +1,11 @@ +mod default; +mod downgrading_consistency; +mod fallthrough; +mod retry_policy; + +pub use default::{DefaultRetryPolicy, DefaultRetrySession}; +pub use downgrading_consistency::{ + DowngradingConsistencyRetryPolicy, DowngradingConsistencyRetrySession, +}; +pub use fallthrough::{FallthroughRetryPolicy, FallthroughRetrySession}; +pub use retry_policy::{QueryInfo, RetryDecision, RetryPolicy, RetrySession}; diff --git a/scylla/src/policies/retry/retry_policy.rs b/scylla/src/policies/retry/retry_policy.rs new file mode 100644 index 0000000000..92949f9a02 --- /dev/null +++ b/scylla/src/policies/retry/retry_policy.rs @@ -0,0 +1,42 @@ +//! Query retries configurations\ +//! To decide when to retry a query the `Session` can use any object which implements +//! the `RetryPolicy` trait + +use crate::errors::QueryError; +use crate::frame::types::Consistency; + +/// Information about a failed query +pub struct QueryInfo<'a> { + /// The error with which the query failed + pub error: &'a QueryError, + /// A query is idempotent if it can be applied multiple times without changing the result of the initial application\ + /// If set to `true` we can be sure that it is idempotent\ + /// If set to `false` it is unknown whether it is idempotent + pub is_idempotent: bool, + /// Consistency with which the query failed + pub consistency: Consistency, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum RetryDecision { + RetrySameNode(Option), // None means that the same consistency should be used as before + RetryNextNode(Option), // ditto + DontRetry, + IgnoreWriteError, +} + +/// Specifies a policy used to decide when to retry a query +pub trait RetryPolicy: std::fmt::Debug + Send + Sync { + /// Called for each new query, starts a session of deciding about retries + fn new_session(&self) -> Box; +} + +/// Used throughout a single query to decide when to retry it +/// After this query is finished it is destroyed or reset +pub trait RetrySession: Send + Sync { + /// Called after the query failed - decide what to do next + fn decide_should_retry(&mut self, query_info: QueryInfo) -> RetryDecision; + + /// Reset before using for a new query + fn reset(&mut self); +} diff --git a/scylla/src/transport/speculative_execution.rs b/scylla/src/policies/speculative_execution.rs similarity index 99% rename from scylla/src/transport/speculative_execution.rs rename to scylla/src/policies/speculative_execution.rs index 756ed3d895..66f0ad588d 100644 --- a/scylla/src/transport/speculative_execution.rs +++ b/scylla/src/policies/speculative_execution.rs @@ -6,9 +6,8 @@ use scylla_cql::frame::response::error::DbError; use std::{future::Future, sync::Arc, time::Duration}; use tracing::{trace_span, warn, Instrument}; -use crate::transport::errors::QueryError; - -use super::metrics::Metrics; +use crate::errors::QueryError; +use crate::observability::metrics::Metrics; /// Context is passed as an argument to `SpeculativeExecutionPolicy` methods pub struct Context { diff --git a/scylla/src/transport/legacy_query_result.rs b/scylla/src/response/legacy_query_result.rs similarity index 99% rename from scylla/src/transport/legacy_query_result.rs rename to scylla/src/response/legacy_query_result.rs index 91fe47a58b..ce76e29479 100644 --- a/scylla/src/transport/legacy_query_result.rs +++ b/scylla/src/response/legacy_query_result.rs @@ -192,7 +192,7 @@ impl LegacyQueryResult { } } -/// An error that occurred during [`QueryResult`](crate::transport::query_result::QueryResult) +/// An error that occurred during [`QueryResult`](crate::response::query_result::QueryResult) /// to [`LegacyQueryResult`] conversion. #[deprecated( since = "0.15.1", diff --git a/scylla/src/response/mod.rs b/scylla/src/response/mod.rs new file mode 100644 index 0000000000..7880dd4600 --- /dev/null +++ b/scylla/src/response/mod.rs @@ -0,0 +1,17 @@ +//! This module holds entities that represent responses to requests +//! sent to the cluster by the driver. +//! The following abstractions are involved: +// - [QueryResponse] - a response to any kind of a CQL request. +// - [NonErrorQueryResponse] - a non-error response to any kind of a CQL request. +//! - [QueryResult](query_result::QueryResult) - a result of a CQL QUERY/EXECUTE/BATCH request. +//! - [QueryRowsResult](query_result::QueryRowsResult) - a result of CQL QUERY/EXECUTE/BATCH +//! request that contains some rows, which can be deserialized by the user. + +pub mod legacy_query_result; +pub mod query_result; +mod request_response; + +pub(crate) use request_response::{ + NonErrorAuthResponse, NonErrorQueryResponse, NonErrorStartupResponse, QueryResponse, +}; +pub use scylla_cql::frame::request::query::{PagingState, PagingStateResponse}; diff --git a/scylla/src/transport/query_result.rs b/scylla/src/response/query_result.rs similarity index 99% rename from scylla/src/transport/query_result.rs rename to scylla/src/response/query_result.rs index b76ec28e5a..f9d8e8bfd6 100644 --- a/scylla/src/transport/query_result.rs +++ b/scylla/src/response/query_result.rs @@ -207,7 +207,7 @@ impl QueryResult { /// Returns an error if the response is not of Rows kind or metadata deserialization failed. /// /// ```rust - /// # use scylla::transport::query_result::{QueryResult, QueryRowsResult}; + /// # use scylla::response::query_result::{QueryResult, QueryRowsResult}; /// # fn example(query_result: QueryResult) -> Result<(), Box> { /// let rows_result = query_result.into_rows_result()?; /// @@ -225,7 +225,7 @@ impl QueryResult { /// returned back to the user in the error type. See [`IntoRowsResultError`] documentation. /// /// ```rust - /// # use scylla::transport::query_result::{QueryResult, QueryRowsResult, IntoRowsResultError}; + /// # use scylla::response::query_result::{QueryResult, QueryRowsResult, IntoRowsResultError}; /// # fn example(non_rows_query_result: QueryResult) -> Result<(), Box> { /// let err = non_rows_query_result.into_rows_result().unwrap_err(); /// @@ -308,7 +308,7 @@ impl QueryResult { /// additionally asserting that it's the only one in the response. /// /// ```rust -/// # use scylla::transport::query_result::QueryResult; +/// # use scylla::response::query_result::QueryResult; /// # fn example(query_result: QueryResult) -> Result<(), Box> { /// let rows_result = query_result.into_rows_result()?; /// diff --git a/scylla/src/response/request_response.rs b/scylla/src/response/request_response.rs new file mode 100644 index 0000000000..950611cc36 --- /dev/null +++ b/scylla/src/response/request_response.rs @@ -0,0 +1,110 @@ +use std::collections::HashMap; + +use bytes::Bytes; +use scylla_cql::frame::request::query::PagingStateResponse; +use scylla_cql::frame::response::{NonErrorResponse, Response}; +use tracing::error; +use uuid::Uuid; + +use crate::errors::{ProtocolError, QueryError, UserRequestError}; +use crate::frame::response::{self, result}; +use crate::response::query_result::QueryResult; + +pub(crate) struct QueryResponse { + pub(crate) response: Response, + pub(crate) tracing_id: Option, + pub(crate) warnings: Vec, + #[allow(dead_code)] // This is not exposed to user (yet?) + pub(crate) custom_payload: Option>, +} + +// A QueryResponse in which response can not be Response::Error +pub(crate) struct NonErrorQueryResponse { + pub(crate) response: NonErrorResponse, + pub(crate) tracing_id: Option, + pub(crate) warnings: Vec, +} + +impl QueryResponse { + pub(crate) fn into_non_error_query_response( + self, + ) -> Result { + Ok(NonErrorQueryResponse { + response: self.response.into_non_error_response()?, + tracing_id: self.tracing_id, + warnings: self.warnings, + }) + } + + pub(crate) fn into_query_result_and_paging_state( + self, + ) -> Result<(QueryResult, PagingStateResponse), UserRequestError> { + self.into_non_error_query_response()? + .into_query_result_and_paging_state() + } + + pub(crate) fn into_query_result(self) -> Result { + self.into_non_error_query_response()?.into_query_result() + } +} + +impl NonErrorQueryResponse { + pub(crate) fn as_set_keyspace(&self) -> Option<&result::SetKeyspace> { + match &self.response { + NonErrorResponse::Result(result::Result::SetKeyspace(sk)) => Some(sk), + _ => None, + } + } + + pub(crate) fn as_schema_change(&self) -> Option<&result::SchemaChange> { + match &self.response { + NonErrorResponse::Result(result::Result::SchemaChange(sc)) => Some(sc), + _ => None, + } + } + + pub(crate) fn into_query_result_and_paging_state( + self, + ) -> Result<(QueryResult, PagingStateResponse), UserRequestError> { + let (raw_rows, paging_state_response) = match self.response { + NonErrorResponse::Result(result::Result::Rows((rs, paging_state_response))) => { + (Some(rs), paging_state_response) + } + NonErrorResponse::Result(_) => (None, PagingStateResponse::NoMorePages), + _ => { + return Err(UserRequestError::UnexpectedResponse( + self.response.to_response_kind(), + )) + } + }; + + Ok(( + QueryResult::new(raw_rows, self.tracing_id, self.warnings), + paging_state_response, + )) + } + + pub(crate) fn into_query_result(self) -> Result { + let (result, paging_state) = self.into_query_result_and_paging_state()?; + + if !paging_state.finished() { + error!( + "Internal driver API misuse or a server bug: nonfinished paging state\ + would be discarded by `NonErrorQueryResponse::into_query_result`" + ); + return Err(ProtocolError::NonfinishedPagingState.into()); + } + + Ok(result) + } +} + +pub(crate) enum NonErrorStartupResponse { + Ready, + Authenticate(response::authenticate::Authenticate), +} + +pub(crate) enum NonErrorAuthResponse { + AuthChallenge(response::authenticate::AuthChallenge), + AuthSuccess(response::authenticate::AuthSuccess), +} diff --git a/scylla/src/transport/locator/mod.rs b/scylla/src/routing/locator/mod.rs similarity index 99% rename from scylla/src/transport/locator/mod.rs rename to scylla/src/routing/locator/mod.rs index 6770b7b5b8..f33b99fa3a 100644 --- a/scylla/src/transport/locator/mod.rs +++ b/scylla/src/routing/locator/mod.rs @@ -12,7 +12,8 @@ pub use token_ring::TokenRing; use self::tablets::TabletsInfo; -use super::{topology::Strategy, Node, NodeRef}; +use crate::cluster::metadata::Strategy; +use crate::cluster::{Node, NodeRef}; use crate::routing::{Shard, Token}; use itertools::Itertools; use precomputed_replicas::PrecomputedReplicas; @@ -829,7 +830,7 @@ impl<'a> IntoIterator for ReplicasOrdered<'a> { #[cfg(test)] mod tests { - use crate::{routing::Token, test_utils::setup_tracing, transport::locator::test::*}; + use crate::{routing::locator::test::*, routing::Token, test_utils::setup_tracing}; #[tokio::test] async fn test_replicas_ordered() { diff --git a/scylla/src/transport/locator/precomputed_replicas.rs b/scylla/src/routing/locator/precomputed_replicas.rs similarity index 98% rename from scylla/src/transport/locator/precomputed_replicas.rs rename to scylla/src/routing/locator/precomputed_replicas.rs index 69851df507..4121b410ed 100644 --- a/scylla/src/transport/locator/precomputed_replicas.rs +++ b/scylla/src/routing/locator/precomputed_replicas.rs @@ -14,9 +14,9 @@ use super::replication_info::ReplicationInfo; use super::TokenRing; +use crate::cluster::metadata::Strategy; +use crate::cluster::node::Node; use crate::routing::Token; -use crate::transport::node::Node; -use crate::transport::topology::Strategy; use std::cmp; use std::collections::BTreeSet; @@ -215,12 +215,12 @@ mod tests { use std::collections::HashMap; use crate::{ + cluster::metadata::{Keyspace, Strategy}, + routing::locator::test::{ + create_ring, mock_metadata_for_token_aware_tests, A, C, D, E, F, G, + }, routing::Token, test_utils::setup_tracing, - transport::{ - locator::test::{create_ring, mock_metadata_for_token_aware_tests, A, C, D, E, F, G}, - topology::{Keyspace, Strategy}, - }, }; use super::{PrecomputedReplicas, ReplicationInfo}; diff --git a/scylla/src/transport/locator/replicas.rs b/scylla/src/routing/locator/replicas.rs similarity index 97% rename from scylla/src/transport/locator/replicas.rs rename to scylla/src/routing/locator/replicas.rs index 131402d113..a07e8104b2 100644 --- a/scylla/src/transport/locator/replicas.rs +++ b/scylla/src/routing/locator/replicas.rs @@ -1,6 +1,6 @@ use itertools::Either; -use crate::transport::{Node, NodeRef}; +use crate::cluster::{Node, NodeRef}; use std::{ops::Index, sync::Arc}; /// Container holding replicas, enabling unified use of both borrowed and owned `Node` sequences. diff --git a/scylla/src/transport/locator/replication_info.rs b/scylla/src/routing/locator/replication_info.rs similarity index 99% rename from scylla/src/transport/locator/replication_info.rs rename to scylla/src/routing/locator/replication_info.rs index 76747abf2c..16318dfd6d 100644 --- a/scylla/src/transport/locator/replication_info.rs +++ b/scylla/src/routing/locator/replication_info.rs @@ -1,8 +1,8 @@ use itertools::Itertools; use super::TokenRing; +use crate::cluster::node::Node; use crate::routing::Token; -use crate::transport::node::Node; use std::cmp; use std::collections::{BTreeSet, HashMap}; @@ -204,11 +204,11 @@ where #[cfg(test)] mod tests { use crate::{ - routing::Token, - test_utils::setup_tracing, - transport::locator::test::{ + routing::locator::test::{ create_ring, mock_metadata_for_token_aware_tests, A, B, C, D, E, F, G, }, + routing::Token, + test_utils::setup_tracing, }; use super::ReplicationInfo; diff --git a/scylla/src/transport/locator/tablets.rs b/scylla/src/routing/locator/tablets.rs similarity index 99% rename from scylla/src/transport/locator/tablets.rs rename to scylla/src/routing/locator/tablets.rs index 472351ac9c..03b4d0df75 100644 --- a/scylla/src/transport/locator/tablets.rs +++ b/scylla/src/routing/locator/tablets.rs @@ -10,8 +10,8 @@ use thiserror::Error; use tracing::warn; use uuid::Uuid; +use crate::cluster::Node; use crate::routing::{Shard, Token}; -use crate::transport::Node; use std::collections::{HashMap, HashSet}; use std::ops::Deref; @@ -415,7 +415,7 @@ impl TableTablets { self.tablet_list.retain_mut(|tablet| { let r = tablet.re_resolve_replicas(|id: Uuid| all_current_nodes.get(&id).cloned()); if let Err(failed) = &r { - warn!("Nodes ({}) listed as replicas for a tablet {{ks: {}, table: {}, range: [{}. {}]}} are not present in ClusterData.known_peers, \ + warn!("Nodes ({}) listed as replicas for a tablet {{ks: {}, table: {}, range: [{}. {}]}} are not present in ClusterState.known_peers, \ despite topology refresh. Removing problematic tablet.", failed.iter().format(", "), self.table_spec.ks_name(), self.table_spec.table_name(), tablet.first_token.value(), tablet.last_token.value()); } @@ -540,7 +540,7 @@ impl TabletsInfo { /// In order to not perform unnecessary work during typical schema refresh /// we avoid iterating through tablets at all if steps 2-4 can be skipped. /// - /// * `removed_nodes`: Nodes that previously were present in ClusterData but are not anymore. + /// * `removed_nodes`: Nodes that previously were present in ClusterState but are not anymore. /// For any such node we should remove all tablets that have it in replica list. /// This is because otherwise: /// 1. We would keep old `Node` objects, not allowing them to release memory. @@ -614,13 +614,13 @@ mod tests { use tracing::debug; use uuid::Uuid; - use crate::routing::Token; - use crate::test_utils::setup_tracing; - use crate::transport::locator::tablets::{ + use crate::cluster::Node; + use crate::routing::locator::tablets::{ RawTablet, RawTabletReplicas, TabletParsingError, CUSTOM_PAYLOAD_TABLETS_V1_KEY, RAW_TABLETS_CQL_TYPE, }; - use crate::transport::Node; + use crate::routing::Token; + use crate::test_utils::setup_tracing; use super::{TableTablets, Tablet, TabletReplicas, TabletsInfo}; diff --git a/scylla/src/transport/locator/test.rs b/scylla/src/routing/locator/test.rs similarity index 99% rename from scylla/src/transport/locator/test.rs rename to scylla/src/routing/locator/test.rs index 2622eb99a6..50084e6c59 100644 --- a/scylla/src/transport/locator/test.rs +++ b/scylla/src/routing/locator/test.rs @@ -5,14 +5,12 @@ use uuid::Uuid; use super::tablets::TabletsInfo; use super::{ReplicaLocator, ReplicaSet}; +use crate::cluster::metadata::{Keyspace, Metadata, Peer, Strategy}; +use crate::cluster::Node; +use crate::cluster::{NodeAddr, NodeRef}; +use crate::network::PoolConfig; use crate::routing::Token; use crate::test_utils::setup_tracing; -use crate::transport::{ - connection_pool::PoolConfig, - topology::{Keyspace, Metadata, Peer, Strategy}, - Node, -}; -use crate::transport::{NodeAddr, NodeRef}; use std::collections::HashSet; use std::sync::Arc; diff --git a/scylla/src/transport/locator/token_ring.rs b/scylla/src/routing/locator/token_ring.rs similarity index 100% rename from scylla/src/transport/locator/token_ring.rs rename to scylla/src/routing/locator/token_ring.rs diff --git a/scylla/src/routing/mod.rs b/scylla/src/routing/mod.rs new file mode 100644 index 0000000000..0d56256118 --- /dev/null +++ b/scylla/src/routing/mod.rs @@ -0,0 +1,56 @@ +//! This module holds entities whose goal is to enable routing requests optimally, +//! that is, choosing a target node and a shard such that it is a replica for +//! given token. +//! +//! This includes: +//! - token representation, +//! - shard representation and shard computing logic, +//! - partitioners, which compute token based on a partition key, +//! - replica locator, which finds replicas (node + shard) for a given token. +//! + +pub mod locator; +pub mod partitioner; +mod sharding; + +pub(crate) use sharding::ShardInfo; +pub use sharding::{Shard, ShardCount, Sharder, ShardingError}; + +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] + +/// Token is a result of computing a hash of a primary key +/// +/// It is basically an i64 with one caveat: i64::MIN is not +/// a valid token. It is used to represent infinity. +/// For this reason tokens are normalized - i64::MIN +/// is replaced with i64::MAX. See this fragment of +/// Scylla code for more information: +/// +/// +/// This struct is a wrapper over i64 that performs this normalization +/// when initialized using `new()` method. +pub struct Token { + value: i64, +} + +impl Token { + /// Creates a new token with given value, normalizing the value if necessary + #[inline] + pub fn new(value: i64) -> Self { + Self { + value: if value == i64::MIN { i64::MAX } else { value }, + } + } + + /// Invalid Token - contains i64::MIN as value. + /// + /// This is (currently) only required by CDCPartitioner. + /// See the following comment: + /// https://github.com/scylladb/scylla-rust-driver/blob/049dc3546d24e45106fed0fdb985ec2511ab5192/scylla/src/transport/partitioner.rs#L312-L322 + pub(crate) const INVALID: Self = Token { value: i64::MIN }; + + #[inline] + pub fn value(&self) -> i64 { + self.value + } +} diff --git a/scylla/src/transport/partitioner.rs b/scylla/src/routing/partitioner.rs similarity index 95% rename from scylla/src/transport/partitioner.rs rename to scylla/src/routing/partitioner.rs index ee36543b61..f73fb63987 100644 --- a/scylla/src/transport/partitioner.rs +++ b/scylla/src/routing/partitioner.rs @@ -1,3 +1,13 @@ +//! Partitioners are algorithms that can compute token for a given partition key, +//! ultimately allowing optimised routing of requests (such that a request is routed +//! to replicas, which are nodes and shards that really own the data the request concerns). +//! Currently, two partitioners are supported: +//! - Murmur3Partitioner +//! - the default partitioner, +//! - modified for compatibility with Cassandra's buggy implementation. +//! - CDCPartitioner +//! - the partitioner employed when using CDC (_Change Data Capture_). + use bytes::Buf; use scylla_cql::{frame::types::RawValue, types::serialize::row::SerializedValues}; use std::num::Wrapping; @@ -369,9 +379,9 @@ mod tests { use rand::Rng; use rand_pcg::Pcg32; - use crate::{test_utils::setup_tracing, transport::partitioner::PartitionerHasher}; + use crate::test_utils::setup_tracing; - use super::{CDCPartitioner, Murmur3Partitioner, Partitioner}; + use super::{CDCPartitioner, Murmur3Partitioner, Partitioner, PartitionerHasher}; fn assert_correct_murmur3_hash(pk: &'static str, expected_hash: i64) { let hash = Murmur3Partitioner.hash_one(pk.as_bytes()).value(); diff --git a/scylla/src/routing.rs b/scylla/src/routing/sharding.rs similarity index 83% rename from scylla/src/routing.rs rename to scylla/src/routing/sharding.rs index a5788c0b10..4c3dec691d 100644 --- a/scylla/src/routing.rs +++ b/scylla/src/routing/sharding.rs @@ -1,47 +1,10 @@ -use rand::Rng; use std::collections::HashMap; -use std::convert::TryFrom; use std::num::NonZeroU16; -use thiserror::Error; - -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] - -/// Token is a result of computing a hash of a primary key -/// -/// It is basically an i64 with one caveat: i64::MIN is not -/// a valid token. It is used to represent infinity. -/// For this reason tokens are normalized - i64::MIN -/// is replaced with i64::MAX. See this fragment of -/// Scylla code for more information: -/// -/// -/// This struct is a wrapper over i64 that performs this normalization -/// when initialized using `new()` method. -pub struct Token { - value: i64, -} -impl Token { - /// Creates a new token with given value, normalizing the value if necessary - #[inline] - pub fn new(value: i64) -> Self { - Self { - value: if value == i64::MIN { i64::MAX } else { value }, - } - } - - /// Invalid Token - contains i64::MIN as value. - /// - /// This is (currently) only required by CDCPartitioner. - /// See the following comment: - /// https://github.com/scylladb/scylla-rust-driver/blob/049dc3546d24e45106fed0fdb985ec2511ab5192/scylla/src/transport/partitioner.rs#L312-L322 - pub(crate) const INVALID: Self = Token { value: i64::MIN }; +use rand::Rng as _; +use thiserror::Error; - #[inline] - pub fn value(&self) -> i64 { - self.value - } -} +use super::Token; pub type Shard = u32; pub type ShardCount = NonZeroU16; diff --git a/scylla/src/statement/batch.rs b/scylla/src/statement/batch.rs index 62bbaab140..f9128a659f 100644 --- a/scylla/src/statement/batch.rs +++ b/scylla/src/statement/batch.rs @@ -1,10 +1,10 @@ use std::borrow::Cow; use std::sync::Arc; -use crate::history::HistoryListener; -use crate::retry_policy::RetryPolicy; +use crate::client::execution_profile::ExecutionProfileHandle; +use crate::observability::history::HistoryListener; +use crate::policies::retry::RetryPolicy; use crate::statement::{prepared_statement::PreparedStatement, query::Query}; -use crate::transport::execution_profile::ExecutionProfileHandle; use super::StatementConfig; use super::{Consistency, SerialConsistency}; @@ -216,8 +216,8 @@ pub(crate) mod batch_values { use scylla_cql::types::serialize::row::SerializedValues; use scylla_cql::types::serialize::{RowWriter, SerializationError}; + use crate::errors::QueryError; use crate::routing::Token; - use crate::transport::errors::QueryError; use super::BatchStatement; diff --git a/scylla/src/statement/mod.rs b/scylla/src/statement/mod.rs index c396d91010..c07dda84f5 100644 --- a/scylla/src/statement/mod.rs +++ b/scylla/src/statement/mod.rs @@ -1,9 +1,17 @@ +//! This module holds entities representing various kinds of CQL statements, +//! together with their execution options. +//! The following statements are supported: +//! - Query (unprepared statements), +//! - PreparedStatement, +//! - Batch. + use std::{sync::Arc, time::Duration}; use thiserror::Error; -use crate::transport::execution_profile::ExecutionProfileHandle; -use crate::{history::HistoryListener, retry_policy::RetryPolicy}; +use crate::client::execution_profile::ExecutionProfileHandle; +use crate::observability::history::HistoryListener; +use crate::policies::retry::RetryPolicy; pub mod batch; pub mod prepared_statement; @@ -11,8 +19,6 @@ pub mod query; pub use crate::frame::types::{Consistency, SerialConsistency}; -pub use crate::frame::request::query::{PagingState, PagingStateResponse}; - // This is the default common to drivers. const DEFAULT_PAGE_SIZE: i32 = 5000; diff --git a/scylla/src/statement/prepared_statement.rs b/scylla/src/statement/prepared_statement.rs index 385fcdf074..45dc461d0b 100644 --- a/scylla/src/statement/prepared_statement.rs +++ b/scylla/src/statement/prepared_statement.rs @@ -13,30 +13,30 @@ use thiserror::Error; use uuid::Uuid; use super::{PageSize, StatementConfig}; +use crate::client::execution_profile::ExecutionProfileHandle; +use crate::errors::{BadQuery, ProtocolError, QueryError}; use crate::frame::response::result::PreparedMetadata; use crate::frame::types::{Consistency, SerialConsistency}; -use crate::history::HistoryListener; -use crate::retry_policy::RetryPolicy; +use crate::observability::history::HistoryListener; +use crate::policies::retry::RetryPolicy; +use crate::routing::partitioner::{Partitioner, PartitionerHasher, PartitionerName}; use crate::routing::Token; -use crate::transport::errors::{BadQuery, ProtocolError, QueryError}; -use crate::transport::execution_profile::ExecutionProfileHandle; -use crate::transport::partitioner::{Partitioner, PartitionerHasher, PartitionerName}; /// Represents a statement prepared on the server. /// -/// To prepare a statement, simply execute [`Session::prepare`](crate::transport::session::Session::prepare). +/// To prepare a statement, simply execute [`Session::prepare`](crate::client::session::Session::prepare). /// /// If you plan on reusing the statement, or bounding some values to it during execution, always /// prefer using prepared statements over `Session::query_*` methods, -/// e.g. [`Session::query_unpaged`](crate::transport::session::Session::query_unpaged). +/// e.g. [`Session::query_unpaged`](crate::client::session::Session::query_unpaged). /// /// Benefits that prepared statements have to offer: /// * Performance - a prepared statement holds information about metadata /// that allows to carry out a statement execution in a type safe manner. /// When any of `Session::query_*` methods is called with non-empty bound values, /// the driver has to prepare the statement before execution (to provide type safety). -/// This implies 2 round trips per [`Session::query_unpaged`](crate::transport::session::Session::query_unpaged). -/// On the other hand, the cost of [`Session::execute_unpaged`](crate::transport::session::Session::execute_unpaged) +/// This implies 2 round trips per [`Session::query_unpaged`](crate::client::session::Session::query_unpaged). +/// On the other hand, the cost of [`Session::execute_unpaged`](crate::client::session::Session::execute_unpaged) /// is only 1 round trip. /// * Increased type-safety - bound values' types are validated with /// the [`PreparedMetadata`] received from the server during the serialization. @@ -48,7 +48,7 @@ use crate::transport::partitioner::{Partitioner, PartitionerHasher, PartitionerN /// # Clone implementation /// Cloning a prepared statement is a cheap operation. It only /// requires copying a couple of small fields and some [Arc] pointers. -/// Always prefer cloning over executing [`Session::prepare`](crate::transport::session::Session::prepare) +/// Always prefer cloning over executing [`Session::prepare`](crate::client::session::Session::prepare) /// multiple times to save some roundtrips. /// /// # Statement repreparation @@ -57,7 +57,7 @@ use crate::transport::partitioner::{Partitioner, PartitionerHasher, PartitionerN /// the server will respond with an error. Users should not worry about it, since /// the driver handles it properly and tries to reprepare the statement. /// However, there are some cases when client-side prepared statement should be dropped -/// and prepared once again via [`Session::prepare`](crate::transport::session::Session::prepare) - +/// and prepared once again via [`Session::prepare`](crate::client::session::Session::prepare) - /// see the mention about altering schema below. /// /// # Altering schema diff --git a/scylla/src/statement/query.rs b/scylla/src/statement/query.rs index 7fc2424d92..a86da581aa 100644 --- a/scylla/src/statement/query.rs +++ b/scylla/src/statement/query.rs @@ -1,8 +1,8 @@ use super::{PageSize, StatementConfig}; +use crate::client::execution_profile::ExecutionProfileHandle; use crate::frame::types::{Consistency, SerialConsistency}; -use crate::history::HistoryListener; -use crate::retry_policy::RetryPolicy; -use crate::transport::execution_profile::ExecutionProfileHandle; +use crate::observability::history::HistoryListener; +use crate::policies::retry::RetryPolicy; use std::sync::Arc; use std::time::Duration; diff --git a/scylla/src/transport/mod.rs b/scylla/src/transport/mod.rs deleted file mode 100644 index 55184aadc6..0000000000 --- a/scylla/src/transport/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -pub(crate) mod caching_session; -mod cluster; -pub(crate) mod connection; -mod connection_pool; -pub mod downgrading_consistency_retry_policy; -pub mod errors; -pub mod execution_profile; -pub mod host_filter; -pub mod iterator; -pub mod legacy_query_result; -pub mod load_balancing; -pub mod locator; -pub(crate) mod metrics; -mod node; -pub mod partitioner; -pub mod query_result; -pub mod retry_policy; -pub mod session; -pub mod session_builder; -pub mod speculative_execution; -pub mod topology; - -pub use crate::frame::{Authenticator, Compression}; -pub use connection::SelfIdentity; -pub use execution_profile::ExecutionProfile; -pub use scylla_cql::frame::request::query::{PagingState, PagingStateResponse}; - -#[cfg(test)] -mod session_test; - -pub use cluster::ClusterData; -pub use node::{KnownNode, Node, NodeAddr, NodeRef}; diff --git a/scylla/src/utils/test_utils.rs b/scylla/src/utils/test_utils.rs index 7e258c352c..137ae822cf 100644 --- a/scylla/src/utils/test_utils.rs +++ b/scylla/src/utils/test_utils.rs @@ -1,11 +1,14 @@ -use crate::load_balancing::{FallbackPlan, LoadBalancingPolicy, RoutingInfo}; +use crate::client::caching_session::CachingSession; +use crate::client::execution_profile::ExecutionProfile; +use crate::client::session::Session; +use crate::client::session_builder::{GenericSessionBuilder, SessionBuilderKind}; +use crate::cluster::ClusterState; +use crate::cluster::NodeRef; +use crate::errors::QueryError; +use crate::network::Connection; +use crate::policies::load_balancing::{FallbackPlan, LoadBalancingPolicy, RoutingInfo}; use crate::query::Query; use crate::routing::Shard; -use crate::transport::connection::Connection; -use crate::transport::errors::QueryError; -use crate::transport::session_builder::{GenericSessionBuilder, SessionBuilderKind}; -use crate::transport::{ClusterData, NodeRef}; -use crate::{CachingSession, ExecutionProfile, Session}; use std::sync::Arc; use std::{num::NonZeroU32, time::Duration}; use std::{ @@ -68,7 +71,7 @@ pub(crate) fn create_new_session_builder() -> GenericSessionBuilder GenericSessionBuilder( &'a self, _query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)> { // I'm not sure if Scylla can handle concurrent DDL queries to different shard, // in other words if its local lock is per-node or per shard. @@ -130,7 +132,7 @@ impl LoadBalancingPolicy for SchemaQueriesLBP { fn fallback<'a>( &'a self, _query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> FallbackPlan<'a> { Box::new(cluster.get_nodes_info().iter().map(|node| (node, Some(0)))) } diff --git a/scylla/tests/integration/authenticate.rs b/scylla/tests/integration/authenticate.rs index c2a6569cca..792d1f1ad8 100644 --- a/scylla/tests/integration/authenticate.rs +++ b/scylla/tests/integration/authenticate.rs @@ -12,7 +12,7 @@ async fn authenticate_superuser() { println!("Connecting to {} with cassandra superuser ...", uri); - let session = scylla::SessionBuilder::new() + let session = scylla::client::session_builder::SessionBuilder::new() .known_node(uri) .user("cassandra", "cassandra") .build() @@ -68,7 +68,7 @@ async fn custom_authentication() { println!("Connecting to {} with cassandra superuser ...", uri); - let session = scylla::SessionBuilder::new() + let session = scylla::client::session_builder::SessionBuilder::new() .known_node(uri) .authenticator_provider(Arc::new(CustomAuthenticatorProvider)) .build() diff --git a/scylla/tests/integration/batch.rs b/scylla/tests/integration/batch.rs index d711cb5014..eac537a4e7 100644 --- a/scylla/tests/integration/batch.rs +++ b/scylla/tests/integration/batch.rs @@ -1,9 +1,9 @@ use scylla::batch::Batch; use scylla::batch::BatchType; +use scylla::errors::QueryError; use scylla::frame::frame_errors::BatchSerializationError; use scylla::frame::frame_errors::CqlRequestSerializationError; use scylla::query::Query; -use scylla::transport::errors::QueryError; use crate::utils::create_new_session_builder; use crate::utils::setup_tracing; diff --git a/scylla/tests/integration/consistency.rs b/scylla/tests/integration/consistency.rs index a503fb7d3b..d975dbce0d 100644 --- a/scylla/tests/integration/consistency.rs +++ b/scylla/tests/integration/consistency.rs @@ -1,21 +1,22 @@ use crate::utils::{setup_tracing, test_with_3_node_cluster, unique_keyspace_name, PerformDDL}; -use scylla::execution_profile::{ExecutionProfileBuilder, ExecutionProfileHandle}; -use scylla::load_balancing::{DefaultPolicy, LoadBalancingPolicy, RoutingInfo}; +use scylla::client::execution_profile::{ExecutionProfileBuilder, ExecutionProfileHandle}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::cluster::NodeRef; +use scylla::policies::load_balancing::{DefaultPolicy, LoadBalancingPolicy, RoutingInfo}; +use scylla::policies::retry::FallthroughRetryPolicy; use scylla::prepared_statement::PreparedStatement; -use scylla::retry_policy::FallthroughRetryPolicy; use scylla::routing::{Shard, Token}; -use scylla::transport::NodeRef; -use scylla::Session; use scylla_cql::frame::response::result::TableSpec; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; +use scylla::client::execution_profile::ExecutionProfile; use scylla::statement::batch::BatchStatement; use scylla::statement::query::Query; use scylla::{ batch::{Batch, BatchType}, statement::SerialConsistency, }; -use scylla::{ExecutionProfile, SessionBuilder}; use scylla_cql::Consistency; use scylla_proxy::ShardAwareness; use scylla_proxy::{ @@ -377,7 +378,7 @@ impl LoadBalancingPolicy for RoutingInfoReportingWrapper { fn pick<'a>( &'a self, query: &'a RoutingInfo, - cluster: &'a scylla::transport::ClusterData, + cluster: &'a scylla::cluster::ClusterState, ) -> Option<(NodeRef<'a>, Option)> { self.routing_info_tx .send(OwnedRoutingInfo::from(query.clone())) @@ -388,8 +389,8 @@ impl LoadBalancingPolicy for RoutingInfoReportingWrapper { fn fallback<'a>( &'a self, query: &'a RoutingInfo, - cluster: &'a scylla::transport::ClusterData, - ) -> scylla::load_balancing::FallbackPlan<'a> { + cluster: &'a scylla::cluster::ClusterState, + ) -> scylla::policies::load_balancing::FallbackPlan<'a> { self.routing_info_tx .send(OwnedRoutingInfo::from(query.clone())) .unwrap(); diff --git a/scylla/tests/integration/cql_collections.rs b/scylla/tests/integration/cql_collections.rs index a36d1bc16d..d86bbaf7d8 100644 --- a/scylla/tests/integration/cql_collections.rs +++ b/scylla/tests/integration/cql_collections.rs @@ -2,8 +2,8 @@ use crate::utils::{ create_new_session_builder, setup_tracing, unique_keyspace_name, DeserializeOwnedValue, PerformDDL, }; +use scylla::client::session::Session; use scylla::frame::response::result::CqlValue; -use scylla::Session; use scylla_cql::types::serialize::value::SerializeValue; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; diff --git a/scylla/tests/integration/cql_types.rs b/scylla/tests/integration/cql_types.rs index 1125914283..22a778b1ba 100644 --- a/scylla/tests/integration/cql_types.rs +++ b/scylla/tests/integration/cql_types.rs @@ -1,8 +1,8 @@ use itertools::Itertools; +use scylla::client::session::Session; use scylla::frame::response::result::CqlValue; use scylla::frame::value::{Counter, CqlDate, CqlTime, CqlTimestamp, CqlTimeuuid, CqlVarint}; use scylla::serialize::value::SerializeValue; -use scylla::Session; use scylla::{DeserializeValue, SerializeValue}; use std::cmp::PartialEq; use std::fmt::Debug; diff --git a/scylla/tests/integration/cql_value.rs b/scylla/tests/integration/cql_value.rs index d0648b1472..16e4a42ee8 100644 --- a/scylla/tests/integration/cql_value.rs +++ b/scylla/tests/integration/cql_value.rs @@ -1,8 +1,8 @@ use assert_matches::assert_matches; +use scylla::client::session::Session; use scylla::frame::response::result::CqlValue; use scylla::frame::value::CqlDuration; -use scylla::Session; use crate::utils::{create_new_session_builder, setup_tracing, unique_keyspace_name, PerformDDL}; diff --git a/scylla/tests/integration/default_policy.rs b/scylla/tests/integration/default_policy.rs index e097cf418a..272c10b21f 100644 --- a/scylla/tests/integration/default_policy.rs +++ b/scylla/tests/integration/default_policy.rs @@ -1,5 +1,5 @@ -use scylla::load_balancing::{DefaultPolicy, LatencyAwarenessBuilder}; -use scylla::ExecutionProfile; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::policies::load_balancing::{DefaultPolicy, LatencyAwarenessBuilder}; use crate::utils::{create_new_session_builder, setup_tracing}; diff --git a/scylla/tests/integration/execution_profiles.rs b/scylla/tests/integration/execution_profiles.rs index dd58cdbae0..587e70dfeb 100644 --- a/scylla/tests/integration/execution_profiles.rs +++ b/scylla/tests/integration/execution_profiles.rs @@ -3,19 +3,17 @@ use std::sync::Arc; use crate::utils::{setup_tracing, test_with_3_node_cluster, unique_keyspace_name, PerformDDL}; use assert_matches::assert_matches; -use scylla::batch::BatchStatement; -use scylla::batch::{Batch, BatchType}; +use scylla::batch::{Batch, BatchStatement, BatchType}; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session_builder::SessionBuilder; +use scylla::cluster::ClusterState; +use scylla::cluster::NodeRef; +use scylla::policies::load_balancing::{LoadBalancingPolicy, RoutingInfo}; +use scylla::policies::retry::{RetryPolicy, RetrySession}; +use scylla::policies::speculative_execution::SpeculativeExecutionPolicy; use scylla::query::Query; use scylla::routing::Shard; use scylla::statement::SerialConsistency; -use scylla::transport::NodeRef; -use scylla::{ - load_balancing::{LoadBalancingPolicy, RoutingInfo}, - retry_policy::{RetryPolicy, RetrySession}, - speculative_execution::SpeculativeExecutionPolicy, - transport::ClusterData, - ExecutionProfile, SessionBuilder, -}; use scylla_cql::Consistency; use tokio::sync::mpsc; @@ -49,7 +47,7 @@ impl LoadBalancingPolicy for BoundToPredefinedNodePolicy { fn pick<'a>( &'a self, _info: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)> { self.report_node(Report::LoadBalancing); cluster @@ -62,8 +60,8 @@ impl LoadBalancingPolicy for BoundToPredefinedNodePolicy { fn fallback<'a>( &'a self, _info: &'a RoutingInfo, - _cluster: &'a ClusterData, - ) -> scylla::load_balancing::FallbackPlan<'a> { + _cluster: &'a ClusterState, + ) -> scylla::policies::load_balancing::FallbackPlan<'a> { Box::new(std::iter::empty()) } @@ -80,7 +78,7 @@ impl LoadBalancingPolicy for BoundToPredefinedNodePolicy { _query: &RoutingInfo, _latency: std::time::Duration, _node: NodeRef<'_>, - _error: &scylla::transport::errors::QueryError, + _error: &scylla::errors::QueryError, ) { } @@ -90,7 +88,7 @@ impl LoadBalancingPolicy for BoundToPredefinedNodePolicy { } impl RetryPolicy for BoundToPredefinedNodePolicy { - fn new_session(&self) -> Box { + fn new_session(&self) -> Box { self.report_node(Report::RetryPolicy); Box::new(self.clone()) } @@ -99,21 +97,24 @@ impl RetryPolicy for BoundToPredefinedNodePolicy { impl RetrySession for BoundToPredefinedNodePolicy { fn decide_should_retry( &mut self, - query_info: scylla::retry_policy::QueryInfo, - ) -> scylla::retry_policy::RetryDecision { + query_info: scylla::policies::retry::QueryInfo, + ) -> scylla::policies::retry::RetryDecision { self.report_consistency(query_info.consistency); - scylla::retry_policy::RetryDecision::DontRetry + scylla::policies::retry::RetryDecision::DontRetry } fn reset(&mut self) {} } impl SpeculativeExecutionPolicy for BoundToPredefinedNodePolicy { - fn max_retry_count(&self, _: &scylla::speculative_execution::Context) -> usize { + fn max_retry_count(&self, _: &scylla::policies::speculative_execution::Context) -> usize { 1 } - fn retry_interval(&self, _: &scylla::speculative_execution::Context) -> std::time::Duration { + fn retry_interval( + &self, + _: &scylla::policies::speculative_execution::Context, + ) -> std::time::Duration { self.report_node(Report::SpeculativeExecution); std::time::Duration::from_millis(200) } diff --git a/scylla/tests/integration/history.rs b/scylla/tests/integration/history.rs index 1bbd21e024..8e8abe5849 100644 --- a/scylla/tests/integration/history.rs +++ b/scylla/tests/integration/history.rs @@ -3,12 +3,12 @@ use std::sync::Arc; use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc}; use futures::StreamExt; +use scylla::errors::QueryError; use scylla::frame::response::result::Row; -use scylla::history::{ +use scylla::observability::history::{ AttemptResult, HistoryCollector, QueryHistoryResult, StructuredHistory, TimePoint, }; use scylla::query::Query; -use scylla::transport::errors::QueryError; use crate::utils::{create_new_session_builder, setup_tracing, unique_keyspace_name, PerformDDL}; diff --git a/scylla/tests/integration/large_batch_statements.rs b/scylla/tests/integration/large_batch_statements.rs index 724d8c9496..e1b2d34d28 100644 --- a/scylla/tests/integration/large_batch_statements.rs +++ b/scylla/tests/integration/large_batch_statements.rs @@ -1,11 +1,12 @@ use assert_matches::assert_matches; +use scylla::client::session::Session; use crate::utils::{create_new_session_builder, setup_tracing, unique_keyspace_name, PerformDDL}; use scylla::batch::Batch; use scylla::batch::BatchType; +use scylla::errors::{BadQuery, QueryError}; use scylla::query::Query; -use scylla::transport::errors::{BadQuery, QueryError}; -use scylla::{QueryResult, Session}; +use scylla::response::query_result::QueryResult; #[tokio::test] async fn test_large_batch_statements() { diff --git a/scylla/tests/integration/lwt_optimisation.rs b/scylla/tests/integration/lwt_optimisation.rs index 466120bce2..90e74819cc 100644 --- a/scylla/tests/integration/lwt_optimisation.rs +++ b/scylla/tests/integration/lwt_optimisation.rs @@ -2,9 +2,9 @@ use crate::utils::{ scylla_supports_tablets, setup_tracing, test_with_3_node_cluster, unique_keyspace_name, PerformDDL, }; -use scylla::retry_policy::FallthroughRetryPolicy; -use scylla::transport::session::Session; -use scylla::{ExecutionProfile, SessionBuilder}; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::Session; +use scylla::policies::retry::FallthroughRetryPolicy; use scylla_cql::frame::protocol_features::ProtocolFeatures; use scylla_cql::frame::types; use std::sync::Arc; @@ -19,6 +19,8 @@ use scylla_proxy::{ #[ntest::timeout(20000)] #[cfg(not(scylla_cloud_tests))] async fn if_lwt_optimisation_mark_offered_then_negotiatied_and_lwt_routed_optimally() { + use scylla::client::session_builder::SessionBuilder; + setup_tracing(); // This is just to increase the likelihood that only intended prepared statements (which contain this mark) are captured by the proxy. diff --git a/scylla/tests/integration/new_session.rs b/scylla/tests/integration/new_session.rs index 6f734f0dab..bbb89bc5bc 100644 --- a/scylla/tests/integration/new_session.rs +++ b/scylla/tests/integration/new_session.rs @@ -1,8 +1,8 @@ use crate::utils::setup_tracing; use assert_matches::assert_matches; -use scylla::transport::errors::NewSessionError; -use scylla::SessionBuilder; +use scylla::client::session_builder::SessionBuilder; +use scylla::errors::NewSessionError; #[cfg(not(scylla_cloud_tests))] #[tokio::test] diff --git a/scylla/tests/integration/retries.rs b/scylla/tests/integration/retries.rs index 7c7d35c4d4..109c6bc1dc 100644 --- a/scylla/tests/integration/retries.rs +++ b/scylla/tests/integration/retries.rs @@ -1,10 +1,10 @@ use crate::utils::{setup_tracing, test_with_3_node_cluster, unique_keyspace_name, PerformDDL}; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::policies::retry::FallthroughRetryPolicy; +use scylla::policies::speculative_execution::SimpleSpeculativeExecutionPolicy; use scylla::query::Query; -use scylla::retry_policy::FallthroughRetryPolicy; -use scylla::speculative_execution::SimpleSpeculativeExecutionPolicy; -use scylla::transport::session::Session; -use scylla::ExecutionProfile; -use scylla::SessionBuilder; use std::sync::Arc; use std::time::Duration; use tracing::info; diff --git a/scylla/tests/integration/self_identity.rs b/scylla/tests/integration/self_identity.rs index cba46f7171..2ac7961401 100644 --- a/scylla/tests/integration/self_identity.rs +++ b/scylla/tests/integration/self_identity.rs @@ -1,15 +1,15 @@ use crate::utils::{setup_tracing, test_with_3_node_cluster}; -use scylla::{Session, SessionBuilder}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; +use scylla::client::SelfIdentity; use scylla_cql::frame::request::options; use scylla_cql::frame::types; -use std::sync::Arc; -use tokio::sync::mpsc; - -use scylla::transport::SelfIdentity; use scylla_proxy::{ Condition, ProxyError, Reaction, RequestOpcode, RequestReaction, RequestRule, ShardAwareness, WorkerError, }; +use std::sync::Arc; +use tokio::sync::mpsc; #[tokio::test] #[ntest::timeout(20000)] diff --git a/scylla/tests/integration/shards.rs b/scylla/tests/integration/shards.rs index 6c1f8fdb8f..d015bf88e1 100644 --- a/scylla/tests/integration/shards.rs +++ b/scylla/tests/integration/shards.rs @@ -5,7 +5,7 @@ use crate::utils::{ scylla_supports_tablets, setup_tracing, test_with_3_node_cluster, unique_keyspace_name, PerformDDL, }; -use scylla::SessionBuilder; +use scylla::client::session_builder::SessionBuilder; use tokio::sync::mpsc; use scylla_proxy::TargetShard; diff --git a/scylla/tests/integration/silent_prepare_batch.rs b/scylla/tests/integration/silent_prepare_batch.rs index b510e04626..040ebc9e9d 100644 --- a/scylla/tests/integration/silent_prepare_batch.rs +++ b/scylla/tests/integration/silent_prepare_batch.rs @@ -1,7 +1,7 @@ use crate::utils::{create_new_session_builder, setup_tracing, unique_keyspace_name, PerformDDL}; use scylla::batch::Batch; +use scylla::client::session::Session; use scylla::prepared_statement::PreparedStatement; -use scylla::Session; use std::collections::BTreeSet; diff --git a/scylla/tests/integration/silent_prepare_query.rs b/scylla/tests/integration/silent_prepare_query.rs index 477b633862..29844cc61b 100644 --- a/scylla/tests/integration/silent_prepare_query.rs +++ b/scylla/tests/integration/silent_prepare_query.rs @@ -1,7 +1,7 @@ use crate::utils::{setup_tracing, test_with_3_node_cluster, unique_keyspace_name, PerformDDL}; +use scylla::client::session::Session; +use scylla::client::session_builder::SessionBuilder; use scylla::query::Query; -use scylla::Session; -use scylla::SessionBuilder; use scylla_proxy::{ Condition, ProxyError, Reaction, RequestOpcode, RequestReaction, RequestRule, ShardAwareness, WorkerError, diff --git a/scylla/tests/integration/skip_metadata_optimization.rs b/scylla/tests/integration/skip_metadata_optimization.rs index eb8ff8520a..7b88ebea7c 100644 --- a/scylla/tests/integration/skip_metadata_optimization.rs +++ b/scylla/tests/integration/skip_metadata_optimization.rs @@ -1,6 +1,5 @@ use crate::utils::{setup_tracing, test_with_3_node_cluster, unique_keyspace_name, PerformDDL}; use scylla::prepared_statement::PreparedStatement; -use scylla::{Session, SessionBuilder}; use scylla_cql::frame::request::query::{PagingState, PagingStateResponse}; use scylla_cql::frame::types; use scylla_proxy::{ @@ -13,6 +12,9 @@ use std::sync::Arc; #[ntest::timeout(20000)] #[cfg(not(scylla_cloud_tests))] async fn test_skip_result_metadata() { + use scylla::client::session::Session; + use scylla::client::session_builder::SessionBuilder; + setup_tracing(); const NO_METADATA_FLAG: i32 = 0x0004; diff --git a/scylla/tests/integration/tablets.rs b/scylla/tests/integration/tablets.rs index fd56c7d939..788f53bc62 100644 --- a/scylla/tests/integration/tablets.rs +++ b/scylla/tests/integration/tablets.rs @@ -8,18 +8,20 @@ use crate::utils::{ use futures::future::try_join_all; use futures::TryStreamExt; use itertools::Itertools; -use scylla::load_balancing::FallbackPlan; -use scylla::load_balancing::LoadBalancingPolicy; -use scylla::load_balancing::RoutingInfo; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::Session; +use scylla::cluster::ClusterState; +use scylla::cluster::Node; +use scylla::cluster::NodeRef; +use scylla::policies::load_balancing::FallbackPlan; +use scylla::policies::load_balancing::LoadBalancingPolicy; +use scylla::policies::load_balancing::RoutingInfo; use scylla::prepared_statement::PreparedStatement; use scylla::query::Query; +use scylla::response::query_result::QueryResult; use scylla::serialize::row::SerializeRow; -use scylla::transport::ClusterData; -use scylla::transport::Node; -use scylla::transport::NodeRef; -use scylla::{ExecutionProfile, QueryResult, Session}; -use scylla::transport::errors::QueryError; +use scylla::errors::QueryError; use scylla_proxy::{ Condition, ProxyError, Reaction, ResponseFrame, ResponseOpcode, ResponseReaction, ResponseRule, ShardAwareness, TargetShard, WorkerError, @@ -163,7 +165,7 @@ impl LoadBalancingPolicy for SingleTargetLBP { fn pick<'a>( &'a self, _query: &'a RoutingInfo, - _cluster: &'a ClusterData, + _cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)> { Some((&self.target.0, self.target.1)) } @@ -171,7 +173,7 @@ impl LoadBalancingPolicy for SingleTargetLBP { fn fallback<'a>( &'a self, _query: &'a RoutingInfo, - _cluster: &'a ClusterData, + _cluster: &'a ClusterState, ) -> FallbackPlan<'a> { Box::new(std::iter::empty()) } @@ -183,7 +185,7 @@ impl LoadBalancingPolicy for SingleTargetLBP { async fn send_statement_everywhere( session: &Session, - cluster: &ClusterData, + cluster: &ClusterState, statement: &PreparedStatement, values: &dyn SerializeRow, ) -> Result, QueryError> { @@ -209,7 +211,7 @@ async fn send_statement_everywhere( async fn send_unprepared_query_everywhere( session: &Session, - cluster: &ClusterData, + cluster: &ClusterState, query: &Query, ) -> Result, QueryError> { let tasks = cluster.get_nodes_info().iter().flat_map(|node| { @@ -288,7 +290,7 @@ async fn test_default_policy_is_tablet_aware() { let res = test_with_3_node_cluster( ShardAwareness::QueryNode, |proxy_uris, translation_map, mut running_proxy| async move { - let session = scylla::SessionBuilder::new() + let session = scylla::client::session_builder::SessionBuilder::new() .known_node(proxy_uris[0].as_str()) .address_translator(Arc::new(translation_map)) .build() @@ -419,7 +421,7 @@ async fn test_tablet_feedback_not_sent_for_unprepared_queries() { let res = test_with_3_node_cluster( ShardAwareness::QueryNode, |proxy_uris, translation_map, mut running_proxy| async move { - let session = scylla::SessionBuilder::new() + let session = scylla::client::session_builder::SessionBuilder::new() .known_node(proxy_uris[0].as_str()) .address_translator(Arc::new(translation_map)) .build() @@ -491,7 +493,7 @@ async fn test_lwt_optimization_works_with_tablets() { let res = test_with_3_node_cluster( ShardAwareness::QueryNode, |proxy_uris, translation_map, mut running_proxy| async move { - let session = scylla::SessionBuilder::new() + let session = scylla::client::session_builder::SessionBuilder::new() .known_node(proxy_uris[0].as_str()) .address_translator(Arc::new(translation_map)) .build() diff --git a/scylla/tests/integration/utils.rs b/scylla/tests/integration/utils.rs index 07d2079745..db3602a258 100644 --- a/scylla/tests/integration/utils.rs +++ b/scylla/tests/integration/utils.rs @@ -1,12 +1,14 @@ use futures::Future; +use scylla::client::execution_profile::ExecutionProfile; +use scylla::client::session::Session; +use scylla::client::session_builder::{GenericSessionBuilder, SessionBuilderKind}; +use scylla::cluster::ClusterState; +use scylla::cluster::NodeRef; use scylla::deserialize::DeserializeValue; -use scylla::load_balancing::{FallbackPlan, LoadBalancingPolicy, RoutingInfo}; +use scylla::errors::QueryError; +use scylla::policies::load_balancing::{FallbackPlan, LoadBalancingPolicy, RoutingInfo}; use scylla::query::Query; use scylla::routing::Shard; -use scylla::transport::errors::QueryError; -use scylla::transport::session_builder::{GenericSessionBuilder, SessionBuilderKind}; -use scylla::transport::{ClusterData, NodeRef}; -use scylla::{ExecutionProfile, Session}; use std::collections::HashMap; use std::env; use std::net::SocketAddr; @@ -134,7 +136,7 @@ pub(crate) fn create_new_session_builder() -> GenericSessionBuilder GenericSessionBuilder( &'a self, _query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> Option<(NodeRef<'a>, Option)> { // I'm not sure if Scylla can handle concurrent DDL queries to different shard, // in other words if its local lock is per-node or per shard. @@ -196,7 +197,7 @@ impl LoadBalancingPolicy for SchemaQueriesLBP { fn fallback<'a>( &'a self, _query: &'a RoutingInfo, - cluster: &'a ClusterData, + cluster: &'a ClusterState, ) -> FallbackPlan<'a> { Box::new(cluster.get_nodes_info().iter().map(|node| (node, Some(0)))) }