summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Brede Vekterli <vekterli@yahooinc.com>2023-06-01 16:39:20 +0200
committerGitHub <noreply@github.com>2023-06-01 16:39:20 +0200
commitd532338aaf7d7f4393f728996f98dfc9ae998d2e (patch)
treefc86e9756af7d7fdf0c44c81be083ff7f23e056b
parentc9bd5bf0a8975ff0b187393b87720e07c6619ff9 (diff)
parent9ec7fc5001f0eff5bda7befda8a34022160949bc (diff)
Merge pull request #27258 from vespa-engine/vekterli/improved-guarding-against-bucket-ownership-change-between-phases
Explicitly detect changed bucket ownership between read and write phases
-rw-r--r--storage/src/tests/distributor/check_condition_test.cpp13
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/check_condition.cpp7
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/check_condition.h1
3 files changed, 20 insertions, 1 deletions
diff --git a/storage/src/tests/distributor/check_condition_test.cpp b/storage/src/tests/distributor/check_condition_test.cpp
index ee8c9b888bb..d355194ec0d 100644
--- a/storage/src/tests/distributor/check_condition_test.cpp
+++ b/storage/src/tests/distributor/check_condition_test.cpp
@@ -242,6 +242,19 @@ TEST_F(CheckConditionTest, check_fails_if_replica_set_changed_between_start_and_
});
}
+TEST_F(CheckConditionTest, check_fails_if_bucket_ownership_changed_between_start_and_completion) {
+ test_cond_with_2_gets_sent([&](auto& cond) {
+ cond.handle_reply(_sender, make_matched_reply(0));
+ enable_cluster_state("version:2 storage:1 distributor:1 .0.s:d"); // technically, no distributors own anything
+ cond.handle_reply(_sender, make_matched_reply(1));
+ }, [&](auto& outcome) {
+ EXPECT_FALSE(outcome.matched_condition());
+ EXPECT_FALSE(outcome.not_found());
+ EXPECT_TRUE(outcome.failed());
+ EXPECT_EQ(outcome.error_code().getResult(), api::ReturnCode::BUCKET_NOT_FOUND);
+ });
+}
+
TEST_F(CheckConditionTest, nested_get_traces_are_propagated_to_outcome) {
test_cond_with_2_gets_sent([&](auto& cond) {
cond.handle_reply(_sender, make_trace_reply(0, 100, "hello"));
diff --git a/storage/src/vespa/storage/distributor/operations/external/check_condition.cpp b/storage/src/vespa/storage/distributor/operations/external/check_condition.cpp
index fc619d9eb23..c5f4788ec51 100644
--- a/storage/src/vespa/storage/distributor/operations/external/check_condition.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/check_condition.cpp
@@ -127,6 +127,10 @@ bool CheckCondition::replica_set_changed_after_get_operation() const {
return (replicas_in_db_now != _cond_get_op->replicas_in_db());
}
+bool CheckCondition::distributor_no_longer_owns_bucket() const {
+ return !_bucket_space.check_ownership_in_pending_and_current_state(_doc_id_bucket.getBucketId()).isOwned();
+}
+
CheckCondition::Outcome::Result
CheckCondition::newest_replica_to_outcome(const std::optional<NewestReplica>& newest) noexcept {
if (!newest) {
@@ -161,7 +165,8 @@ void CheckCondition::handle_internal_get_operation_reply(std::shared_ptr<api::St
}
const auto state_version_now = _bucket_space.getClusterState().getVersion();
if ((state_version_now != _cluster_state_version_at_creation_time)
- && replica_set_changed_after_get_operation())
+ && (replica_set_changed_after_get_operation()
+ || distributor_no_longer_owns_bucket()))
{
// BUCKET_NOT_FOUND is semantically (usually) inaccurate here, but it's what we use for this purpose
// in existing operations. Checking the replica set will implicitly check for ownership changes,
diff --git a/storage/src/vespa/storage/distributor/operations/external/check_condition.h b/storage/src/vespa/storage/distributor/operations/external/check_condition.h
index 382aec6242c..999b79adc3d 100644
--- a/storage/src/vespa/storage/distributor/operations/external/check_condition.h
+++ b/storage/src/vespa/storage/distributor/operations/external/check_condition.h
@@ -139,6 +139,7 @@ public:
uint32_t trace_level);
private:
[[nodiscard]] bool replica_set_changed_after_get_operation() const;
+ [[nodiscard]] bool distributor_no_longer_owns_bucket() const;
void handle_internal_get_operation_reply(std::shared_ptr<api::StorageReply> reply);