kudu-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t...@apache.org
Subject [3/3] kudu git commit: Move clock-related classes to src/kudu/clock
Date Thu, 03 Aug 2017 19:02:55 GMT
Move clock-related classes to src/kudu/clock

This creates a new module for clock-related classes (currently just
logical and hybrid clock). This is in preparation for introducing
a built-in NTP client.

Since these clock-related classes don't depend on anything else in the
server, it makes sense to move them into a new small module.

Change-Id: Id4f49be6944ec636387f0c9f5721355402e51fc2
Reviewed-on: http://gerrit.cloudera.org:8080/7519
Reviewed-by: Adar Dembo <adar@cloudera.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/7ff27dcf
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/7ff27dcf
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/7ff27dcf

Branch: refs/heads/master
Commit: 7ff27dcf1191d4cbca297fdfdbfdd99d8eec7182
Parents: c386310
Author: Todd Lipcon <todd@apache.org>
Authored: Wed Jul 26 13:27:37 2017 -0700
Committer: Todd Lipcon <todd@apache.org>
Committed: Wed Aug 2 18:55:27 2017 +0000

----------------------------------------------------------------------
 CMakeLists.txt                                  |   1 +
 src/kudu/client/client-test.cc                  |  10 +-
 src/kudu/clock/CMakeLists.txt                   |  28 ++
 src/kudu/clock/clock.h                          | 112 +++++
 src/kudu/clock/hybrid_clock-test.cc             | 293 +++++++++++
 src/kudu/clock/hybrid_clock.cc                  | 495 +++++++++++++++++++
 src/kudu/clock/hybrid_clock.h                   | 224 +++++++++
 src/kudu/clock/logical_clock-test.cc            |  87 ++++
 src/kudu/clock/logical_clock.cc                 | 106 ++++
 src/kudu/clock/logical_clock.h                  |  87 ++++
 src/kudu/consensus/CMakeLists.txt               |   2 +-
 src/kudu/consensus/consensus-test-util.h        |   4 +-
 src/kudu/consensus/consensus_peers-test.cc      |   8 +-
 src/kudu/consensus/consensus_queue-test.cc      |   8 +-
 src/kudu/consensus/log-test-base.h              |  10 +-
 src/kudu/consensus/log_cache-test.cc            |   6 +-
 src/kudu/consensus/raft_consensus.cc            |   2 +-
 .../consensus/raft_consensus_quorum-test.cc     |   6 +-
 src/kudu/consensus/time_manager-test.cc         |  12 +-
 src/kudu/consensus/time_manager.cc              |   2 +-
 src/kudu/consensus/time_manager.h               |   6 +-
 src/kudu/integration-tests/alter_table-test.cc  |   6 +-
 .../authn_token_expire-itest.cc                 |  12 +-
 src/kudu/integration-tests/consistency-itest.cc |  14 +-
 src/kudu/integration-tests/fuzz-itest.cc        |  10 +-
 .../integration-tests/linked_list-test-util.h   |   8 +-
 .../tablet_history_gc-itest.cc                  |   4 +-
 src/kudu/integration-tests/ts_recovery-itest.cc |  10 +-
 src/kudu/master/CMakeLists.txt                  |   2 +-
 src/kudu/master/sys_catalog.cc                  |   4 +-
 src/kudu/server/CMakeLists.txt                  |  30 +-
 src/kudu/server/clock.h                         | 116 -----
 src/kudu/server/generic_service.cc              |   8 +-
 src/kudu/server/hybrid_clock-test.cc            | 293 -----------
 src/kudu/server/hybrid_clock.cc                 | 495 -------------------
 src/kudu/server/hybrid_clock.h                  | 228 ---------
 src/kudu/server/logical_clock-test.cc           |  87 ----
 src/kudu/server/logical_clock.cc                | 106 ----
 src/kudu/server/logical_clock.h                 |  92 ----
 src/kudu/server/server_base.cc                  |  10 +-
 src/kudu/server/server_base.h                   |  10 +-
 src/kudu/tablet/CMakeLists.txt                  |   2 +-
 src/kudu/tablet/compaction-test.cc              |   6 +-
 src/kudu/tablet/compaction.cc                   |   4 +-
 src/kudu/tablet/deltamemstore-test.cc           |   8 +-
 src/kudu/tablet/diskrowset-test-base.h          |   8 +-
 src/kudu/tablet/major_delta_compaction-test.cc  |   4 +-
 src/kudu/tablet/memrowset-test.cc               |   6 +-
 src/kudu/tablet/mvcc-test.cc                    |  12 +-
 src/kudu/tablet/mvcc.cc                         |   2 +-
 src/kudu/tablet/mvcc.h                          |   2 +-
 src/kudu/tablet/tablet-harness.h                |  12 +-
 src/kudu/tablet/tablet-test-util.h              |   2 +-
 src/kudu/tablet/tablet.cc                       |   7 +-
 src/kudu/tablet/tablet.h                        |  21 +-
 src/kudu/tablet/tablet_bootstrap-test.cc        |  13 +-
 src/kudu/tablet/tablet_bootstrap.cc             |  12 +-
 src/kudu/tablet/tablet_bootstrap.h              |   4 +-
 src/kudu/tablet/tablet_history_gc-test.cc       |   6 +-
 src/kudu/tablet/tablet_replica-test.cc          |  10 +-
 src/kudu/tablet/tablet_replica.cc               |   2 +-
 src/kudu/tablet/tablet_replica.h                |   6 +-
 .../transactions/alter_schema_transaction.cc    |   6 +-
 .../tablet/transactions/transaction_driver.h    |   4 +-
 .../tablet/transactions/write_transaction.cc    |   4 +-
 src/kudu/tools/CMakeLists.txt                   |   2 +-
 src/kudu/tserver/CMakeLists.txt                 |   2 +-
 src/kudu/tserver/tablet_server-test.cc          |   6 +-
 src/kudu/tserver/tablet_service.cc              |   4 +-
 src/kudu/tserver/ts_tablet_manager.cc           |   4 +-
 70 files changed, 1612 insertions(+), 1623 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5b93506..e377025 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1120,6 +1120,7 @@ endif (UNIX)
 add_subdirectory(src/kudu/benchmarks)
 add_subdirectory(src/kudu/cfile)
 add_subdirectory(src/kudu/client)
+add_subdirectory(src/kudu/clock)
 add_subdirectory(src/kudu/codegen)
 add_subdirectory(src/kudu/common)
 add_subdirectory(src/kudu/consensus)

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/client/client-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/client/client-test.cc b/src/kudu/client/client-test.cc
index 5a70a3a..337f78d 100644
--- a/src/kudu/client/client-test.cc
+++ b/src/kudu/client/client-test.cc
@@ -26,14 +26,14 @@
 #include <utility>
 #include <vector>
 
-#include <gtest/gtest.h>
 #include <gflags/gflags.h>
 #include <glog/stl_logging.h>
+#include <gtest/gtest.h>
 
 #include "kudu/client/callbacks.h"
-#include "kudu/client/client.h"
 #include "kudu/client/client-internal.h"
 #include "kudu/client/client-test-util.h"
+#include "kudu/client/client.h"
 #include "kudu/client/error_collector.h"
 #include "kudu/client/meta_cache.h"
 #include "kudu/client/row_result.h"
@@ -41,6 +41,7 @@
 #include "kudu/client/session-internal.h"
 #include "kudu/client/value.h"
 #include "kudu/client/write_op.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/partial_row.h"
 #include "kudu/common/wire_protocol.h"
 #include "kudu/gutil/atomicops.h"
@@ -55,7 +56,6 @@
 #include "kudu/master/ts_descriptor.h"
 #include "kudu/rpc/messenger.h"
 #include "kudu/security/tls_context.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/tablet/tablet_replica.h"
 #include "kudu/tablet/transactions/write_transaction.h"
 #include "kudu/tserver/mini_tablet_server.h"
@@ -766,7 +766,7 @@ TEST_F(ClientTest, TestScanAtSnapshot) {
 
   // Get the time from the server and transform to micros, disregarding any
   // logical values (we shouldn't have any with a single server anyway).
-  int64_t ts = server::HybridClock::GetPhysicalValueMicros(
+  int64_t ts = clock::HybridClock::GetPhysicalValueMicros(
       cluster_->mini_tablet_server(0)->server()->clock()->Now());
 
   // Insert the second half of the rows
@@ -810,7 +810,7 @@ TEST_F(ClientTest, TestScanAtFutureTimestamp) {
 
   // Try to perform a scan at NowLatest(). This is in the future,
   // but the server should wait until it's in the past.
-  int64_t ts = server::HybridClock::GetPhysicalValueMicros(
+  int64_t ts = clock::HybridClock::GetPhysicalValueMicros(
       cluster_->mini_tablet_server(0)->server()->clock()->NowLatest());
   ASSERT_OK(scanner.SetSnapshotMicros(ts));
   ASSERT_OK(scanner.Open());

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/clock/CMakeLists.txt b/src/kudu/clock/CMakeLists.txt
new file mode 100644
index 0000000..786d3ef
--- /dev/null
+++ b/src/kudu/clock/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+add_library(clock
+  hybrid_clock.cc
+  logical_clock.cc)
+target_link_libraries(clock
+  kudu_util)
+
+set(KUDU_TEST_LINK_LIBS ${KUDU_MIN_TEST_LIBS}
+  clock
+  kudu_common)
+ADD_KUDU_TEST(hybrid_clock-test)
+ADD_KUDU_TEST(logical_clock-test)

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/clock.h
----------------------------------------------------------------------
diff --git a/src/kudu/clock/clock.h b/src/kudu/clock/clock.h
new file mode 100644
index 0000000..20ba6d8
--- /dev/null
+++ b/src/kudu/clock/clock.h
@@ -0,0 +1,112 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+#pragma once
+
+#include <string>
+
+#include "kudu/common/common.pb.h"
+#include "kudu/common/timestamp.h"
+#include "kudu/gutil/ref_counted.h"
+#include "kudu/util/monotime.h"
+#include "kudu/util/status.h"
+
+namespace kudu {
+class faststring;
+class MetricEntity;
+class Slice;
+class Status;
+namespace clock {
+
+// An interface for a clock that can be used to assign timestamps to
+// operations.
+// Implementations must respect the following assumptions:
+// 1 - Now() must return monotonically increasing numbers
+//     i.e. for any two calls, i.e. Now returns timestamp1 and timestamp2, it must
+//     hold that timestamp1 < timestamp2.
+// 2 - Update() must never set the clock backwards (corollary of 1)
+class Clock : public RefCountedThreadSafe<Clock> {
+ public:
+
+  // Initializes the clock.
+  virtual Status Init() = 0;
+
+  // Obtains a new transaction timestamp corresponding to the current instant.
+  virtual Timestamp Now() = 0;
+
+  // Obtains a new transaction timestamp corresponding to the current instant
+  // plus the max_error.
+  virtual Timestamp NowLatest() = 0;
+
+  // Obtain a timestamp which is guaranteed to be later than the current time
+  // on any machine in the cluster.
+  //
+  // NOTE: this is not a very tight bound.
+  virtual Status GetGlobalLatest(Timestamp* t) {
+    return Status::NotSupported("clock does not support global properties");
+  }
+
+  // Indicates whether this clock supports the required external consistency mode.
+  virtual bool SupportsExternalConsistencyMode(ExternalConsistencyMode mode) = 0;
+
+  // Indicates whether the clock has a physical component to its timestamps
+  // (wallclock time).
+  virtual bool HasPhysicalComponent() const {
+    return false;
+  }
+
+  // Get a MonoDelta representing the physical component difference between two timestamps,
+  // specifically lhs - rhs.
+  //
+  // Requires that this clock's timestamps have a physical component, i.e.
+  // that HasPhysicalComponent() return true, otherwise it will crash.
+  virtual MonoDelta GetPhysicalComponentDifference(Timestamp /*lhs*/, Timestamp /*rhs*/) const {
+    LOG(FATAL) << "Clock's timestamps don't have a physical component.";
+  }
+
+  // Update the clock with a transaction timestamp originating from
+  // another server. For instance replicas can call this so that,
+  // if elected leader, they are guaranteed to generate timestamps
+  // higher than the timestamp of the last transaction accepted from the
+  // leader.
+  virtual Status Update(const Timestamp& to_update) = 0;
+
+  // Waits until the clock on all machines has advanced past 'then'.
+  // Can also be used to implement 'external consistency' in the same sense as
+  // Google's Spanner.
+  virtual Status WaitUntilAfter(const Timestamp& then,
+                                const MonoTime& deadline) = 0;
+
+  // Waits until the clock on this machine advances past 'then'. Unlike
+  // WaitUntilAfter(), this does not make any global guarantees.
+  virtual Status WaitUntilAfterLocally(const Timestamp& then,
+                                       const MonoTime& deadline) = 0;
+
+  // Return true if the given time has definitely passed (i.e any future call
+  // to Now() would return a higher value than t).
+  virtual bool IsAfter(Timestamp t) = 0;
+
+  // Register the clock metrics in the given entity.
+  virtual void RegisterMetrics(const scoped_refptr<MetricEntity>& metric_entity) = 0;
+
+  // Strigifies the provided timestamp according to this clock's internal format.
+  virtual std::string Stringify(Timestamp timestamp) = 0;
+
+  virtual ~Clock() {}
+};
+
+} // namespace clock
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/hybrid_clock-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/clock/hybrid_clock-test.cc b/src/kudu/clock/hybrid_clock-test.cc
new file mode 100644
index 0000000..4b73e57
--- /dev/null
+++ b/src/kudu/clock/hybrid_clock-test.cc
@@ -0,0 +1,293 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <algorithm>
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include "kudu/clock/hybrid_clock.h"
+#include "kudu/util/monotime.h"
+#include "kudu/util/random.h"
+#include "kudu/util/random_util.h"
+#include "kudu/util/test_util.h"
+
+DECLARE_bool(use_mock_wall_clock);
+
+namespace kudu {
+namespace clock {
+
+class HybridClockTest : public KuduTest {
+ public:
+  HybridClockTest()
+      : clock_(new HybridClock) {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    KuduTest::SetUp();
+    ASSERT_OK(clock_->Init());
+  }
+
+ protected:
+  scoped_refptr<HybridClock> clock_;
+};
+
+TEST(MockHybridClockTest, TestMockedSystemClock) {
+  google::FlagSaver saver;
+  FLAGS_use_mock_wall_clock = true;
+  scoped_refptr<HybridClock> clock(new HybridClock());
+  clock->Init();
+  Timestamp timestamp;
+  uint64_t max_error_usec;
+  clock->NowWithError(&timestamp, &max_error_usec);
+  ASSERT_EQ(timestamp.ToUint64(), 0);
+  ASSERT_EQ(max_error_usec, 0);
+  // If we read the clock again we should see the logical component be incremented.
+  clock->NowWithError(&timestamp, &max_error_usec);
+  ASSERT_EQ(timestamp.ToUint64(), 1);
+  // Now set an arbitrary time and check that is the time returned by the clock.
+  uint64_t time = 1234;
+  uint64_t error = 100 * 1000;
+  clock->SetMockClockWallTimeForTests(time);
+  clock->SetMockMaxClockErrorForTests(error);
+  clock->NowWithError(&timestamp, &max_error_usec);
+  ASSERT_EQ(timestamp.ToUint64(),
+            HybridClock::TimestampFromMicrosecondsAndLogicalValue(time, 0).ToUint64());
+  ASSERT_EQ(max_error_usec, error);
+  // Perform another read, we should observe the logical component increment, again.
+  clock->NowWithError(&timestamp, &max_error_usec);
+  ASSERT_EQ(timestamp.ToUint64(),
+            HybridClock::TimestampFromMicrosecondsAndLogicalValue(time, 1).ToUint64());
+}
+
+// Test that, if the rate at which the clock is read is greater than the maximum
+// resolution of the logical counter (12 bits in our implementation), it properly
+// "overflows" into the physical portion of the clock, and maintains all ordering
+// guarantees even as the physical clock continues to increase.
+//
+// This is a regression test for KUDU-1345.
+TEST(MockHybridClockTest, TestClockDealsWithWrapping) {
+  google::FlagSaver saver;
+  FLAGS_use_mock_wall_clock = true;
+  scoped_refptr<HybridClock> clock(new HybridClock());
+  clock->SetMockClockWallTimeForTests(1000);
+  clock->Init();
+
+  Timestamp prev = clock->Now();
+
+  // Update the clock from 10us in the future
+  clock->Update(HybridClock::TimestampFromMicroseconds(1010));
+
+  // Now read the clock value enough times so that the logical value wraps
+  // over, and should increment the _physical_ portion of the clock.
+  for (int i = 0; i < 10000; i++) {
+    Timestamp now = clock->Now();
+    ASSERT_GT(now.value(), prev.value());
+    prev = now;
+  }
+  ASSERT_EQ(1012, HybridClock::GetPhysicalValueMicros(prev));
+
+  // Advance the time microsecond by microsecond, and ensure the clock never
+  // goes backwards.
+  for (int time = 1001; time < 1020; time++) {
+    clock->SetMockClockWallTimeForTests(time);
+    Timestamp now = clock->Now();
+
+    // Clock should run strictly forwards.
+    ASSERT_GT(now.value(), prev.value());
+
+    // Additionally, once the physical time surpasses the logical time, we should
+    // be running on the physical clock. Otherwise, we should stick with the physical
+    // time we had rolled forward to above.
+    if (time > 1012) {
+      ASSERT_EQ(time, HybridClock::GetPhysicalValueMicros(now));
+    } else {
+      ASSERT_EQ(1012, HybridClock::GetPhysicalValueMicros(now));
+    }
+
+    prev = now;
+  }
+}
+
+// Test that two subsequent time reads are monotonically increasing.
+TEST_F(HybridClockTest, TestNow_ValuesIncreaseMonotonically) {
+  const Timestamp now1 = clock_->Now();
+  const Timestamp now2 = clock_->Now();
+  ASSERT_LT(now1.value(), now2.value());
+}
+
+// Tests the clock updates with the incoming value if it is higher.
+TEST_F(HybridClockTest, TestUpdate_LogicalValueIncreasesByAmount) {
+  Timestamp now = clock_->Now();
+  uint64_t now_micros = HybridClock::GetPhysicalValueMicros(now);
+
+  // increase the logical value
+  uint64_t logical = HybridClock::GetLogicalValue(now);
+  logical += 10;
+
+  // increase the physical value so that we're sure the clock will take this
+  // one, 200 msecs should be more than enough.
+  now_micros += 200000;
+
+  Timestamp now_increased = HybridClock::TimestampFromMicrosecondsAndLogicalValue(now_micros,
+                                                                                  logical);
+
+  ASSERT_OK(clock_->Update(now_increased));
+
+  Timestamp now2 = clock_->Now();
+  ASSERT_EQ(logical + 1, HybridClock::GetLogicalValue(now2));
+  ASSERT_EQ(HybridClock::GetPhysicalValueMicros(now) + 200000,
+            HybridClock::GetPhysicalValueMicros(now2));
+}
+
+// Test that the incoming event is in the past, i.e. less than now - max_error
+TEST_F(HybridClockTest, TestWaitUntilAfter_TestCase1) {
+  MonoTime no_deadline;
+  MonoTime before = MonoTime::Now();
+
+  Timestamp past_ts;
+  uint64_t max_error;
+  clock_->NowWithError(&past_ts, &max_error);
+
+  // make the event 3 * the max. possible error in the past
+  Timestamp past_ts_changed = HybridClock::AddPhysicalTimeToTimestamp(
+      past_ts,
+      MonoDelta::FromMicroseconds(-3 * max_error));
+
+  Status s = clock_->WaitUntilAfter(past_ts_changed, no_deadline);
+
+  ASSERT_OK(s);
+
+  MonoTime after = MonoTime::Now();
+  MonoDelta delta = after - before;
+  // The delta should be close to 0, but it takes some time for the hybrid
+  // logical clock to decide that it doesn't need to wait.
+  ASSERT_LT(delta.ToMicroseconds(), 25000);
+}
+
+// The normal case for transactions. Obtain a timestamp and then wait until
+// we're sure that tx_latest < now_earliest.
+TEST_F(HybridClockTest, TestWaitUntilAfter_TestCase2) {
+  MonoTime before = MonoTime::Now();
+
+  // we do no time adjustment, this event should fall right within the possible
+  // error interval
+  Timestamp past_ts;
+  uint64_t past_max_error;
+  clock_->NowWithError(&past_ts, &past_max_error);
+  // Make sure the error is at least a small number of microseconds, to ensure
+  // that we always have to wait.
+  past_max_error = std::max(past_max_error, static_cast<uint64_t>(20));
+  Timestamp wait_until = HybridClock::AddPhysicalTimeToTimestamp(
+      past_ts,
+      MonoDelta::FromMicroseconds(past_max_error));
+
+  Timestamp current_ts;
+  uint64_t current_max_error;
+  clock_->NowWithError(&current_ts, &current_max_error);
+
+  // Check waiting with a deadline which already expired.
+  {
+    MonoTime deadline = before;
+    Status s = clock_->WaitUntilAfter(wait_until, deadline);
+    ASSERT_TRUE(s.IsTimedOut());
+  }
+
+  // Wait with a deadline well in the future. This should succeed.
+  {
+    MonoTime deadline = before + MonoDelta::FromSeconds(60);
+    ASSERT_OK(clock_->WaitUntilAfter(wait_until, deadline));
+  }
+
+  MonoTime after = MonoTime::Now();
+  MonoDelta delta = after - before;
+
+  // In the common case current_max_error >= past_max_error and we should have waited
+  // 2 * past_max_error, but if the clock's error is reset between the two reads we might
+  // have waited less time, but always more than 'past_max_error'.
+  if (current_max_error >= past_max_error) {
+    ASSERT_GE(delta.ToMicroseconds(), 2 * past_max_error);
+  } else {
+    ASSERT_GE(delta.ToMicroseconds(), past_max_error);
+  }
+}
+
+TEST_F(HybridClockTest, TestIsAfter) {
+  Timestamp ts1 = clock_->Now();
+  ASSERT_TRUE(clock_->IsAfter(ts1));
+
+  // Update the clock in the future, make sure it still
+  // handles "IsAfter" properly even when it's running in
+  // "logical" mode.
+  Timestamp now_increased = HybridClock::TimestampFromMicroseconds(
+    HybridClock::GetPhysicalValueMicros(ts1) + 1 * 1000 * 1000);
+  ASSERT_OK(clock_->Update(now_increased));
+  Timestamp ts2 = clock_->Now();
+
+  ASSERT_TRUE(clock_->IsAfter(ts1));
+  ASSERT_TRUE(clock_->IsAfter(ts2));
+}
+
+// Thread which loops polling the clock and updating it slightly
+// into the future.
+void StresserThread(HybridClock* clock, AtomicBool* stop) {
+  Random rng(GetRandomSeed32());
+  Timestamp prev(0);;
+  while (!stop->Load()) {
+    Timestamp t = clock->Now();
+    CHECK_GT(t.value(), prev.value());
+    prev = t;
+
+    // Add a random bit of offset to the clock, and perform an update.
+    Timestamp new_ts = HybridClock::AddPhysicalTimeToTimestamp(
+        t, MonoDelta::FromMicroseconds(rng.Uniform(10000)));
+    clock->Update(new_ts);
+  }
+}
+
+// Regression test for KUDU-953: if threads are updating and polling the
+// clock concurrently, the clock should still never run backwards.
+TEST_F(HybridClockTest, TestClockDoesntGoBackwardsWithUpdates) {
+  vector<scoped_refptr<kudu::Thread> > threads;
+
+  AtomicBool stop(false);
+  for (int i = 0; i < 4; i++) {
+    scoped_refptr<Thread> thread;
+    ASSERT_OK(Thread::Create("test", "stresser",
+                             &StresserThread, clock_.get(), &stop,
+                             &thread));
+    threads.push_back(thread);
+  }
+
+  SleepFor(MonoDelta::FromSeconds(1));
+  stop.Store(true);
+  for (const scoped_refptr<Thread> t : threads) {
+    t->Join();
+  }
+}
+
+TEST_F(HybridClockTest, TestGetPhysicalComponentDifference) {
+  Timestamp now1 = HybridClock::TimestampFromMicrosecondsAndLogicalValue(100, 100);
+  SleepFor(MonoDelta::FromMilliseconds(1));
+  Timestamp now2 = HybridClock::TimestampFromMicrosecondsAndLogicalValue(200, 0);
+  MonoDelta delta = clock_->GetPhysicalComponentDifference(now2, now1);
+  MonoDelta negative_delta = clock_->GetPhysicalComponentDifference(now1, now2);
+  ASSERT_EQ(100, delta.ToMicroseconds());
+  ASSERT_EQ(-100, negative_delta.ToMicroseconds());
+}
+
+}  // namespace clock
+}  // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/hybrid_clock.cc
----------------------------------------------------------------------
diff --git a/src/kudu/clock/hybrid_clock.cc b/src/kudu/clock/hybrid_clock.cc
new file mode 100644
index 0000000..dfe668a
--- /dev/null
+++ b/src/kudu/clock/hybrid_clock.cc
@@ -0,0 +1,495 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "kudu/clock/hybrid_clock.h"
+
+#include <algorithm>
+#include <glog/logging.h>
+#include <mutex>
+
+#include "kudu/gutil/bind.h"
+#include "kudu/gutil/strings/substitute.h"
+#include "kudu/gutil/walltime.h"
+#include "kudu/util/debug/trace_event.h"
+#include "kudu/util/errno.h"
+#include "kudu/util/flag_tags.h"
+#include "kudu/util/locks.h"
+#include "kudu/util/logging.h"
+#include "kudu/util/metrics.h"
+#include "kudu/util/status.h"
+
+#if !defined(__APPLE__)
+#include <sys/timex.h>
+#endif // !defined(__APPLE__)
+
+DEFINE_int32(max_clock_sync_error_usec, 10 * 1000 * 1000, // 10 secs
+             "Maximum allowed clock synchronization error as reported by NTP "
+             "before the server will abort.");
+TAG_FLAG(max_clock_sync_error_usec, advanced);
+TAG_FLAG(max_clock_sync_error_usec, runtime);
+
+DEFINE_bool(use_hybrid_clock, true,
+            "Whether HybridClock should be used as the default clock"
+            " implementation. This should be disabled for testing purposes only.");
+TAG_FLAG(use_hybrid_clock, hidden);
+
+DEFINE_bool(use_mock_wall_clock, false,
+            "Whether HybridClock should use a mock wall clock which is updated manually"
+            "instead of reading time from the system clock, for tests.");
+TAG_FLAG(use_mock_wall_clock, hidden);
+
+METRIC_DEFINE_gauge_uint64(server, hybrid_clock_timestamp,
+                           "Hybrid Clock Timestamp",
+                           kudu::MetricUnit::kMicroseconds,
+                           "Hybrid clock timestamp.");
+METRIC_DEFINE_gauge_uint64(server, hybrid_clock_error,
+                           "Hybrid Clock Error",
+                           kudu::MetricUnit::kMicroseconds,
+                           "Server clock maximum error.");
+
+using kudu::Status;
+using strings::Substitute;
+
+namespace kudu {
+namespace clock {
+
+namespace {
+
+#if !defined(__APPLE__)
+// Returns the clock modes and checks if the clock is synchronized.
+Status GetClockModes(timex* timex) {
+  // this makes ntp_adjtime a read-only call
+  timex->modes = 0;
+  int rc = ntp_adjtime(timex);
+  if (PREDICT_FALSE(rc == TIME_ERROR)) {
+    return Status::ServiceUnavailable(
+        Substitute("Error reading clock. Clock considered unsynchronized. Return code: $0", rc));
+  }
+  // TODO what to do about leap seconds? see KUDU-146
+  if (PREDICT_FALSE(rc != TIME_OK)) {
+    LOG(ERROR) << Substitute("TODO Server undergoing leap second. Return code: $0", rc);
+  }
+  return Status::OK();
+}
+
+// Returns the current time/max error and checks if the clock is synchronized.
+kudu::Status GetClockTime(ntptimeval* timeval) {
+  int rc = ntp_gettime(timeval);
+  switch (rc) {
+    case TIME_OK:
+      return Status::OK();
+    case -1: // generic error
+      return Status::ServiceUnavailable("Error reading clock. ntp_gettime() failed",
+                                        ErrnoToString(errno));
+    case TIME_ERROR:
+      return Status::ServiceUnavailable("Error reading clock. Clock considered unsynchronized");
+    default:
+      // TODO what to do about leap seconds? see KUDU-146
+      KLOG_FIRST_N(ERROR, 1) << "Server undergoing leap second. This may cause consistency issues "
+        << "(rc=" << rc << ")";
+      return Status::OK();
+  }
+}
+#endif // !defined(__APPLE__)
+
+Status CheckDeadlineNotWithinMicros(const MonoTime& deadline, int64_t wait_for_usec) {
+  if (!deadline.Initialized()) {
+    // No deadline.
+    return Status::OK();
+  }
+  int64_t us_until_deadline = (deadline - MonoTime::Now()).ToMicroseconds();
+  if (us_until_deadline <= wait_for_usec) {
+    return Status::TimedOut(Substitute(
+        "specified time is $0us in the future, but deadline expires in $1us",
+        wait_for_usec, us_until_deadline));
+  }
+  return Status::OK();
+}
+
+}  // anonymous namespace
+
+// Left shifting 12 bits gives us 12 bits for the logical value
+// and should still keep accurate microseconds time until 2100+
+const int HybridClock::kBitsToShift = 12;
+// This mask gives us back the logical bits.
+const uint64_t HybridClock::kLogicalBitMask = (1 << kBitsToShift) - 1;
+
+const uint64_t HybridClock::kNanosPerSec = 1000000;
+
+const double HybridClock::kAdjtimexScalingFactor = 65536;
+
+HybridClock::HybridClock()
+    : mock_clock_time_usec_(0),
+      mock_clock_max_error_usec_(0),
+#if !defined(__APPLE__)
+      divisor_(1),
+#endif
+      tolerance_adjustment_(1),
+      next_timestamp_(0),
+      state_(kNotInitialized) {
+}
+
+Status HybridClock::Init() {
+  if (PREDICT_FALSE(FLAGS_use_mock_wall_clock)) {
+    LOG(WARNING) << "HybridClock set to mock the wall clock.";
+    state_ = kInitialized;
+    return Status::OK();
+  }
+#if defined(__APPLE__)
+  LOG(WARNING) << "HybridClock initialized in local mode (OS X only). "
+               << "Not suitable for distributed clusters.";
+#else
+  // Read the current time. This will return an error if the clock is not synchronized.
+  uint64_t now_usec;
+  uint64_t error_usec;
+  RETURN_NOT_OK(WalltimeWithError(&now_usec, &error_usec));
+
+  timex timex;
+  RETURN_NOT_OK(GetClockModes(&timex));
+  // read whether the STA_NANO bit is set to know whether we'll get back nanos
+  // or micros in timeval.time.tv_usec. See:
+  // http://stackoverflow.com/questions/16063408/does-ntp-gettime-actually-return-nanosecond-precision
+  // set the timeval.time.tv_usec divisor so that we always get micros
+  if (timex.status & STA_NANO) {
+    divisor_ = 1000;
+  } else {
+    divisor_ = 1;
+  }
+
+  // Calculate the sleep skew adjustment according to the max tolerance of the clock.
+  // Tolerance comes in parts per million but needs to be applied a scaling factor.
+  tolerance_adjustment_ = (1 + ((timex.tolerance / kAdjtimexScalingFactor) / 1000000.0));
+
+  LOG(INFO) << "HybridClock initialized. Resolution in nanos?: " << (divisor_ == 1000)
+            << " Wait times tolerance adjustment: " << tolerance_adjustment_
+            << " Current error: " << error_usec;
+#endif // defined(__APPLE__)
+
+  state_ = kInitialized;
+
+  return Status::OK();
+}
+
+Timestamp HybridClock::Now() {
+  Timestamp now;
+  uint64_t error;
+
+  std::lock_guard<simple_spinlock> lock(lock_);
+  NowWithError(&now, &error);
+  return now;
+}
+
+Timestamp HybridClock::NowLatest() {
+  Timestamp now;
+  uint64_t error;
+
+  {
+    std::lock_guard<simple_spinlock> lock(lock_);
+    NowWithError(&now, &error);
+  }
+
+  uint64_t now_latest = GetPhysicalValueMicros(now) + error;
+  uint64_t now_logical = GetLogicalValue(now);
+
+  return TimestampFromMicrosecondsAndLogicalValue(now_latest, now_logical);
+}
+
+Status HybridClock::GetGlobalLatest(Timestamp* t) {
+  Timestamp now = Now();
+  uint64_t now_latest = GetPhysicalValueMicros(now) + FLAGS_max_clock_sync_error_usec;
+  uint64_t now_logical = GetLogicalValue(now);
+  *t = TimestampFromMicrosecondsAndLogicalValue(now_latest, now_logical);
+  return Status::OK();
+}
+
+void HybridClock::NowWithError(Timestamp* timestamp, uint64_t* max_error_usec) {
+
+  DCHECK_EQ(state_, kInitialized) << "Clock not initialized. Must call Init() first.";
+
+  uint64_t now_usec;
+  uint64_t error_usec;
+  Status s = WalltimeWithError(&now_usec, &error_usec);
+  if (PREDICT_FALSE(!s.ok())) {
+    LOG(FATAL) << Substitute("Couldn't get the current time: Clock unsynchronized. "
+        "Status: $0", s.ToString());
+  }
+
+  // If the physical time from the system clock is higher than our last-returned
+  // time, we should use the physical timestamp.
+  uint64_t candidate_phys_timestamp = now_usec << kBitsToShift;
+  if (PREDICT_TRUE(candidate_phys_timestamp > next_timestamp_)) {
+    next_timestamp_ = candidate_phys_timestamp;
+    *timestamp = Timestamp(next_timestamp_++);
+    *max_error_usec = error_usec;
+    if (PREDICT_FALSE(VLOG_IS_ON(2))) {
+      VLOG(2) << "Current clock is higher than the last one. Resetting logical values."
+          << " Physical Value: " << now_usec << " usec Logical Value: 0  Error: "
+          << error_usec;
+    }
+    return;
+  }
+
+  // We don't have the last time read max error since it might have originated
+  // in another machine, but we can put a bound on the maximum error of the
+  // timestamp we are providing.
+  // In particular we know that the "true" time falls within the interval
+  // now_usec +- now.maxerror so we get the following situations:
+  //
+  // 1)
+  // --------|----------|----|---------|--------------------------> time
+  //     now - e       now  last   now + e
+  // 2)
+  // --------|----------|--------------|------|-------------------> time
+  //     now - e       now         now + e   last
+  //
+  // Assuming, in the worst case, that the "true" time is now - error we need to
+  // always return: last - (now - e) as the new maximum error.
+  // This broadens the error interval for both cases but always returns
+  // a correct error interval.
+
+  *max_error_usec = (next_timestamp_ >> kBitsToShift) - (now_usec - error_usec);
+  *timestamp = Timestamp(next_timestamp_++);
+  if (PREDICT_FALSE(VLOG_IS_ON(2))) {
+    VLOG(2) << "Current clock is lower than the last one. Returning last read and incrementing"
+        " logical values. Clock: " + Stringify(*timestamp) << " Error: " << *max_error_usec;
+  }
+}
+
+Status HybridClock::Update(const Timestamp& to_update) {
+  std::lock_guard<simple_spinlock> lock(lock_);
+  Timestamp now;
+  uint64_t error_ignored;
+  NowWithError(&now, &error_ignored);
+
+  // If the incoming message is in the past relative to our current
+  // physical clock, there's nothing to do.
+  if (PREDICT_TRUE(now > to_update)) {
+    return Status::OK();
+  }
+
+  uint64_t to_update_physical = GetPhysicalValueMicros(to_update);
+  uint64_t now_physical = GetPhysicalValueMicros(now);
+
+  // we won't update our clock if to_update is more than 'max_clock_sync_error_usec'
+  // into the future as it might have been corrupted or originated from an out-of-sync
+  // server.
+  if ((to_update_physical - now_physical) > FLAGS_max_clock_sync_error_usec) {
+    return Status::InvalidArgument("Tried to update clock beyond the max. error.");
+  }
+
+  // Our next timestamp must be higher than the one that we are updating
+  // from.
+  next_timestamp_ = to_update.value() + 1;
+  return Status::OK();
+}
+
+bool HybridClock::SupportsExternalConsistencyMode(ExternalConsistencyMode mode) {
+  return true;
+}
+
+bool HybridClock::HasPhysicalComponent() const {
+  return true;
+}
+
+MonoDelta HybridClock::GetPhysicalComponentDifference(Timestamp lhs, Timestamp rhs) const {
+  return MonoDelta::FromMicroseconds(GetPhysicalValueMicros(lhs) - GetPhysicalValueMicros(rhs));
+}
+
+Status HybridClock::WaitUntilAfter(const Timestamp& then,
+                                   const MonoTime& deadline) {
+  TRACE_EVENT0("clock", "HybridClock::WaitUntilAfter");
+  Timestamp now;
+  uint64_t error;
+  {
+    std::lock_guard<simple_spinlock> lock(lock_);
+    NowWithError(&now, &error);
+  }
+
+  // "unshift" the timestamps so that we can measure actual time
+  uint64_t now_usec = GetPhysicalValueMicros(now);
+  uint64_t then_latest_usec = GetPhysicalValueMicros(then);
+
+  uint64_t now_earliest_usec = now_usec - error;
+
+  // Case 1, event happened definitely in the past, return
+  if (PREDICT_TRUE(then_latest_usec < now_earliest_usec)) {
+    return Status::OK();
+  }
+
+  // Case 2 wait out until we are sure that then has passed
+
+  // We'll sleep then_latest_usec - now_earliest_usec so that the new
+  // nw.earliest is higher than then.latest.
+  uint64_t wait_for_usec = (then_latest_usec - now_earliest_usec);
+
+  // Additionally adjust the sleep time with the max tolerance adjustment
+  // to account for the worst case clock skew while we're sleeping.
+  wait_for_usec *= tolerance_adjustment_;
+
+  // Check that sleeping wouldn't sleep longer than our deadline.
+  RETURN_NOT_OK(CheckDeadlineNotWithinMicros(deadline, wait_for_usec));
+
+  SleepFor(MonoDelta::FromMicroseconds(wait_for_usec));
+
+
+  VLOG(1) << "WaitUntilAfter(): Incoming time(latest): " << then_latest_usec
+          << " Now(earliest): " << now_earliest_usec << " error: " << error
+          << " Waiting for: " << wait_for_usec;
+
+  return Status::OK();
+}
+
+Status HybridClock::WaitUntilAfterLocally(const Timestamp& then,
+                                          const MonoTime& deadline) {
+  while (true) {
+    Timestamp now;
+    uint64_t error;
+    {
+      std::lock_guard<simple_spinlock> lock(lock_);
+      NowWithError(&now, &error);
+    }
+    if (now > then) {
+      return Status::OK();
+    }
+    uint64_t wait_for_usec = GetPhysicalValueMicros(then) - GetPhysicalValueMicros(now);
+
+    // Check that sleeping wouldn't sleep longer than our deadline.
+    RETURN_NOT_OK(CheckDeadlineNotWithinMicros(deadline, wait_for_usec));
+  }
+}
+
+bool HybridClock::IsAfter(Timestamp t) {
+  // Manually get the time, rather than using Now(), so we don't end up causing
+  // a time update.
+  uint64_t now_usec;
+  uint64_t error_usec;
+  CHECK_OK(WalltimeWithError(&now_usec, &error_usec));
+
+  Timestamp now;
+  {
+    std::lock_guard<simple_spinlock> lock(lock_);
+    now = Timestamp(std::max(next_timestamp_, now_usec << kBitsToShift));
+  }
+  return t.value() < now.value();
+}
+
+kudu::Status HybridClock::WalltimeWithError(uint64_t* now_usec, uint64_t* error_usec) {
+  if (PREDICT_FALSE(FLAGS_use_mock_wall_clock)) {
+    VLOG(1) << "Current clock time: " << mock_clock_time_usec_ << " error: "
+            << mock_clock_max_error_usec_ << ". Updating to time: " << now_usec
+            << " and error: " << error_usec;
+    *now_usec = mock_clock_time_usec_;
+    *error_usec = mock_clock_max_error_usec_;
+  } else {
+#if defined(__APPLE__)
+    *now_usec = GetCurrentTimeMicros();
+    *error_usec = 0;
+  }
+#else
+    // Read the time. This will return an error if the clock is not synchronized.
+    ntptimeval timeval;
+    RETURN_NOT_OK(GetClockTime(&timeval));
+    *now_usec = timeval.time.tv_sec * kNanosPerSec + timeval.time.tv_usec / divisor_;
+    *error_usec = timeval.maxerror;
+  }
+
+  // If the clock is synchronized but has max_error beyond max_clock_sync_error_usec
+  // we also return a non-ok status.
+  if (*error_usec > FLAGS_max_clock_sync_error_usec) {
+    return Status::ServiceUnavailable(Substitute("Error: Clock synchronized but error was"
+        "too high ($0 us).", *error_usec));
+  }
+#endif // defined(__APPLE__)
+  return kudu::Status::OK();
+}
+
+void HybridClock::SetMockClockWallTimeForTests(uint64_t now_usec) {
+  CHECK(FLAGS_use_mock_wall_clock);
+  std::lock_guard<simple_spinlock> lock(lock_);
+  CHECK_GE(now_usec, mock_clock_time_usec_);
+  mock_clock_time_usec_ = now_usec;
+}
+
+void HybridClock::SetMockMaxClockErrorForTests(uint64_t max_error_usec) {
+  CHECK(FLAGS_use_mock_wall_clock);
+  std::lock_guard<simple_spinlock> lock(lock_);
+  mock_clock_max_error_usec_ = max_error_usec;
+}
+
+// Used to get the timestamp for metrics.
+uint64_t HybridClock::NowForMetrics() {
+  return Now().ToUint64();
+}
+
+// Used to get the current error, for metrics.
+uint64_t HybridClock::ErrorForMetrics() {
+  Timestamp now;
+  uint64_t error;
+
+  std::lock_guard<simple_spinlock> lock(lock_);
+  NowWithError(&now, &error);
+  return error;
+}
+
+void HybridClock::RegisterMetrics(const scoped_refptr<MetricEntity>& metric_entity) {
+  METRIC_hybrid_clock_timestamp.InstantiateFunctionGauge(
+      metric_entity,
+      Bind(&HybridClock::NowForMetrics, Unretained(this)))
+    ->AutoDetachToLastValue(&metric_detacher_);
+  METRIC_hybrid_clock_error.InstantiateFunctionGauge(
+      metric_entity,
+      Bind(&HybridClock::ErrorForMetrics, Unretained(this)))
+    ->AutoDetachToLastValue(&metric_detacher_);
+}
+
+string HybridClock::Stringify(Timestamp timestamp) {
+  return StringifyTimestamp(timestamp);
+}
+
+uint64_t HybridClock::GetLogicalValue(const Timestamp& timestamp) {
+  return timestamp.value() & kLogicalBitMask;
+}
+
+uint64_t HybridClock::GetPhysicalValueMicros(const Timestamp& timestamp) {
+  return timestamp.value() >> kBitsToShift;
+}
+
+Timestamp HybridClock::TimestampFromMicroseconds(uint64_t micros) {
+  return Timestamp(micros << kBitsToShift);
+}
+
+Timestamp HybridClock::TimestampFromMicrosecondsAndLogicalValue(
+    uint64_t micros,
+    uint64_t logical_value) {
+  return Timestamp((micros << kBitsToShift) + logical_value);
+}
+
+Timestamp HybridClock::AddPhysicalTimeToTimestamp(const Timestamp& original,
+                                                  const MonoDelta& to_add) {
+  uint64_t new_physical = GetPhysicalValueMicros(original) + to_add.ToMicroseconds();
+  uint64_t old_logical = GetLogicalValue(original);
+  return TimestampFromMicrosecondsAndLogicalValue(new_physical, old_logical);
+}
+
+string HybridClock::StringifyTimestamp(const Timestamp& timestamp) {
+  return Substitute("P: $0 usec, L: $1",
+                    GetPhysicalValueMicros(timestamp),
+                    GetLogicalValue(timestamp));
+}
+
+}  // namespace clock
+}  // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/hybrid_clock.h
----------------------------------------------------------------------
diff --git a/src/kudu/clock/hybrid_clock.h b/src/kudu/clock/hybrid_clock.h
new file mode 100644
index 0000000..d6c50b6
--- /dev/null
+++ b/src/kudu/clock/hybrid_clock.h
@@ -0,0 +1,224 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+#pragma once
+
+#include <string>
+
+#include "kudu/gutil/ref_counted.h"
+#include "kudu/clock/clock.h"
+#include "kudu/util/locks.h"
+#include "kudu/util/metrics.h"
+#include "kudu/util/status.h"
+
+namespace kudu {
+namespace clock {
+
+// The HybridTime clock.
+//
+// HybridTime should not be used on a distributed cluster running on OS X hosts,
+// since NTP clock error is not available.
+class HybridClock : public Clock {
+ public:
+  HybridClock();
+
+  virtual Status Init() OVERRIDE;
+
+  // Obtains the timestamp corresponding to the current time.
+  virtual Timestamp Now() OVERRIDE;
+
+  // Obtains the timestamp corresponding to latest possible current
+  // time.
+  virtual Timestamp NowLatest() OVERRIDE;
+
+  // Obtain a timestamp which is guaranteed to be later than the current time
+  // on any machine in the cluster.
+  //
+  // NOTE: this is not a very tight bound.
+  virtual Status GetGlobalLatest(Timestamp* t) OVERRIDE;
+
+  // Updates the clock with a timestamp originating on another machine.
+  virtual Status Update(const Timestamp& to_update) OVERRIDE;
+
+  virtual void RegisterMetrics(const scoped_refptr<MetricEntity>& metric_entity) OVERRIDE;
+
+  // HybridClock supports all external consistency modes.
+  virtual bool SupportsExternalConsistencyMode(ExternalConsistencyMode mode) OVERRIDE;
+
+  virtual bool HasPhysicalComponent() const OVERRIDE;
+
+  MonoDelta GetPhysicalComponentDifference(Timestamp lhs, Timestamp rhs) const OVERRIDE;
+
+  // Blocks the caller thread until the true time is after 'then'.
+  // In other words, waits until the HybridClock::Now() on _all_ nodes
+  // will return a value greater than 'then'.
+  //
+  // The incoming time 'then' is assumed to be the latest time possible
+  // at the time the read was performed, i.e. 'then' = now + max_error.
+  //
+  // This method can be used to make Kudu behave like Spanner/TrueTime.
+  // This is implemented by possibly making the caller thread wait for a
+  // a certain period of time.
+  //
+  // As an example, the following cases might happen:
+  //
+  // 1 - 'then' is lower than now.earliest() -> Definitely in
+  // the past, no wait necessary.
+  //
+  // 2 - 'then' is greater than > now.earliest(): need to wait until
+  // 'then' <= now.earliest()
+  //
+  // Returns OK if it waited long enough or if no wait was necessary.
+  //
+  // Returns Status::ServiceUnavailable if the system clock was not
+  // synchronized and therefore it couldn't wait out the error.
+  //
+  // Returns Status::TimedOut() if 'deadline' will pass before the specified
+  // timestamp. NOTE: unlike most "wait" methods, this may return _immediately_
+  // with a timeout, rather than actually waiting for the timeout to expire.
+  // This is because, by looking at the current clock, we can know how long
+  // we'll have to wait, in contrast to most Wait() methods which are waiting
+  // on some external condition to become true.
+  virtual Status WaitUntilAfter(const Timestamp& then,
+                                const MonoTime& deadline) OVERRIDE;
+
+  // Blocks the caller thread until the local time is after 'then'.
+  // This is in contrast to the above method, which waits until the time
+  // on _all_ machines is past the given time.
+  //
+  // Returns Status::TimedOut() if 'deadline' will pass before the specified
+  // timestamp. NOTE: unlike most "wait" methods, this may return _immediately_
+  // with a timeout. See WaitUntilAfter() for details.
+  virtual Status WaitUntilAfterLocally(const Timestamp& then,
+                                       const MonoTime& deadline) OVERRIDE;
+
+  // Return true if the given time has passed (i.e any future call
+  // to Now() would return a higher value than t).
+  //
+  // NOTE: this only refers to the _local_ clock, and is not a guarantee
+  // that other nodes' clocks have definitely passed this timestamp.
+  // This is in contrast to WaitUntilAfter() above.
+  virtual bool IsAfter(Timestamp t) OVERRIDE;
+
+  // Obtains the timestamp corresponding to the current time and the associated
+  // error in micros. This may fail if the clock is unsynchronized or synchronized
+  // but the error is too high and, since we can't do anything about it,
+  // LOG(FATAL)'s in that case.
+  void NowWithError(Timestamp* timestamp, uint64_t* max_error_usec);
+
+  virtual std::string Stringify(Timestamp timestamp) OVERRIDE;
+
+  // Static encoding/decoding methods for timestamps. Public mostly
+  // for testing/debugging purposes.
+
+  // Returns the logical value embedded in 'timestamp'
+  static uint64_t GetLogicalValue(const Timestamp& timestamp);
+
+  // Returns the physical value embedded in 'timestamp', in microseconds.
+  static uint64_t GetPhysicalValueMicros(const Timestamp& timestamp);
+
+  // Obtains a new Timestamp with the logical value zeroed out.
+  static Timestamp TimestampFromMicroseconds(uint64_t micros);
+
+  // Obtains a new Timestamp that embeds both the physical and logical values.
+  static Timestamp TimestampFromMicrosecondsAndLogicalValue(uint64_t micros,
+                                                            uint64_t logical_value);
+
+  // Creates a new timestamp whose physical time is GetPhysicalValue(original) +
+  // 'to_add' and which retains the same logical value.
+  static Timestamp AddPhysicalTimeToTimestamp(const Timestamp& original,
+                                              const MonoDelta& to_add);
+
+  // Outputs a string containing the physical and logical values of the timestamp,
+  // separated.
+  static std::string StringifyTimestamp(const Timestamp& timestamp);
+
+  // Sets the time to be returned by a mock call to the system clock, for tests.
+  // Requires that 'FLAGS_use_mock_wall_clock' is set to true and that 'now_usec' is higher
+  // than the previously set time.
+  // NOTE: This refers to the time returned by the system clock, not the time returned
+  // by HybridClock, i.e. 'now_usec' is not a HybridTime timestmap and shouldn't have
+  // a logical component.
+  void SetMockClockWallTimeForTests(uint64_t now_usec);
+
+  // Sets the max. error to be returned by a mock call to the system clock, for tests.
+  // Requires that 'FLAGS_use_mock_wall_clock' is set to true.
+  // This can be used to make HybridClock report the wall clock as unsynchronized, by
+  // setting error to be more than the configured tolerance.
+  void SetMockMaxClockErrorForTests(uint64_t max_error_usec);
+
+ private:
+
+  // Obtains the current wallclock time and maximum error in microseconds,
+  // and checks if the clock is synchronized.
+  //
+  // On OS X, the error will always be 0.
+  kudu::Status WalltimeWithError(uint64_t* now_usec, uint64_t* error_usec);
+
+  // Used to get the timestamp for metrics.
+  uint64_t NowForMetrics();
+
+  // Used to get the current error, for metrics.
+  uint64_t ErrorForMetrics();
+
+  // Set by calls to SetMockClockWallTimeForTests().
+  // For testing purposes only.
+  uint64_t mock_clock_time_usec_;
+
+  // Set by calls to SetMockClockErrorForTests().
+  // For testing purposes only.
+  uint64_t mock_clock_max_error_usec_;
+
+#if !defined(__APPLE__)
+  uint64_t divisor_;
+#endif
+
+  double tolerance_adjustment_;
+
+  mutable simple_spinlock lock_;
+
+  // The next timestamp to be generated from this clock, assuming that
+  // the physical clock hasn't advanced beyond the value stored here.
+  uint64_t next_timestamp_;
+
+  // How many bits to left shift a microseconds clock read. The remainder
+  // of the timestamp will be reserved for logical values.
+  static const int kBitsToShift;
+
+  // Mask to extract the pure logical bits.
+  static const uint64_t kLogicalBitMask;
+
+  static const uint64_t kNanosPerSec;
+
+  // The scaling factor used to obtain ppms. From the adjtimex source:
+  // "scale factor used by adjtimex freq param.  1 ppm = 65536"
+  static const double kAdjtimexScalingFactor;
+
+  enum State {
+    kNotInitialized,
+    kInitialized
+  };
+
+  State state_;
+
+  // Clock metrics are set to detach to their last value. This means
+  // that, during our destructor, we'll need to access other class members
+  // declared above this. Hence, this member must be declared last.
+  FunctionGaugeDetacher metric_detacher_;
+};
+
+}  // namespace clock
+}  // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/logical_clock-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/clock/logical_clock-test.cc b/src/kudu/clock/logical_clock-test.cc
new file mode 100644
index 0000000..5b352a3
--- /dev/null
+++ b/src/kudu/clock/logical_clock-test.cc
@@ -0,0 +1,87 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include "kudu/clock/logical_clock.h"
+#include "kudu/util/monotime.h"
+#include "kudu/util/test_util.h"
+
+namespace kudu {
+namespace clock {
+
+class LogicalClockTest : public KuduTest {
+ public:
+  LogicalClockTest()
+      : clock_(LogicalClock::CreateStartingAt(Timestamp::kInitialTimestamp)) {
+  }
+
+ protected:
+  scoped_refptr<LogicalClock> clock_;
+};
+
+// Test that two subsequent time reads are monotonically increasing.
+TEST_F(LogicalClockTest, TestNow_ValuesIncreaseMonotonically) {
+  const Timestamp now1 = clock_->Now();
+  const Timestamp now2 = clock_->Now();
+  ASSERT_EQ(now1.value() + 1, now2.value());
+}
+
+// Tests that the clock gets updated if the incoming value is higher.
+TEST_F(LogicalClockTest, TestUpdate_LogicalValueIncreasesByAmount) {
+  Timestamp initial = clock_->Now();
+  Timestamp future(initial.value() + 10);
+  clock_->Update(future);
+  Timestamp now = clock_->Now();
+  // now should be 1 after future
+  ASSERT_EQ(initial.value() + 11, now.value());
+}
+
+// Tests that the clock doesn't get updated if the incoming value is lower.
+TEST_F(LogicalClockTest, TestUpdate_LogicalValueDoesNotIncrease) {
+  Timestamp ts(1);
+  // update the clock to 1, the initial value, should do nothing
+  clock_->Update(ts);
+  Timestamp now = clock_->Now();
+  ASSERT_EQ(now.value(), 2);
+}
+
+TEST_F(LogicalClockTest, TestWaitUntilAfterIsUnavailable) {
+  Status status = clock_->WaitUntilAfter(
+      Timestamp(10), MonoTime::Now());
+  ASSERT_TRUE(status.IsServiceUnavailable());
+}
+
+TEST_F(LogicalClockTest, TestIsAfter) {
+  Timestamp ts1 = clock_->Now();
+  ASSERT_TRUE(clock_->IsAfter(ts1));
+
+  // Update the clock in the future, make sure it still
+  // handles "IsAfter" properly even when it's running in
+  // "logical" mode.
+  Timestamp now_increased = Timestamp(1000);
+  ASSERT_OK(clock_->Update(now_increased));
+  Timestamp ts2 = clock_->Now();
+
+  ASSERT_TRUE(clock_->IsAfter(ts1));
+  ASSERT_TRUE(clock_->IsAfter(ts2));
+}
+
+}  // namespace clock
+}  // namespace kudu
+

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/logical_clock.cc
----------------------------------------------------------------------
diff --git a/src/kudu/clock/logical_clock.cc b/src/kudu/clock/logical_clock.cc
new file mode 100644
index 0000000..8be4843
--- /dev/null
+++ b/src/kudu/clock/logical_clock.cc
@@ -0,0 +1,106 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "kudu/clock/logical_clock.h"
+
+#include "kudu/gutil/atomicops.h"
+#include "kudu/gutil/bind.h"
+#include "kudu/gutil/strings/substitute.h"
+#include "kudu/util/metrics.h"
+#include "kudu/util/monotime.h"
+#include "kudu/util/status.h"
+
+namespace kudu {
+namespace clock {
+
+METRIC_DEFINE_gauge_uint64(server, logical_clock_timestamp,
+                           "Logical Clock Timestamp",
+                           kudu::MetricUnit::kUnits,
+                           "Logical clock timestamp.");
+
+using base::subtle::Atomic64;
+using base::subtle::Barrier_AtomicIncrement;
+using base::subtle::NoBarrier_CompareAndSwap;
+
+Timestamp LogicalClock::Now() {
+  return Timestamp(Barrier_AtomicIncrement(&now_, 1));
+}
+
+Timestamp LogicalClock::NowLatest() {
+  return Now();
+}
+
+Status LogicalClock::Update(const Timestamp& to_update) {
+  DCHECK_NE(to_update.value(), Timestamp::kInvalidTimestamp.value())
+      << "Updating the clock with an invalid timestamp";
+  Atomic64 new_value = to_update.value();
+
+  while (true) {
+    Atomic64 current_value = NoBarrier_Load(&now_);
+    // if the incoming value is less than the current one, or we've failed the
+    // CAS because the current clock increased to higher than the incoming value,
+    // we can stop the loop now.
+    if (new_value <= current_value) return Status::OK();
+    // otherwise try a CAS
+    if (PREDICT_TRUE(NoBarrier_CompareAndSwap(&now_, current_value, new_value)
+        == current_value))
+      break;
+  }
+  return Status::OK();
+}
+
+Status LogicalClock::WaitUntilAfter(const Timestamp& then,
+                                    const MonoTime& deadline) {
+  return Status::ServiceUnavailable(
+      "Logical clock does not support WaitUntilAfter()");
+}
+
+Status LogicalClock::WaitUntilAfterLocally(const Timestamp& then,
+                                           const MonoTime& deadline) {
+  if (IsAfter(then)) return Status::OK();
+  return Status::ServiceUnavailable(
+      "Logical clock does not support WaitUntilAfterLocally()");
+}
+
+bool LogicalClock::IsAfter(Timestamp t) {
+  return base::subtle::Acquire_Load(&now_) >= t.value();
+}
+
+LogicalClock* LogicalClock::CreateStartingAt(const Timestamp& timestamp) {
+  // initialize at 'timestamp' - 1 so that the  first output value is 'timestamp'.
+  return new LogicalClock(timestamp.value() - 1);
+}
+
+uint64_t LogicalClock::GetCurrentTime() {
+  // We don't want reading metrics to change the clock.
+  return NoBarrier_Load(&now_);
+}
+
+void LogicalClock::RegisterMetrics(const scoped_refptr<MetricEntity>& metric_entity) {
+  METRIC_logical_clock_timestamp.InstantiateFunctionGauge(
+      metric_entity,
+      Bind(&LogicalClock::GetCurrentTime, Unretained(this)))
+    ->AutoDetachToLastValue(&metric_detacher_);
+}
+
+string LogicalClock::Stringify(Timestamp timestamp) {
+  return strings::Substitute("L: $0", timestamp.ToUint64());
+}
+
+}  // namespace clock
+}  // namespace kudu
+

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/clock/logical_clock.h
----------------------------------------------------------------------
diff --git a/src/kudu/clock/logical_clock.h b/src/kudu/clock/logical_clock.h
new file mode 100644
index 0000000..3d91448
--- /dev/null
+++ b/src/kudu/clock/logical_clock.h
@@ -0,0 +1,87 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+#pragma once
+
+#include <string>
+
+#include "kudu/clock/clock.h"
+#include "kudu/util/metrics.h"
+#include "kudu/util/status.h"
+
+namespace kudu {
+class MonoDelta;
+class MonoTime;
+namespace clock {
+
+// An implementation of Clock that behaves as a plain Lamport Clock.
+// In a single node, single tablet, setting this generates exactly the
+// same Timestamp sequence as the original MvccManager did, but it can be
+// updated to make sure replicas generate new timestamps on becoming leader.
+// This can be used as a deterministic timestamp generator that has the same
+// consistency properties as a HybridTime clock.
+//
+// The Wait* methods are unavailable in this implementation and will
+// return Status::ServiceUnavailable().
+//
+// NOTE: this class is thread safe.
+class LogicalClock : public Clock {
+ public:
+
+  virtual Status Init() OVERRIDE { return Status::OK(); }
+
+  virtual Timestamp Now() OVERRIDE;
+
+  // In the logical clock this call is equivalent to Now();
+  virtual Timestamp NowLatest() OVERRIDE;
+
+  virtual Status Update(const Timestamp& to_update) OVERRIDE;
+
+  // The Wait*() functions are not available for this clock.
+  virtual Status WaitUntilAfter(const Timestamp& then,
+                                const MonoTime& deadline) OVERRIDE;
+  virtual Status WaitUntilAfterLocally(const Timestamp& then,
+                                       const MonoTime& deadline) OVERRIDE;
+
+  virtual bool IsAfter(Timestamp t) OVERRIDE;
+
+  virtual void RegisterMetrics(const scoped_refptr<MetricEntity>& metric_entity) OVERRIDE;
+
+  virtual std::string Stringify(Timestamp timestamp) OVERRIDE;
+
+  // Used to get the timestamp without incrementing the logical component.
+  // Mostly used for tests/metrics.
+  uint64_t GetCurrentTime();
+
+  // Logical clock doesn't support COMMIT_WAIT.
+  virtual bool SupportsExternalConsistencyMode(ExternalConsistencyMode mode) OVERRIDE {
+    return mode != COMMIT_WAIT;
+  }
+
+  // Creates a logical clock whose first output value on a Now() call is 'timestamp'.
+  static LogicalClock* CreateStartingAt(const Timestamp& timestamp);
+
+ private:
+  // Should use LogicalClock::CreatingStartingAt()
+  explicit LogicalClock(Timestamp::val_type initial_time) : now_(initial_time) {}
+
+  base::subtle::Atomic64 now_;
+
+  FunctionGaugeDetacher metric_detacher_;
+};
+
+}  // namespace clock
+}  // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/CMakeLists.txt b/src/kudu/consensus/CMakeLists.txt
index 00df31b..03fad03 100644
--- a/src/kudu/consensus/CMakeLists.txt
+++ b/src/kudu/consensus/CMakeLists.txt
@@ -86,7 +86,7 @@ set(LOG_SRCS
 
 add_library(log ${LOG_SRCS})
 target_link_libraries(log
-  server_common
+  clock
   gutil
   kudu_common
   kudu_fs

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/consensus-test-util.h
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/consensus-test-util.h b/src/kudu/consensus/consensus-test-util.h
index b000dde..de1b587 100644
--- a/src/kudu/consensus/consensus-test-util.h
+++ b/src/kudu/consensus/consensus-test-util.h
@@ -36,7 +36,7 @@
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/rpc/messenger.h"
-#include "kudu/server/clock.h"
+#include "kudu/clock/clock.h"
 #include "kudu/util/countdown_latch.h"
 #include "kudu/util/locks.h"
 #include "kudu/util/pb_util.h"
@@ -90,7 +90,7 @@ inline RaftPeerPB FakeRaftPeerPB(const std::string& uuid) {
 // TestOperationStatus::AckPeer().
 inline void AppendReplicateMessagesToQueue(
     PeerMessageQueue* queue,
-    const scoped_refptr<server::Clock>& clock,
+    const scoped_refptr<clock::Clock>& clock,
     int64_t first,
     int64_t count,
     int64_t payload_size = 0) {

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/consensus_peers-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/consensus_peers-test.cc b/src/kudu/consensus/consensus_peers-test.cc
index 2ff9f41..e1b0ac3 100644
--- a/src/kudu/consensus/consensus_peers-test.cc
+++ b/src/kudu/consensus/consensus_peers-test.cc
@@ -19,17 +19,17 @@
 
 #include <gtest/gtest.h>
 
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/schema.h"
 #include "kudu/common/wire_protocol-test-util.h"
-#include "kudu/consensus/consensus_peers.h"
 #include "kudu/consensus/consensus-test-util.h"
+#include "kudu/consensus/consensus_peers.h"
 #include "kudu/consensus/log.h"
 #include "kudu/consensus/log_anchor_registry.h"
 #include "kudu/consensus/log_util.h"
 #include "kudu/consensus/opid_util.h"
 #include "kudu/fs/fs_manager.h"
 #include "kudu/rpc/messenger.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/util/metrics.h"
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
@@ -72,7 +72,7 @@ class ConsensusPeersTest : public KuduTest {
                        0, // schema_version
                        NULL,
                        &log_));
-    clock_.reset(new server::HybridClock());
+    clock_.reset(new clock::HybridClock());
     ASSERT_OK(clock_->Init());
 
     scoped_refptr<TimeManager> time_manager(new TimeManager(clock_, Timestamp::kMin));
@@ -146,7 +146,7 @@ class ConsensusPeersTest : public KuduTest {
   const Schema schema_;
   LogOptions options_;
   unique_ptr<ThreadPoolToken> raft_pool_token_;
-  scoped_refptr<server::Clock> clock_;
+  scoped_refptr<clock::Clock> clock_;
   shared_ptr<Messenger> messenger_;
 };
 

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/consensus_queue-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/consensus_queue-test.cc b/src/kudu/consensus/consensus_queue-test.cc
index 6c732b7..0ce4419 100644
--- a/src/kudu/consensus/consensus_queue-test.cc
+++ b/src/kudu/consensus/consensus_queue-test.cc
@@ -20,6 +20,7 @@
 #include <gflags/gflags.h>
 #include <gtest/gtest.h>
 
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/schema.h"
 #include "kudu/common/wire_protocol-test-util.h"
 #include "kudu/consensus/consensus-test-util.h"
@@ -31,7 +32,6 @@
 #include "kudu/consensus/log_util.h"
 #include "kudu/consensus/time_manager.h"
 #include "kudu/fs/fs_manager.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/util/metrics.h"
 #include "kudu/util/pb_util.h"
 #include "kudu/util/test_macros.h"
@@ -69,7 +69,7 @@ class ConsensusQueueTest : public KuduTest {
                             0, // schema_version
                             NULL,
                             &log_));
-    clock_.reset(new server::HybridClock());
+    clock_.reset(new clock::HybridClock());
     ASSERT_OK(clock_->Init());
 
     ASSERT_OK(ThreadPoolBuilder("raft").Build(&raft_pool_));
@@ -77,7 +77,7 @@ class ConsensusQueueTest : public KuduTest {
   }
 
   void CloseAndReopenQueue() {
-    scoped_refptr<server::Clock> clock(new server::HybridClock());
+    scoped_refptr<clock::Clock> clock(new clock::HybridClock());
     ASSERT_OK(clock->Init());
     scoped_refptr<TimeManager> time_manager(new TimeManager(clock, Timestamp::kMin));
     queue_.reset(new PeerMessageQueue(metric_entity_,
@@ -198,7 +198,7 @@ class ConsensusQueueTest : public KuduTest {
   gscoped_ptr<ThreadPool> raft_pool_;
   gscoped_ptr<PeerMessageQueue> queue_;
   scoped_refptr<log::LogAnchorRegistry> registry_;
-  scoped_refptr<server::Clock> clock_;
+  scoped_refptr<clock::Clock> clock_;
 };
 
 // Tests that the queue is able to track a peer when it starts tracking a peer

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/log-test-base.h
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/log-test-base.h b/src/kudu/consensus/log-test-base.h
index 77a9bc7..a4ee663 100644
--- a/src/kudu/consensus/log-test-base.h
+++ b/src/kudu/consensus/log-test-base.h
@@ -26,6 +26,8 @@
 #include <utility>
 #include <vector>
 
+#include "kudu/clock/clock.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/timestamp.h"
 #include "kudu/common/wire_protocol-test-util.h"
 #include "kudu/consensus/log_anchor_registry.h"
@@ -37,8 +39,6 @@
 #include "kudu/gutil/stringprintf.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/gutil/strings/util.h"
-#include "kudu/server/clock.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/tserver/tserver.pb.h"
 #include "kudu/util/env_util.h"
 #include "kudu/util/metrics.h"
@@ -53,14 +53,14 @@ METRIC_DECLARE_entity(tablet);
 namespace kudu {
 namespace log {
 
+using clock::Clock;
+
 using consensus::OpId;
 using consensus::CommitMsg;
 using consensus::ReplicateMsg;
 using consensus::WRITE_OP;
 using consensus::NO_OP;
 
-using server::Clock;
-
 using tserver::WriteRequestPB;
 
 using tablet::TxResultPB;
@@ -169,7 +169,7 @@ class LogTestBase : public KuduTest {
     ASSERT_OK(fs_manager_->CreateInitialFileSystemLayout());
     ASSERT_OK(fs_manager_->Open());
 
-    clock_.reset(new server::HybridClock());
+    clock_.reset(new clock::HybridClock());
     ASSERT_OK(clock_->Init());
   }
 

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/log_cache-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/log_cache-test.cc b/src/kudu/consensus/log_cache-test.cc
index bb61454..12910fe 100644
--- a/src/kudu/consensus/log_cache-test.cc
+++ b/src/kudu/consensus/log_cache-test.cc
@@ -19,6 +19,7 @@
 #include <memory>
 #include <string>
 
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/wire_protocol-test-util.h"
 #include "kudu/consensus/consensus-test-util.h"
 #include "kudu/consensus/log.h"
@@ -26,7 +27,6 @@
 #include "kudu/fs/fs_manager.h"
 #include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/stl_util.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/util/mem_tracker.h"
 #include "kudu/util/metrics.h"
 #include "kudu/util/test_util.h"
@@ -65,7 +65,7 @@ class LogCacheTest : public KuduTest {
                             &log_));
 
     CloseAndReopenCache(MinimumOpId());
-    clock_.reset(new server::HybridClock());
+    clock_.reset(new clock::HybridClock());
     ASSERT_OK(clock_->Init());
   }
 
@@ -106,7 +106,7 @@ class LogCacheTest : public KuduTest {
   gscoped_ptr<FsManager> fs_manager_;
   gscoped_ptr<LogCache> cache_;
   scoped_refptr<log::Log> log_;
-  scoped_refptr<server::Clock> clock_;
+  scoped_refptr<clock::Clock> clock_;
 };
 
 

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/raft_consensus.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/raft_consensus.cc b/src/kudu/consensus/raft_consensus.cc
index 1756931..cefe569 100644
--- a/src/kudu/consensus/raft_consensus.cc
+++ b/src/kudu/consensus/raft_consensus.cc
@@ -25,6 +25,7 @@
 #include <boost/optional.hpp>
 #include <gflags/gflags.h>
 
+#include "kudu/clock/clock.h"
 #include "kudu/common/wire_protocol.h"
 #include "kudu/consensus/consensus.pb.h"
 #include "kudu/consensus/consensus_meta_manager.h"
@@ -37,7 +38,6 @@
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/stl_util.h"
 #include "kudu/gutil/stringprintf.h"
-#include "kudu/server/clock.h"
 #include "kudu/util/debug/trace_event.h"
 #include "kudu/util/flag_tags.h"
 #include "kudu/util/logging.h"

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/raft_consensus_quorum-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/raft_consensus_quorum-test.cc b/src/kudu/consensus/raft_consensus_quorum-test.cc
index 491e1ad..6bddb5e 100644
--- a/src/kudu/consensus/raft_consensus_quorum-test.cc
+++ b/src/kudu/consensus/raft_consensus_quorum-test.cc
@@ -18,6 +18,7 @@
 #include <gtest/gtest.h>
 #include <memory>
 
+#include "kudu/clock/logical_clock.h"
 #include "kudu/common/schema.h"
 #include "kudu/common/wire_protocol-test-util.h"
 #include "kudu/consensus/consensus-test-util.h"
@@ -37,7 +38,6 @@
 #include "kudu/gutil/strings/strcat.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/rpc/rpc_context.h"
-#include "kudu/server/logical_clock.h"
 #include "kudu/util/auto_release_pool.h"
 #include "kudu/util/mem_tracker.h"
 #include "kudu/util/metrics.h"
@@ -93,7 +93,7 @@ Status WaitUntilLeaderForTests(RaftConsensus* raft) {
 class RaftConsensusQuorumTest : public KuduTest {
  public:
   RaftConsensusQuorumTest()
-    : clock_(server::LogicalClock::CreateStartingAt(Timestamp(0))),
+    : clock_(clock::LogicalClock::CreateStartingAt(Timestamp(0))),
       metric_entity_(METRIC_ENTITY_tablet.Instantiate(&metric_registry_, "raft-test")),
       schema_(GetSimpleTestSchema()) {
     options_.tablet_id = kTestTablet;
@@ -563,7 +563,7 @@ class RaftConsensusQuorumTest : public KuduTest {
   vector<scoped_refptr<ConsensusMetadataManager>> cmeta_managers_;
   gscoped_ptr<TestPeerMapManager> peers_;
   vector<TestTransactionFactory*> txn_factories_;
-  scoped_refptr<server::Clock> clock_;
+  scoped_refptr<clock::Clock> clock_;
   MetricRegistry metric_registry_;
   scoped_refptr<MetricEntity> metric_entity_;
   const Schema schema_;

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/time_manager-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/time_manager-test.cc b/src/kudu/consensus/time_manager-test.cc
index 3254dd3..2aeb212 100644
--- a/src/kudu/consensus/time_manager-test.cc
+++ b/src/kudu/consensus/time_manager-test.cc
@@ -15,14 +15,14 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include <thread>
 #include <gtest/gtest.h>
+#include <thread>
 
+#include "kudu/clock/clock.h"
+#include "kudu/clock/hybrid_clock.h"
+#include "kudu/clock/logical_clock.h"
 #include "kudu/consensus/consensus.pb.h"
 #include "kudu/consensus/time_manager.h"
-#include "kudu/server/clock.h"
-#include "kudu/server/hybrid_clock.h"
-#include "kudu/server/logical_clock.h"
 #include "kudu/util/test_util.h"
 #include "kudu/util/thread.h"
 
@@ -33,7 +33,7 @@ using std::unique_ptr;
 
 class TimeManagerTest : public KuduTest {
  public:
-  TimeManagerTest() : clock_(new server::HybridClock()) {}
+  TimeManagerTest() : clock_(new clock::HybridClock()) {}
 
   void SetUp() override {
     CHECK_OK(clock_->Init());
@@ -63,7 +63,7 @@ class TimeManagerTest : public KuduTest {
     return latch;
   }
 
-  scoped_refptr<server::HybridClock> clock_;
+  scoped_refptr<clock::HybridClock> clock_;
   scoped_refptr<TimeManager> time_manager_;
   vector<unique_ptr<CountDownLatch>> latches_;
   vector<std::thread> threads_;

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/time_manager.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/time_manager.cc b/src/kudu/consensus/time_manager.cc
index 23312f8..b1f1482 100644
--- a/src/kudu/consensus/time_manager.cc
+++ b/src/kudu/consensus/time_manager.cc
@@ -45,7 +45,7 @@ DECLARE_int32(scanner_max_wait_ms);
 namespace kudu {
 namespace consensus {
 
-using server::Clock;
+using clock::Clock;
 using strings::Substitute;
 
 typedef std::lock_guard<simple_spinlock> Lock;

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/consensus/time_manager.h
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/time_manager.h b/src/kudu/consensus/time_manager.h
index 58720fe..a54916a 100644
--- a/src/kudu/consensus/time_manager.h
+++ b/src/kudu/consensus/time_manager.h
@@ -20,9 +20,9 @@
 #include <string>
 #include <vector>
 
+#include "kudu/clock/clock.h"
 #include "kudu/common/timestamp.h"
 #include "kudu/gutil/ref_counted.h"
-#include "kudu/server/clock.h"
 #include "kudu/util/locks.h"
 #include "kudu/util/status.h"
 
@@ -69,7 +69,7 @@ class TimeManager : public RefCountedThreadSafe<TimeManager> {
  public:
 
   // Constructs a TimeManager in non-leader mode.
-  TimeManager(scoped_refptr<server::Clock> clock,  Timestamp initial_safe_time);
+  TimeManager(scoped_refptr<clock::Clock> clock,  Timestamp initial_safe_time);
 
   // Sets this TimeManager to leader mode.
   void SetLeaderMode();
@@ -207,7 +207,7 @@ class TimeManager : public RefCountedThreadSafe<TimeManager> {
   // The current mode of the TimeManager.
   Mode mode_;
 
-  const scoped_refptr<server::Clock> clock_;
+  const scoped_refptr<clock::Clock> clock_;
   const std::string local_peer_uuid_;
 };
 

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/integration-tests/alter_table-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/alter_table-test.cc b/src/kudu/integration-tests/alter_table-test.cc
index 224b02a..5c63537 100644
--- a/src/kudu/integration-tests/alter_table-test.cc
+++ b/src/kudu/integration-tests/alter_table-test.cc
@@ -26,20 +26,20 @@
 #include <gflags/gflags.h>
 #include <gtest/gtest.h>
 
-#include "kudu/client/client.h"
 #include "kudu/client/client-test-util.h"
+#include "kudu/client/client.h"
 #include "kudu/client/row_result.h"
 #include "kudu/client/scan_batch.h"
 #include "kudu/client/schema.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/gutil/stl_util.h"
 #include "kudu/gutil/strings/join.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/integration-tests/internal_mini_cluster.h"
+#include "kudu/master/master-test-util.h"
 #include "kudu/master/master.h"
 #include "kudu/master/master.pb.h"
-#include "kudu/master/master-test-util.h"
 #include "kudu/master/mini_master.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/tablet/tablet_replica.h"
 #include "kudu/tserver/mini_tablet_server.h"
 #include "kudu/tserver/tablet_server.h"

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/integration-tests/authn_token_expire-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/authn_token_expire-itest.cc b/src/kudu/integration-tests/authn_token_expire-itest.cc
index f21a9bc..ced3b1f 100644
--- a/src/kudu/integration-tests/authn_token_expire-itest.cc
+++ b/src/kudu/integration-tests/authn_token_expire-itest.cc
@@ -22,21 +22,21 @@
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
-#include "kudu/client/client.h"
 #include "kudu/client/client-test-util.h"
+#include "kudu/client/client.h"
 #include "kudu/client/shared_ptr.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/partial_row.h"
 #include "kudu/gutil/stringprintf.h"
 #include "kudu/gutil/strings/substitute.h"
-#include "kudu/master/catalog_manager.h"
-#include "kudu/master/master.h"
-#include "kudu/master/master.pb.h"
-#include "kudu/master/mini_master.h"
 #include "kudu/integration-tests/cluster_itest_util.h"
 #include "kudu/integration-tests/cluster_verifier.h"
 #include "kudu/integration-tests/external_mini_cluster.h"
 #include "kudu/integration-tests/test_workload.h"
-#include "kudu/server/hybrid_clock.h"
+#include "kudu/master/catalog_manager.h"
+#include "kudu/master/master.h"
+#include "kudu/master/master.pb.h"
+#include "kudu/master/mini_master.h"
 #include "kudu/tablet/key_value_test_schema.h"
 #include "kudu/tablet/tablet.h"
 #include "kudu/tablet/tablet_replica.h"

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/integration-tests/consistency-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/consistency-itest.cc b/src/kudu/integration-tests/consistency-itest.cc
index 992b8d3..6aa2f23 100644
--- a/src/kudu/integration-tests/consistency-itest.cc
+++ b/src/kudu/integration-tests/consistency-itest.cc
@@ -23,22 +23,22 @@
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
-#include "kudu/client/client.h"
 #include "kudu/client/client-test-util.h"
-#include "kudu/client/scanner-internal.h"
+#include "kudu/client/client.h"
 #include "kudu/client/scan_configuration.h"
+#include "kudu/client/scanner-internal.h"
 #include "kudu/client/shared_ptr.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/partial_row.h"
 #include "kudu/gutil/stringprintf.h"
 #include "kudu/gutil/strings/substitute.h"
+#include "kudu/integration-tests/cluster_itest_util.h"
+#include "kudu/integration-tests/internal_mini_cluster-itest-base.h"
+#include "kudu/integration-tests/internal_mini_cluster.h"
 #include "kudu/master/catalog_manager.h"
 #include "kudu/master/master.h"
 #include "kudu/master/master.pb.h"
 #include "kudu/master/mini_master.h"
-#include "kudu/integration-tests/cluster_itest_util.h"
-#include "kudu/integration-tests/internal_mini_cluster-itest-base.h"
-#include "kudu/integration-tests/internal_mini_cluster.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/tablet/tablet.h"
 #include "kudu/tablet/tablet_replica.h"
 #include "kudu/tserver/mini_tablet_server.h"
@@ -58,7 +58,7 @@ using kudu::client::sp::shared_ptr;
 using kudu::master::CatalogManager;
 using kudu::master::GetTableLocationsRequestPB;
 using kudu::master::GetTableLocationsResponsePB;
-using kudu::server::HybridClock;
+using kudu::clock::HybridClock;
 using kudu::tablet::TabletReplica;
 using kudu::tserver::MiniTabletServer;
 using kudu::tserver::TabletServer;

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/integration-tests/fuzz-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/fuzz-itest.cc b/src/kudu/integration-tests/fuzz-itest.cc
index 2631966..15f37d7 100644
--- a/src/kudu/integration-tests/fuzz-itest.cc
+++ b/src/kudu/integration-tests/fuzz-itest.cc
@@ -17,24 +17,24 @@
 
 #include <boost/optional.hpp>
 #include <boost/optional/optional_io.hpp>
+#include <gflags/gflags.h>
 #include <glog/logging.h>
 #include <glog/stl_logging.h>
 #include <gtest/gtest.h>
-#include <gflags/gflags.h>
 #include <list>
 #include <string>
 #include <vector>
 
-#include "kudu/client/client.h"
 #include "kudu/client/client-test-util.h"
+#include "kudu/client/client.h"
 #include "kudu/client/row_result.h"
 #include "kudu/client/schema.h"
+#include "kudu/clock/logical_clock.h"
 #include "kudu/gutil/casts.h"
 #include "kudu/gutil/strings/join.h"
 #include "kudu/gutil/strings/substitute.h"
-#include "kudu/master/mini_master.h"
 #include "kudu/integration-tests/internal_mini_cluster.h"
-#include "kudu/server/logical_clock.h"
+#include "kudu/master/mini_master.h"
 #include "kudu/tablet/key_value_test_schema.h"
 #include "kudu/tablet/tablet.h"
 #include "kudu/tablet/tablet_replica.h"
@@ -661,7 +661,7 @@ void FuzzTest::RunFuzzCase(const vector<TestOp>& test_ops,
       case TEST_FLUSH_OPS: {
         FlushSessionOrDie(session_);
         cur_val = pending_val;
-        int current_time = down_cast<kudu::server::LogicalClock*>(
+        int current_time = down_cast<kudu::clock::LogicalClock*>(
             tablet()->clock().get())->GetCurrentTime();
         saved_values_[current_time] = cur_val;
         break;

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/integration-tests/linked_list-test-util.h
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/linked_list-test-util.h b/src/kudu/integration-tests/linked_list-test-util.h
index baf9ebf..97d149a 100644
--- a/src/kudu/integration-tests/linked_list-test-util.h
+++ b/src/kudu/integration-tests/linked_list-test-util.h
@@ -25,16 +25,16 @@
 
 #include <glog/logging.h>
 
-#include "kudu/client/client.h"
 #include "kudu/client/client-test-util.h"
+#include "kudu/client/client.h"
 #include "kudu/client/row_result.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/gutil/stl_util.h"
 #include "kudu/gutil/strings/join.h"
-#include "kudu/gutil/strings/substitute.h"
 #include "kudu/gutil/strings/split.h"
+#include "kudu/gutil/strings/substitute.h"
 #include "kudu/gutil/walltime.h"
 #include "kudu/integration-tests/external_mini_cluster.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/tablet/tablet.h"
 #include "kudu/util/atomic.h"
 #include "kudu/util/blocking_queue.h"
@@ -585,7 +585,7 @@ Status LinkedListTester::VerifyLinkedListRemote(
   if (snapshot_timestamp == kSnapshotAtNow) {
     snapshot_str = "NOW";
   } else {
-    snapshot_str = server::HybridClock::StringifyTimestamp(Timestamp(snapshot_timestamp));
+    snapshot_str = clock::HybridClock::StringifyTimestamp(Timestamp(snapshot_timestamp));
   }
 
   client::KuduScanner scanner(table.get());

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/integration-tests/tablet_history_gc-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/tablet_history_gc-itest.cc b/src/kudu/integration-tests/tablet_history_gc-itest.cc
index 2210cbc..009df58 100644
--- a/src/kudu/integration-tests/tablet_history_gc-itest.cc
+++ b/src/kudu/integration-tests/tablet_history_gc-itest.cc
@@ -21,13 +21,13 @@
 #include <utility>
 
 #include "kudu/client/client-test-util.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/common/wire_protocol-test-util.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/ref_counted.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/integration-tests/internal_mini_cluster-itest-base.h"
 #include "kudu/integration-tests/test_workload.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/tablet/local_tablet_writer.h"
 #include "kudu/tablet/tablet.h"
 #include "kudu/tablet/tablet_metrics.h"
@@ -40,7 +40,7 @@
 using kudu::client::KuduScanner;
 using kudu::client::KuduTable;
 using kudu::client::sp::shared_ptr;
-using kudu::server::HybridClock;
+using kudu::clock::HybridClock;
 using kudu::tablet::Tablet;
 using kudu::tablet::TabletReplica;
 using kudu::tserver::MiniTabletServer;

http://git-wip-us.apache.org/repos/asf/kudu/blob/7ff27dcf/src/kudu/integration-tests/ts_recovery-itest.cc
----------------------------------------------------------------------
diff --git a/src/kudu/integration-tests/ts_recovery-itest.cc b/src/kudu/integration-tests/ts_recovery-itest.cc
index c00967d..e674884 100644
--- a/src/kudu/integration-tests/ts_recovery-itest.cc
+++ b/src/kudu/integration-tests/ts_recovery-itest.cc
@@ -22,6 +22,8 @@
 #include <glog/stl_logging.h>
 
 #include "kudu/client/client.h"
+#include "kudu/clock/clock.h"
+#include "kudu/clock/hybrid_clock.h"
 #include "kudu/consensus/consensus-test-util.h"
 #include "kudu/consensus/consensus.pb.h"
 #include "kudu/consensus/consensus_meta.h"
@@ -31,11 +33,9 @@
 #include "kudu/fs/fs_manager.h"
 #include "kudu/integration-tests/cluster_itest_util.h"
 #include "kudu/integration-tests/cluster_verifier.h"
-#include "kudu/integration-tests/external_mini_cluster.h"
 #include "kudu/integration-tests/external_mini_cluster-itest-base.h"
+#include "kudu/integration-tests/external_mini_cluster.h"
 #include "kudu/integration-tests/test_workload.h"
-#include "kudu/server/clock.h"
-#include "kudu/server/hybrid_clock.h"
 #include "kudu/util/random.h"
 #include "kudu/util/random_util.h"
 #include "kudu/util/test_util.h"
@@ -52,6 +52,8 @@ using client::KuduSession;
 using client::KuduTable;
 using client::KuduUpdate;
 using client::sp::shared_ptr;
+using clock::Clock;
+using clock::HybridClock;
 using consensus::ConsensusMetadata;
 using consensus::ConsensusMetadataManager;
 using consensus::OpId;
@@ -59,8 +61,6 @@ using consensus::RECEIVED_OPID;
 using log::AppendNoOpsToLogSync;
 using log::Log;
 using log::LogOptions;
-using server::Clock;
-using server::HybridClock;
 
 namespace {
 // Generate a row key such that an increasing sequence (0...N) ends up spreading writes


Mime
View raw message