/Users/deen/code/yugabyte-db/src/yb/integration-tests/yb_table_test_base.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #include "yb/integration-tests/yb_table_test_base.h" |
15 | | |
16 | | #include "yb/client/client.h" |
17 | | #include "yb/client/session.h" |
18 | | #include "yb/client/table.h" |
19 | | #include "yb/client/table_creator.h" |
20 | | #include "yb/client/yb_op.h" |
21 | | |
22 | | #include "yb/common/ql_value.h" |
23 | | |
24 | | #include "yb/master/master_client.proxy.h" |
25 | | |
26 | | #include "yb/tools/yb-admin_client.h" |
27 | | |
28 | | #include "yb/tserver/mini_tablet_server.h" |
29 | | #include "yb/tserver/tablet_server.h" |
30 | | |
31 | | #include "yb/util/curl_util.h" |
32 | | #include "yb/util/monotime.h" |
33 | | #include "yb/util/result.h" |
34 | | #include "yb/util/status_log.h" |
35 | | #include "yb/util/string_util.h" |
36 | | |
37 | | DECLARE_bool(enable_ysql); |
38 | | |
39 | | using std::unique_ptr; |
40 | | using std::shared_ptr; |
41 | | |
42 | | namespace yb { |
43 | | |
44 | | using client::YBClient; |
45 | | using client::YBClientBuilder; |
46 | | using client::YBColumnSchema; |
47 | | using client::YBSchemaBuilder; |
48 | | using client::YBSession; |
49 | | using client::YBTableCreator; |
50 | | using client::YBTableType; |
51 | | using client::YBTableName; |
52 | | using strings::Substitute; |
53 | | |
54 | | namespace integration_tests { |
55 | | |
56 | 22 | YBTableTestBase::~YBTableTestBase() { |
57 | 22 | } |
58 | | |
59 | | const YBTableName YBTableTestBase::kDefaultTableName( |
60 | | YQL_DATABASE_CQL, "my_keyspace", "kv-table-test"); |
61 | | |
62 | 95 | size_t YBTableTestBase::num_masters() { |
63 | 95 | return kDefaultNumMasters; |
64 | 95 | } |
65 | | |
66 | 248 | size_t YBTableTestBase::num_tablet_servers() { |
67 | 248 | return kDefaultNumTabletServers; |
68 | 248 | } |
69 | | |
70 | 33 | int YBTableTestBase::num_drives() { |
71 | 33 | return kDefaultNumDrives; |
72 | 33 | } |
73 | | |
74 | 14 | int YBTableTestBase::num_tablets() { |
75 | 14 | return CalcNumTablets(num_tablet_servers()); |
76 | 14 | } |
77 | | |
78 | 28 | int YBTableTestBase::session_timeout_ms() { |
79 | 28 | return kDefaultSessionTimeoutMs; |
80 | 28 | } |
81 | | |
82 | 96 | YBTableName YBTableTestBase::table_name() { |
83 | 96 | if (table_names_.empty()) { |
84 | 19 | table_names_.push_back(kDefaultTableName); |
85 | 19 | } |
86 | 96 | return table_names_[0]; |
87 | 96 | } |
88 | | |
89 | 0 | bool YBTableTestBase::need_redis_table() { |
90 | 0 | return true; |
91 | 0 | } |
92 | | |
93 | 172 | int YBTableTestBase::client_rpc_timeout_ms() { |
94 | 172 | return kDefaultClientRpcTimeoutMs; |
95 | 172 | } |
96 | | |
97 | 5 | bool YBTableTestBase::use_external_mini_cluster() { |
98 | 5 | return kDefaultUsingExternalMiniCluster; |
99 | 5 | } |
100 | | |
101 | 13 | bool YBTableTestBase::use_yb_admin_client() { |
102 | 13 | return false; |
103 | 13 | } |
104 | | |
105 | 9 | bool YBTableTestBase::enable_ysql() { |
106 | 9 | return kDefaultEnableYSQL; |
107 | 9 | } |
108 | | |
109 | 45 | YBTableTestBase::YBTableTestBase() { |
110 | 45 | } |
111 | | |
112 | 26 | void YBTableTestBase::BeforeCreateTable() { |
113 | 26 | } |
114 | | |
115 | 14 | void YBTableTestBase::BeforeStartCluster() { |
116 | 14 | } |
117 | | |
118 | 45 | void YBTableTestBase::SetUp() { |
119 | 45 | YBTest::SetUp(); |
120 | | |
121 | 45 | Status mini_cluster_status; |
122 | 45 | if (use_external_mini_cluster()) { |
123 | 26 | auto opts = ExternalMiniClusterOptions { |
124 | 26 | .num_masters = num_masters(), |
125 | 26 | .num_tablet_servers = num_tablet_servers(), |
126 | 26 | .num_drives = num_drives(), |
127 | 26 | .master_rpc_ports = master_rpc_ports(), |
128 | 26 | .enable_ysql = enable_ysql() |
129 | 26 | }; |
130 | 26 | CustomizeExternalMiniCluster(&opts); |
131 | | |
132 | 26 | external_mini_cluster_.reset(new ExternalMiniCluster(opts)); |
133 | 26 | mini_cluster_status = external_mini_cluster_->Start(); |
134 | 19 | } else { |
135 | 19 | auto opts = MiniClusterOptions { |
136 | 19 | .num_masters = num_masters(), |
137 | 19 | .num_tablet_servers = num_tablet_servers(), |
138 | 19 | .num_drives = num_drives(), |
139 | 19 | .master_env = env_.get(), |
140 | 19 | .ts_env = ts_env_.get(), |
141 | 19 | .ts_rocksdb_env = ts_rocksdb_env_.get() |
142 | 19 | }; |
143 | 19 | SetAtomicFlag(enable_ysql(), &FLAGS_enable_ysql); |
144 | | |
145 | 19 | mini_cluster_.reset(new MiniCluster(opts)); |
146 | 19 | BeforeStartCluster(); |
147 | 19 | mini_cluster_status = mini_cluster_->Start(); |
148 | 19 | } |
149 | 45 | if (!mini_cluster_status.ok()) { |
150 | | // We sometimes crash during cleanup if the cluster creation fails and don't get to report |
151 | | // the root cause, so log it here just in case. |
152 | 0 | LOG(INFO) << "Failed starting the mini cluster: " << mini_cluster_status.ToString(); |
153 | 0 | } |
154 | 45 | ASSERT_OK(mini_cluster_status); |
155 | | |
156 | 27 | CreateClient(); |
157 | 27 | CreateAdminClient(); |
158 | | |
159 | 27 | BeforeCreateTable(); |
160 | | |
161 | 27 | CreateTable(); |
162 | 27 | OpenTable(); |
163 | 27 | } |
164 | | |
165 | 22 | void YBTableTestBase::TearDown() { |
166 | 22 | DeleteTable(); |
167 | | |
168 | | // Fetch the tablet server metrics page after we delete the table. [ENG-135]. |
169 | 22 | FetchTSMetricsPage(); |
170 | | |
171 | 22 | client_.reset(); |
172 | 22 | if (use_yb_admin_client()) { |
173 | 17 | yb_admin_client_.reset(); |
174 | 17 | } |
175 | 22 | if (use_external_mini_cluster()) { |
176 | 20 | external_mini_cluster_->Shutdown(); |
177 | 2 | } else { |
178 | 2 | mini_cluster_->Shutdown(); |
179 | 2 | } |
180 | 22 | YBTest::TearDown(); |
181 | 22 | } |
182 | | |
183 | 26 | vector<uint16_t> YBTableTestBase::master_rpc_ports() { |
184 | 26 | vector<uint16_t> master_rpc_ports; |
185 | 64 | for (size_t i = 0; i < num_masters(); ++i) { |
186 | 38 | master_rpc_ports.push_back(0); |
187 | 38 | } |
188 | 26 | return master_rpc_ports; |
189 | 26 | } |
190 | | |
191 | 27 | void YBTableTestBase::CreateClient() { |
192 | 27 | client_ = CreateYBClient(); |
193 | 27 | } |
194 | | |
195 | 29 | std::unique_ptr<YBClient> YBTableTestBase::CreateYBClient() { |
196 | 29 | YBClientBuilder builder; |
197 | 29 | builder.default_rpc_timeout(MonoDelta::FromMilliseconds(client_rpc_timeout_ms())); |
198 | 29 | if (use_external_mini_cluster()) { |
199 | 28 | return CHECK_RESULT(external_mini_cluster_->CreateClient(&builder)); |
200 | 1 | } else { |
201 | 1 | return CHECK_RESULT(mini_cluster_->CreateClient(&builder)); |
202 | 1 | } |
203 | 29 | } |
204 | | |
205 | 26 | void YBTableTestBase::CreateAdminClient() { |
206 | 26 | if (use_yb_admin_client()) { |
207 | 18 | string addrs; |
208 | 18 | if (use_external_mini_cluster()) { |
209 | 18 | addrs = external_mini_cluster_->GetMasterAddresses(); |
210 | 0 | } else { |
211 | 0 | addrs = mini_cluster_->GetMasterAddresses(); |
212 | 0 | } |
213 | 18 | yb_admin_client_ = std::make_unique<tools::enterprise::ClusterAdminClient>( |
214 | 18 | addrs, MonoDelta::FromMilliseconds(client_rpc_timeout_ms())); |
215 | | |
216 | 18 | ASSERT_OK(yb_admin_client_->Init()); |
217 | 18 | } |
218 | 26 | } |
219 | | |
220 | 26 | void YBTableTestBase::OpenTable() { |
221 | 26 | ASSERT_OK(table_.Open(table_name(), client_.get())); |
222 | 26 | session_ = NewSession(); |
223 | 26 | } |
224 | | |
225 | 0 | void YBTableTestBase::CreateRedisTable(const YBTableName& table_name) { |
226 | 0 | CHECK(table_name.namespace_type() == YQLDatabase::YQL_DATABASE_REDIS); |
227 | |
|
228 | 0 | ASSERT_OK(client_->CreateNamespaceIfNotExists(table_name.namespace_name(), |
229 | 0 | table_name.namespace_type())); |
230 | 0 | ASSERT_OK(NewTableCreator()->table_name(table_name) |
231 | 0 | .table_type(YBTableType::REDIS_TABLE_TYPE) |
232 | 0 | .num_tablets(num_tablets()) |
233 | 0 | .Create()); |
234 | 0 | } |
235 | | |
236 | 18 | void YBTableTestBase::CreateTable() { |
237 | 18 | const auto tn = table_name(); |
238 | 18 | if (!table_exists_) { |
239 | 18 | ASSERT_OK(client_->CreateNamespaceIfNotExists(tn.namespace_name(), tn.namespace_type())); |
240 | | |
241 | 18 | YBSchemaBuilder b; |
242 | 18 | b.AddColumn("k")->Type(BINARY)->NotNull()->HashPrimaryKey(); |
243 | 18 | b.AddColumn("v")->Type(BINARY)->NotNull(); |
244 | 18 | ASSERT_OK(b.Build(&schema_)); |
245 | | |
246 | 18 | ASSERT_OK(NewTableCreator()->table_name(tn).schema(&schema_).Create()); |
247 | 18 | table_exists_ = true; |
248 | 18 | } |
249 | 18 | } |
250 | | |
251 | 17 | void YBTableTestBase::DeleteTable() { |
252 | 17 | if (table_exists_) { |
253 | 14 | ASSERT_OK(client_->DeleteTable(table_name())); |
254 | 14 | table_exists_ = false; |
255 | 14 | } |
256 | 17 | } |
257 | | |
258 | 28 | shared_ptr<YBSession> YBTableTestBase::NewSession() { |
259 | 28 | shared_ptr<YBSession> session = client_->NewSession(); |
260 | 28 | session->SetTimeout(MonoDelta::FromMilliseconds(session_timeout_ms())); |
261 | 28 | return session; |
262 | 28 | } |
263 | | |
264 | 0 | void YBTableTestBase::PutKeyValue(YBSession* session, string key, string value) { |
265 | 0 | auto insert = table_.NewInsertOp(); |
266 | 0 | QLAddStringHashValue(insert->mutable_request(), key); |
267 | 0 | table_.AddStringColumnValue(insert->mutable_request(), "v", value); |
268 | 0 | ASSERT_OK(session->ApplyAndFlush(insert)); |
269 | 0 | } |
270 | | |
271 | 0 | void YBTableTestBase::PutKeyValue(string key, string value) { |
272 | 0 | PutKeyValue(session_.get(), key, value); |
273 | 0 | } |
274 | | |
275 | 0 | void YBTableTestBase::RestartCluster() { |
276 | 0 | DCHECK(!use_external_mini_cluster()); |
277 | 0 | CHECK_OK(mini_cluster_->RestartSync()); |
278 | 0 | ASSERT_NO_FATALS(CreateClient()); |
279 | 0 | ASSERT_NO_FATALS(OpenTable()); |
280 | 0 | } |
281 | | |
282 | 14 | Result<std::vector<uint32_t>> YBTableTestBase::GetTserverLoads(const std::vector<int>& ts_idxs) { |
283 | 14 | std::vector<uint32_t> tserver_loads; |
284 | 41 | for (const auto& ts_idx : ts_idxs) { |
285 | 41 | tserver_loads.push_back( |
286 | 41 | VERIFY_RESULT(GetLoadOnTserver(external_mini_cluster_->tablet_server(ts_idx)))); |
287 | 41 | } |
288 | 14 | return tserver_loads; |
289 | 14 | } |
290 | | |
291 | 43 | Result<uint32_t> YBTableTestBase::GetLoadOnTserver(ExternalTabletServer* server) { |
292 | 43 | auto proxy = GetMasterLeaderProxy<master::MasterClientProxy>(); |
293 | 43 | uint32_t count = 0; |
294 | 43 | std::vector<string> replicas; |
295 | | // Need to get load from each table. |
296 | 125 | for (const auto& table_name : table_names_) { |
297 | 125 | master::GetTableLocationsRequestPB req; |
298 | 125 | if (table_name.namespace_type() == YQL_DATABASE_PGSQL) { |
299 | | // Use table_id/namespace_id for SQL tables. |
300 | 9 | req.mutable_table()->set_table_id(table_name.table_id()); |
301 | 9 | req.mutable_table()->mutable_namespace_()->set_id(table_name.namespace_id()); |
302 | 116 | } else { |
303 | 116 | req.mutable_table()->set_table_name(table_name.table_name()); |
304 | 116 | req.mutable_table()->mutable_namespace_()->set_name(table_name.namespace_name()); |
305 | 116 | } |
306 | 125 | master::GetTableLocationsResponsePB resp; |
307 | | |
308 | 125 | rpc::RpcController rpc; |
309 | 125 | rpc.set_timeout(MonoDelta::FromMilliseconds(client_rpc_timeout_ms())); |
310 | 125 | RETURN_NOT_OK(proxy.GetTableLocations(req, &resp, &rpc)); |
311 | | |
312 | 587 | for (const auto& loc : resp.tablet_locations()) { |
313 | 1.76k | for (const auto& replica : loc.replicas()) { |
314 | 1.76k | if (replica.ts_info().permanent_uuid() == server->instance_id().permanent_uuid()) { |
315 | 367 | replicas.push_back(loc.tablet_id()); |
316 | 367 | count++; |
317 | 367 | } |
318 | 1.76k | } |
319 | 587 | } |
320 | 125 | } |
321 | | |
322 | 43 | LOG(INFO) << Format("For ts $0, tablets are $1 with count $2", |
323 | 43 | server->instance_id().permanent_uuid(), VectorToString(replicas), count); |
324 | 43 | return count; |
325 | 43 | } |
326 | | |
327 | | std::vector<std::pair<std::string, std::string>> YBTableTestBase::GetScanResults( |
328 | 0 | const client::TableRange& range) { |
329 | 0 | std::vector<std::pair<std::string, std::string>> result; |
330 | 0 | for (const auto& row : range) { |
331 | 0 | result.emplace_back(row.column(0).binary_value(), row.column(1).binary_value()); |
332 | 0 | } |
333 | 0 | std::sort(result.begin(), result.end()); |
334 | 0 | return result; |
335 | 0 | } |
336 | | |
337 | 22 | void YBTableTestBase::FetchTSMetricsPage() { |
338 | 22 | EasyCurl c; |
339 | 22 | faststring buf; |
340 | | |
341 | 22 | string addr; |
342 | | // TODO: unify external and in-process mini cluster interfaces. |
343 | 22 | if (use_external_mini_cluster()) { |
344 | 20 | if (external_mini_cluster_->num_tablet_servers() > 0) { |
345 | 20 | addr = external_mini_cluster_->tablet_server(0)->bound_http_hostport().ToString(); |
346 | 20 | } |
347 | 2 | } else { |
348 | 2 | if (mini_cluster_->num_tablet_servers() > 0) { |
349 | 2 | addr = ToString(mini_cluster_->mini_tablet_server(0)->bound_http_addr()); |
350 | 2 | } |
351 | 2 | } |
352 | | |
353 | 22 | if (!addr.empty()) { |
354 | 22 | LOG(INFO) << "Fetching metrics from " << addr; |
355 | 22 | ASSERT_OK(c.FetchURL(Substitute("http://$0/metrics", addr), &buf)); |
356 | 22 | } |
357 | 22 | } |
358 | | |
359 | 15 | void YBTableTestBase::WaitForLoadBalanceCompletion(yb::MonoDelta timeout) { |
360 | 15 | ASSERT_OK(WaitFor([&]() -> Result<bool> { |
361 | 15 | bool is_idle = VERIFY_RESULT(client_->IsLoadBalancerIdle()); |
362 | 15 | return !is_idle; |
363 | 15 | }, timeout, "IsLoadBalancerActive")); |
364 | | |
365 | 15 | ASSERT_OK(WaitFor([&]() -> Result<bool> { |
366 | 15 | return client_->IsLoadBalancerIdle(); |
367 | 15 | }, timeout, "IsLoadBalancerIdle")); |
368 | 15 | } |
369 | | |
370 | 39 | std::unique_ptr<client::YBTableCreator> YBTableTestBase::NewTableCreator() { |
371 | 39 | unique_ptr<YBTableCreator> table_creator(client_->NewTableCreator()); |
372 | 39 | if (num_tablets() > 0) { |
373 | 39 | table_creator->num_tablets(num_tablets()); |
374 | 39 | } |
375 | 39 | table_creator->table_type(YBTableType::YQL_TABLE_TYPE); |
376 | 39 | return table_creator; |
377 | 39 | } |
378 | | |
379 | | } // namespace integration_tests |
380 | | } // namespace yb |