1
0
Fork 0

fixed epoch computation

This commit is contained in:
Frank Celler 2016-07-31 11:27:59 +02:00 committed by Wilfried Goesgens
parent 376075f51d
commit af6cbe272a
2 changed files with 128 additions and 48 deletions

View File

@ -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();
}

View File

@ -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