From 95d9efa8395b6033572604f19557914a59cbdc59 Mon Sep 17 00:00:00 2001 From: Dimitris Christodoulou Date: Wed, 13 Dec 2023 12:09:12 +0000 Subject: [PATCH 1/2] CXXCBC-412: Support document_not_locked --- core/impl/key_value_error_category.cxx | 6 ++++-- core/meta/features.hxx | 5 +++++ core/protocol/status.cxx | 3 +++ core/protocol/status.hxx | 1 + couchbase/error_codes.hxx | 23 ++++++++++++++++++++++- couchbase/fmt/key_value_status_code.hxx | 3 +++ couchbase/key_value_status_code.hxx | 1 + test/test_integration_crud.cxx | 18 ++++++++++++++++++ test/utils/server_version.hxx | 5 +++++ 9 files changed, 62 insertions(+), 3 deletions(-) diff --git a/core/impl/key_value_error_category.cxx b/core/impl/key_value_error_category.cxx index 20452659c..e09d527f2 100644 --- a/core/impl/key_value_error_category.cxx +++ b/core/impl/key_value_error_category.cxx @@ -80,10 +80,12 @@ struct key_value_error_category : std::error_category { return "xattr_unknown_virtual_attribute (127)"; case errc::key_value::xattr_cannot_modify_virtual_attribute: return "xattr_cannot_modify_virtual_attribute (128)"; - case errc::key_value::cannot_revive_living_document: - return "cannot_revive_living_document (131)"; case errc::key_value::xattr_no_access: return "xattr_no_access (130)"; + case errc::key_value::document_not_locked: + return "document_not_locked (131)"; + case errc::key_value::cannot_revive_living_document: + return "cannot_revive_living_document (132)"; case errc::key_value::mutation_token_outdated: return "mutation_token_outdated (133)"; case errc::key_value::range_scan_completed: diff --git a/core/meta/features.hxx b/core/meta/features.hxx index e241d2fa3..ca0ebeb67 100644 --- a/core/meta/features.hxx +++ b/core/meta/features.hxx @@ -96,3 +96,8 @@ * couchbase::cluster::search_query() and couchbase::scope::search_query() support */ #define COUCHBASE_CXX_CLIENT_HAS_PUBLIC_SEARCH 1 + +/** + * The document not locked (couchbase::errc::key_value::document_not_locked) error code is supported + */ +#define COUCHBASE_CXX_CLIENT_HAS_DOCUMENT_NOT_LOCKED diff --git a/core/protocol/status.cxx b/core/protocol/status.cxx index 11c440dcd..1b829c10d 100644 --- a/core/protocol/status.cxx +++ b/core/protocol/status.cxx @@ -80,6 +80,9 @@ map_status_code(protocol::client_opcode opcode, std::uint16_t status) } return errc::key_value::document_locked; + case key_value_status_code::not_locked: + return errc::key_value::document_not_locked; + case key_value_status_code::auth_stale: case key_value_status_code::auth_error: case key_value_status_code::no_access: diff --git a/core/protocol/status.hxx b/core/protocol/status.hxx index 0ae48979e..8234427e7 100644 --- a/core/protocol/status.hxx +++ b/core/protocol/status.hxx @@ -41,6 +41,7 @@ is_valid_status(std::uint16_t code) case key_value_status_code::not_my_vbucket: case key_value_status_code::no_bucket: case key_value_status_code::locked: + case key_value_status_code::not_locked: case key_value_status_code::auth_stale: case key_value_status_code::auth_error: case key_value_status_code::auth_continue: diff --git a/couchbase/error_codes.hxx b/couchbase/error_codes.hxx index 24e6160e4..2d1d918d9 100644 --- a/couchbase/error_codes.hxx +++ b/couchbase/error_codes.hxx @@ -590,6 +590,15 @@ enum class key_value { // KV Code: 0x24 xattr_no_access = 130, + /** + * The document is already locked - generally returned when an unlocking operation is being performed. + * + * @since 1.0.0 + * @committed + */ + // KV Code: 0x0e + document_not_locked = 131, + /** * Only deleted document could be revived * @@ -597,9 +606,21 @@ enum class key_value { * @committed */ // KV Code: 0xd6 - cannot_revive_living_document = 131, + cannot_revive_living_document = 132, + /** + * The provided mutation token is outdated compared to the current state of the server. + * + * @since 1.0.0 + * @uncommitted + */ + // KV Code: 0xa8 mutation_token_outdated = 133, + + /** + * @internal + */ + // KV Code: 0xa7 range_scan_completed = 134, }; diff --git a/couchbase/fmt/key_value_status_code.hxx b/couchbase/fmt/key_value_status_code.hxx index 8133bc91b..cd605d5e7 100644 --- a/couchbase/fmt/key_value_status_code.hxx +++ b/couchbase/fmt/key_value_status_code.hxx @@ -71,6 +71,9 @@ struct fmt::formatter { case key_value_status_code::locked: name = "locked (0x09)"; break; + case key_value_status_code::not_locked: + name = "not_locked (0x0e)"; + break; case key_value_status_code::auth_stale: name = "auth_stale (0x1f)"; break; diff --git a/couchbase/key_value_status_code.hxx b/couchbase/key_value_status_code.hxx index c08cd24d0..9c98c5353 100644 --- a/couchbase/key_value_status_code.hxx +++ b/couchbase/key_value_status_code.hxx @@ -34,6 +34,7 @@ enum class key_value_status_code : std::uint16_t { dcp_stream_not_found = 0x0a, opaque_no_match = 0x0b, locked = 0x09, + not_locked = 0x0e, auth_stale = 0x1f, auth_error = 0x20, auth_continue = 0x21, diff --git a/test/test_integration_crud.cxx b/test/test_integration_crud.cxx index 9b1135d75..1ec5a4e99 100644 --- a/test/test_integration_crud.cxx +++ b/test/test_integration_crud.cxx @@ -297,6 +297,16 @@ TEST_CASE("integration: pessimistic locking", "[integration]") auto resp = test::utils::execute(integration.cluster, req); REQUIRE_SUCCESS(resp.ctx.ec()); } + + if (integration.cluster_version().supports_document_not_locked_status()) { + // if unlock is performer again, a document_not_locked error code should be returned + { + couchbase::core::operations::unlock_request req{ id }; + req.cas = cas; + auto resp = test::utils::execute(integration.cluster, req); + REQUIRE(resp.ctx.ec() == couchbase::errc::key_value::document_not_locked); + } + } } TEST_CASE("integration: lock/unlock without lock time", "[integration]") @@ -909,6 +919,14 @@ TEST_CASE("integration: pessimistic locking with public API", "[integration]") REQUIRE_SUCCESS(ctx.ec()); } + if (integration.cluster_version().supports_document_not_locked_status()) { + // if unlock is performer again, a document_not_locked error code should be returned + { + auto ctx = collection.unlock(id, cas, {}).get(); + REQUIRE(ctx.ec() == couchbase::errc::key_value::document_not_locked); + } + } + // now the key is not locked { auto [ctx, resp] = collection.upsert(id, basic_doc, {}).get(); diff --git a/test/utils/server_version.hxx b/test/utils/server_version.hxx index 42518d849..ebc981d92 100644 --- a/test/utils/server_version.hxx +++ b/test/utils/server_version.hxx @@ -221,6 +221,11 @@ struct server_version { return supports_search() && (is_mad_hatter() || is_cheshire_cat() || is_neo()); } + [[nodiscard]] bool supports_document_not_locked_status() const + { + return !use_gocaves && (major > 7 || (major == 7 && minor >= 6)); + } + [[nodiscard]] bool is_capella() const { return deployment == deployment_type::capella; From cfafe3a83f93a79f5a07e0588268738b47b0ef99 Mon Sep 17 00:00:00 2001 From: Dimitris Christodoulou Date: Wed, 13 Dec 2023 13:25:20 +0000 Subject: [PATCH 2/2] Update feature macro --- core/meta/features.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/meta/features.hxx b/core/meta/features.hxx index ca0ebeb67..b93f7d628 100644 --- a/core/meta/features.hxx +++ b/core/meta/features.hxx @@ -100,4 +100,4 @@ /** * The document not locked (couchbase::errc::key_value::document_not_locked) error code is supported */ -#define COUCHBASE_CXX_CLIENT_HAS_DOCUMENT_NOT_LOCKED +#define COUCHBASE_CXX_CLIENT_HAS_ERRC_DOCUMENT_NOT_LOCKED 1