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