/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 |