diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index f76bb6348b65..53175dc443de 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -40,6 +40,7 @@ jobs: -DUSERVER_FEATURE_CLICKHOUSE=OFF -DUSERVER_FEATURE_STACKTRACE=OFF -DUSERVER_FEATURE_PATCH_LIBPQ=OFF + -DUSERVER_FEATURE_SCYLLADB=OFF -DUSERVER_FEATURE_YDB=OFF -DUSERVER_DISABLE_RSEQ_ACCELERATION=YES -DUSERVER_FORCE_DOWNLOAD_ABSEIL=1 diff --git a/.github/workflows/archlinux.yml b/.github/workflows/archlinux.yml index 8611ad2a0204..abc07ff45764 100644 --- a/.github/workflows/archlinux.yml +++ b/.github/workflows/archlinux.yml @@ -42,6 +42,7 @@ jobs: -DUSERVER_FEATURE_MONGODB=0 -DUSERVER_FEATURE_OTLP=0 -DUSERVER_FEATURE_ROCKS=0 + -DUSERVER_FEATURE_SCYLLADB=0 -DUSERVER_FEATURE_YDB=0 -DUSERVER_USE_STATIC_LIBS=0 -DUSERVER_FEATURE_PATCH_LIBPQ=0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2e3b1c12345..8b98555ff496 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,6 +148,13 @@ jobs: run: | ./scripts/rabbitmq/ubuntu_install_rabbitmq_server.sh + - name: Install ScyllaDB cpp-rs-driver + run: | + sudo ./scripts/scylla/ubuntu-install-scylla.sh + + - name: Run ScyllaDB for tests + run: docker run -d -p 9042:9042 scylladb/scylla:2025.1 --smp 1 --memory 750M + - name: Install gdb and pytest run: | sudo apt install -y gdb python3-pytest diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index b3a6a680a49e..9c922cfdfb7a 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -61,6 +61,7 @@ jobs: -DUSERVER_FEATURE_CLICKHOUSE=OFF -DUSERVER_FEATURE_STACKTRACE=OFF -DUSERVER_FEATURE_PATCH_LIBPQ=OFF + -DUSERVER_FEATURE_SCYLLADB=OFF -DUSERVER_FEATURE_YDB=OFF -DUSERVER_DISABLE_RSEQ_ACCELERATION=YES -DUSERVER_CHAOTIC_FORMAT=OFF diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 6d0a22d80cc4..602c9bcb5e9f 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -35,6 +35,7 @@ jobs: -DUSERVER_NO_WERROR=0 -DUSERVER_BUILD_ALL_COMPONENTS=1 -DUSERVER_FEATURE_ROCKS=0 + -DUSERVER_FEATURE_SCYLLADB=0 -DUSERVER_BUILD_SAMPLES=1 -DUSERVER_BUILD_TESTS=1 -DCMAKE_BUILD_TYPE=Release @@ -51,6 +52,7 @@ jobs: -DUSERVER_NO_WERROR=0 -DUSERVER_BUILD_ALL_COMPONENTS=1 -DUSERVER_FEATURE_ROCKS=0 + -DUSERVER_FEATURE_SCYLLADB=0 -DUSERVER_BUILD_SAMPLES=1 -DUSERVER_BUILD_TESTS=1 -DCMAKE_BUILD_TYPE=Release @@ -67,6 +69,7 @@ jobs: -DUSERVER_NO_WERROR=1 -DUSERVER_BUILD_ALL_COMPONENTS=1 -DUSERVER_FEATURE_ROCKS=0 + -DUSERVER_FEATURE_SCYLLADB=0 -DUSERVER_BUILD_SAMPLES=1 -DUSERVER_BUILD_TESTS=1 -DCMAKE_BUILD_TYPE=Release diff --git a/.github/workflows/fedora.yml b/.github/workflows/fedora.yml index fcad74e74d4e..8f298fb1c48b 100644 --- a/.github/workflows/fedora.yml +++ b/.github/workflows/fedora.yml @@ -49,6 +49,7 @@ jobs: -DUSERVER_FEATURE_CLICKHOUSE=OFF -DUSERVER_FEATURE_RABBITMQ=OFF -DUSERVER_FEATURE_PATCH_LIBPQ=OFF + -DUSERVER_FEATURE_SCYLLADB=OFF -DUSERVER_FEATURE_YDB=OFF -DUSERVER_DOWNLOAD_PACKAGES=OFF -DUSERVER_FEATURE_STACKTRACE=OFF diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 9d42ee1ea947..ead65e8aacd5 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -31,6 +31,7 @@ jobs: -DUSERVER_BUILD_SAMPLES=1 -DUSERVER_BUILD_TESTS=1 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 + -DUSERVER_FEATURE_SCYLLADB=0 -DUSERVER_FEATURE_YDB=0 -DUSERVER_USE_LD=lld -DUSERVER_FORCE_DOWNLOAD_RE2=1 diff --git a/CMakeLists.txt b/CMakeLists.txt index fffa0ed9d0af..ea61b5753adf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,8 @@ option(USERVER_FEATURE_MYSQL "Provide asynchronous driver for MariaDB/MySQL" "${ # @ingroup libraries option(USERVER_FEATURE_ROCKS "Provide asynchronous driver for Rocks" "${USERVER_LIB_ENABLED_DEFAULT}") # @ingroup libraries +option(USERVER_FEATURE_SCYLLADB "Provide asynchronous driver for ScyllaDB" "${USERVER_LIB_ENABLED_DEFAULT}") +# @ingroup libraries option(USERVER_FEATURE_YDB "Provide asynchronous driver for YDB" "${USERVER_YDB_DEFAULT}") # @ingroup libraries option(USERVER_FEATURE_OTLP "Provide asynchronous OTLP exporters" "${USERVER_LIB_ENABLED_DEFAULT}") diff --git a/samples/scylla_service/README.md b/samples/scylla_service/README.md deleted file mode 100644 index f84667547555..000000000000 --- a/samples/scylla_service/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# scylla_service demo - -Enter the ScyllaDB container and open cqlsh - -```shell -docker exec -it scylla cqlsh -``` - -Create the keyspace and table - -```sql -CREATE KEYSPACE IF NOT EXISTS examples - WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }; - -CREATE TABLE IF NOT EXISTS examples.basic ( - key text PRIMARY KEY, - bln boolean, - flt float, - dbl double, - i32 int, - i64 bigint -); -``` - - ---- - -```shell -docker exec -it scylla-dev-1 bash -``` - -## Operations - - -### InsertOne - -```bash -curl -sS -X POST "http://localhost:8080/v1/kv" \ - -H 'Content-Type: application/json' \ - -d '{"key":"alpha","bln":true,"i32":1,"i64":42,"flt":1.5,"dbl":2.5}' -``` - -### 2. SelectOne - -```bash -curl -sS "http://localhost:8080/v1/kv?key=alpha" - -# should return 404 -curl -sS -w '\n%{http_code}\n' "http://localhost:8080/v1/kv?key=does-not-exist" -``` - -### 3. UpdateOne - -```bash -curl -sS -X PATCH "http://localhost:8080/v1/kv?key=alpha" \ - -H 'Content-Type: application/json' \ - -d '{"bln":false,"i32":99}' - -curl -sS "http://localhost:8080/v1/kv?key=alpha" -``` - -### 4. DeleteOne - -```bash -curl -sS -X DELETE "http://localhost:8080/v1/kv?key=alpha" -``` - -### 5. InsertMany - -```bash -curl -sS -X POST "http://localhost:8080/v1/kv/bulk" \ - -H 'Content-Type: application/json' \ - -d '[ - {"key":"bulk-1","i32":1,"bln":true}, - {"key":"bulk-2","i32":2,"bln":true}, - {"key":"bulk-3","i32":3,"bln":false} - ]' -``` - -### 6. SelectMany - -```bash -curl -sS "http://localhost:8080/v1/kv/list" - -curl -sS "http://localhost:8080/v1/kv/list?limit=2" -``` - -### 7. Count - -```bash -curl -sS "http://localhost:8080/v1/kv/count" - -curl -sS "http://localhost:8080/v1/kv/count?key=bulk-1" -``` - -### 8. Truncate - -```bash -curl -sS -X POST "http://localhost:8080/v1/kv/truncate" - -curl -sS "http://localhost:8080/v1/kv/count" -``` - -### 9. InsertOne IF NOT EXISTS (LWT) - -```bash -curl -sS -X POST "http://localhost:8080/v1/kv/create_if_absent" \ - -H 'Content-Type: application/json' \ - -d '{"key":"lwt-1","i32":100}' - -curl -sS -w '\n%{http_code}\n' -X POST "http://localhost:8080/v1/kv/create_if_absent" \ - -H 'Content-Type: application/json' \ - -d '{"key":"lwt-1","i32":999}' -``` - -### 10. UpdateOne IF col = ? (Compare-And-Set) - -```bash -curl -sS -X POST "http://localhost:8080/v1/kv/cas?key=lwt-1" \ - -H 'Content-Type: application/json' \ - -d '{"expect":{"i32":100},"set":{"i32":101}}' - -curl -sS -w '\n%{http_code}\n' -X POST "http://localhost:8080/v1/kv/cas?key=lwt-1" \ - -H 'Content-Type: application/json' \ - -d '{"expect":{"i32":100},"set":{"i32":200}}' -``` - -### 11. DeleteOne IF EXISTS - -```bash -curl -sS -X DELETE "http://localhost:8080/v1/kv/delete_if_exists?key=lwt-1" - -curl -sS -w '\n%{http_code}\n' -X DELETE "http://localhost:8080/v1/kv/delete_if_exists?key=lwt-1" -``` - - ---- \ No newline at end of file diff --git a/samples/scylla_service/src/main.cpp b/samples/scylla_service/src/main.cpp index 0af175681ff0..e8c86a53f55b 100644 --- a/samples/scylla_service/src/main.cpp +++ b/samples/scylla_service/src/main.cpp @@ -402,6 +402,11 @@ class SchemaInitHandler final : public server::handlers::HttpHandlerBase { std::string HandleRequest(server::http::HttpRequest& request, server::request::RequestContext&) const override { request.GetHttpResponse().SetContentType(http::content_type::kApplicationJson); + session_->ExecuteVoid( + "CREATE KEYSPACE IF NOT EXISTS examples " + "WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1}" + ); + session_->ExecuteVoid( "CREATE TABLE IF NOT EXISTS examples.basic (" "key text PRIMARY KEY, " diff --git a/samples/scylla_service/testsuite/conftest.py b/samples/scylla_service/testsuite/conftest.py index f689489db46e..2077b483ab1b 100644 --- a/samples/scylla_service/testsuite/conftest.py +++ b/samples/scylla_service/testsuite/conftest.py @@ -10,7 +10,7 @@ @pytest.fixture(scope='session') def scylla_connection_info(pytestconfig) -> ConnectionInfo: - host = pytestconfig.option.scylla_host or os.environ.get('TESTSUITE_SCYLLA_HOST') or 'scylla' + host = pytestconfig.option.scylla_host or os.environ.get('TESTSUITE_SCYLLA_HOST') or 'localhost' port = pytestconfig.option.scylla_port or int(os.environ.get('TESTSUITE_SCYLLA_PORT') or 9042) return ConnectionInfo(host=host, port=port) diff --git a/scripts/build_and_install_all.sh b/scripts/build_and_install_all.sh index e747c9b98666..6cd2e4450f0d 100755 --- a/scripts/build_and_install_all.sh +++ b/scripts/build_and_install_all.sh @@ -11,6 +11,7 @@ set -euox pipefail BUILD_OPTIONS=" -DUSERVER_BUILD_ALL_COMPONENTS=1 \ -DUSERVER_FEATURE_YDB=0 \ + -DUSERVER_FEATURE_SCYLLADB=0 \ -DUSERVER_FEATURE_GRPC_CHANNELZ=0 \ ${BUILD_OPTIONS:-""} \ " diff --git a/scripts/docker/base-ubuntu-22.04.dockerfile b/scripts/docker/base-ubuntu-22.04.dockerfile index b536d42ff751..457b58312b96 100644 --- a/scripts/docker/base-ubuntu-22.04.dockerfile +++ b/scripts/docker/base-ubuntu-22.04.dockerfile @@ -5,6 +5,7 @@ COPY scripts/docker/setup-base-ubuntu-22.04-env.sh /userver_tmp/ COPY scripts/clickhouse/ubuntu-install-clickhouse.sh /userver_tmp/ COPY scripts/rabbitmq/ubuntu_install_rabbitmq_dev.sh /userver_tmp/ COPY scripts/kafka/ubuntu_install_kafka.sh /userver_tmp/ +COPY scripts/scylla/ubuntu-install-scylla.sh /userver_tmp/ COPY scripts/docker/ubuntu_install_grpc.sh /userver_tmp/ COPY scripts/grpc/requirements-4.txt /userver_tmp/requirements/grpc-userver.txt diff --git a/scripts/docker/setup-base-ubuntu-22.04-env.sh b/scripts/docker/setup-base-ubuntu-22.04-env.sh index 4746acf2c258..98a965ed9fb5 100755 --- a/scripts/docker/setup-base-ubuntu-22.04-env.sh +++ b/scripts/docker/setup-base-ubuntu-22.04-env.sh @@ -143,6 +143,9 @@ git clone --depth 1 -b ${ROCKSDB_VERSION} https://github.com/facebook/rocksdb # Installing Kafka ./ubuntu_install_kafka.sh +# Installing ScyllaDB +./ubuntu-install-scylla.sh + # Set UTC timezone TZ=Etc/UTC ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone diff --git a/scripts/docker/ubuntu-24.04-base.dockerfile b/scripts/docker/ubuntu-24.04-base.dockerfile index a255035d46c0..2d628bccd672 100644 --- a/scripts/docker/ubuntu-24.04-base.dockerfile +++ b/scripts/docker/ubuntu-24.04-base.dockerfile @@ -42,4 +42,7 @@ COPY scripts/clickhouse/ubuntu-install-clickhouse.sh /userver_tmp/ RUN /userver_tmp/ubuntu-install-clickhouse.sh COPY scripts/rabbitmq/ubuntu_install_rabbitmq_dev.sh /userver_tmp/ -RUN /userver_tmp/ubuntu_install_rabbitmq_dev.sh +RUN /userver_tmp/ubuntu_install_rabbitmq_dev.sh + +COPY scripts/scylla/ubuntu-install-scylla.sh /userver_tmp/ +RUN /userver_tmp/ubuntu-install-scylla.sh diff --git a/scripts/docs/en/userver/build/options.md b/scripts/docs/en/userver/build/options.md index c120df154a0a..34f295a81694 100644 --- a/scripts/docs/en/userver/build/options.md +++ b/scripts/docs/en/userver/build/options.md @@ -26,6 +26,7 @@ userver is split into multiple CMake libraries. | `userver::rabbitmq` | `USERVER_FEATURE_RABBITMQ` | `rabbitmq` | @ref scripts/docs/en/userver/rabbitmq_driver.md | | `userver::mysql` | `USERVER_FEATURE_MYSQL` | `mysql` | @ref scripts/docs/en/userver/mysql/mysql_driver.md | | `userver::rocks` | `USERVER_FEATURE_ROCKS` | `rocks` | TODO | +| `userver::scylla` | `USERVER_FEATURE_SCYLLADB` | `scylla` | @ref scripts/docs/en/userver/scylladb.md | | `userver::sqlite` | `USERVER_FEATURE_SQLITE` | `sqlite` | @ref scripts/docs/en/userver/sqlite/sqlite_driver.md | | `userver::odbc` | `USERVER_FEATURE_ODBC` | `odbc` | @ref scripts/docs/en/userver/odbc.md | | `userver::ydb` | `USERVER_FEATURE_YDB` | `ydb` | @ref scripts/docs/en/userver/ydb.md | @@ -82,6 +83,7 @@ The exact format of setting cmake options varies depending on the method of buil | `USERVER_FEATURE_ROCKS` | Provide asynchronous driver for RocksDB | `${USERVER_BUILD_ALL_COMPONENTS}` | | `USERVER_FEATURE_SQLITE` | Provide asynchronous driver for SQLite | `${USERVER_BUILD_ALL_COMPONENTS}` | | `USERVER_FEATURE_ODBC` | Provide asynchronous driver for ODBC | `${USERVER_BUILD_ALL_COMPONENTS}` | +| `USERVER_FEATURE_SCYLLADB` | Provide asynchronous driver for ScyllaDB | `${USERVER_BUILD_ALL_COMPONENTS}` | | `USERVER_FEATURE_YDB` | Provide asynchronous driver for YDB | `${USERVER_BUILD_ALL_COMPONENTS}` AND C++ standard >= 20 | | `USERVER_FEATURE_OTLP` | Provide Logger for OpenTelemetry protocol | `${USERVER_BUILD_ALL_COMPONENTS}` | | `USERVER_FEATURE_GRPC_REFLECTION` | Provide reflection service for gRPC | `${USERVER_BUILD_ALL_COMPONENTS}` | diff --git a/scripts/scylla/ubuntu-install-scylla.sh b/scripts/scylla/ubuntu-install-scylla.sh new file mode 100755 index 000000000000..b97340aec43d --- /dev/null +++ b/scripts/scylla/ubuntu-install-scylla.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Exit on any error and treat unset variables as errors, print all commands +set -euox pipefail + +SCYLLA_CPP_DRIVER_VERSION=${SCYLLA_CPP_DRIVER_VERSION:=1.1.0} +RELEASE_URL="https://github.com/scylladb/cpp-rs-driver/releases/download/v${SCYLLA_CPP_DRIVER_VERSION}" + +apt update +apt install -y --no-install-recommends ca-certificates curl + +# Prebuilt packages of the ScyllaDB cpp-rs-driver, which provides the +# Cassandra compatible C++ API +curl -fsSLO "${RELEASE_URL}/scylla_cpp_driver_${SCYLLA_CPP_DRIVER_VERSION}_amd64.deb" +curl -fsSLO "${RELEASE_URL}/scylla_cpp_driver-dev_${SCYLLA_CPP_DRIVER_VERSION}_amd64.deb" +apt install -y --no-install-recommends ./scylla_cpp_driver*_amd64.deb +rm -f ./scylla_cpp_driver*.deb + +echo /usr/lib64 > /etc/ld.so.conf.d/scylla-cpp-driver.conf +ln -sf /usr/lib64/libscylladb.so /usr/lib/x86_64-linux-gnu/libscylla-cpp-driver.so +ldconfig diff --git a/scylla/src/storages/scylla/driver/session_impl.cpp b/scylla/src/storages/scylla/driver/session_impl.cpp index 522108738ea6..1c2d9e50b19d 100644 --- a/scylla/src/storages/scylla/driver/session_impl.cpp +++ b/scylla/src/storages/scylla/driver/session_impl.cpp @@ -181,7 +181,7 @@ DriverSessionImpl::DriverSessionImpl( clients::dns::Resolver*, std::optional ssl_secrets ) - : SessionImpl(std::move(id), session_config, config_source), + : SessionImpl(std::move(id), config_source), session_config_(session_config), ssl_secrets_(std::move(ssl_secrets)), default_keyspace_(session_config.default_keyspace), diff --git a/scylla/src/storages/scylla/session_config.cpp b/scylla/src/storages/scylla/session_config.cpp index b3d94e55cd6f..6699afb85117 100644 --- a/scylla/src/storages/scylla/session_config.cpp +++ b/scylla/src/storages/scylla/session_config.cpp @@ -1,6 +1,5 @@ #include -#include #include #include @@ -31,10 +30,10 @@ void IsValidDuration(const std::chrono::milliseconds& timeout, const char* field } } -constexpr Consistency kDefaultConsistency = Consistency::kLocalQuorum; -constexpr SerialConsistency kDefaultSerialConsistency = SerialConsistency::kLocalSerial; +[[maybe_unused]] constexpr Consistency kDefaultConsistency = Consistency::kLocalQuorum; +[[maybe_unused]] constexpr SerialConsistency kDefaultSerialConsistency = SerialConsistency::kLocalSerial; -std::optional ConsistencyFromRaw(uint16_t value) { +[[maybe_unused]] std::optional ConsistencyFromRaw(uint16_t value) { switch (value) { case 0x0000: return Consistency::kAny; diff --git a/scylla/src/storages/scylla/session_impl.cpp b/scylla/src/storages/scylla/session_impl.cpp index 0a024556bcb2..fcd500665794 100644 --- a/scylla/src/storages/scylla/session_impl.cpp +++ b/scylla/src/storages/scylla/session_impl.cpp @@ -5,7 +5,7 @@ USERVER_NAMESPACE_BEGIN namespace storages::scylla::impl { -SessionImpl::SessionImpl(std::string&& id, const SessionConfig session_config, dynamic_config::Source config_source) +SessionImpl::SessionImpl(std::string&& id, dynamic_config::Source config_source) : id_(std::move(id)), config_source_(config_source) {}; diff --git a/scylla/src/storages/scylla/session_impl.hpp b/scylla/src/storages/scylla/session_impl.hpp index 2d889520b664..b613effeeb69 100644 --- a/scylla/src/storages/scylla/session_impl.hpp +++ b/scylla/src/storages/scylla/session_impl.hpp @@ -46,7 +46,7 @@ class SessionImpl { virtual void ExecuteRawVoid(std::string_view query, const std::vector& params) = 0; protected: - SessionImpl(std::string&& id, const SessionConfig session_config, dynamic_config::Source config_source); + SessionImpl(std::string&& id, dynamic_config::Source config_source); private: const std::string id_;