YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/server/hybrid_clock-test.cc
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include <algorithm>
34
35
#include <glog/logging.h>
36
#include <gtest/gtest.h>
37
38
#include "yb/server/hybrid_clock.h"
39
40
#include "yb/util/atomic.h"
41
#include "yb/util/monotime.h"
42
#include "yb/util/random.h"
43
#include "yb/util/random_util.h"
44
#include "yb/util/test_util.h"
45
#include "yb/util/thread.h"
46
47
DECLARE_uint64(max_clock_sync_error_usec);
48
DECLARE_bool(disable_clock_sync_error);
49
50
namespace yb {
51
namespace server {
52
53
class HybridClockTest : public YBTest {
54
 public:
55
  HybridClockTest()
56
5
      : clock_(new HybridClock()) {
57
5
  }
58
59
5
  void SetUp() override {
60
5
    YBTest::SetUp();
61
5
    ASSERT_OK(clock_->Init());
62
5
  }
63
64
 protected:
65
  void RunMultiThreadedTest(int num_reads_per_update);
66
67
  scoped_refptr<HybridClock> clock_;
68
};
69
70
1
TEST(MockHybridClockTest, TestMockedSystemClock) {
71
1
  ASSERT_EQ(kMaxHybridTimePhysicalMicros, HybridTime::kMax.GetPhysicalValueMicros());
72
1
  MockClock mock_clock;
73
1
  scoped_refptr<HybridClock> clock(new HybridClock(mock_clock.AsClock()));
74
1
  ASSERT_OK(clock->Init());
75
1
  HybridTime hybrid_time;
76
1
  uint64_t max_error_usec;
77
1
  clock->NowWithError(&hybrid_time, &max_error_usec);
78
1
  ASSERT_EQ(hybrid_time.ToUint64(), 0);
79
1
  ASSERT_EQ(max_error_usec, 0);
80
  // If we read the clock again we should see the logical component be incremented.
81
1
  clock->NowWithError(&hybrid_time, &max_error_usec);
82
1
  ASSERT_EQ(hybrid_time.ToUint64(), 1);
83
  // Now set an arbitrary time and check that is the time returned by the clock.
84
1
  PhysicalTime time = {1234, 100 * 1000};
85
1
  mock_clock.Set(time);
86
1
  clock->NowWithError(&hybrid_time, &max_error_usec);
87
1
  ASSERT_EQ(hybrid_time.ToUint64(),
88
1
            HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(time.time_point, 0).ToUint64());
89
1
  ASSERT_EQ(max_error_usec, time.max_error);
90
  // Perform another read, we should observe the logical component increment, again.
91
1
  clock->NowWithError(&hybrid_time, &max_error_usec);
92
1
  ASSERT_EQ(hybrid_time.ToUint64(),
93
1
            HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(time.time_point, 1).ToUint64());
94
1
}
95
96
// Test that two subsequent time reads are monotonically increasing.
97
1
TEST_F(HybridClockTest, TestNow_ValuesIncreaseMonotonically) {
98
1
  const HybridTime now1 = clock_->Now();
99
1
  const HybridTime now2 = clock_->Now();
100
1
  ASSERT_LT(now1.value(), now2.value());
101
1
}
102
103
// Tests the clock updates with the incoming value if it is higher.
104
1
TEST_F(HybridClockTest, TestUpdate_LogicalValueIncreasesByAmount) {
105
1
  HybridTime now = clock_->Now();
106
1
  uint64_t now_micros = HybridClock::GetPhysicalValueMicros(now);
107
108
  // increase the logical value
109
1
  auto logical = HybridClock::GetLogicalValue(now);
110
1
  logical += 10;
111
112
  // increase the physical value so that we're sure the clock will take this
113
  // one, 200 msecs should be more than enough.
114
1
  now_micros += 200000;
115
116
1
  HybridTime now_increased = HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(
117
1
      now_micros, logical);
118
119
1
  clock_->Update(now_increased);
120
121
1
  HybridTime now2 = clock_->Now();
122
1
  ASSERT_EQ(logical + 1, HybridClock::GetLogicalValue(now2));
123
1
  ASSERT_EQ(HybridClock::GetPhysicalValueMicros(now) + 200000,
124
1
            HybridClock::GetPhysicalValueMicros(now2));
125
1
}
126
127
// Thread which loops polling the clock and updating it slightly
128
// into the future.
129
8
void StresserThread(HybridClock* clock, AtomicBool* stop, int num_reads_per_update) {
130
8
  Random rng(GetRandomSeed32());
131
8
  HybridTime prev = HybridTime::kMin;
132
5.72M
  while (!stop->Load()) {
133
5.72M
    HybridTime t;
134
18.8M
    for (int i = 0; i < num_reads_per_update; ++i) {
135
13.6M
      t = clock->Now();
136
13.6M
      ASSERT_GT(t, prev);
137
13.1M
      prev = t;
138
13.1M
    }
139
140
    // Add a random bit of offset to the clock, and perform an update.
141
5.26M
    HybridTime new_ht = HybridClock::AddPhysicalTimeToHybridTime(
142
5.26M
        t, MonoDelta::FromMicroseconds(rng.Uniform(10000)));
143
5.26M
    clock->Update(new_ht);
144
5.26M
    prev = new_ht;
145
5.26M
  }
146
8
}
147
148
// Regression test for KUDU-953: if threads are updating and polling the
149
// clock concurrently, the clock should still never run backwards.
150
1
TEST_F(HybridClockTest, TestClockDoesntGoBackwardsWithUpdates) {
151
1
  RunMultiThreadedTest(1);
152
1
}
153
154
1
TEST_F(HybridClockTest, TestClockDoesntGoBackwardsWithOccasionalUpdates) {
155
1
  RunMultiThreadedTest(1000000);
156
1
}
157
158
2
void HybridClockTest::RunMultiThreadedTest(int num_reads_per_update) {
159
2
  vector<scoped_refptr<yb::Thread> > threads;
160
161
2
  AtomicBool stop(false);
162
10
  for (int i = 0; i < 4; i++) {
163
8
    scoped_refptr<Thread> thread;
164
8
    ASSERT_OK(Thread::Create("test", "stresser",
165
8
                             &StresserThread, clock_.get(), &stop, num_reads_per_update,
166
8
                             &thread));
167
8
    threads.push_back(thread);
168
8
  }
169
170
2
  SleepFor(MonoDelta::FromSeconds(10));
171
2
  stop.Store(true);
172
8
  for (const scoped_refptr<Thread>& t : threads) {
173
8
    t->Join();
174
8
  }
175
2
}
176
177
1
TEST_F(HybridClockTest, CompareHybridClocksToDelta) {
178
1
  EXPECT_EQ(1, HybridClock::CompareHybridClocksToDelta(
179
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
180
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1002, 10),
181
1
      MonoDelta::FromMicroseconds(1)));
182
183
1
  EXPECT_EQ(-1, HybridClock::CompareHybridClocksToDelta(
184
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
185
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1002, 10),
186
1
      MonoDelta::FromMicroseconds(5)));
187
188
1
  EXPECT_EQ(0, HybridClock::CompareHybridClocksToDelta(
189
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
190
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1001, 10),
191
1
      MonoDelta::FromMicroseconds(1)));
192
193
1
  EXPECT_EQ(1, HybridClock::CompareHybridClocksToDelta(
194
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
195
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1001, 11),
196
1
      MonoDelta::FromMicroseconds(1)));
197
198
1
  EXPECT_EQ(-1, HybridClock::CompareHybridClocksToDelta(
199
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
200
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1001, 9),
201
1
      MonoDelta::FromMicroseconds(1)));
202
203
1
  EXPECT_EQ(-1, HybridClock::CompareHybridClocksToDelta(
204
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
205
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
206
1
      MonoDelta::FromNanoseconds(MonoTime::kNanosecondsPerMicrosecond - 1)));
207
208
1
  EXPECT_EQ(-1, HybridClock::CompareHybridClocksToDelta(
209
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
210
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1001, 10),
211
1
      MonoDelta::FromNanoseconds(MonoTime::kNanosecondsPerMicrosecond + 1)));
212
213
1
  ASSERT_NO_FATALS(HybridClock::GetPhysicalValueNanos(
214
1
      HybridTime(std::numeric_limits<uint64_t>::max())));
215
216
1
  EXPECT_EQ(-1, HybridClock::CompareHybridClocksToDelta(
217
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 10),
218
1
      HybridClock::HybridTimeFromMicrosecondsAndLogicalValue(1000, 9),
219
1
      MonoDelta::FromMicroseconds(1)));
220
1
}
221
222
}  // namespace server
223
}  // namespace yb