diff --git a/include/wsrep/sr_key_set.hpp b/include/wsrep/sr_key_set.hpp index 69227f5f..efa2c7e7 100644 --- a/include/wsrep/sr_key_set.hpp +++ b/include/wsrep/sr_key_set.hpp @@ -36,6 +36,7 @@ namespace wsrep : root_() { } void insert(const wsrep::key& key); + bool contains(const wsrep::key& key) const; const branch_type& root() const { return root_; } void clear(); bool empty() const { return root_.empty(); } diff --git a/include/wsrep/transaction.hpp b/include/wsrep/transaction.hpp index 3328c093..8f29c188 100644 --- a/include/wsrep/transaction.hpp +++ b/include/wsrep/transaction.hpp @@ -171,6 +171,8 @@ namespace wsrep int append_key(const wsrep::key&); + bool has_key(const wsrep::key&) const; + int append_data(const wsrep::const_buffer&); int after_row(); diff --git a/src/sr_key_set.cpp b/src/sr_key_set.cpp index 31b6e692..95a095a1 100644 --- a/src/sr_key_set.cpp +++ b/src/sr_key_set.cpp @@ -37,6 +37,26 @@ void wsrep::sr_key_set::insert(const wsrep::key& key) key.key_parts()[1].size())); } +bool wsrep::sr_key_set::contains(const wsrep::key& key) const +{ + assert(key.size() >= 2); + if (key.size() < 2) + { + throw wsrep::runtime_error("Invalid key size"); + } + + std::string key_part_1(static_cast(key.key_parts()[0].data()), + key.key_parts()[0].size()); + std::string key_part_2(static_cast(key.key_parts()[1].data()), + key.key_parts()[1].size()); + + auto it(root_.find(key_part_1)); + if (it == root_.end()) + return false; + leaf_type leafs(it->second); + return (leafs.find(key_part_2) != leafs.end()); +} + void wsrep::sr_key_set::clear() { root_.clear(); diff --git a/src/transaction.cpp b/src/transaction.cpp index c5e5bf3b..16e1fa8a 100644 --- a/src/transaction.cpp +++ b/src/transaction.cpp @@ -253,6 +253,12 @@ int wsrep::transaction::append_key(const wsrep::key& key) } } +bool wsrep::transaction::has_key(const wsrep::key& key) const +{ + assert(active()); + return sr_keys_.contains(key); +} + int wsrep::transaction::append_data(const wsrep::const_buffer& data) { assert(active()); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 366cc478..bc7c1e3d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,6 +14,7 @@ set(TEST_SOURCES nbo_test.cpp rsu_test.cpp server_context_test.cpp + sr_key_set_test.cpp toi_test.cpp transaction_test.cpp transaction_test_2pc.cpp diff --git a/test/sr_key_set_test.cpp b/test/sr_key_set_test.cpp new file mode 100644 index 00000000..2601199f --- /dev/null +++ b/test/sr_key_set_test.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wsrep-lib. If not, see . + */ + +#include "wsrep/key.hpp" +#include "wsrep/sr_key_set.hpp" +#include + +static void append_key_parts(wsrep::key& key, + const std::vector& parts) +{ + for (const std::string& part : parts) + { + key.append_key_part(part.c_str(), part.length()); + } +} + +BOOST_AUTO_TEST_CASE(sr_key_set_test_contains) +{ + wsrep::sr_key_set key_set; + + { // contains same key + wsrep::key key(wsrep::key::exclusive); + std::vector parts = { "1", "2" }; + append_key_parts(key, parts); + BOOST_REQUIRE(!key_set.contains(key)); + key_set.insert(key); + BOOST_REQUIRE(key_set.contains(key)); + } + + { // contains same key with different type + wsrep::key key(wsrep::key::shared); + std::vector parts = { "1", "2" }; + append_key_parts(key, parts); + BOOST_REQUIRE(key_set.contains(key)); + } + + { // contains same key with one more level + wsrep::key key(wsrep::key::shared); + std::vector parts = { "1", "2", "3" }; + append_key_parts(key, parts); + BOOST_REQUIRE(key_set.contains(key)); + } + + { // does not contain different key first at first level + wsrep::key key(wsrep::key::shared); + std::vector parts = { "different", "2" }; + append_key_parts(key, parts); + BOOST_REQUIRE(!key_set.contains(key)); + } + + { // does not contain different key part at second level + wsrep::key key(wsrep::key::shared); + std::vector parts = { "1", "different" }; + append_key_parts(key, parts); + BOOST_REQUIRE(!key_set.contains(key)); + } +}