mirror of https://gitee.com/bigwinds/arangodb
fixed epoch computation
This commit is contained in:
parent
376075f51d
commit
af6cbe272a
|
@ -23,23 +23,96 @@
|
|||
|
||||
#include "Basics/HybridLogicalClock.h"
|
||||
|
||||
char arangodb::basics::HybridLogicalClock::encodeTable[65]
|
||||
= "-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
namespace {
|
||||
template <typename DurationT, typename ReprT = typename DurationT::rep>
|
||||
constexpr DurationT maxDuration() noexcept {
|
||||
return DurationT{std::numeric_limits<ReprT>::max()};
|
||||
}
|
||||
|
||||
signed char arangodb::basics::HybridLogicalClock::decodeTable[256]
|
||||
= {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 0 - 15
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 16 - 31
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1, // 32 - 47
|
||||
54,55,56,57,58,59,60,61,62,63,-1,-1,-1,-1,-1,-1, // 48 - 63
|
||||
-1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16, // 64 - 79
|
||||
17,18,19,20,21,22,23,24,25,26,27,-1,-1,-1,-1, 1, // 80 - 95
|
||||
-1,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42, // 96 - 111
|
||||
43,44,45,46,47,48,49,50,51,52,53,-1,-1,-1,-1,-1, // 112 - 127
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 128 - 143
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 144 - 159
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 160 - 175
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 176 - 191
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 192 - 207
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 208 - 223
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 224 - 239
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; // 240 - 255
|
||||
template <typename DurationT>
|
||||
constexpr DurationT absDuration(const DurationT d) noexcept {
|
||||
return DurationT{(d.count() < 0) ? -d.count() : d.count()};
|
||||
}
|
||||
|
||||
template <typename SrcTimePointT, typename DstTimePointT,
|
||||
typename SrcDurationT = typename SrcTimePointT::duration,
|
||||
typename DstDurationT = typename DstTimePointT::duration,
|
||||
typename SrcClockT = typename SrcTimePointT::clock,
|
||||
typename DstClockT = typename DstTimePointT::clock>
|
||||
DstDurationT clockOffset(
|
||||
const SrcDurationT tolerance =
|
||||
std::chrono::duration_cast<SrcDurationT>(std::chrono::nanoseconds{300}),
|
||||
const int limit = 10000) {
|
||||
if (std::is_same<SrcClockT, DstClockT>::value) {
|
||||
return DstDurationT{};
|
||||
}
|
||||
|
||||
auto itercnt = 0;
|
||||
auto src_now = SrcTimePointT{};
|
||||
auto dst_now = DstTimePointT{};
|
||||
auto epsilon = maxDuration<SrcDurationT>();
|
||||
do {
|
||||
const auto src_before = SrcClockT::now();
|
||||
const auto dst_between = DstClockT::now();
|
||||
const auto src_after = SrcClockT::now();
|
||||
const auto src_diff = src_after - src_before;
|
||||
const auto delta = absDuration(src_diff);
|
||||
if (delta < epsilon) {
|
||||
src_now = src_before + src_diff / 2;
|
||||
dst_now = dst_between;
|
||||
epsilon = delta;
|
||||
}
|
||||
if (++itercnt >= limit) {
|
||||
break;
|
||||
}
|
||||
} while (epsilon > tolerance);
|
||||
|
||||
auto diff1970 = SrcClockT::from_time_t(0) - src_now;
|
||||
|
||||
return (dst_now + diff1970).time_since_epoch();
|
||||
}
|
||||
}
|
||||
|
||||
char arangodb::basics::HybridLogicalClock::encodeTable[65] =
|
||||
"-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
signed char arangodb::basics::HybridLogicalClock::decodeTable[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 0 - 15
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 16 - 31
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, 0, -1, -1, // 32 - 47
|
||||
54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, -1, -1, -1, -1, -1, -1, // 48 - 63
|
||||
-1, 2, 3, 4, 5, 6, 7, 8,
|
||||
9, 10, 11, 12, 13, 14, 15, 16, // 64 - 79
|
||||
17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, -1, -1, -1, -1, 1, // 80 - 95
|
||||
-1, 28, 29, 30, 31, 32, 33, 34,
|
||||
35, 36, 37, 38, 39, 40, 41, 42, // 96 - 111
|
||||
43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, -1, -1, -1, -1, -1, // 112 - 127
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 128 - 143
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 144 - 159
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 160 - 175
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 176 - 191
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 192 - 207
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 208 - 223
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // 224 - 239
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1}; // 240 - 255
|
||||
|
||||
uint64_t arangodb::basics::HybridLogicalClock::computeOffset1970() {
|
||||
auto diff = clockOffset<std::chrono::system_clock::time_point,
|
||||
HybridLogicalClock::ClockT::time_point>();
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(diff).count();
|
||||
}
|
||||
|
|
|
@ -32,12 +32,16 @@ namespace arangodb {
|
|||
namespace basics {
|
||||
|
||||
class HybridLogicalClock {
|
||||
std::chrono::high_resolution_clock clock;
|
||||
std::atomic<uint64_t> lastTimeStamp;
|
||||
public:
|
||||
typedef std::chrono::high_resolution_clock ClockT;
|
||||
|
||||
private:
|
||||
ClockT _clock;
|
||||
std::atomic<uint64_t> _lastTimeStamp;
|
||||
uint64_t _offset1970;
|
||||
|
||||
public:
|
||||
HybridLogicalClock() : lastTimeStamp(0) {
|
||||
}
|
||||
HybridLogicalClock() : _lastTimeStamp(0), _offset1970(computeOffset1970()) {}
|
||||
HybridLogicalClock(HybridLogicalClock const& other) = delete;
|
||||
HybridLogicalClock(HybridLogicalClock&& other) = delete;
|
||||
HybridLogicalClock& operator=(HybridLogicalClock const& other) = delete;
|
||||
|
@ -48,13 +52,15 @@ class HybridLogicalClock {
|
|||
uint64_t newTimeStamp;
|
||||
do {
|
||||
uint64_t physical = getPhysicalTime();
|
||||
oldTimeStamp = lastTimeStamp.load(std::memory_order_relaxed);
|
||||
oldTimeStamp = _lastTimeStamp.load(std::memory_order_relaxed);
|
||||
uint64_t oldTime = extractTime(oldTimeStamp);
|
||||
newTimeStamp = (physical <= oldTime) ?
|
||||
assembleTimeStamp(oldTime, extractCount(oldTimeStamp)+1) :
|
||||
assembleTimeStamp(physical, 0);
|
||||
} while (!lastTimeStamp.compare_exchange_weak(oldTimeStamp, newTimeStamp,
|
||||
std::memory_order_release, std::memory_order_relaxed));
|
||||
newTimeStamp =
|
||||
(physical <= oldTime)
|
||||
? assembleTimeStamp(oldTime, extractCount(oldTimeStamp) + 1)
|
||||
: assembleTimeStamp(physical, 0);
|
||||
} while (!_lastTimeStamp.compare_exchange_weak(oldTimeStamp, newTimeStamp,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed));
|
||||
return newTimeStamp;
|
||||
}
|
||||
|
||||
|
@ -64,17 +70,18 @@ class HybridLogicalClock {
|
|||
uint64_t newTimeStamp;
|
||||
do {
|
||||
uint64_t physical = getPhysicalTime();
|
||||
oldTimeStamp = lastTimeStamp.load(std::memory_order_relaxed);
|
||||
oldTimeStamp = _lastTimeStamp.load(std::memory_order_relaxed);
|
||||
uint64_t oldTime = extractTime(oldTimeStamp);
|
||||
uint64_t recTime = extractTime(receivedTimeStamp);
|
||||
uint64_t newTime = (std::max)((std::max)(oldTime, physical),recTime);
|
||||
uint64_t newTime = (std::max)((std::max)(oldTime, physical), recTime);
|
||||
// Note that this implies newTime >= oldTime and newTime >= recTime
|
||||
uint64_t newCount;
|
||||
if (newTime == oldTime) {
|
||||
if (newTime == recTime) {
|
||||
// all three identical
|
||||
newCount = (std::max)(extractCount(oldTimeStamp),
|
||||
extractCount(receivedTimeStamp))+1;
|
||||
extractCount(receivedTimeStamp)) +
|
||||
1;
|
||||
} else {
|
||||
// this means recTime < newTime
|
||||
newCount = extractCount(oldTimeStamp) + 1;
|
||||
|
@ -88,8 +95,9 @@ class HybridLogicalClock {
|
|||
}
|
||||
}
|
||||
newTimeStamp = assembleTimeStamp(newTime, newCount);
|
||||
} while (!lastTimeStamp.compare_exchange_weak(oldTimeStamp, newTimeStamp,
|
||||
std::memory_order_release, std::memory_order_relaxed));
|
||||
} while (!_lastTimeStamp.compare_exchange_weak(oldTimeStamp, newTimeStamp,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed));
|
||||
return newTimeStamp;
|
||||
}
|
||||
|
||||
|
@ -100,7 +108,7 @@ class HybridLogicalClock {
|
|||
r[--pos] = encodeTable[static_cast<uint8_t>(t & 0x3ful)];
|
||||
t >>= 6;
|
||||
}
|
||||
return r.substr(pos, 11-pos);
|
||||
return r.substr(pos, 11 - pos);
|
||||
}
|
||||
|
||||
static uint64_t decodeTimeStamp(std::string const& s) {
|
||||
|
@ -137,21 +145,22 @@ class HybridLogicalClock {
|
|||
}
|
||||
|
||||
private:
|
||||
// Helper to get the physical time in milliseconds since the epoch:
|
||||
// helper to compute the offset between epoch and 1970
|
||||
uint64_t computeOffset1970();
|
||||
|
||||
// helper to get the physical time in milliseconds since the epoch:
|
||||
uint64_t getPhysicalTime() {
|
||||
auto now = clock.now();
|
||||
auto now = _clock.now();
|
||||
uint64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch()).count();
|
||||
now.time_since_epoch())
|
||||
.count() -
|
||||
_offset1970;
|
||||
return ms;
|
||||
}
|
||||
|
||||
static uint64_t extractTime(uint64_t t) {
|
||||
return t >> 20;
|
||||
}
|
||||
static uint64_t extractTime(uint64_t t) { return t >> 20; }
|
||||
|
||||
static uint64_t extractCount(uint64_t t) {
|
||||
return t & 0xfffffUL;
|
||||
}
|
||||
static uint64_t extractCount(uint64_t t) { return t & 0xfffffUL; }
|
||||
|
||||
static uint64_t assembleTimeStamp(uint64_t time, uint64_t count) {
|
||||
return (time << 20) + count;
|
||||
|
@ -160,10 +169,8 @@ class HybridLogicalClock {
|
|||
static char encodeTable[65];
|
||||
|
||||
static signed char decodeTable[256];
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}; // namespace basics
|
||||
}; // namespace arangodb
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue