Details
Description
LogicalClock class provides API to change the LogicalTime. Currently its done via global functions in global_timestamp where the equivalent of LogicalTime class is AtomicUInt64.
The suggested LogicalClock API:
|
class LogicalClock:
|
public:
|
void setClusterTime(const LogicalTime& newTime);
|
const LogicalTime& getClusterTime() const;
|
|
// increments clusterTime and return the result. this method should sync with the wall clock
|
LogicalTime addTicks(unsigned ticks);
|
|
// increments clusterTime but returns the time before the increment therefor "reserving" ticks.
|
// Needed for the batch writes oplog functionality. this method should sync with the wall clock
|
LogicalTime reserveTicks(unsigned ticks);
|
|
private:
|
mutable stdx::mutex _mutex; // unless there is a measurable performance degradation
|
// serialize on mutex
|
LogicalTime _clusterTime;
|
};
|
|
LogicalTime LogicalClock::reserveTicks(unsigned ticks) {
|
|
const unsigned wallClockSecs = durationCount<Seconds>(
|
getGlobalServiceContext()->getFastClockSource()->now().toDurationSinceEpoch());
|
|
stdx::lock_guard<stdx::mutex> lock(_mutex);
|
// Optimistic assumption that seconds did not change
|
LogicalTime currentTime = _clusterTime;
|
_clusterTime.addTicks(ticks);
|
|
unsigned currentSecs = _clusterTime.asTimestamp().getSecs();
|
// If the seconds need to be updated, try to do it. This can happen at most once per second.
|
if (MONGO_unlikely(currentSecs < wallClockSecs)) {
|
// First fix the seconds portion.
|
_clusterTime = LogicalTime(Timestamp(wallClockSecs, 1));
|
currentTime = _clusterTime;
|
_clusterTime.addTicks(ticks);
|
}
|
|
return currentTime;
|
}
|
|
The Implementation should decouple RateCheck into a separate class and depend on it.
The task should include unit tests that will need mock for the wall clocks that will verify API