YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/tools/ts-cli.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
// Tool to query tablet server operational data
33
34
#include <memory>
35
36
#include <gflags/gflags.h>
37
#include <glog/logging.h>
38
39
#include "yb/common/partition.h"
40
#include "yb/common/ql_rowblock.h"
41
#include "yb/common/schema.h"
42
#include "yb/common/wire_protocol.h"
43
44
#include "yb/consensus/consensus.proxy.h"
45
46
#include "yb/rpc/messenger.h"
47
#include "yb/rpc/proxy.h"
48
#include "yb/rpc/rpc_controller.h"
49
#include "yb/rpc/secure_stream.h"
50
51
#include "yb/consensus/metadata.pb.h"
52
#include "yb/server/secure.h"
53
#include "yb/server/server_base.proxy.h"
54
55
#include "yb/tablet/tablet.pb.h"
56
57
#include "yb/tserver/tablet_server.h"
58
#include "yb/tserver/tserver_admin.proxy.h"
59
#include "yb/tserver/tserver_service.proxy.h"
60
61
#include "yb/util/faststring.h"
62
#include "yb/util/flags.h"
63
#include "yb/util/logging.h"
64
#include "yb/util/net/net_util.h"
65
#include "yb/util/protobuf_util.h"
66
#include "yb/util/result.h"
67
68
using std::ostringstream;
69
using std::shared_ptr;
70
using std::string;
71
using std::vector;
72
using yb::HostPort;
73
using yb::consensus::ConsensusServiceProxy;
74
using yb::consensus::RaftConfigPB;
75
using yb::rpc::Messenger;
76
using yb::rpc::MessengerBuilder;
77
using yb::rpc::RpcController;
78
using yb::server::ServerStatusPB;
79
using yb::tablet::TabletStatusPB;
80
using yb::tserver::CountIntentsRequestPB;
81
using yb::tserver::CountIntentsResponsePB;
82
using yb::tserver::DeleteTabletRequestPB;
83
using yb::tserver::DeleteTabletResponsePB;
84
using yb::tserver::FlushTabletsRequestPB;
85
using yb::tserver::FlushTabletsResponsePB;
86
using yb::tserver::IsTabletServerReadyRequestPB;
87
using yb::tserver::IsTabletServerReadyResponsePB;
88
using yb::tserver::ListTabletsRequestPB;
89
using yb::tserver::ListTabletsResponsePB;
90
using yb::tserver::TabletServerAdminServiceProxy;
91
using yb::tserver::TabletServerServiceProxy;
92
93
const char* const kListTabletsOp = "list_tablets";
94
const char* const kVerifyTabletOp = "verify_tablet";
95
const char* const kAreTabletsRunningOp = "are_tablets_running";
96
const char* const kIsServerReadyOp = "is_server_ready";
97
const char* const kSetFlagOp = "set_flag";
98
const char* const kRefreshFlagsOp = "refresh_flags";
99
const char* const kDumpTabletOp = "dump_tablet";
100
const char* const kTabletStateOp = "get_tablet_state";
101
const char* const kDeleteTabletOp = "delete_tablet";
102
const char* const kUnsafeConfigChange = "unsafe_config_change";
103
const char* const kCurrentHybridTime = "current_hybrid_time";
104
const char* const kStatus = "status";
105
const char* const kCountIntents = "count_intents";
106
const char* const kFlushTabletOp = "flush_tablet";
107
const char* const kFlushAllTabletsOp = "flush_all_tablets";
108
const char* const kCompactTabletOp = "compact_tablet";
109
const char* const kCompactAllTabletsOp = "compact_all_tablets";
110
111
DEFINE_string(server_address, "localhost",
112
              "Address of server to run against");
113
DEFINE_int64(timeout_ms, 1000 * 60, "RPC timeout in milliseconds");
114
115
DEFINE_bool(force, false, "set_flag: If true, allows command to set a flag "
116
            "which is not explicitly marked as runtime-settable. Such flag changes may be "
117
            "simply ignored on the server, or may cause the server to crash.\n"
118
            "delete_tablet: If true, command will delete the tablet and remove the tablet "
119
            "from the memory, otherwise tablet metadata will be kept in memory with state "
120
            "TOMBSTONED.");
121
122
DEFINE_string(certs_dir_name, "",
123
              "Directory with certificates to use for secure server connection.");
124
125
DEFINE_string(client_node_name, "", "Client node name.");
126
127
PB_ENUM_FORMATTERS(yb::consensus::LeaderLeaseStatus);
128
129
// Check that the value of argc matches what's expected, otherwise return a
130
// non-zero exit code. Should be used in main().
131
#define CHECK_ARGC_OR_RETURN_WITH_USAGE(op, expected) \
132
7
  do { \
133
7
    const string& _op = (op); \
134
7
    const int _expected = (expected); \
135
7
    if (argc != _expected) { \
136
0
      /* We substract 2 from _expected because we don't want to count argv[0] or [1]. */ \
137
0
      std::cerr << "Invalid number of arguments for " << _op \
138
0
                << ": expected " << (_expected - 2) << " arguments" << std::endl; \
139
0
      google::ShowUsageWithFlagsRestrict(argv[0], __FILE__); \
140
0
      return 2; \
141
0
    } \
142
7
  } while (0);
143
144
// Invoke 'to_call' and check its result. If it failed, print 'to_prepend' and
145
// the error to cerr and return a non-zero exit code. Should be used in main().
146
#define RETURN_NOT_OK_PREPEND_FROM_MAIN(to_call, to_prepend) \
147
74
  do { \
148
74
    ::yb::Status s = (to_call); \
149
74
    if (!s.ok()) { \
150
0
      std::cerr << (to_prepend) << ": " << s.ToString() << std::endl; \
151
0
      return 1; \
152
0
    } \
153
74
  } while (0);
154
155
namespace yb {
156
namespace tools {
157
158
typedef ListTabletsResponsePB::StatusAndSchemaPB StatusAndSchemaPB;
159
160
class TsAdminClient {
161
 public:
162
  // Creates an admin client for host/port combination e.g.,
163
  // "localhost" or "127.0.0.1:7050".
164
  TsAdminClient(std::string addr, int64_t timeout_millis);
165
166
  ~TsAdminClient();
167
168
  // Initialized the client and connects to the specified tablet
169
  // server.
170
  Status Init();
171
172
  // Sets 'tablets' a list of status information for all tablets on a
173
  // given tablet server.
174
  Status ListTablets(std::vector<StatusAndSchemaPB>* tablets);
175
176
  // Gets the number of tablets waiting to be bootstrapped and prints to console.
177
  Status GetNumUnbootstrappedTablets(int64_t* num_unbootstrapped_tablets);
178
179
  // Sets the gflag 'flag' to 'val' on the remote server via RPC.
180
  // If 'force' is true, allows setting flags even if they're not marked as
181
  // safe to change at runtime.
182
  Status SetFlag(const string& flag, const string& val,
183
                 bool force);
184
185
  // Refreshes all gflags on the remote server to the flagfile, via RPC.
186
  Status RefreshFlags();
187
188
  // Get the schema for the given tablet.
189
  Status GetTabletSchema(const std::string& tablet_id, SchemaPB* schema);
190
191
  // Dump the contents of the given tablet, in key order, to the console.
192
  Status DumpTablet(const std::string& tablet_id);
193
194
  // Print the consensus state to the console.
195
  Status PrintConsensusState(const std::string& tablet_id);
196
197
  // Delete a tablet replica from the specified peer.
198
  // The 'reason' string is passed to the tablet server, used for logging.
199
  Status DeleteTablet(const std::string& tablet_id,
200
                      const std::string& reason,
201
                      tablet::TabletDataState delete_type);
202
203
  Status UnsafeConfigChange(const std::string& tablet_id,
204
                            const std::vector<string>& peers);
205
206
207
  // Sets hybrid_time to the value of the tablet server's current hybrid_time.
208
  Status CurrentHybridTime(uint64_t* hybrid_time);
209
210
  // Get the server status
211
  Status GetStatus(ServerStatusPB* pb);
212
213
  // Count write intents on all tablets.
214
  Status CountIntents(int64_t* num_intents);
215
216
  // Flush or compact a given tablet on a given tablet server.
217
  // If 'tablet_id' is empty string, flush or compact all tablets.
218
  Status FlushTablets(const std::string& tablet_id, bool is_compaction);
219
220
  // Verify the given tablet against its indexes
221
  // Assume the tablet belongs to a main table
222
  Status VerifyTablet(
223
      const std::string& tablet_id,
224
      const std::vector<string>& index_ids,
225
      const string& start_key,
226
      const int num_rows);
227
228
 private:
229
  std::string addr_;
230
  MonoDelta timeout_;
231
  bool initted_;
232
  std::unique_ptr<rpc::SecureContext> secure_context_;
233
  std::unique_ptr<rpc::Messenger> messenger_;
234
  shared_ptr<server::GenericServiceProxy> generic_proxy_;
235
  std::unique_ptr<tserver::TabletServerServiceProxy> ts_proxy_;
236
  std::unique_ptr<tserver::TabletServerAdminServiceProxy> ts_admin_proxy_;
237
  std::unique_ptr<consensus::ConsensusServiceProxy> cons_proxy_;
238
239
  DISALLOW_COPY_AND_ASSIGN(TsAdminClient);
240
};
241
242
TsAdminClient::TsAdminClient(string addr, int64_t timeout_millis)
243
    : addr_(std::move(addr)),
244
      timeout_(MonoDelta::FromMilliseconds(timeout_millis)),
245
13
      initted_(false) {}
246
247
13
TsAdminClient::~TsAdminClient() {
248
13
  if (messenger_) {
249
13
    messenger_->Shutdown();
250
13
  }
251
13
}
252
253
13
Status TsAdminClient::Init() {
254
13
  CHECK(!initted_);
255
256
13
  HostPort host_port;
257
13
  RETURN_NOT_OK(host_port.ParseString(addr_, tserver::TabletServer::kDefaultPort));
258
13
  auto messenger_builder = MessengerBuilder("ts-cli");
259
13
  if (!FLAGS_certs_dir_name.empty()) {
260
2
    const std::string& cert_name = FLAGS_client_node_name;
261
2
    secure_context_ = VERIFY_RESULT(server::CreateSecureContext(
262
0
        FLAGS_certs_dir_name, server::UseClientCerts(!cert_name.empty()), cert_name));
263
0
    server::ApplySecureContext(secure_context_.get(), &messenger_builder);
264
2
  }
265
13
  messenger_ = VERIFY_RESULT(messenger_builder.Build());
266
267
0
  rpc::ProxyCache proxy_cache(messenger_.get());
268
269
13
  generic_proxy_.reset(new server::GenericServiceProxy(&proxy_cache, host_port));
270
13
  ts_proxy_.reset(new TabletServerServiceProxy(&proxy_cache, host_port));
271
13
  ts_admin_proxy_.reset(new TabletServerAdminServiceProxy(&proxy_cache, host_port));
272
13
  cons_proxy_.reset(new ConsensusServiceProxy(&proxy_cache, host_port));
273
13
  initted_ = true;
274
275
13
  VLOG
(1) << "Connected to " << addr_0
;
276
277
13
  return Status::OK();
278
13
}
279
280
2
Status TsAdminClient::ListTablets(vector<StatusAndSchemaPB>* tablets) {
281
2
  CHECK(initted_);
282
283
2
  ListTabletsRequestPB req;
284
2
  ListTabletsResponsePB resp;
285
2
  RpcController rpc;
286
287
2
  rpc.set_timeout(timeout_);
288
2
  RETURN_NOT_OK(ts_proxy_->ListTablets(req, &resp, &rpc));
289
2
  if (resp.has_error()) {
290
0
    return StatusFromPB(resp.error().status());
291
0
  }
292
293
2
  tablets->assign(resp.status_and_schema().begin(), resp.status_and_schema().end());
294
295
2
  return Status::OK();
296
2
}
297
298
0
Status TsAdminClient::GetNumUnbootstrappedTablets(int64_t* num_unbootstrapped_tablets) {
299
0
  CHECK(initted_);
300
301
0
  IsTabletServerReadyRequestPB req;
302
0
  IsTabletServerReadyResponsePB resp;
303
0
  RpcController rpc;
304
305
0
  rpc.set_timeout(timeout_);
306
0
  RETURN_NOT_OK(ts_proxy_->IsTabletServerReady(req, &resp, &rpc));
307
0
  if (resp.has_error()) {
308
0
    return StatusFromPB(resp.error().status());
309
0
  }
310
311
0
  std::cout << resp.num_tablets_not_running() << "/" << resp.total_tablets()
312
0
            << " tablets are not yet bootstrapped" << std::endl;
313
0
  *num_unbootstrapped_tablets = resp.num_tablets_not_running();
314
315
0
  return Status::OK();
316
0
}
317
318
Status TsAdminClient::SetFlag(const string& flag, const string& val,
319
2
                              bool force) {
320
2
  server::SetFlagRequestPB req;
321
2
  server::SetFlagResponsePB resp;
322
2
  RpcController rpc;
323
324
2
  rpc.set_timeout(timeout_);
325
2
  req.set_flag(flag);
326
2
  req.set_value(val);
327
2
  req.set_force(force);
328
329
2
  RETURN_NOT_OK(generic_proxy_->SetFlag(req, &resp, &rpc));
330
2
  switch (resp.result()) {
331
2
    case server::SetFlagResponsePB::SUCCESS:
332
2
      return Status::OK();
333
0
    case server::SetFlagResponsePB::NOT_SAFE:
334
0
      return STATUS(RemoteError, resp.msg() + " (use --force flag to allow anyway)");
335
0
    default:
336
0
      return STATUS(RemoteError, resp.ShortDebugString());
337
2
  }
338
2
}
339
340
2
Status TsAdminClient::RefreshFlags() {
341
2
  server::RefreshFlagsRequestPB req;
342
2
  server::RefreshFlagsResponsePB resp;
343
2
  RpcController rpc;
344
345
2
  rpc.set_timeout(timeout_);
346
347
2
  return generic_proxy_->RefreshFlags(req, &resp, &rpc);
348
2
}
349
350
Status TsAdminClient::VerifyTablet(
351
    const std::string& tablet_id,
352
    const std::vector<string>& index_ids,
353
    const string& start_key,
354
0
    const int num_rows) {
355
0
  tserver::VerifyTableRowRangeRequestPB req;
356
0
  tserver::VerifyTableRowRangeResponsePB resp;
357
358
0
  req.set_tablet_id(tablet_id);
359
0
  req.set_start_key("");
360
0
  req.set_num_rows(num_rows);
361
0
  for (const std::string& str : index_ids) {
362
0
    req.add_index_ids(str);
363
0
  }
364
365
0
  RpcController rpc;
366
0
  rpc.set_timeout(timeout_);
367
368
0
  RETURN_NOT_OK(ts_proxy_->VerifyTableRowRange(req, &resp, &rpc));
369
0
  if (resp.has_error()) {
370
0
    return StatusFromPB(resp.error().status());
371
0
  }
372
373
0
  std::cout << "Reporting VerifyJob stats." << std::endl;
374
0
  for (auto it = resp.consistency_stats().begin(); it != resp.consistency_stats().end(); it++) {
375
0
    std::cout << "VerifyJob found " << it->second << " mismatched rows for index " << it->first
376
0
              << std::endl;
377
0
  }
378
379
0
  return Status::OK();
380
0
}
381
382
Status TsAdminClient::GetTabletSchema(const std::string& tablet_id,
383
0
                                      SchemaPB* schema) {
384
0
  VLOG(1) << "Fetching schema for tablet " << tablet_id;
385
0
  vector<StatusAndSchemaPB> tablets;
386
0
  RETURN_NOT_OK(ListTablets(&tablets));
387
0
  for (const StatusAndSchemaPB& pair : tablets) {
388
0
    if (pair.tablet_status().tablet_id() == tablet_id) {
389
0
      *schema = pair.schema();
390
0
      return Status::OK();
391
0
    }
392
0
  }
393
0
  return STATUS(NotFound, "Cannot find tablet", tablet_id);
394
0
}
395
396
0
Status TsAdminClient::PrintConsensusState(const std::string& tablet_id) {
397
0
  ServerStatusPB status_pb;
398
0
  RETURN_NOT_OK(GetStatus(&status_pb));
399
400
0
  consensus::GetConsensusStateRequestPB cons_reqpb;
401
0
  cons_reqpb.set_dest_uuid(status_pb.node_instance().permanent_uuid());
402
0
  cons_reqpb.set_tablet_id(tablet_id);
403
404
0
  consensus::GetConsensusStateResponsePB cons_resp_pb;
405
0
  RpcController rpc;
406
0
  RETURN_NOT_OK_PREPEND(
407
0
      cons_proxy_->GetConsensusState(cons_reqpb, &cons_resp_pb, &rpc),
408
0
      "Failed to query tserver for consensus state");
409
0
  std::cout << "Lease-Status"
410
0
            << "\t\t"
411
0
            << " Leader-UUID ";
412
0
  std::cout << PBEnumToString(cons_resp_pb.leader_lease_status()) << "\t\t"
413
0
            << cons_resp_pb.cstate().leader_uuid();
414
415
0
  return Status::OK();
416
0
}
417
418
0
Status TsAdminClient::DumpTablet(const std::string& tablet_id) {
419
0
  SchemaPB schema_pb;
420
0
  RETURN_NOT_OK(GetTabletSchema(tablet_id, &schema_pb));
421
0
  Schema schema;
422
0
  RETURN_NOT_OK(SchemaFromPB(schema_pb, &schema));
423
424
0
  tserver::ReadRequestPB req;
425
0
  tserver::ReadResponsePB resp;
426
427
0
  req.set_tablet_id(tablet_id);
428
0
  RpcController rpc;
429
0
  rpc.set_timeout(timeout_);
430
0
  RETURN_NOT_OK_PREPEND(ts_proxy_->Read(req, &resp, &rpc), "Read() failed");
431
432
0
  if (resp.has_error()) {
433
0
    return STATUS(IOError, "Failed to read: ", resp.error().ShortDebugString());
434
0
  }
435
436
0
  QLRowBlock row_block(schema);
437
0
  Slice data = VERIFY_RESULT(rpc.GetSidecar(0));
438
0
  if (!data.empty()) {
439
0
    RETURN_NOT_OK(row_block.Deserialize(YQL_CLIENT_CQL, &data));
440
0
  }
441
442
0
  for (const auto& row : row_block.rows()) {
443
0
    std::cout << row.ToString() << std::endl;
444
0
  }
445
446
0
  return Status::OK();
447
0
}
448
449
Status TsAdminClient::DeleteTablet(const string& tablet_id,
450
                                   const string& reason,
451
1
                                   tablet::TabletDataState delete_type) {
452
1
  ServerStatusPB status_pb;
453
1
  RETURN_NOT_OK(GetStatus(&status_pb));
454
455
1
  DeleteTabletRequestPB req;
456
1
  DeleteTabletResponsePB resp;
457
1
  RpcController rpc;
458
459
1
  req.set_tablet_id(tablet_id);
460
1
  req.set_dest_uuid(status_pb.node_instance().permanent_uuid());
461
1
  req.set_reason(reason);
462
1
  req.set_delete_type(delete_type);
463
1
  rpc.set_timeout(timeout_);
464
1
  RETURN_NOT_OK_PREPEND(ts_admin_proxy_->DeleteTablet(req, &resp, &rpc),
465
1
                        "DeleteTablet() failed");
466
467
1
  if (resp.has_error()) {
468
0
    return STATUS(IOError, "Failed to delete tablet: ",
469
0
                           resp.error().ShortDebugString());
470
0
  }
471
1
  return Status::OK();
472
1
}
473
474
Status TsAdminClient::UnsafeConfigChange(const std::string& tablet_id,
475
6
                                         const std::vector<string>& peers) {
476
6
  ServerStatusPB status_pb;
477
6
  RETURN_NOT_OK(GetStatus(&status_pb));
478
479
6
  if (peers.empty()) {
480
0
    return STATUS(InvalidArgument, "No peer UUIDs specified for the new config");
481
0
  }
482
6
  RaftConfigPB new_config;
483
7
  for (const auto& arg : peers) {
484
7
    consensus::RaftPeerPB new_peer;
485
7
    new_peer.set_permanent_uuid(arg);
486
7
    new_config.add_peers()->CopyFrom(new_peer);
487
7
  }
488
489
  // Send a request to replace the config to node dst_address.
490
6
  consensus::UnsafeChangeConfigRequestPB req;
491
6
  consensus::UnsafeChangeConfigResponsePB resp;
492
6
  RpcController rpc;
493
6
  rpc.set_timeout(timeout_);
494
6
  req.set_dest_uuid(status_pb.node_instance().permanent_uuid());
495
6
  req.set_tablet_id(tablet_id);
496
6
  req.set_caller_id("yb-ts-cli");
497
6
  *req.mutable_new_config() = new_config;
498
6
  RETURN_NOT_OK(cons_proxy_->UnsafeChangeConfig(req, &resp, &rpc));
499
6
  if (resp.has_error()) {
500
0
    return StatusFromPB(resp.error().status());
501
0
  }
502
6
  return Status::OK();
503
6
}
504
505
0
Status TsAdminClient::CurrentHybridTime(uint64_t* hybrid_time) {
506
0
  server::ServerClockRequestPB req;
507
0
  server::ServerClockResponsePB resp;
508
0
  RpcController rpc;
509
0
  rpc.set_timeout(timeout_);
510
0
  RETURN_NOT_OK(generic_proxy_->ServerClock(req, &resp, &rpc));
511
0
  CHECK(resp.has_hybrid_time()) << resp.DebugString();
512
0
  *hybrid_time = resp.hybrid_time();
513
0
  return Status::OK();
514
0
}
515
516
7
Status TsAdminClient::GetStatus(ServerStatusPB* pb) {
517
7
  server::GetStatusRequestPB req;
518
7
  server::GetStatusResponsePB resp;
519
7
  RpcController rpc;
520
7
  rpc.set_timeout(timeout_);
521
7
  RETURN_NOT_OK(generic_proxy_->GetStatus(req, &resp, &rpc));
522
7
  CHECK
(resp.has_status()) << resp.DebugString()0
;
523
7
  pb->Swap(resp.mutable_status());
524
7
  return Status::OK();
525
7
}
526
527
0
Status TsAdminClient::CountIntents(int64_t* num_intents) {
528
0
  CountIntentsRequestPB req;
529
0
  CountIntentsResponsePB resp;
530
0
  RpcController rpc;
531
0
  rpc.set_timeout(timeout_);
532
0
  RETURN_NOT_OK(ts_admin_proxy_->CountIntents(req, &resp, &rpc));
533
0
  *num_intents = resp.num_intents();
534
0
  return Status::OK();
535
0
}
536
537
0
Status TsAdminClient::FlushTablets(const std::string& tablet_id, bool is_compaction) {
538
0
  ServerStatusPB status_pb;
539
0
  RETURN_NOT_OK(GetStatus(&status_pb));
540
541
0
  FlushTabletsRequestPB req;
542
0
  FlushTabletsResponsePB resp;
543
0
  RpcController rpc;
544
545
0
  if (!tablet_id.empty()) {
546
0
    req.add_tablet_ids(tablet_id);
547
0
    req.set_all_tablets(false);
548
0
  } else {
549
0
    req.set_all_tablets(true);
550
0
  }
551
0
  req.set_dest_uuid(status_pb.node_instance().permanent_uuid());
552
0
  req.set_operation(is_compaction ? tserver::FlushTabletsRequestPB::COMPACT
553
0
                                  : tserver::FlushTabletsRequestPB::FLUSH);
554
0
  rpc.set_timeout(timeout_);
555
0
  RETURN_NOT_OK_PREPEND(ts_admin_proxy_->FlushTablets(req, &resp, &rpc),
556
0
                        "FlushTablets() failed");
557
558
0
  if (resp.has_error()) {
559
0
    return STATUS(IOError, "Failed to flush tablet: ",
560
0
                           resp.error().ShortDebugString());
561
0
  }
562
0
  std::cout << "Successfully " << (is_compaction ? "compacted " : "flushed ")
563
0
            << (tablet_id.empty() ? "all tablets" : "tablet <" + tablet_id + ">")
564
0
            << std::endl;
565
0
  return Status::OK();
566
0
}
567
568
namespace {
569
570
13
void SetUsage(const char* argv0) {
571
13
  ostringstream str;
572
573
13
  str << argv0 << " [--server_address=<addr>] <operation> <flags>\n"
574
13
      << "<operation> must be one of:\n"
575
13
      << "  " << kListTabletsOp << "\n"
576
13
      << "  " << kAreTabletsRunningOp << "\n"
577
13
      << "  " << kIsServerReadyOp << "\n"
578
13
      << "  " << kSetFlagOp << " [-force] <flag> <value>\n"
579
13
      << "  " << kRefreshFlagsOp << "\n"
580
13
      << "  " << kTabletStateOp << " <tablet_id>\n"
581
13
      << "  " << kDumpTabletOp << " <tablet_id>\n"
582
13
      << "  " << kDeleteTabletOp << " [-force] <tablet_id> <reason string>\n"
583
13
      << "  " << kUnsafeConfigChange << " <tablet_id> <peer1> [<peer2>...]\n"
584
13
      << "  " << kCurrentHybridTime << "\n"
585
13
      << "  " << kStatus << "\n"
586
13
      << "  " << kCountIntents << "\n"
587
13
      << "  " << kFlushTabletOp << " <tablet_id>\n"
588
13
      << "  " << kFlushAllTabletsOp << "\n"
589
13
      << "  " << kCompactTabletOp << " <tablet_id>\n"
590
13
      << "  " << kCompactAllTabletsOp << "\n"
591
13
      << "  " << kVerifyTabletOp
592
13
      << " <tablet_id> <number of indexes> <index list> <start_key> <number of rows>\n";
593
13
  google::SetUsageMessage(str.str());
594
13
}
595
596
13
string GetOp(int argc, char** argv) {
597
13
  if (argc < 2) {
598
0
    google::ShowUsageWithFlagsRestrict(argv[0], __FILE__);
599
0
    exit(1);
600
0
  }
601
602
13
  return argv[1];
603
13
}
604
605
} // anonymous namespace
606
607
13
static int TsCliMain(int argc, char** argv) {
608
13
  FLAGS_logtostderr = 1;
609
13
  FLAGS_minloglevel = 2;
610
13
  SetUsage(argv[0]);
611
13
  ParseCommandLineFlags(&argc, &argv, true);
612
13
  InitGoogleLoggingSafe(argv[0]);
613
13
  const string addr = FLAGS_server_address;
614
615
13
  string op = GetOp(argc, argv);
616
617
13
  TsAdminClient client(addr, FLAGS_timeout_ms);
618
619
13
  RETURN_NOT_OK_PREPEND_FROM_MAIN(client.Init(),
620
13
                                  "Unable to establish connection to " + addr);
621
622
  // TODO add other operations here...
623
13
  if (op == kListTabletsOp) {
624
2
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
625
626
2
    vector<StatusAndSchemaPB> tablets;
627
2
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.ListTablets(&tablets),
628
2
                                    "Unable to list tablets on " + addr);
629
24
    for (const StatusAndSchemaPB& status_and_schema : tablets) {
630
24
      Schema schema;
631
24
      RETURN_NOT_OK_PREPEND_FROM_MAIN(SchemaFromPB(status_and_schema.schema(), &schema),
632
24
                                      "Unable to deserialize schema from " + addr);
633
24
      PartitionSchema partition_schema;
634
24
      RETURN_NOT_OK_PREPEND_FROM_MAIN(PartitionSchema::FromPB(status_and_schema.partition_schema(),
635
24
                                                              schema, &partition_schema),
636
24
                                      "Unable to deserialize partition schema from " + addr);
637
638
639
24
      TabletStatusPB ts = status_and_schema.tablet_status();
640
641
24
      Partition partition;
642
24
      Partition::FromPB(ts.partition(), &partition);
643
644
24
      string state = tablet::RaftGroupStatePB_Name(ts.state());
645
24
      std::cout << "Tablet id: " << ts.tablet_id() << std::endl;
646
24
      std::cout << "State: " << state << std::endl;
647
24
      std::cout << "Table name: " << ts.table_name() << std::endl;
648
24
      std::cout << "Partition: " << partition_schema.PartitionDebugString(partition, schema)
649
24
                << std::endl;
650
24
      std::cout << "Schema: " << schema.ToString() << std::endl;
651
24
    }
652
11
  } else if (op == kVerifyTabletOp) {
653
0
    string tablet_id = argv[2];
654
0
    int num_indexes = std::stoi(argv[3]);
655
0
    std::vector<string> index_ids;
656
0
    for (int i = 0; i < num_indexes; i++) {
657
0
      index_ids.push_back(argv[4 + i]);
658
0
    }
659
0
    string start_key = argv[num_indexes + 4];
660
0
    int num_rows = std::stoi(argv[num_indexes + 5]);
661
662
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(
663
0
        client.VerifyTablet(tablet_id, index_ids, start_key, num_rows),
664
0
        "Unable to verify tablet " + tablet_id);
665
666
11
  } else if (op == kAreTabletsRunningOp) {
667
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
668
669
0
    vector<StatusAndSchemaPB> tablets;
670
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.ListTablets(&tablets),
671
0
                                    "Unable to list tablets on " + addr);
672
0
    bool all_running = true;
673
0
    for (const StatusAndSchemaPB& status_and_schema : tablets) {
674
0
      TabletStatusPB ts = status_and_schema.tablet_status();
675
0
      if (ts.state() != tablet::RUNNING) {
676
0
        std::cout << "Tablet id: " << ts.tablet_id() << " is "
677
0
                  << tablet::RaftGroupStatePB_Name(ts.state()) << std::endl;
678
0
        all_running = false;
679
0
      }
680
0
    }
681
682
0
    if (all_running) {
683
0
      std::cout << "All tablets are running" << std::endl;
684
0
    } else {
685
0
      std::cout << "Not all tablets are running" << std::endl;
686
0
      return 1;
687
0
    }
688
11
  } else if (op == kIsServerReadyOp) {
689
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
690
691
0
    int64_t unbootstrapped_tablets;
692
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(
693
0
        client.GetNumUnbootstrappedTablets(&unbootstrapped_tablets), "Unable to read server state");
694
695
0
    if (unbootstrapped_tablets > 0) {
696
0
      std::cout << "Tablet server is not ready" << std::endl;
697
0
      return 1;
698
0
    } else {
699
0
      std::cout << "Tablet server is ready" << std::endl;
700
0
    }
701
11
  } else if (op == kSetFlagOp) {
702
2
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 4);
703
704
2
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.SetFlag(argv[2], argv[3], FLAGS_force),
705
2
                                    "Unable to set flag");
706
707
9
  } else if (op == kRefreshFlagsOp) {
708
2
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
709
710
2
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.RefreshFlags(),
711
2
        "Unable to refresh flags");
712
7
  } else if (op == kTabletStateOp) {
713
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 3);
714
715
0
    string tablet_id = argv[2];
716
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(
717
0
        client.PrintConsensusState(tablet_id), "Unable to print tablet state");
718
7
  } else if (op == kDumpTabletOp) {
719
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 3);
720
721
0
    string tablet_id = argv[2];
722
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.DumpTablet(tablet_id),
723
0
                                    "Unable to dump tablet");
724
7
  } else if (op == kDeleteTabletOp) {
725
1
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 4);
726
727
1
    string tablet_id = argv[2];
728
1
    string reason = argv[3];
729
1
    tablet::TabletDataState state = FLAGS_force ? tablet::TABLET_DATA_DELETED :
730
1
                                                  
tablet::TABLET_DATA_TOMBSTONED0
;
731
1
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.DeleteTablet(tablet_id, reason, state),
732
1
                                    "Unable to delete tablet");
733
6
  } else if (op == kUnsafeConfigChange) {
734
6
    if (argc < 4) {
735
0
      CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 4);
736
0
    }
737
738
6
    string tablet_id = argv[2];
739
6
    vector<string> peers;
740
13
    for (int i = 3; i < argc; 
i++7
) {
741
7
      peers.push_back(argv[i]);
742
7
    }
743
744
6
    RETURN_NOT_OK_PREPEND_FROM_MAIN(
745
6
        client.UnsafeConfigChange(tablet_id, peers), "Unable to change config unsafely.");
746
6
  } else 
if (0
op == kCurrentHybridTime0
) {
747
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
748
749
0
    uint64_t hybrid_time;
750
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.CurrentHybridTime(&hybrid_time),
751
0
                                    "Unable to get hybrid_time");
752
0
    std::cout << hybrid_time << std::endl;
753
0
  } else if (op == kStatus) {
754
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
755
756
0
    ServerStatusPB status;
757
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.GetStatus(&status),
758
0
                                    "Unable to get status");
759
0
    std::cout << status.DebugString() << std::endl;
760
0
  } else if (op == kCountIntents) {
761
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
762
0
    int64_t num_intents = 0;
763
764
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.CountIntents(&num_intents),
765
0
                                    "Unable to count intents");
766
767
0
    std::cout << num_intents << std::endl;
768
0
  } else if (op == kFlushTabletOp) {
769
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 3);
770
771
0
    string tablet_id = argv[2];
772
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.FlushTablets(tablet_id, false /* is_compaction */),
773
0
                                    "Unable to flush tablet");
774
0
  } else if (op == kFlushAllTabletsOp) {
775
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
776
777
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.FlushTablets(std::string(), false /* is_compaction */),
778
0
                                    "Unable to flush all tablets");
779
0
  } else if (op == kCompactTabletOp) {
780
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 3);
781
782
0
    string tablet_id = argv[2];
783
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.FlushTablets(tablet_id, true /* is_compaction */),
784
0
                                    "Unable to compact tablet");
785
0
  } else if (op == kCompactAllTabletsOp) {
786
0
    CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
787
788
0
    RETURN_NOT_OK_PREPEND_FROM_MAIN(client.FlushTablets(std::string(), true /* is_compaction */),
789
0
                                    "Unable to compact all tablets");
790
0
  } else {
791
0
    std::cerr << "Invalid operation: " << op << std::endl;
792
0
    google::ShowUsageWithFlagsRestrict(argv[0], __FILE__);
793
0
    return 2;
794
0
  }
795
796
13
  return 0;
797
13
}
798
799
} // namespace tools
800
} // namespace yb
801
802
18.6k
int main(int argc, char** argv) {
803
18.6k
  return yb::tools::TsCliMain(argc, argv);
804
18.6k
}