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