YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/integration-tests/registration-test.cc
Line
Count
Source (jump to first uncovered line)
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 <memory>
34
#include <string>
35
36
#include <gflags/gflags.h>
37
#include <gtest/gtest.h>
38
39
#include "yb/client/yb_table_name.h"
40
41
#include "yb/common/schema.h"
42
43
#include "yb/fs/fs_manager.h"
44
45
#include "yb/integration-tests/mini_cluster.h"
46
#include "yb/integration-tests/yb_mini_cluster_test_base.h"
47
48
#include "yb/master/master-test-util.h"
49
#include "yb/master/master_client.pb.h"
50
#include "yb/master/mini_master.h"
51
#include "yb/master/ts_descriptor.h"
52
53
#include "yb/tablet/tablet.h"
54
#include "yb/tablet/tablet_peer.h"
55
56
#include "yb/tserver/mini_tablet_server.h"
57
#include "yb/tserver/tablet_server.h"
58
59
#include "yb/util/curl_util.h"
60
#include "yb/util/faststring.h"
61
#include "yb/util/metrics.h"
62
#include "yb/util/test_util.h"
63
#include "yb/util/tsan_util.h"
64
65
DECLARE_int32(heartbeat_interval_ms);
66
DECLARE_int32(yb_num_shards_per_tserver);
67
DECLARE_bool(enable_ysql);
68
69
METRIC_DECLARE_counter(rows_inserted);
70
71
namespace yb {
72
73
using std::vector;
74
using std::shared_ptr;
75
using master::MiniMaster;
76
using master::TSDescriptor;
77
using master::TabletLocationsPB;
78
using tserver::MiniTabletServer;
79
using client::YBTableName;
80
81
// Tests for the Tablet Server registering with the Master,
82
// and the master maintaining the tablet descriptor.
83
class RegistrationTest : public YBMiniClusterTestBase<MiniCluster> {
84
 public:
85
  RegistrationTest()
86
4
      : schema_({ ColumnSchema("c1", UINT32, /* is_nullable */ false, /* is_hash_key */ true)}, 1) {
87
4
  }
88
89
4
  void SetUp() override {
90
    // Make heartbeats faster to speed test runtime.
91
4
    FLAGS_heartbeat_interval_ms = 10;
92
93
    // To prevent automatic creation of the transaction status table.
94
4
    FLAGS_enable_ysql = false;
95
96
4
    YBMiniClusterTestBase::SetUp();
97
98
4
    cluster_.reset(new MiniCluster(MiniClusterOptions()));
99
4
    ASSERT_OK(cluster_->Start());
100
4
  }
101
102
2
  void DoTearDown() override {
103
2
    cluster_->Shutdown();
104
2
  }
105
106
1
  void CheckTabletServersPage() {
107
1
    EasyCurl c;
108
1
    faststring buf;
109
1
    std::string addr = yb::ToString(cluster_->mini_master()->bound_http_addr());
110
1
    ASSERT_OK(c.FetchURL(strings::Substitute("http://$0/tablet-servers", addr), &buf));
111
112
    // Should include the TS UUID
113
1
    string expected_uuid =
114
1
      cluster_->mini_tablet_server(0)->server()->instance_pb().permanent_uuid();
115
1
    ASSERT_STR_CONTAINS(buf.ToString(), expected_uuid);
116
1
  }
117
118
  // For debugging, try running with --test-args --vmodule=sys_catalog_writer=2,tablet=3.
119
2
  void CheckTabletReports(bool co_partition = false) {
120
2
    string tablet_id_1;
121
2
    string tablet_id_2;
122
2
    string table_id_1;
123
    // Speed up test by having low number of tablets.
124
2
    FLAGS_yb_num_shards_per_tserver = 2;
125
126
2
    ASSERT_OK(cluster_->WaitForTabletServerCount(1));
127
128
2
    MiniTabletServer* ts = cluster_->mini_tablet_server(0);
129
130
2
    auto GetCatalogMetric = [&](CounterPrototype& prototype) -> int64_t {
131
2
      auto metrics = cluster_->mini_master()
132
2
                         ->tablet_peer()
133
2
                         ->shared_tablet()
134
2
                         ->GetTabletMetricsEntity();
135
2
      return prototype.Instantiate(metrics)->value();
136
2
    };
137
2
    auto before_rows_inserted = GetCatalogMetric(METRIC_rows_inserted);
138
2
    LOG(INFO) << "Begin calculating sys catalog rows inserted";
139
140
    // Add a tablet, make sure it reports itself.
141
2
    CreateTabletForTesting(cluster_->mini_master(),
142
2
                           YBTableName(YQL_DATABASE_CQL, "my_keyspace", "fake-table"),
143
2
                           schema_,
144
2
                           &tablet_id_1,
145
2
                           &table_id_1);
146
147
2
    TabletLocationsPB locs;
148
2
    ASSERT_OK(cluster_->WaitForReplicaCount(tablet_id_1, 1, &locs));
149
0
    ASSERT_EQ(1, locs.replicas_size());
150
0
    LOG(INFO) << "Tablet successfully reported on " <<
151
0
              locs.replicas(0).ts_info().permanent_uuid();
152
153
0
    LOG(INFO) << "Finish calculating sys catalog rows inserted";
154
0
    auto after_create_rows_inserted = GetCatalogMetric(METRIC_rows_inserted);
155
    // Check that we inserted the right number of rows for the first table:
156
    // - 2 for the namespace
157
    // - 1 for the table
158
    // - 3 * FLAGS_yb_num_shards_per_tserver for the tablets:
159
    //    PREPARING, first heartbeat, leader election heartbeat
160
0
    int64_t expected_rows = 2 + 1 + FLAGS_yb_num_shards_per_tserver * 3;
161
0
    EXPECT_EQ(expected_rows, after_create_rows_inserted - before_rows_inserted);
162
163
    // Add another tablet, make sure it is reported via incremental.
164
0
    Schema schema_copy = Schema(schema_);
165
0
    if (co_partition) {
166
0
      schema_copy.SetCopartitionTableId(table_id_1);
167
0
    }
168
169
    // Record the number of rows before the new table.
170
0
    before_rows_inserted = GetCatalogMetric(METRIC_rows_inserted);
171
0
    LOG(INFO) << "Begin calculating sys catalog rows inserted (2)";
172
0
    CreateTabletForTesting(cluster_->mini_master(),
173
0
                           YBTableName(YQL_DATABASE_CQL, "my_keyspace", "fake-table2"),
174
0
                           schema_copy,
175
0
                           &tablet_id_2);
176
    // Sleep for enough to make sure the TS has plenty of time to re-heartbeat.
177
0
    auto sleep_duration_sec = MonoDelta::FromSeconds(RegularBuildVsSanitizers(2, 5));
178
0
    SleepFor(sleep_duration_sec);
179
0
    LOG(INFO) << "Finish calculating sys catalog rows inserted (2)";
180
0
    after_create_rows_inserted = GetCatalogMetric(METRIC_rows_inserted);
181
    // For a normal table, we expect 3 writes per tablet.
182
    // For a copartitioned table, we expect just 1 write per tablet.
183
    // For both, we expect 1 write for the table.
184
0
    expected_rows = 1 + FLAGS_yb_num_shards_per_tserver * (co_partition ? 1 : 3);
185
0
    EXPECT_EQ(expected_rows, after_create_rows_inserted - before_rows_inserted);
186
0
    ASSERT_OK(cluster_->WaitForReplicaCount(tablet_id_2, 1, &locs));
187
188
0
    if (co_partition) {
189
0
      ASSERT_EQ(tablet_id_1, tablet_id_2);
190
0
    }
191
192
    // Shut down the whole system, bring it back up, and make sure the tablets
193
    // are reported.
194
0
    ts->Shutdown();
195
0
    ASSERT_OK(cluster_->mini_master()->Restart());
196
0
    ASSERT_OK(ts->Start());
197
0
    ASSERT_OK(cluster_->WaitForTabletServerCount(1));
198
199
0
    ASSERT_OK(cluster_->WaitForReplicaCount(tablet_id_1, 1, &locs));
200
0
    ASSERT_OK(cluster_->WaitForReplicaCount(tablet_id_2, 1, &locs));
201
    // Sleep for enough to make sure the TS has plenty of time to re-heartbeat.
202
0
    SleepFor(sleep_duration_sec);
203
204
    // After restart, check that the tablet reports produced the expected number of
205
    // writes to the catalog table:
206
    // - If no copartitions, then two updates per tablet, since both replicas should have increased
207
    //   their term on restart.
208
    // - If copartitioned, then one update per tablet.
209
0
    EXPECT_EQ(
210
0
        (co_partition ? 1 : 2) * FLAGS_yb_num_shards_per_tserver,
211
0
        GetCatalogMetric(METRIC_rows_inserted));
212
213
    // If we restart just the master, it should not write any data to the catalog, since the
214
    // tablets themselves are not changing term, etc.
215
0
    ASSERT_OK(cluster_->mini_master()->Restart());
216
    // Sleep for enough to make sure the TS has plenty of time to re-heartbeat.
217
0
    ASSERT_OK(cluster_->WaitForTabletServerCount(1));
218
0
    SleepFor(sleep_duration_sec);
219
0
    EXPECT_EQ(0, GetCatalogMetric(METRIC_rows_inserted));
220
221
    // TODO: KUDU-870: once the master supports detecting failed/lost replicas,
222
    // we should add a test case here which removes or corrupts metadata, restarts
223
    // the TS, and verifies that the master notices the issue.
224
0
  }
225
226
 protected:
227
  Schema schema_;
228
};
229
230
1
TEST_F(RegistrationTest, TestTSRegisters) {
231
1
  DontVerifyClusterBeforeNextTearDown();
232
  // Wait for the TS to register.
233
1
  vector<shared_ptr<TSDescriptor> > descs;
234
1
  ASSERT_OK(cluster_->WaitForTabletServerCount(1, &descs));
235
1
  ASSERT_EQ(1, descs.size());
236
237
  // Verify that the registration is sane.
238
1
  master::TSRegistrationPB reg = descs[0]->GetRegistration();
239
1
  {
240
1
    SCOPED_TRACE(reg.ShortDebugString());
241
2
    ASSERT_EQ(reg.ShortDebugString().find("0.0.0.0"), string::npos)
242
2
      << "Should not include wildcards in registration";
243
1
  }
244
245
1
  ASSERT_NO_FATALS(CheckTabletServersPage());
246
247
  // Restart the master, so it loses the descriptor, and ensure that the
248
  // heartbeater thread handles re-registering.
249
1
  ASSERT_OK(cluster_->mini_master()->Restart());
250
251
1
  ASSERT_OK(cluster_->WaitForTabletServerCount(1));
252
253
  // TODO: when the instance ID / sequence number stuff is implemented,
254
  // restart the TS and ensure that it re-registers with the newer sequence
255
  // number.
256
1
}
257
258
// Test starting multiple tablet servers and ensuring they both register with the master.
259
1
TEST_F(RegistrationTest, TestMultipleTS) {
260
1
  DontVerifyClusterBeforeNextTearDown();
261
1
  ASSERT_OK(cluster_->WaitForTabletServerCount(1));
262
1
  ASSERT_OK(cluster_->AddTabletServer());
263
0
  ASSERT_OK(cluster_->WaitForTabletServerCount(2));
264
0
}
265
266
// TODO: this doesn't belong under "RegistrationTest" - rename this file
267
// to something more appropriate - doesn't seem worth having separate
268
// whole test suites for registration, tablet reports, etc.
269
1
TEST_F(RegistrationTest, TestTabletReports) {
270
1
  CheckTabletReports();
271
1
}
272
273
1
TEST_F(RegistrationTest, TestCopartitionedTables) {
274
1
  CheckTabletReports(/* co_partition */ true);
275
1
}
276
277
} // namespace yb