summaryrefslogtreecommitdiffstats
path: root/storage/src/vespa/storage/bucketdb/bucketinfo.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/src/vespa/storage/bucketdb/bucketinfo.hpp')
-rw-r--r--storage/src/vespa/storage/bucketdb/bucketinfo.hpp50
1 files changed, 50 insertions, 0 deletions
diff --git a/storage/src/vespa/storage/bucketdb/bucketinfo.hpp b/storage/src/vespa/storage/bucketdb/bucketinfo.hpp
index 562e8d562fb..07316ff0d71 100644
--- a/storage/src/vespa/storage/bucketdb/bucketinfo.hpp
+++ b/storage/src/vespa/storage/bucketdb/bucketinfo.hpp
@@ -2,6 +2,7 @@
#include "bucketcopy.h"
#include <vespa/vespalib/util/arrayref.h>
+#include <vespa/vespalib/stllike/hash_map.hpp>
#include <iostream>
#include <sstream>
@@ -65,6 +66,55 @@ bool BucketInfoBase<NodeSeq>::consistentNodes(bool countInvalidAsConsistent) con
return true;
}
+namespace {
+
+// BucketInfo wrapper which only concerns itself with fields that indicate
+// whether replicas are in sync.
+struct ReplicaMetadata {
+ api::BucketInfo info;
+
+ ReplicaMetadata() noexcept = default;
+ explicit ReplicaMetadata(const api::BucketInfo& info_) noexcept
+ : info(info_)
+ {}
+ bool operator==(const ReplicaMetadata& rhs) const noexcept {
+ // TODO merge state checker itself only considers checksum, should we do the same...?
+ return ((info.getChecksum() == rhs.info.getChecksum()) &&
+ (info.getDocumentCount() == rhs.info.getDocumentCount()));
+ }
+ struct hash {
+ size_t operator()(const ReplicaMetadata& rm) const noexcept {
+ // We assume that just using the checksum is extremely likely to be unique in the table.
+ return rm.info.getChecksum();
+ }
+ };
+};
+
+constexpr bool is_majority(size_t n, size_t m) {
+ return (n >= (m / 2) + 1);
+}
+
+}
+
+template <typename NodeSeq>
+api::BucketInfo BucketInfoBase<NodeSeq>::majority_consistent_bucket_info() const noexcept {
+ if (_nodes.size() < 3) {
+ return {};
+ }
+ vespalib::hash_map<ReplicaMetadata, uint16_t, ReplicaMetadata::hash> meta_tracker;
+ for (const auto& n : _nodes) {
+ if (n.valid()) {
+ meta_tracker[ReplicaMetadata(n.getBucketInfo())]++;
+ }
+ }
+ for (const auto& meta : meta_tracker) {
+ if (is_majority(meta.second, _nodes.size())) {
+ return meta.first.info;
+ }
+ }
+ return {};
+}
+
template <typename NodeSeq>
void BucketInfoBase<NodeSeq>::print(std::ostream& out, bool verbose, const std::string& indent) const {
if (_nodes.size() == 0) {