|
@@ -5,20 +5,19 @@
|
|
#include "device.h"
|
|
#include "device.h"
|
|
#include "proto/proto-helpers.h"
|
|
#include "proto/proto-helpers.h"
|
|
#include "utils/time.h"
|
|
#include "utils/time.h"
|
|
-#include <limits>
|
|
|
|
-
|
|
|
|
-static constexpr auto undef = std::numeric_limits<uint32_t>::max();
|
|
|
|
|
|
|
|
using namespace syncspirit::model;
|
|
using namespace syncspirit::model;
|
|
|
|
|
|
-version_t::version_t() noexcept : best_index{undef} {}
|
|
|
|
|
|
+static constexpr std::uint64_t BEST_MASK = 1ull << 63;
|
|
|
|
+
|
|
|
|
+version_t::version_t() noexcept {}
|
|
|
|
|
|
version_t::version_t(const proto::Vector &v) noexcept {
|
|
version_t::version_t(const proto::Vector &v) noexcept {
|
|
auto counters_sz = proto::get_counters_size(v);
|
|
auto counters_sz = proto::get_counters_size(v);
|
|
assert(counters_sz);
|
|
assert(counters_sz);
|
|
counters.resize(counters_sz);
|
|
counters.resize(counters_sz);
|
|
auto best = proto::get_counters(v, 0);
|
|
auto best = proto::get_counters(v, 0);
|
|
- best_index = 0;
|
|
|
|
|
|
+ auto best_index = 0;
|
|
for (int i = 0; i < counters_sz; ++i) {
|
|
for (int i = 0; i < counters_sz; ++i) {
|
|
auto &c = proto::get_counters(v, i);
|
|
auto &c = proto::get_counters(v, i);
|
|
counters[i] = c;
|
|
counters[i] = c;
|
|
@@ -27,13 +26,14 @@ version_t::version_t(const proto::Vector &v) noexcept {
|
|
best_index = i;
|
|
best_index = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
|
|
-version_t::version_t(const device_t &device) noexcept : best_index{undef} {
|
|
|
|
- counters.reserve(1);
|
|
|
|
- update(device);
|
|
|
|
|
|
+ auto &selected = counters[best_index];
|
|
|
|
+ auto marked = proto::get_value(selected) | BEST_MASK;
|
|
|
|
+ proto::set_value(selected, marked);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+version_t::version_t(const device_t &device) noexcept { update(device); }
|
|
|
|
+
|
|
auto version_t::as_proto() const noexcept -> proto::Vector {
|
|
auto version_t::as_proto() const noexcept -> proto::Vector {
|
|
proto::Vector v;
|
|
proto::Vector v;
|
|
to_proto(v);
|
|
to_proto(v);
|
|
@@ -43,7 +43,9 @@ auto version_t::as_proto() const noexcept -> proto::Vector {
|
|
void version_t::to_proto(proto::Vector &v) const noexcept {
|
|
void version_t::to_proto(proto::Vector &v) const noexcept {
|
|
proto::clear_counters(v);
|
|
proto::clear_counters(v);
|
|
for (auto &c : counters) {
|
|
for (auto &c : counters) {
|
|
- proto::add_counters(v, c);
|
|
|
|
|
|
+ auto id = proto::get_id(c);
|
|
|
|
+ auto value = proto::get_value(c);
|
|
|
|
+ proto::add_counters(v, proto::Counter(id, value & ~BEST_MASK));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -52,43 +54,54 @@ void version_t::update(const device_t &device) noexcept {
|
|
auto id = device.device_id().get_uint();
|
|
auto id = device.device_id().get_uint();
|
|
auto v = static_cast<std::uint64_t>(utils::as_seconds(clock_t::universal_time()));
|
|
auto v = static_cast<std::uint64_t>(utils::as_seconds(clock_t::universal_time()));
|
|
auto counter = (proto::Counter *)(nullptr);
|
|
auto counter = (proto::Counter *)(nullptr);
|
|
- if (best_index != undef) {
|
|
|
|
- v = std::max(proto::get_value(counters[best_index]) + 1, v);
|
|
|
|
- best_index = undef;
|
|
|
|
- for (size_t i = 0; i < counters.size(); ++i) {
|
|
|
|
- if (proto::get_id(counters[i]) == id) {
|
|
|
|
- counter = &counters[i];
|
|
|
|
- best_index = i;
|
|
|
|
- break;
|
|
|
|
|
|
+ int best_index = -1;
|
|
|
|
+ for (auto &c : counters) {
|
|
|
|
+ auto value = proto::get_value(c);
|
|
|
|
+ if (value & BEST_MASK) {
|
|
|
|
+ v = std::max((proto::get_value(c) & ~BEST_MASK) + 1, v);
|
|
|
|
+ for (size_t i = 0; i < counters.size(); ++i) {
|
|
|
|
+ if (proto::get_id(counters[i]) == id) {
|
|
|
|
+ counter = &counters[i];
|
|
|
|
+ best_index = i;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if (best_index == undef) {
|
|
|
|
- counters.emplace_back(proto::Counter());
|
|
|
|
- counter = &counters.back();
|
|
|
|
- proto::set_id(*counter, id);
|
|
|
|
- best_index = &counters.back() - counters.data();
|
|
|
|
|
|
+ if (best_index < 0) {
|
|
|
|
+ auto copy = proto::Counter(id, v | BEST_MASK);
|
|
|
|
+ auto new_sz = counters.size();
|
|
|
|
+ counters.resize(new_sz + 1);
|
|
|
|
+ counters[new_sz] = std::move(copy);
|
|
|
|
+ best_index = new_sz;
|
|
|
|
+ } else {
|
|
|
|
+ assert(counter);
|
|
|
|
+ proto::set_value(*counter, v | BEST_MASK);
|
|
}
|
|
}
|
|
- proto::set_value(*counter, v);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-auto version_t::get_best() noexcept -> proto::Counter & {
|
|
|
|
- assert(best_index != undef);
|
|
|
|
- return counters[best_index];
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-auto version_t::get_best() const noexcept -> const proto::Counter & {
|
|
|
|
- assert(best_index != undef);
|
|
|
|
- return counters[best_index];
|
|
|
|
|
|
+auto version_t::get_best() const noexcept -> proto::Counter {
|
|
|
|
+ auto r = proto::Counter();
|
|
|
|
+ for (auto &c : counters) {
|
|
|
|
+ auto value = proto::get_value(c);
|
|
|
|
+ if (value & BEST_MASK) {
|
|
|
|
+ r = proto::Counter{proto::get_id(c), value & ~BEST_MASK};
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return r;
|
|
}
|
|
}
|
|
|
|
|
|
bool version_t::contains(const version_t &other) const noexcept {
|
|
bool version_t::contains(const version_t &other) const noexcept {
|
|
- auto &other_best = other.get_best();
|
|
|
|
|
|
+ auto other_best = other.get_best();
|
|
for (size_t i = 0; i < counters.size(); ++i) {
|
|
for (size_t i = 0; i < counters.size(); ++i) {
|
|
auto &c = counters[i];
|
|
auto &c = counters[i];
|
|
- auto ids_match = proto::get_id(c) == proto::get_id(other_best);
|
|
|
|
|
|
+ auto id_my = proto::get_id(c);
|
|
|
|
+ auto id_other = proto::get_id(other_best);
|
|
|
|
+ auto ids_match = id_my == id_other;
|
|
if (ids_match) {
|
|
if (ids_match) {
|
|
- return proto::get_value(c) >= proto::get_value(other_best);
|
|
|
|
|
|
+ auto value_my = proto::get_value(c) & ~BEST_MASK;
|
|
|
|
+ auto value_other = proto::get_value(other_best);
|
|
|
|
+ return value_my >= value_other;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
return false;
|
|
@@ -101,7 +114,9 @@ bool version_t::identical_to(const version_t &other) const noexcept {
|
|
auto end = p1 + counters.size();
|
|
auto end = p1 + counters.size();
|
|
while (p1 != end) {
|
|
while (p1 != end) {
|
|
auto ids_match = proto::get_id(*p1) == proto::get_id(*p2);
|
|
auto ids_match = proto::get_id(*p1) == proto::get_id(*p2);
|
|
- auto values_match = proto::get_value(*p1) == proto::get_value(*p2);
|
|
|
|
|
|
+ auto v1 = proto::get_value(*p1) & ~BEST_MASK;
|
|
|
|
+ auto v2 = proto::get_value(*p2) & ~BEST_MASK;
|
|
|
|
+ auto values_match = v1 == v2;
|
|
if (ids_match && values_match) {
|
|
if (ids_match && values_match) {
|
|
++p1;
|
|
++p1;
|
|
++p2;
|
|
++p2;
|
|
@@ -121,4 +136,13 @@ auto version_t::get_counter(size_t index) noexcept -> const proto::Counter & {
|
|
return counters[index];
|
|
return counters[index];
|
|
}
|
|
}
|
|
|
|
|
|
-auto version_t::get_counters() noexcept -> const counters_t & { return counters; }
|
|
|
|
|
|
+auto version_t::get_counters() const noexcept -> counters_t {
|
|
|
|
+ auto copy = counters_t();
|
|
|
|
+ copy.resize(counters.size());
|
|
|
|
+ for (std::uint32_t i = 0; i < counters.sz; ++i) {
|
|
|
|
+ auto id = proto::get_id(counters[i]);
|
|
|
|
+ auto value = proto::get_value(counters[i]) & ~BEST_MASK;
|
|
|
|
+ copy[i] = proto::Counter(id, value);
|
|
|
|
+ }
|
|
|
|
+ return counters;
|
|
|
|
+}
|