diff --git a/.github/workflows/authenticate_test.yml b/.github/workflows/authenticate_test.yml index be2faaf789..b6a8251661 100644 --- a/.github/workflows/authenticate_test.yml +++ b/.github/workflows/authenticate_test.yml @@ -27,5 +27,7 @@ jobs: options: --health-cmd "cqlsh --username cassandra --password cassandra --debug" --health-interval 5s --health-retries 30 steps: - uses: actions/checkout@v3 + - name: Update rust toolchain + run: rustup update - name: Run tests run: RUST_LOG=trace cargo test --verbose authenticate_superuser -- custom_authentication --ignored diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml index 7fed7200e4..4d3caa5062 100644 --- a/.github/workflows/book.yml +++ b/.github/workflows/book.yml @@ -27,6 +27,8 @@ jobs: options: --health-cmd "cqlsh --debug scylladb" --health-interval 5s --health-retries 10 steps: - uses: actions/checkout@v3 + - name: Update rust toolchain + run: rustup update - name: Install mdbook run: cargo install mdbook --no-default-features - name: Build the project diff --git a/.github/workflows/cassandra.yml b/.github/workflows/cassandra.yml index de8ed032bd..4926ece5d6 100644 --- a/.github/workflows/cassandra.yml +++ b/.github/workflows/cassandra.yml @@ -25,6 +25,8 @@ jobs: run: | docker compose -f test/cluster/cassandra/docker-compose.yml up -d --wait # A separate step for building to separate measuring time of compilation and testing + - name: Update rust toolchain + run: rustup update - name: Build the project run: cargo build --verbose --tests --features "full-serialization" - name: Run tests on cassandra diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8fbfab11e8..d6f9fbfe5f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,6 +26,14 @@ jobs: run: | sudo sh -c "echo 2097152 >> /proc/sys/fs/aio-max-nr" docker compose -f test/cluster/docker-compose.yml up -d --wait + - name: Update rust toolchain + run: rustup update + - name: Print rustc version + run: rustc --version + - name: Print rustfmt version + run: cargo fmt --version + - name: Print clippy version + run: cargo clippy --version - name: Format check run: cargo fmt --verbose --all -- --check - name: Clippy check @@ -92,5 +100,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - name: Update rust toolchain + run: rustup update - name: Compile docs run: RUSTDOCFLAGS=-Dwarnings cargo doc diff --git a/.github/workflows/semver_checks.yml b/.github/workflows/semver_checks.yml index 174d0aa409..976057b125 100644 --- a/.github/workflows/semver_checks.yml +++ b/.github/workflows/semver_checks.yml @@ -56,6 +56,8 @@ jobs: # I don't know any way to do this using checkout action - name: Fetch PR base run: git fetch origin "$PR_BASE" + - name: Update rust toolchain + run: rustup update - name: Install semver-checks # Official action uses binary releases fetched from GitHub # If this pipeline becomes too slow, we should do this too @@ -142,6 +144,8 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v3 + - name: Update rust toolchain + run: rustup update - name: Install semver-checks run: cargo install cargo-semver-checks --no-default-features - name: Run semver-checks to see if it agrees with version updates diff --git a/.github/workflows/serverless.yaml b/.github/workflows/serverless.yaml index 8edc70b821..e8ffc74d6c 100644 --- a/.github/workflows/serverless.yaml +++ b/.github/workflows/serverless.yaml @@ -29,7 +29,8 @@ jobs: run: | ccm create serverless -i 127.0.1. -n 1 --scylla -v release:5.1.6 ccm start --sni-proxy --sni-port 7777 - + - name: Update rust toolchain + run: rustup update - name: Check run: cargo check --verbose - name: Run cloud example diff --git a/.github/workflows/tls.yml b/.github/workflows/tls.yml index 94d3b4926c..65e0721b59 100644 --- a/.github/workflows/tls.yml +++ b/.github/workflows/tls.yml @@ -32,6 +32,8 @@ jobs: working-directory: ./scylla steps: - uses: actions/checkout@v3 + - name: Update rust toolchain + run: rustup update - name: Check run: cargo check --verbose --features "ssl" working-directory: ${{env.working-directory}} diff --git a/Cargo.lock.msrv b/Cargo.lock.msrv index ed60c12bcf..64b81b820a 100644 --- a/Cargo.lock.msrv +++ b/Cargo.lock.msrv @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.17.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -113,9 +113,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.65" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -247,7 +247,7 @@ dependencies = [ "clap_lex", "indexmap 1.9.3", "once_cell", - "strsim", + "strsim 0.10.0", "termcolor", "textwrap", ] @@ -287,9 +287,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "criterion" @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -382,23 +382,23 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.32", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", @@ -451,6 +451,19 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -495,6 +508,7 @@ dependencies = [ "anyhow", "chrono", "clap", + "env_logger", "futures", "openssl", "rand", @@ -653,9 +667,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "half" @@ -706,6 +720,12 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -765,6 +785,17 @@ dependencies = [ "hashbrown 0.14.0", ] +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi 0.3.2", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -791,9 +822,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -882,9 +913,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] @@ -1018,9 +1049,9 @@ dependencies = [ [[package]] name = "object" -version = "0.28.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -1293,9 +1324,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags 1.3.2", ] @@ -1316,7 +1347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall 0.2.13", + "redox_syscall 0.2.16", "thiserror", ] @@ -1440,7 +1471,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scylla" -version = "0.13.0" +version = "0.13.1" dependencies = [ "arc-swap", "assert_matches", @@ -1485,7 +1516,7 @@ dependencies = [ [[package]] name = "scylla-cql" -version = "0.2.0" +version = "0.2.1" dependencies = [ "async-trait", "bigdecimal", @@ -1508,7 +1539,7 @@ dependencies = [ [[package]] name = "scylla-macros" -version = "0.5.0" +version = "0.5.1" dependencies = [ "darling", "proc-macro2", @@ -1518,7 +1549,7 @@ dependencies = [ [[package]] name = "scylla-proxy" -version = "0.0.3" +version = "0.0.4" dependencies = [ "assert_matches", "bigdecimal", @@ -1663,6 +1694,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -2037,9 +2074,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2047,24 +2084,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.32", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2072,28 +2109,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.32", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.58" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/docs/pyproject.toml b/docs/pyproject.toml index 32be277d2d..a3eb0566fa 100644 --- a/docs/pyproject.toml +++ b/docs/pyproject.toml @@ -1,14 +1,14 @@ [tool.poetry] name = "sphinx-docs" description = "ScyllaDB Documentation" -version = "0.13.0" +version = "0.13.1" authors = ["ScyllaDB Documentation Contributors"] [tool.poetry.dependencies] python = "^3.9" pyyaml = "6.0.1" pygments = "2.15.1" -redirects_cli ="~0.1.2" +redirects_cli = "~0.1.2" sphinx-scylladb-theme = "~1.6.1" sphinx-sitemap = "2.5.1" sphinx-autobuild = "2021.3.14" diff --git a/docs/source/conf.py b/docs/source/conf.py index cbe4d39573..64a3c51d11 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,14 +13,14 @@ # -- Global variables # Build documentation for the following tags and branches -TAGS = ['v0.12.0', 'v0.13.0'] +TAGS = ['v0.12.0', 'v0.13.1'] BRANCHES = ['main'] # Set the latest version. -LATEST_VERSION = 'v0.13.0' +LATEST_VERSION = 'v0.13.1' # Set which versions are not released yet. UNSTABLE_VERSIONS = ['main'] # Set which versions are deprecated -DEPRECATED_VERSIONS = ['v0.12.0'] +DEPRECATED_VERSIONS = ['v0.12.0', 'v0.13.0'] # -- General configuration diff --git a/docs/source/logging/logging.md b/docs/source/logging/logging.md index 198b3291f4..c99d1b1e0f 100644 --- a/docs/source/logging/logging.md +++ b/docs/source/logging/logging.md @@ -1,9 +1,15 @@ # Logging The driver uses the [tracing](https://github.com/tokio-rs/tracing) crate for all logs.\ -To view the logs you have to create a `tracing` subscriber to which all logs will be written. +There are two ways to view the logs: +- Create a `tracing` subscriber to which all logs will be written (recommended). +- Enable `log` feature on `tracing` crate and use some logger from `log` ecosystem. \ +Only do this if you can't use `tracing` subscriber for some reason. + +## Using tracing subscriber + +To print the logs you can use the default subscriber: -To just print the logs you can use the default subscriber: ```rust # extern crate scylla; # extern crate tokio; @@ -45,4 +51,44 @@ To start this example execute: RUST_LOG=info cargo run ``` -The full [example](https://github.com/scylladb/scylla-rust-driver/tree/main/examples/logging.rs) is available in the `examples` folder \ No newline at end of file +The full [example](https://github.com/scylladb/scylla-rust-driver/tree/main/examples/logging.rs) is available in the `examples` folder. +You can run it from main folder of driver repository using `RUST_LOG=trace SCYLLA_URI=:9042 cargo run --example logging`. + +## Using log + +To collect tracing events using log collector you first need to enable `log` feature on `tracing` crate. +You can use `cargo add tracing -F log` or edit `Cargo.toml`: +```toml +tracing = { version = "0.1.40" , features = ["log"] } +``` +then you can setup `env_logger` os some other logger and it will output logs from the driver: + +```rust +# extern crate scylla; +# extern crate tokio; +# extern crate tracing; +# extern crate env_logger; +# use std::error::Error; +# use scylla::{Session, SessionBuilder}; +use tracing::info; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Setup `log` collector that uses RUST_LOG env variable to configure + // verbosity. + env_logger::init(); + + let uri = std::env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9042".to_string()); + info!("Connecting to {}", uri); + + let session: Session = SessionBuilder::new().known_node(uri).build().await?; + session.query("CREATE KEYSPACE IF NOT EXISTS examples_ks WITH REPLICATION = {'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1}", &[]).await?; + + session.query("USE examples_ks", &[]).await?; + + Ok(()) +} +``` + +The full [example](https://github.com/scylladb/scylla-rust-driver/tree/main/examples/logging_log.rs) is available in the `examples` folder. +You can run it from main folder of driver repository using `RUST_LOG=trace SCYLLA_URI=:9042 cargo run --example logging_log`. \ No newline at end of file diff --git a/docs/source/quickstart/create-project.md b/docs/source/quickstart/create-project.md index d264e54d87..48fcaa4a85 100644 --- a/docs/source/quickstart/create-project.md +++ b/docs/source/quickstart/create-project.md @@ -8,7 +8,7 @@ cargo new myproject In `Cargo.toml` add useful dependencies: ```toml [dependencies] -scylla = "0.13" +scylla = "0.13.1" tokio = { version = "1.12", features = ["full"] } futures = "0.3.6" uuid = "1.0" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index b068ee9e3c..bd56a0798b 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -12,7 +12,7 @@ rustyline = "9" rustyline-derive = "0.6" scylla = {path = "../scylla", features = ["ssl", "cloud", "chrono", "time", "num-bigint-03", "num-bigint-04", "bigdecimal-04"]} tokio = {version = "1.1.0", features = ["full"]} -tracing = "0.1.25" +tracing = { version = "0.1.25" , features = ["log"] } tracing-subscriber = { version = "0.3.14", features = ["env-filter"] } chrono = { version = "0.4", default-features = false } time = { version = "0.3.22" } @@ -21,6 +21,7 @@ tower = "0.4" stats_alloc = "0.1" clap = { version = "3.2.4", features = ["derive"] } rand = "0.8.5" +env_logger = "0.10" [[example]] name = "auth" @@ -34,6 +35,10 @@ path = "basic.rs" name = "logging" path = "logging.rs" +[[example]] +name = "logging_log" +path = "logging_log.rs" + [[example]] name = "tls" path = "tls.rs" diff --git a/examples/logging_log.rs b/examples/logging_log.rs new file mode 100644 index 0000000000..33a2b794c8 --- /dev/null +++ b/examples/logging_log.rs @@ -0,0 +1,27 @@ +use anyhow::Result; +use scylla::transport::session::Session; +use scylla::SessionBuilder; +use std::env; +use tracing::info; + +// To run this example, and view logged messages, RUST_LOG env var needs to be set +// This can be done using shell command presented below +// RUST_LOG=info cargo run --example logging_log +#[tokio::main] +async fn main() -> Result<()> { + // Driver uses `tracing` for logging purposes, but it's possible to use `log` + // ecosystem to view the messages. This requires adding `tracing` crate to + // dependencies and enabling its "log" feature. Then you will be able to use + // loggers like `env_logger` to see driver's messages. + env_logger::init(); + + let uri = env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9042".to_string()); + info!("Connecting to {}", uri); + + let session: Session = SessionBuilder::new().known_node(uri).build().await?; + session.query("CREATE KEYSPACE IF NOT EXISTS examples_ks WITH REPLICATION = {'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1}", &[]).await?; + + session.query("USE examples_ks", &[]).await?; + + Ok(()) +} diff --git a/scylla-cql/Cargo.toml b/scylla-cql/Cargo.toml index 75753dded7..751459cee3 100644 --- a/scylla-cql/Cargo.toml +++ b/scylla-cql/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scylla-cql" -version = "0.2.0" +version = "0.2.1" edition = "2021" description = "CQL data types and primitives, for interacting with Scylla." repository = "https://github.com/scylladb/scylla-rust-driver" @@ -10,7 +10,7 @@ categories = ["database"] license = "MIT OR Apache-2.0" [dependencies] -scylla-macros = { version = "0.5.0", path = "../scylla-macros" } +scylla-macros = { version = "0.5.1", path = "../scylla-macros" } byteorder = "1.3.4" bytes = "1.0.1" tokio = { version = "1.12", features = ["io-util", "time"] } @@ -43,7 +43,14 @@ chrono = ["dep:chrono"] num-bigint-03 = ["dep:num-bigint-03"] num-bigint-04 = ["dep:num-bigint-04"] bigdecimal-04 = ["dep:bigdecimal-04"] -full-serialization = ["chrono", "time", "secret", "num-bigint-03", "num-bigint-04", "bigdecimal-04"] +full-serialization = [ + "chrono", + "time", + "secret", + "num-bigint-03", + "num-bigint-04", + "bigdecimal-04", +] [lints.rust] unreachable_pub = "warn" diff --git a/scylla-cql/src/frame/mod.rs b/scylla-cql/src/frame/mod.rs index e0f8309a81..e84ca159e6 100644 --- a/scylla-cql/src/frame/mod.rs +++ b/scylla-cql/src/frame/mod.rs @@ -15,6 +15,7 @@ use thiserror::Error; use tokio::io::{AsyncRead, AsyncReadExt}; use uuid::Uuid; +use std::fmt::Display; use std::{collections::HashMap, convert::TryFrom}; use request::SerializableRequest; @@ -47,11 +48,11 @@ pub enum Compression { Snappy, } -impl ToString for Compression { - fn to_string(&self) -> String { +impl Display for Compression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Compression::Lz4 => "lz4".to_owned(), - Compression::Snappy => "snappy".to_owned(), + Compression::Lz4 => f.write_str("lz4"), + Compression::Snappy => f.write_str("snappy"), } } } diff --git a/scylla-cql/src/frame/value.rs b/scylla-cql/src/frame/value.rs index dd5212c25b..6728675ef0 100644 --- a/scylla-cql/src/frame/value.rs +++ b/scylla-cql/src/frame/value.rs @@ -699,6 +699,12 @@ pub trait ValueList { } } +impl Default for LegacySerializedValues { + fn default() -> Self { + Self::new() + } +} + impl LegacySerializedValues { /// Creates empty value list pub const fn new() -> Self { diff --git a/scylla-cql/src/types/serialize/row.rs b/scylla-cql/src/types/serialize/row.rs index f4c107bad3..c8f04cc6bc 100644 --- a/scylla-cql/src/types/serialize/row.rs +++ b/scylla-cql/src/types/serialize/row.rs @@ -1141,6 +1141,7 @@ mod tests { // Do not remove. It's not used in tests but we keep it here to check that // we properly ignore warnings about unused variables, unnecessary `mut`s // etc. that usually pop up when generating code for empty structs. + #[allow(unused)] #[derive(SerializeRow)] #[scylla(crate = crate)] struct TestRowWithNoColumns {} diff --git a/scylla-cql/src/types/serialize/value.rs b/scylla-cql/src/types/serialize/value.rs index 39403f3c48..6f917f8de4 100644 --- a/scylla-cql/src/types/serialize/value.rs +++ b/scylla-cql/src/types/serialize/value.rs @@ -2038,6 +2038,7 @@ mod tests { // Do not remove. It's not used in tests but we keep it here to check that // we properly ignore warnings about unused variables, unnecessary `mut`s // etc. that usually pop up when generating code for empty structs. + #[allow(unused)] #[derive(SerializeCql)] #[scylla(crate = crate)] struct TestUdtWithNoFields {} @@ -2596,6 +2597,7 @@ mod tests { assert_eq!(reference, udt); } + #[allow(unused)] #[derive(SerializeCql, Debug)] #[scylla(crate = crate, flavor = "enforce_order", skip_name_checks)] struct TestUdtWithSkippedNameChecks { diff --git a/scylla-macros/Cargo.toml b/scylla-macros/Cargo.toml index 9d015b50ea..dc008b7d2c 100644 --- a/scylla-macros/Cargo.toml +++ b/scylla-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scylla-macros" -version = "0.5.0" +version = "0.5.1" edition = "2021" description = "proc macros for scylla async CQL driver" repository = "https://github.com/scylladb/scylla-rust-driver" @@ -12,10 +12,10 @@ license = "MIT OR Apache-2.0" proc-macro = true [dependencies] -darling = "0.20.0" +darling = "0.20.10" syn = "2.0" -quote = "1.0" +quote = "1.0" proc-macro2 = "1.0" [lints.rust] -unreachable_pub = "warn" \ No newline at end of file +unreachable_pub = "warn" diff --git a/scylla-proxy/Cargo.toml b/scylla-proxy/Cargo.toml index 704c81061d..e0e734fcc0 100644 --- a/scylla-proxy/Cargo.toml +++ b/scylla-proxy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scylla-proxy" -version = "0.0.3" +version = "0.0.4" edition = "2021" description = "Proxy layer between Scylla driver and cluster that enables testing Scylla drivers' behaviour in unfavourable conditions" repository = "https://github.com/scylladb/scylla-rust-driver" @@ -13,11 +13,19 @@ license = "MIT OR Apache-2.0" defaults = [] [dependencies] -scylla-cql = { version = "0.2.0", path = "../scylla-cql" } +scylla-cql = { version = "0.2.1", path = "../scylla-cql" } byteorder = "1.3.4" bytes = "1.2.0" futures = "0.3.6" -tokio = { version = "1.12", features = ["net", "time", "io-util", "sync", "rt", "macros", "rt-multi-thread"] } +tokio = { version = "1.12", features = [ + "net", + "time", + "io-util", + "sync", + "rt", + "macros", + "rt-multi-thread", +] } uuid = "1.0" thiserror = "1.0.32" bigdecimal = "0.4" diff --git a/scylla-proxy/examples/cmdline.rs b/scylla-proxy/examples/cmdline.rs index 9ac8fd4c9b..193e3e2a6a 100644 --- a/scylla-proxy/examples/cmdline.rs +++ b/scylla-proxy/examples/cmdline.rs @@ -13,7 +13,6 @@ use std::{ }; use scylla_proxy::{Node, Proxy, ShardAwareness}; -use tracing::instrument::WithSubscriber; fn init_logger() { tracing_subscriber::fmt::fmt() @@ -53,7 +52,7 @@ async fn main() { None, None, )]); - let running_proxy = proxy.run().with_current_subscriber().await.unwrap(); + let running_proxy = proxy.run().await.unwrap(); pause().await; running_proxy.finish().await.unwrap(); diff --git a/scylla-proxy/examples/identity_proxy.rs b/scylla-proxy/examples/identity_proxy.rs index 33b6ea746e..7460e04c11 100644 --- a/scylla-proxy/examples/identity_proxy.rs +++ b/scylla-proxy/examples/identity_proxy.rs @@ -1,7 +1,6 @@ use std::{net::SocketAddr, str::FromStr}; use scylla_proxy::{Node, Proxy, ShardAwareness}; -use tracing::instrument::WithSubscriber; fn init_logger() { tracing_subscriber::fmt::fmt() @@ -30,7 +29,7 @@ async fn main() { .build(), ) .build(); - let running_proxy = proxy.run().with_current_subscriber().await.unwrap(); + let running_proxy = proxy.run().await.unwrap(); pause().await; running_proxy.finish().await.unwrap(); diff --git a/scylla-proxy/examples/identity_shard_aware_proxy.rs b/scylla-proxy/examples/identity_shard_aware_proxy.rs index 6f94ad214a..b94126e0ff 100644 --- a/scylla-proxy/examples/identity_shard_aware_proxy.rs +++ b/scylla-proxy/examples/identity_shard_aware_proxy.rs @@ -1,7 +1,6 @@ use std::{net::SocketAddr, str::FromStr}; use scylla_proxy::{Node, Proxy, ShardAwareness}; -use tracing::instrument::WithSubscriber; fn init_logger() { tracing_subscriber::fmt::fmt() @@ -27,7 +26,7 @@ async fn main() { None, None, )]); - let running_proxy = proxy.run().with_current_subscriber().await.unwrap(); + let running_proxy = proxy.run().await.unwrap(); pause().await; running_proxy.finish().await.unwrap(); diff --git a/scylla/Cargo.toml b/scylla/Cargo.toml index 028406f6ca..301651b0e3 100644 --- a/scylla/Cargo.toml +++ b/scylla/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scylla" -version = "0.13.0" +version = "0.13.1" edition = "2021" description = "Async CQL driver for Rust, optimized for Scylla, fully compatible with Apache Cassandraâ„¢" repository = "https://github.com/scylladb/scylla-rust-driver" @@ -16,24 +16,45 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = [] ssl = ["dep:tokio-openssl", "dep:openssl"] -cloud = ["ssl", "scylla-cql/serde", "dep:serde_yaml", "dep:serde", "dep:url", "dep:base64"] +cloud = [ + "ssl", + "scylla-cql/serde", + "dep:serde_yaml", + "dep:serde", + "dep:url", + "dep:base64", +] secret = ["scylla-cql/secret"] chrono = ["scylla-cql/chrono"] time = ["scylla-cql/time"] num-bigint-03 = ["scylla-cql/num-bigint-03"] num-bigint-04 = ["scylla-cql/num-bigint-04"] bigdecimal-04 = ["scylla-cql/bigdecimal-04"] -full-serialization = ["chrono", "time", "secret", "num-bigint-03", "num-bigint-04", "bigdecimal-04"] +full-serialization = [ + "chrono", + "time", + "secret", + "num-bigint-03", + "num-bigint-04", + "bigdecimal-04", +] [dependencies] -scylla-macros = { version = "0.5.0", path = "../scylla-macros" } -scylla-cql = { version = "0.2.0", path = "../scylla-cql" } +scylla-macros = { version = "0.5.1", path = "../scylla-macros" } +scylla-cql = { version = "0.2.1", path = "../scylla-cql" } byteorder = "1.3.4" bytes = "1.0.1" futures = "0.3.6" hashbrown = "0.14" histogram = "0.6.9" -tokio = { version = "1.34", features = ["net", "time", "io-util", "sync", "rt", "macros"] } +tokio = { version = "1.34", features = [ + "net", + "time", + "io-util", + "sync", + "rt", + "macros", +] } snap = "1.0" uuid = { version = "1.0", features = ["v4"] } rand = "0.8.3" @@ -60,9 +81,9 @@ lazy_static = "1" num-bigint-03 = { package = "num-bigint", version = "0.3" } num-bigint-04 = { package = "num-bigint", version = "0.4" } bigdecimal-04 = { package = "bigdecimal", version = "0.4" } -scylla-proxy = { version = "0.0.3", path = "../scylla-proxy" } +scylla-proxy = { version = "0.0.4", path = "../scylla-proxy" } ntest = "0.9.0" -criterion = "0.4" # Note: v0.5 needs at least rust 1.70.0 +criterion = "0.4" # Note: v0.5 needs at least rust 1.70.0 tokio = { version = "1.27", features = ["test-util"] } tracing-subscriber = { version = "0.3.14", features = ["env-filter"] } assert_matches = "1.5.0" diff --git a/scylla/src/statement/batch.rs b/scylla/src/statement/batch.rs index efe95031e2..30e46ac278 100644 --- a/scylla/src/statement/batch.rs +++ b/scylla/src/statement/batch.rs @@ -30,6 +30,17 @@ impl Batch { } } + /// Creates an empty batch, with the configuration of existing batch. + pub(crate) fn new_from(batch: &Batch) -> Batch { + let batch_type = batch.get_type(); + let config = batch.config.clone(); + Batch { + batch_type, + config, + ..Default::default() + } + } + /// Creates a new, empty `Batch` of `batch_type` type with the provided statements. pub fn new_with_statements(batch_type: BatchType, statements: Vec) -> Self { Self { diff --git a/scylla/src/transport/cluster.rs b/scylla/src/transport/cluster.rs index 2f576f33ea..29d9505e6b 100644 --- a/scylla/src/transport/cluster.rs +++ b/scylla/src/transport/cluster.rs @@ -24,7 +24,6 @@ use std::collections::{HashMap, HashSet}; use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; -use tracing::instrument::WithSubscriber; use tracing::{debug, warn}; use uuid::Uuid; @@ -206,7 +205,7 @@ impl Cluster { }; let (fut, worker_handle) = worker.work().remote_handle(); - tokio::spawn(fut.with_current_subscriber()); + tokio::spawn(fut); let result = Cluster { data: cluster_data, @@ -647,7 +646,7 @@ impl ClusterWorker { let cluster_data = self.cluster_data.load_full(); let use_keyspace_future = Self::handle_use_keyspace_request(cluster_data, request); - tokio::spawn(use_keyspace_future.with_current_subscriber()); + tokio::spawn(use_keyspace_future); }, None => return, // If use_keyspace_channel was closed then cluster was dropped, we can stop working } diff --git a/scylla/src/transport/connection.rs b/scylla/src/transport/connection.rs index c3f91ec6b4..cdc6e730ea 100644 --- a/scylla/src/transport/connection.rs +++ b/scylla/src/transport/connection.rs @@ -13,7 +13,6 @@ use tokio::io::{split, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWrite use tokio::net::{TcpSocket, TcpStream}; use tokio::sync::{mpsc, oneshot}; use tokio::time::Instant; -use tracing::instrument::WithSubscriber; use tracing::{debug, error, trace, warn}; use uuid::Uuid; @@ -915,8 +914,7 @@ impl Connection { prepared_queries.insert(query, prepared); } - let mut batch: Cow = Cow::Owned(Default::default()); - batch.to_mut().config = init_batch.config.clone(); + let mut batch: Cow = Cow::Owned(Batch::new_from(init_batch)); for stmt in &init_batch.statements { match stmt { BatchStatement::Query(query) => match prepared_queries.get(query.contents.as_str()) @@ -1090,7 +1088,7 @@ impl Connection { node_address, ) .remote_handle(); - tokio::task::spawn(task.with_current_subscriber()); + tokio::task::spawn(task); return Ok(handle); } @@ -1104,7 +1102,7 @@ impl Connection { node_address, ) .remote_handle(); - tokio::task::spawn(task.with_current_subscriber()); + tokio::task::spawn(task); Ok(handle) } @@ -1827,7 +1825,7 @@ struct StreamIdSet { impl StreamIdSet { fn new() -> Self { - const BITMAP_SIZE: usize = (std::i16::MAX as usize + 1) / 64; + const BITMAP_SIZE: usize = (i16::MAX as usize + 1) / 64; Self { used_bitmap: vec![0; BITMAP_SIZE].into_boxed_slice(), } diff --git a/scylla/src/transport/connection_pool.rs b/scylla/src/transport/connection_pool.rs index 84632a4078..849ef8cb8d 100644 --- a/scylla/src/transport/connection_pool.rs +++ b/scylla/src/transport/connection_pool.rs @@ -27,7 +27,6 @@ use std::sync::{Arc, RwLock, Weak}; use std::time::Duration; use tokio::sync::{broadcast, mpsc, Notify}; -use tracing::instrument::WithSubscriber; use tracing::{debug, error, trace, warn}; /// The target size of a per-node connection pool. @@ -212,7 +211,7 @@ impl NodeConnectionPool { let conns = refiller.get_shared_connections(); let (fut, refiller_handle) = refiller.run(use_keyspace_request_receiver).remote_handle(); - tokio::spawn(fut.with_current_subscriber()); + tokio::spawn(fut); Self { conns, @@ -974,7 +973,7 @@ impl PoolRefiller { new_sharder, ); - self.sharder = new_sharder.clone(); + self.sharder.clone_from(&new_sharder); // If the sharder has changed, we can throw away all previous connections. // All connections to the same live node will have the same sharder, @@ -1138,17 +1137,14 @@ impl PoolRefiller { Err(QueryError::IoError(io_error.unwrap())) }; - tokio::task::spawn( - async move { - let res = fut.await; - match &res { - Ok(()) => debug!("[{}] Successfully changed current keyspace", address), - Err(err) => warn!("[{}] Failed to change keyspace: {:?}", address, err), - } - let _ = response_sender.send(res); + tokio::task::spawn(async move { + let res = fut.await; + match &res { + Ok(()) => debug!("[{}] Successfully changed current keyspace", address), + Err(err) => warn!("[{}] Failed to change keyspace: {:?}", address, err), } - .with_current_subscriber(), - ); + let _ = response_sender.send(res); + }); } // Requires the keyspace to be set diff --git a/scylla/src/transport/iterator.rs b/scylla/src/transport/iterator.rs index 1167d6bdbb..6c340b3453 100644 --- a/scylla/src/transport/iterator.rs +++ b/scylla/src/transport/iterator.rs @@ -16,7 +16,6 @@ use scylla_cql::types::serialize::row::SerializedValues; use std::result::Result; use thiserror::Error; use tokio::sync::mpsc; -use tracing::instrument::WithSubscriber; use super::errors::QueryError; use super::execution_profile::ExecutionProfileInner; @@ -387,7 +386,7 @@ impl RowIterator { worker_task: impl Future + Send + 'static, mut receiver: mpsc::Receiver>, ) -> Result { - tokio::task::spawn(worker_task.with_current_subscriber()); + tokio::task::spawn(worker_task); // This unwrap is safe because: // - The future returned by worker.work sends at least one item diff --git a/scylla/src/transport/load_balancing/default.rs b/scylla/src/transport/load_balancing/default.rs index fe058a50e2..46aa282992 100644 --- a/scylla/src/transport/load_balancing/default.rs +++ b/scylla/src/transport/load_balancing/default.rs @@ -70,6 +70,16 @@ enum StatementType { NonLwt, } +/// A result of `pick_replica`. +enum PickedReplica<'a> { + /// A replica that could be computed cheaply. + Computed((NodeRef<'a>, Shard)), + + /// A replica that could not be computed cheaply. `pick` should therefore return None + /// and `fallback` will then return that replica as the first in the iterator. + ToBeComputedInFallback, +} + /// The default load balancing policy. /// /// It can be configured to be datacenter-aware and token-aware. @@ -137,8 +147,14 @@ or refrain from preferring datacenters (which may ban all other datacenters, if table_spec, ); - if let Some((alive_local_rack_replica, shard)) = local_rack_picked { - return Some((alive_local_rack_replica, Some(shard))); + if let Some(picked) = local_rack_picked { + return match picked { + PickedReplica::Computed((alive_local_rack_replica, shard)) => { + Some((alive_local_rack_replica, Some(shard))) + } + // Let call to fallback() compute the replica, because it requires allocation. + PickedReplica::ToBeComputedInFallback => None, + }; } } @@ -155,8 +171,14 @@ or refrain from preferring datacenters (which may ban all other datacenters, if table_spec, ); - if let Some((alive_local_replica, shard)) = picked { - return Some((alive_local_replica, Some(shard))); + if let Some(picked) = picked { + return match picked { + PickedReplica::Computed((alive_local_replica, shard)) => { + Some((alive_local_replica, Some(shard))) + } + // Let call to fallback() compute the replica, because it requires allocation. + PickedReplica::ToBeComputedInFallback => None, + }; } } @@ -173,8 +195,14 @@ or refrain from preferring datacenters (which may ban all other datacenters, if statement_type, table_spec, ); - if let Some((alive_remote_replica, shard)) = picked { - return Some((alive_remote_replica, Some(shard))); + if let Some(picked) = picked { + return match picked { + PickedReplica::Computed((alive_remote_replica, shard)) => { + Some((alive_remote_replica, Some(shard))) + } + // Let call to fallback() compute the replica, because it requires allocation. + PickedReplica::ToBeComputedInFallback => None, + }; } } }; @@ -313,7 +341,7 @@ or refrain from preferring datacenters (which may ban all other datacenters, if let maybe_local_rack_nodes = if let NodeLocationPreference::DatacenterAndRack(dc, rack) = &self.preferences { let rack_predicate = Self::make_rack_predicate( - |node| (self.pick_predicate)(node, None), + |node| Self::is_alive(node, None), NodeLocationCriteria::DatacenterAndRack(dc, rack), ); Either::Left( @@ -540,14 +568,14 @@ impl DefaultPolicy { cluster: &'a ClusterData, statement_type: StatementType, table_spec: &TableSpec, - ) -> Option<(NodeRef<'a>, Shard)> { + ) -> Option { match statement_type { StatementType::Lwt => { self.pick_first_replica(ts, replica_location, predicate, cluster, table_spec) } - StatementType::NonLwt => { - self.pick_random_replica(ts, replica_location, predicate, cluster, table_spec) - } + StatementType::NonLwt => self + .pick_random_replica(ts, replica_location, predicate, cluster, table_spec) + .map(PickedReplica::Computed), } } @@ -562,7 +590,8 @@ impl DefaultPolicy { // // If no DC/rack preferences are set, then the only possible replica to be returned // (due to expensive computation of the others, and we avoid expensive computation in `pick()`) - // is the primary replica. It is returned **iff** it satisfies the predicate, else None. + // is the primary replica. If it exists, Some is returned, with either Computed(primary_replica) + // **iff** it satisfies the predicate or ToBeComputedInFallback otherwise. fn pick_first_replica<'a>( &'a self, ts: &TokenWithStrategy<'a>, @@ -570,30 +599,34 @@ impl DefaultPolicy { predicate: impl Fn(NodeRef<'a>, Shard) -> bool + 'a, cluster: &'a ClusterData, table_spec: &TableSpec, - ) -> Option<(NodeRef<'a>, Shard)> { + ) -> Option { match replica_location { NodeLocationCriteria::Any => { // ReplicaSet returned by ReplicaLocator for this case: - // 1) can be precomputed and lated used cheaply, + // 1) can be precomputed and later used cheaply, // 2) returns replicas in the **non-ring order** (this because ReplicaSet chains // ring-ordered replicas sequences from different DCs, thus not preserving // the global ring order). // Because of 2), we can't use a precomputed ReplicaSet, but instead we need ReplicasOrdered. // As ReplicasOrdered can compute cheaply only the primary global replica // (computation of the remaining ones is expensive), in case that the primary replica - // does not satisfy the `predicate`, None is returned. All expensive computation - // is to be done only when `fallback()` is called. + // does not satisfy the `predicate`, ToBeComputedInFallback is returned. + // All expensive computation is to be done only when `fallback()` is called. self.nonfiltered_replica_set(ts, replica_location, cluster, table_spec) .into_replicas_ordered() .into_iter() .next() - .and_then(|(primary_replica, shard)| { - predicate(primary_replica, shard).then_some((primary_replica, shard)) + .map(|(primary_replica, shard)| { + if predicate(primary_replica, shard) { + PickedReplica::Computed((primary_replica, shard)) + } else { + PickedReplica::ToBeComputedInFallback + } }) } NodeLocationCriteria::Datacenter(_) | NodeLocationCriteria::DatacenterAndRack(_, _) => { // ReplicaSet returned by ReplicaLocator for this case: - // 1) can be precomputed and lated used cheaply, + // 1) can be precomputed and later used cheaply, // 2) returns replicas in the ring order (this is not true for the case // when multiple DCs are allowed, because ReplicaSet chains replicas sequences // from different DCs, thus not preserving the global ring order) @@ -606,6 +639,7 @@ impl DefaultPolicy { table_spec, ) .next() + .map(PickedReplica::Computed) } } } @@ -959,6 +993,8 @@ impl<'a> TokenWithStrategy<'a> { #[cfg(test)] mod tests { + use std::collections::HashMap; + use scylla_cql::{frame::types::SerialConsistency, Consistency}; use tracing::info; @@ -966,7 +1002,12 @@ mod tests { get_plan_and_collect_node_identifiers, mock_cluster_data_for_token_unaware_tests, ExpectedGroups, ExpectedGroupsBuilder, }; - use crate::transport::locator::test::{TABLE_NTS_RF_2, TABLE_NTS_RF_3, TABLE_SS_RF_2}; + use crate::host_filter::HostFilter; + use crate::transport::locator::tablets::TabletsInfo; + use crate::transport::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::{ default::tests::framework::mock_cluster_data_for_token_aware_tests, Plan, RoutingInfo, @@ -1078,7 +1119,9 @@ mod tests { assert_eq!( got.len(), combined_groups_len, - "Plan length different than expected" + "Plan length different than expected. Got plan {:?}, expected groups {:?}", + got, + self.groups, ); // Now, split `got` into groups of expected sizes @@ -1095,10 +1138,10 @@ mod tests { // Verify that the group has the same nodes as the // expected one let got_set: HashSet<_> = got_group.iter().copied().collect(); - assert_eq!(&got_set, expected_set); + assert_eq!(&got_set, expected_set, "Unordered group mismatch"); } ExpectedGroup::Ordered(sequence) => { - assert_eq!(&got_group, sequence); + assert_eq!(&got_group, sequence, "Ordered group mismatch"); } } @@ -1117,7 +1160,11 @@ mod tests { // then expect there to be more than one group // in the set. if gots.len() > 1 && s.len() > 1 { - assert!(sets.len() > 1); + assert!( + sets.len() > 1, + "Group {:?} is expected to be nondeterministic, but it appears to be deterministic", + expected + ); } } ExpectedGroup::Deterministic(_) | ExpectedGroup::Ordered(_) => { @@ -1127,7 +1174,12 @@ mod tests { // the same order. // There will only be one, unique ordering shared // by all plans - check this - assert_eq!(sets.len(), 1); + assert_eq!( + sets.len(), + 1, + "Group {:?} is expected to be deterministic, but it appears to be nondeterministic", + expected + ); } } } @@ -2261,6 +2313,73 @@ mod tests { ) .await; } + + let cluster_with_disabled_node_f = ClusterData::new( + mock_metadata_for_token_aware_tests(), + &Default::default(), + &HashMap::new(), + &None, + { + struct FHostFilter; + impl HostFilter for FHostFilter { + fn accept(&self, peer: &crate::transport::topology::Peer) -> bool { + peer.address != id_to_invalid_addr(F) + } + } + + Some(&FHostFilter) + }, + TabletsInfo::new(), + ) + .await; + + let tests_with_disabled_node_f = [ + // Keyspace NTS with RF=3 without preferred DC. + // The primary replica does not satisfy the predicate (being disabled by HostFilter), + // so pick() should return None and fallback should return A first. + // + // This is a regression test after a bug was fixed. + Test { + policy: DefaultPolicy { + preferences: NodeLocationPreference::Any, + is_token_aware: true, + permit_dc_failover: true, + pick_predicate: Box::new(|node, _shard| node.address != id_to_invalid_addr(F)), + ..Default::default() + }, + routing_info: RoutingInfo { + token: Some(Token::new(160)), + table: Some(TABLE_NTS_RF_3), + consistency: Consistency::One, + is_confirmed_lwt: true, + ..Default::default() + }, + // going through the ring, we get order: F , A , C , D , G , B , E + // us eu eu us eu eu us + // r2 r1 r1 r1 r2 r1 r1 + expected_groups: ExpectedGroupsBuilder::new() + // pick is empty, because the primary replica does not satisfy pick predicate, + // and with LWT we cannot compute other replicas for NTS without allocations. + .ordered([A, C, D, G, E]) // replicas + .group([B]) // nodes + .build(), + }, + ]; + + for Test { + policy, + routing_info, + expected_groups, + } in tests_with_disabled_node_f + { + test_default_policy_with_given_cluster_and_routing_info( + &policy, + &cluster_with_disabled_node_f, + &routing_info, + &expected_groups, + ) + .await; + } } } @@ -2269,7 +2388,7 @@ mod latency_awareness { use itertools::Either; use scylla_cql::errors::{DbError, QueryError}; use tokio::time::{Duration, Instant}; - use tracing::{instrument::WithSubscriber, trace, warn}; + use tracing::{trace, warn}; use uuid::Uuid; use crate::{load_balancing::NodeRef, routing::Shard, transport::node::Node}; @@ -2454,7 +2573,7 @@ mod latency_awareness { } } .remote_handle(); - tokio::task::spawn(updater_fut.with_current_subscriber()); + tokio::task::spawn(updater_fut); Self { _updater_handle: Some(updater_handle), diff --git a/scylla/src/transport/locator/mod.rs b/scylla/src/transport/locator/mod.rs index 64b4dc9fa0..e0f06e8ba2 100644 --- a/scylla/src/transport/locator/mod.rs +++ b/scylla/src/transport/locator/mod.rs @@ -472,19 +472,23 @@ impl<'a> IntoIterator for ReplicaSet<'a> { } enum ReplicaSetIteratorInner<'a> { + /// Token ring with SimpleStrategy, any datacenter Plain { replicas: ReplicasArray<'a>, idx: usize, }, + /// Tablets PlainSharded { replicas: &'a [(Arc, Shard)], idx: usize, }, + /// Token ring with SimpleStrategy, specific datacenter FilteredSimple { replicas: ReplicasArray<'a>, datacenter: &'a str, idx: usize, }, + /// Token ring with NetworkTopologyStrategy ChainedNTS { replicas: ReplicasArray<'a>, replicas_idx: usize, @@ -637,8 +641,8 @@ impl<'a> ReplicaSet<'a> { /// or it must compute them on-demand (in case of NetworkTopologyStrategy). /// The computation is lazy (performed by `ReplicasOrderedIterator` upon call to `next()`). /// For obtaining the primary replica, no allocations are needed. Therefore, the first call -/// to `next()` is optimised and doesn not allocate. -/// For the remaining others, unfortunately, allocation is unevitable. +/// to `next()` is optimised and does not allocate. +/// For the remaining others, unfortunately, allocation is inevitable. pub struct ReplicasOrdered<'a> { replica_set: ReplicaSet<'a>, } @@ -650,7 +654,8 @@ pub struct ReplicasOrderedIterator<'a> { enum ReplicasOrderedIteratorInner<'a> { AlreadyRingOrdered { - // In case of Plain and FilteredSimple variants, ReplicaSetIterator respects ring order. + // In case of Plain, PlainSharded and FilteredSimple variants, + // ReplicaSetIterator respects ring order. replica_set_iter: ReplicaSetIterator<'a>, }, PolyDatacenterNTS { diff --git a/scylla/src/transport/session_test.rs b/scylla/src/transport/session_test.rs index 8136477251..f4a49daf85 100644 --- a/scylla/src/transport/session_test.rs +++ b/scylla/src/transport/session_test.rs @@ -354,6 +354,57 @@ async fn test_prepared_statement() { } } +#[tokio::test] +async fn test_counter_batch() { + use crate::frame::value::Counter; + use scylla_cql::frame::request::batch::BatchType; + + setup_tracing(); + let session = Arc::new(create_new_session_builder().build().await.unwrap()); + let ks = unique_keyspace_name(); + + session.query(format!("CREATE KEYSPACE IF NOT EXISTS {} WITH REPLICATION = {{'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1}}", ks), &[]).await.unwrap(); + session + .query( + format!( + "CREATE TABLE IF NOT EXISTS {}.t_batch (key int PRIMARY KEY, value counter)", + ks + ), + &[], + ) + .await + .unwrap(); + + let statement_str = format!("UPDATE {}.t_batch SET value = value + ? WHERE key = ?", ks); + let query = Query::from(statement_str); + let prepared = session.prepare(query.clone()).await.unwrap(); + + let mut counter_batch = Batch::new(BatchType::Counter); + counter_batch.append_statement(query.clone()); + counter_batch.append_statement(prepared.clone()); + counter_batch.append_statement(query.clone()); + counter_batch.append_statement(prepared.clone()); + counter_batch.append_statement(query.clone()); + counter_batch.append_statement(prepared.clone()); + + // Check that we do not get a server error - the driver + // should send a COUNTER batch instead of a LOGGED (default) one. + session + .batch( + &counter_batch, + ( + (Counter(1), 1), + (Counter(2), 2), + (Counter(3), 3), + (Counter(4), 4), + (Counter(5), 5), + (Counter(6), 6), + ), + ) + .await + .unwrap(); +} + #[tokio::test] async fn test_batch() { setup_tracing(); @@ -2424,7 +2475,11 @@ async fn test_batch_lwts() { let session = create_new_session_builder().build().await.unwrap(); let ks = unique_keyspace_name(); - session.query(format!("CREATE KEYSPACE IF NOT EXISTS {} WITH REPLICATION = {{'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1}}", ks), &[]).await.unwrap(); + let mut create_ks = format!("CREATE KEYSPACE {} WITH REPLICATION = {{'class': 'NetworkTopologyStrategy', 'replication_factor': 1}}", ks); + if scylla_supports_tablets(&session).await { + create_ks += " and TABLETS = { 'enabled': false}"; + } + session.query(create_ks, &[]).await.unwrap(); session.use_keyspace(ks.clone(), false).await.unwrap(); session diff --git a/scylla/src/utils/parse.rs b/scylla/src/utils/parse.rs index d57c1df775..1c5e59ecb7 100644 --- a/scylla/src/utils/parse.rs +++ b/scylla/src/utils/parse.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + /// An error that can occur during parsing. #[derive(Copy, Clone)] pub(crate) struct ParseError { @@ -27,11 +29,11 @@ pub(crate) enum ParseErrorCause { Other(&'static str), } -impl ToString for ParseErrorCause { - fn to_string(&self) -> String { +impl Display for ParseErrorCause { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ParseErrorCause::Expected(e) => format!("expected {:?}", e), - ParseErrorCause::Other(e) => e.to_string(), + ParseErrorCause::Expected(e) => write!(f, "expected {:?}", e), + ParseErrorCause::Other(e) => f.write_str(e), } } } diff --git a/scylla/tests/integration/hygiene.rs b/scylla/tests/integration/hygiene.rs index 85c753589e..a3b400f474 100644 --- a/scylla/tests/integration/hygiene.rs +++ b/scylla/tests/integration/hygiene.rs @@ -64,6 +64,7 @@ macro_rules! test_crate { assert_eq!(sv, sv2); } + #[allow(unused)] #[derive(_scylla::macros::SerializeCql, _scylla::macros::SerializeRow)] #[scylla(crate = _scylla)] struct TestStructNew { diff --git a/scylla/tests/integration/lwt_optimisation.rs b/scylla/tests/integration/lwt_optimisation.rs index a36d7367de..da2c89bdef 100644 --- a/scylla/tests/integration/lwt_optimisation.rs +++ b/scylla/tests/integration/lwt_optimisation.rs @@ -1,5 +1,6 @@ use crate::utils::{setup_tracing, test_with_3_node_cluster}; use scylla::retry_policy::FallthroughRetryPolicy; +use scylla::test_utils::scylla_supports_tablets; use scylla::test_utils::unique_keyspace_name; use scylla::transport::session::Session; use scylla::{ExecutionProfile, SessionBuilder}; @@ -68,7 +69,11 @@ async fn if_lwt_optimisation_mark_offered_then_negotiatied_and_lwt_routed_optima // Create schema let ks = unique_keyspace_name(); - session.query(format!("CREATE KEYSPACE IF NOT EXISTS {} WITH REPLICATION = {{'class' : 'NetworkTopologyStrategy', 'replication_factor' : 3}}", ks), &[]).await.unwrap(); + let mut create_ks = format!("CREATE KEYSPACE IF NOT EXISTS {} WITH REPLICATION = {{'class' : 'NetworkTopologyStrategy', 'replication_factor' : 3}}", ks); + if scylla_supports_tablets(&session).await { + create_ks += " and TABLETS = { 'enabled': false}"; + } + session.query(create_ks, &[]).await.unwrap(); session.use_keyspace(ks, false).await.unwrap(); session diff --git a/scylla/tests/integration/tablets.rs b/scylla/tests/integration/tablets.rs index 00441181a5..5f91b43d39 100644 --- a/scylla/tests/integration/tablets.rs +++ b/scylla/tests/integration/tablets.rs @@ -479,9 +479,12 @@ async fn test_tablet_feedback_not_sent_for_unprepared_queries() { /// for every tablet. /// After that it sends 100 queries fro each tablet and verifies that only 1 shard on 1 node /// recevied requests for a given tablet. +/// +/// TODO: Remove #[ignore] once LWTs are supported with tablets. #[cfg(not(scylla_cloud_tests))] #[tokio::test] #[ntest::timeout(30000)] +#[ignore] async fn test_lwt_optimization_works_with_tablets() { setup_tracing(); const TABLET_COUNT: usize = 16; diff --git a/scylla/tests/integration/utils.rs b/scylla/tests/integration/utils.rs index 7839d772f3..4d5b10f7a4 100644 --- a/scylla/tests/integration/utils.rs +++ b/scylla/tests/integration/utils.rs @@ -3,7 +3,6 @@ use std::collections::HashMap; use std::env; use std::net::SocketAddr; use std::str::FromStr; -use tracing::instrument::WithSubscriber; use scylla_proxy::{Node, Proxy, ProxyError, RunningProxy, ShardAwareness}; @@ -53,7 +52,7 @@ where ); let translation_map = proxy.translation_map(); - let running_proxy = proxy.run().with_current_subscriber().await.unwrap(); + let running_proxy = proxy.run().await.unwrap(); let running_proxy = test( [proxy1_uri, proxy2_uri, proxy3_uri],