YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/master/call_home.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
#include "yb/master/call_home.h"
14
15
#include <sstream>
16
#include <thread>
17
18
#include <boost/algorithm/string.hpp>
19
#include <boost/optional.hpp>
20
#include <rapidjson/reader.h>
21
#include <rapidjson/writer.h>
22
23
#include "yb/master/catalog_entity_info.pb.h"
24
#include "yb/master/catalog_manager_if.h"
25
#include "yb/master/master.h"
26
#include "yb/master/master_client.pb.h"
27
#include "yb/master/master_ddl.pb.h"
28
#include "yb/master/ts_manager.h"
29
30
#include "yb/rpc/scheduler.h"
31
32
#include "yb/tserver/ts_tablet_manager.h"
33
34
#include "yb/util/flag_tags.h"
35
#include "yb/util/jsonwriter.h"
36
#include "yb/util/logging.h"
37
#include "yb/util/metrics.h"
38
#include "yb/util/result.h"
39
#include "yb/util/user.h"
40
#include "yb/util/version_info.h"
41
42
static const char* kLowLevel = "low";
43
static const char* kMediumLevel = "medium";
44
static const char* kHighLevel = "high";
45
46
DEFINE_bool(callhome_enabled, true,
47
            "Enables callhome feature that sends analytics data to yugabyte");
48
TAG_FLAG(callhome_enabled, runtime);
49
50
DEFINE_int32(callhome_interval_secs, 3600, "How often to run callhome");
51
TAG_FLAG(callhome_interval_secs, runtime);
52
// TODO: We need to change this to https, it involves updating our libcurl
53
// implementation to support SSL.
54
DEFINE_string(callhome_url, "http://diagnostics.yugabyte.com",
55
              "URL of callhome server");
56
TAG_FLAG(callhome_url, runtime);
57
DEFINE_string(callhome_collection_level, kMediumLevel, "Level of details sent by callhome");
58
TAG_FLAG(callhome_collection_level, runtime);
59
60
DEFINE_string(callhome_tag, "", "Tag to be inserted in the json sent to FLAGS_callhome_url. "
61
                                "This tag is used by itest to specify that the data generated by "
62
                                "callhome should be discarded by the receiver.");
63
TAG_FLAG(callhome_tag, runtime);
64
65
using google::CommandlineFlagsIntoString;
66
using strings::Substitute;
67
using yb::master::Master;
68
using yb::master::ListMastersResponsePB;
69
using yb::master::ListTablesRequestPB;
70
using yb::master::ListTablesResponsePB;
71
using yb::master::ListTabletServersResponsePB;
72
using yb::master::GetMasterClusterConfigResponsePB;
73
using yb::master::TSDescriptor;
74
using yb::server::RpcAndWebServerBase;
75
using yb::tserver::TabletServer;
76
77
namespace yb {
78
79
32
Collector::~Collector() {}
80
81
class CollectorBase : public Collector {
82
 public:
83
  CollectorBase(server::RpcAndWebServerBase* server, ServerType server_type);
84
85
  virtual ~CollectorBase();
86
87
  bool Run(CollectionLevel collection_level);
88
  virtual void Collect(CollectionLevel collection_level) = 0;
89
90
52
  const std::string& as_json() { return json_; }
91
0
  ServerType server_type() { return server_type_; }
92
93
  virtual std::string collector_name() = 0;
94
95
  virtual CollectionLevel collection_level() = 0;
96
  virtual ServerType collector_type() = 0;
97
98
 protected:
99
23
  inline master::Master* master() { return down_cast<master::Master*>(server_); }
100
0
  inline tserver::TabletServer* tserver() { return down_cast<tserver::TabletServer*>(server_); }
101
102
  server::RpcAndWebServerBase* server_;
103
  ServerType server_type_;
104
  std::string json_;
105
};
106
107
32
CollectorBase::~CollectorBase() {}
108
109
CollectorBase::CollectorBase(RpcAndWebServerBase* server, ServerType server_type):
110
82.6k
    server_(server), server_type_(server_type) {}
111
112
32
bool CollectorBase::Run(CollectionLevel level) {
113
32
  json_.clear();
114
32
  if (collector_type() == ServerType::ALL || collector_type() == server_type_) {
115
32
    if (collection_level() <= level) {
116
26
      Collect(level);
117
26
      return true;
118
6
    } else {
119
6
      LOG(INFO) << "Skipping collector " << collector_name()
120
6
                << " because it has a higher collection level than the requested one";
121
6
    }
122
0
  } else {
123
0
    LOG(INFO) << "Skipping collector " << collector_name() << " because of server type";
124
0
  }
125
6
  return false;
126
32
}
127
128
namespace {
129
130
template<class Key, class Value>
131
22
void AppendPairToJson(const Key& key, const Value& value, std::string *out) {
132
22
  if (!out->empty()) {
133
18
    *out += ",";
134
18
  }
135
22
  *out += '\"';
136
22
  *out += key;
137
22
  *out += "\":\"";
138
22
  *out += value;
139
22
  *out += '\"';
140
22
}
call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA13_cNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRKT_RKT0_PS9_
Line
Count
Source
131
7
void AppendPairToJson(const Key& key, const Value& value, std::string *out) {
132
7
  if (!out->empty()) {
133
3
    *out += ",";
134
3
  }
135
7
  *out += '\"';
136
7
  *out += key;
137
7
  *out += "\":\"";
138
7
  *out += value;
139
7
  *out += '\"';
140
7
}
call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA10_cNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRKT_RKT0_PS9_
Line
Count
Source
131
8
void AppendPairToJson(const Key& key, const Value& value, std::string *out) {
132
8
  if (!out->empty()) {
133
8
    *out += ",";
134
8
  }
135
8
  *out += '\"';
136
8
  *out += key;
137
8
  *out += "\":\"";
138
8
  *out += value;
139
8
  *out += '\"';
140
8
}
call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA12_cA7_cEEvRKT_RKT0_PNSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEE
Line
Count
Source
131
4
void AppendPairToJson(const Key& key, const Value& value, std::string *out) {
132
4
  if (!out->empty()) {
133
4
    *out += ",";
134
4
  }
135
4
  *out += '\"';
136
4
  *out += key;
137
4
  *out += "\":\"";
138
4
  *out += value;
139
4
  *out += '\"';
140
4
}
call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA9_cNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRKT_RKT0_PS9_
Line
Count
Source
131
3
void AppendPairToJson(const Key& key, const Value& value, std::string *out) {
132
3
  if (!out->empty()) {
133
3
    *out += ",";
134
3
  }
135
3
  *out += '\"';
136
3
  *out += key;
137
3
  *out += "\":\"";
138
3
  *out += value;
139
3
  *out += '\"';
140
3
}
Unexecuted instantiation: call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA12_cA8_cEEvRKT_RKT0_PNSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEE
141
142
3
std::string GetCurrentUser() {
143
3
  auto user_name = GetLoggedInUser();
144
3
  if (user_name.ok()) {
145
2
    YB_LOG_FIRST_N(INFO, 1) << "Logged in user: " << *user_name;
146
3
    return *user_name;
147
0
  } else {
148
0
    YB_LOG_FIRST_N(WARNING, 1) << "Failed to get current user: " << user_name.status();
149
0
    return "unknown_user";
150
0
  }
151
3
}
152
153
} // namespace
154
155
class BasicCollector : public CollectorBase {
156
 public:
157
  using CollectorBase::CollectorBase;
158
159
4
  void Collect(CollectionLevel collection_level) {
160
4
    switch (server_type_) {
161
0
      case ServerType::ALL:
162
0
        LOG(FATAL) << "Invalid server type ALL";
163
4
      case ServerType::MASTER: {
164
4
        master::SysClusterConfigEntryPB config;
165
4
        auto status = master()->catalog_manager()->GetClusterConfig(&config);
166
4
        if (status.ok()) {
167
4
          AppendPairToJson("cluster_uuid", config.cluster_uuid(), &json_);
168
4
        }
169
4
        AppendPairToJson("node_uuid", master()->fs_manager()->uuid(), &json_);
170
4
        AppendPairToJson("server_type", "master", &json_);
171
172
        // Only collect hostname and username if collection level is medium or high.
173
4
        if (collection_level != CollectionLevel::LOW) {
174
3
          AppendPairToJson("hostname", master()->get_hostname(), &json_);
175
3
          AppendPairToJson("current_user", GetCurrentUser(), &json_);
176
3
        }
177
4
        json_ += ",\"version_info\":" + VersionInfo::GetAllVersionInfoJson();
178
4
        break;
179
0
      }
180
0
      case ServerType::TSERVER: {
181
0
        AppendPairToJson("cluster_uuid", tserver()->cluster_uuid(), &json_);
182
0
        AppendPairToJson("node_uuid", tserver()->permanent_uuid(), &json_);
183
0
        AppendPairToJson("server_type", "tserver", &json_);
184
185
        // Only collect hostname and username if collection level is medium or high.
186
0
        if (collection_level != CollectionLevel::LOW) {
187
0
          AppendPairToJson("hostname", tserver()->get_hostname(), &json_);
188
0
          AppendPairToJson("current_user", GetCurrentUser(), &json_);
189
0
        }
190
0
        break;
191
4
      }
192
4
    }
193
4
    AppendPairToJson("timestamp", std::to_string(WallTime_Now()), &json_);
194
4
  }
195
196
4
  string collector_name() { return "BasicCollector"; }
197
198
4
  virtual CollectionLevel collection_level() { return CollectionLevel::LOW; }
199
4
  virtual ServerType collector_type() { return ServerType::ALL; }
200
};
201
202
class MetricsCollector : public CollectorBase {
203
 public:
204
  using CollectorBase::CollectorBase;
205
206
1
  void Collect(CollectionLevel collection_level) {
207
1
    std::stringstream s;
208
1
    JsonWriter w(&s, JsonWriter::COMPACT);
209
210
1
    Status status = server_->metric_registry()->WriteAsJson(&w, {"*"}, MetricJsonOptions());
211
1
    if (!status.ok()) {
212
0
      json_ = "\"metrics\":{}";
213
0
      return;
214
0
    }
215
1
    json_ = "\"metrics\":" + s.str();
216
1
  }
217
218
4
  string collector_name() { return "MetricsCollector"; }
219
220
4
  virtual CollectionLevel collection_level() { return CollectionLevel::HIGH; }
221
4
  virtual ServerType collector_type() { return ServerType::ALL; }
222
};
223
224
class RpcsCollector : public CollectorBase {
225
 public:
226
  using CollectorBase::CollectorBase;
227
228
1
  void Collect(CollectionLevel collection_level) {
229
1
    if (!UpdateAddr().ok()) {
230
0
      json_ = "\"rpcs\":{}";
231
0
      return;
232
0
    }
233
234
1
    faststring buf;
235
1
    auto url = Substitute("http://$0/rpcz", yb::ToString(*addr_));
236
1
    auto status = curl_.FetchURL(url, &buf);
237
1
    if (!status.ok()) {
238
0
      LOG(ERROR) << "Unable to read url " << url;
239
0
      return;
240
0
    }
241
242
1
    if (buf.length() > 0) {
243
1
      auto rpcs_json = buf.ToString();
244
1
      boost::replace_all(rpcs_json, "\n", "");
245
1
      json_ = "\"rpcs\":" +  rpcs_json;
246
0
    } else {
247
0
      LOG(WARNING) << "Error getting rpcs";
248
0
    }
249
250
1
  }
251
252
4
  string collector_name() { return "RpcsCollector"; }
253
254
4
  virtual CollectionLevel collection_level() { return CollectionLevel::HIGH; }
255
4
  virtual ServerType collector_type() { return ServerType::ALL; }
256
257
 private:
258
1
  CHECKED_STATUS UpdateAddr() {
259
1
    if (addr_) {
260
0
      return Status::OK();
261
0
    }
262
263
1
    vector<Endpoint> addrs;
264
1
    auto status = server_->web_server()->GetBoundAddresses(&addrs);
265
1
    if (!status.ok()) {
266
0
      LOG(WARNING) << "Unable to get webserver address: " << status.ToString();
267
0
      return STATUS(InternalError, "Unable to get webserver address");
268
0
    }
269
1
    addr_.emplace(addrs[0]);
270
1
    return Status::OK();
271
1
  }
272
273
  boost::optional<Endpoint> addr_;
274
  EasyCurl curl_;
275
};
276
277
class TablesCollector : public CollectorBase {
278
 public:
279
  using CollectorBase::CollectorBase;
280
281
4
  void Collect(CollectionLevel collection_level) {
282
4
    ListTablesRequestPB req;
283
4
    req.set_exclude_system_tables(true);
284
4
    ListTablesResponsePB resp;
285
4
    auto status = master()->catalog_manager()->ListTables(&req, &resp);
286
4
    if (!status.ok()) {
287
0
      LOG(INFO) << "Error getting number of tables";
288
0
      return;
289
0
    }
290
4
    if (collection_level == CollectionLevel::LOW) {
291
1
      json_ = Substitute("\"tables\":$0", resp.tables_size());
292
3
    } else {
293
      // TODO(hector): Add more table details.
294
3
      json_ = Substitute("\"tables\":$0", resp.tables_size());
295
3
    }
296
4
  }
297
298
4
  string collector_name() { return "TablesCollector"; }
299
300
4
  virtual CollectionLevel collection_level() { return CollectionLevel::ALL; }
301
8
  virtual ServerType collector_type() { return ServerType::MASTER; }
302
};
303
304
class MasterInfoCollector : public CollectorBase {
305
 public:
306
  using CollectorBase::CollectorBase;
307
308
4
  void Collect(CollectionLevel collection_level) {
309
4
    vector<ServerEntryPB> masters;
310
4
    Status s = master()->ListMasters(&masters);
311
4
    if (s.ok()) {
312
4
      if (collection_level == CollectionLevel::LOW) {
313
1
        json_ = Substitute("\"masters\":$0", masters.size());
314
3
      } else {
315
        // TODO(hector): Add more details.
316
3
        json_ = Substitute("\"masters\":$0", masters.size());
317
3
      }
318
4
    }
319
4
  }
320
321
4
  string collector_name() { return "MasterInfoCollector"; }
322
323
4
  virtual CollectionLevel collection_level() { return CollectionLevel::ALL; }
324
8
  virtual ServerType collector_type() { return ServerType::MASTER; }
325
};
326
327
class TServersInfoCollector : public CollectorBase {
328
 public:
329
  using CollectorBase::CollectorBase;
330
331
4
  void Collect(CollectionLevel collection_level) {
332
4
    vector<std::shared_ptr<TSDescriptor>> descs;
333
4
    master()->ts_manager()->GetAllDescriptors(&descs);
334
4
    if (collection_level == CollectionLevel::LOW) {
335
1
      json_ = Substitute("\"tservers\":$0", descs.size());
336
3
    } else {
337
      // TODO(hector): Add more details.
338
3
      json_ = Substitute("\"tservers\":$0", descs.size());
339
3
    }
340
4
  }
341
342
4
  string collector_name() { return "TServersInfoCollector"; }
343
344
4
  virtual CollectionLevel collection_level() { return CollectionLevel::ALL; }
345
8
  virtual ServerType collector_type() { return ServerType::MASTER; }
346
};
347
348
class TabletsCollector : public CollectorBase {
349
 public:
350
  using CollectorBase::CollectorBase;
351
352
4
  void Collect(CollectionLevel collection_level) {
353
4
    int ntablets;
354
4
    if (server_type_ == ServerType::MASTER) {
355
4
      ntablets = 1;
356
0
    } else {
357
0
      ntablets = tserver()->tablet_manager()->GetNumLiveTablets();
358
0
    }
359
4
    json_ = Substitute("\"tablets\":$0", ntablets);
360
4
  }
361
362
4
  string collector_name() { return "TabletsCollector"; }
363
364
4
  virtual CollectionLevel collection_level() { return CollectionLevel::ALL; }
365
4
  virtual ServerType collector_type() { return ServerType::ALL; }
366
};
367
368
class GFlagsCollector : public CollectorBase {
369
 public:
370
  using CollectorBase::CollectorBase;
371
372
4
  void Collect(CollectionLevel collection_level) {
373
4
    auto gflags = CommandlineFlagsIntoString();
374
4
    boost::replace_all(gflags, "\n", " ");
375
4
    json_ = Substitute("\"gflags\":\"$0\"", gflags);
376
4
  }
377
378
4
  string collector_name() { return "GFlagsCollector"; }
379
380
4
  virtual CollectionLevel collection_level() { return CollectionLevel::LOW; }
381
4
  virtual ServerType collector_type() { return ServerType::ALL; }
382
};
383
384
CallHome::CallHome(server::RpcAndWebServerBase* server, ServerType server_type) :
385
10.3k
    server_(server), pool_("call_home", 1), server_type_(server_type) {
386
387
10.3k
  scheduler_ = std::make_unique<yb::rpc::Scheduler>(&pool_.io_service());
388
389
10.3k
  AddCollector<BasicCollector>();
390
10.3k
  AddCollector<MasterInfoCollector>();
391
10.3k
  AddCollector<TServersInfoCollector>();
392
10.3k
  AddCollector<TablesCollector>();
393
10.3k
  AddCollector<TabletsCollector>();
394
10.3k
  AddCollector<MetricsCollector>();
395
10.3k
  AddCollector<RpcsCollector>();
396
10.3k
  AddCollector<GFlagsCollector>();
397
10.3k
}
398
399
4
CallHome::~CallHome() {
400
4
  scheduler_->Shutdown();
401
4
  pool_.Shutdown();
402
4
  pool_.Join();
403
4
}
404
405
template <typename T>
406
82.6k
void CallHome::AddCollector() {
407
82.6k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
82.6k
}
_ZN2yb8CallHome12AddCollectorINS_14BasicCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
_ZN2yb8CallHome12AddCollectorINS_19MasterInfoCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
_ZN2yb8CallHome12AddCollectorINS_21TServersInfoCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
_ZN2yb8CallHome12AddCollectorINS_15TablesCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
_ZN2yb8CallHome12AddCollectorINS_16TabletsCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
_ZN2yb8CallHome12AddCollectorINS_16MetricsCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
_ZN2yb8CallHome12AddCollectorINS_13RpcsCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
_ZN2yb8CallHome12AddCollectorINS_15GFlagsCollectorEEEvv
Line
Count
Source
406
10.3k
void CallHome::AddCollector() {
407
10.3k
  collectors_.emplace_back(std::make_unique<T>(server_, server_type_));
408
10.3k
}
409
410
4
std::string CallHome::BuildJson() {
411
4
  string str = "{";
412
4
  string comma = "";
413
4
  auto collection_level = GetCollectionLevel();
414
32
  for (const auto& collector : collectors_) {
415
32
    if (collector->Run(collection_level) && !collector->as_json().empty()) {
416
26
      str += comma;
417
26
      str += collector->as_json();
418
26
      comma = ",";
419
26
      LOG(INFO) << "Done with collector " << collector->collector_name();
420
26
    }
421
32
  }
422
4
  if (!FLAGS_callhome_tag.empty()) {
423
4
    str += comma;
424
4
    str += Substitute("\"tag\":\"$0\"", FLAGS_callhome_tag);
425
4
  }
426
4
  str += "}";
427
428
4
  rapidjson::StringBuffer buffer;
429
4
  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
430
4
  rapidjson::Reader reader;
431
4
  rapidjson::StringStream ss(str.c_str());
432
4
  if (!reader.Parse<rapidjson::kParseDefaultFlags>(ss, writer)) {
433
0
    LOG(ERROR) << "Unable to parse json. Error: " << reader.GetParseErrorCode()
434
0
        << " at offset " << reader.GetErrorOffset() << " in string " <<
435
0
        str.substr(reader.GetErrorOffset(), 10);
436
0
    return str;
437
0
  }
438
439
4
  return buffer.GetString();
440
4
}
441
442
1
void CallHome::BuildJsonAndSend() {
443
1
  auto json = BuildJson();
444
1
  SendData(json);
445
1
}
446
447
1.11M
void CallHome::DoCallHome() {
448
1.11M
  if (FLAGS_callhome_enabled) {
449
1
    if (server_type_ == ServerType::MASTER &&
450
1
        !master()->catalog_manager()->CheckIsLeaderAndReady().ok()) {
451
0
      VLOG(3) << "This master instance is not a leader. Skipping call home";
452
1
    } else {
453
1
      BuildJsonAndSend();
454
1
    }
455
1
  }
456
457
1.11M
  ScheduleCallHome(FLAGS_callhome_interval_secs);
458
1.11M
}
459
460
4
void CallHome::SendData(const string& payload) {
461
4
  faststring reply;
462
463
4
  auto status = curl_.PostToURL(FLAGS_callhome_url, payload, "application/json", &reply);
464
4
  if (!status.ok()) {
465
0
    LOG(INFO) << "Unable to send diagnostics data to " << FLAGS_callhome_url;
466
0
  }
467
0
  VLOG(1) << "Received reply: " << reply;
468
4
}
469
470
1.12M
void CallHome::ScheduleCallHome(int delay_seconds) {
471
1.11M
  scheduler_->Schedule([this](const Status& status) { DoCallHome(); },
472
1.12M
                       std::chrono::seconds(delay_seconds));
473
1.12M
}
474
475
4
CollectionLevel CallHome::GetCollectionLevel() {
476
4
  if (FLAGS_callhome_collection_level == kHighLevel) {
477
1
    return CollectionLevel::HIGH;
478
3
  } else if (FLAGS_callhome_collection_level == kMediumLevel) {
479
2
    return CollectionLevel::MEDIUM;
480
1
  } else if (FLAGS_callhome_collection_level == kLowLevel) {
481
1
    return CollectionLevel::LOW;
482
1
  }
483
0
  return CollectionLevel::LOW;
484
0
}
485
486
1
master::Master* CallHome::master() {
487
1
  return down_cast<master::Master*>(server_);
488
1
}
489
490
0
tserver::TabletServer* CallHome::tserver() {
491
0
  return down_cast<tserver::TabletServer*>(server_);
492
0
}
493
494
} // namespace yb