YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/consensus/consensus_meta.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 "yb/consensus/consensus_meta.h"
34
35
#include "yb/common/entity_ids_types.h"
36
#include "yb/common/wire_protocol.h"
37
38
#include "yb/consensus/consensus_util.h"
39
#include "yb/consensus/consensus.pb.h"
40
#include "yb/consensus/metadata.pb.h"
41
#include "yb/consensus/opid_util.h"
42
#include "yb/consensus/quorum_util.h"
43
44
#include "yb/fs/fs_manager.h"
45
46
#include "yb/gutil/strings/substitute.h"
47
#include "yb/util/fault_injection.h"
48
#include "yb/util/flag_tags.h"
49
#include "yb/util/logging.h"
50
#include "yb/util/pb_util.h"
51
#include "yb/util/result.h"
52
#include "yb/util/stopwatch.h"
53
54
DEFINE_test_flag(double, fault_crash_before_cmeta_flush, 0.0,
55
              "Fraction of the time when the server will crash just before flushing "
56
              "consensus metadata. (For testing only!)");
57
58
namespace yb {
59
namespace consensus {
60
61
using std::string;
62
using strings::Substitute;
63
64
namespace {
65
66
const int kBitsPerPackedRole = 3;
67
static_assert(0 <= PeerRole_MIN, "RaftPeerPB_Role_Role_MIN must be non-negative.");
68
static_assert(PeerRole_MAX < (1 << kBitsPerPackedRole),
69
              "RaftPeerPB_Role_Role_MAX must fit in kBitsPerPackedRole bits.");
70
71
1.13M
ConsensusMetadata::PackedRoleAndTerm PackRoleAndTerm(PeerRole role, int64_t term) {
72
  // Ensure we've had no more than 2305843009213693952 terms in this tablet.
73
1.13M
  CHECK_LT(term, 1ull << (8 * sizeof(ConsensusMetadata::PackedRoleAndTerm) - kBitsPerPackedRole));
74
1.13M
  return to_underlying(role) | (term << kBitsPerPackedRole);
75
1.13M
}
76
77
1.77M
int64_t UnpackTerm(ConsensusMetadata::PackedRoleAndTerm role_and_term) {
78
1.77M
  return role_and_term >> kBitsPerPackedRole;
79
1.77M
}
80
81
1.77M
PeerRole UnpackRole(ConsensusMetadata::PackedRoleAndTerm role_and_term) {
82
1.77M
  return static_cast<PeerRole>(role_and_term & ((1 << kBitsPerPackedRole) - 1));
83
1.77M
}
84
85
} // anonymous namespace
86
87
Status ConsensusMetadata::Create(FsManager* fs_manager,
88
                                 const string& tablet_id,
89
                                 const std::string& peer_uuid,
90
                                 const RaftConfigPB& config,
91
                                 int64_t current_term,
92
88.8k
                                 std::unique_ptr<ConsensusMetadata>* cmeta_out) {
93
88.8k
  std::unique_ptr<ConsensusMetadata> cmeta(new ConsensusMetadata(fs_manager, tablet_id, peer_uuid));
94
88.8k
  cmeta->set_committed_config(config);
95
88.8k
  cmeta->set_current_term(current_term);
96
88.8k
  RETURN_NOT_OK(cmeta->Flush());
97
88.8k
  cmeta_out->swap(cmeta);
98
88.8k
  return Status::OK();
99
88.8k
}
100
101
Status ConsensusMetadata::Load(FsManager* fs_manager,
102
                               const std::string& tablet_id,
103
                               const std::string& peer_uuid,
104
178k
                               std::unique_ptr<ConsensusMetadata>* cmeta_out) {
105
178k
  std::unique_ptr<ConsensusMetadata> cmeta(new ConsensusMetadata(fs_manager, tablet_id, peer_uuid));
106
178k
  RETURN_NOT_OK(pb_util::ReadPBContainerFromPath(fs_manager->env(),
107
178k
                                                 fs_manager->GetConsensusMetadataPath(tablet_id),
108
178k
                                                 &cmeta->pb_));
109
178k
  cmeta->UpdateActiveRole(); // Needs to happen here as we sidestep the accessor APIs.
110
178k
  RETURN_NOT_OK(cmeta->UpdateOnDiskSize());
111
178k
  cmeta_out->swap(cmeta);
112
178k
  return Status::OK();
113
178k
}
114
115
46.9k
Status ConsensusMetadata::DeleteOnDiskData(FsManager* fs_manager, const string& tablet_id) {
116
46.9k
  string cmeta_path = fs_manager->GetConsensusMetadataPath(tablet_id);
117
46.9k
  Env* env = fs_manager->env();
118
46.9k
  if (!env->FileExists(cmeta_path)) {
119
94
    return Status::OK();
120
94
  }
121
46.9k
  LOG(INFO) << "T " << tablet_id << " Deleting consensus metadata";
122
46.9k
  RETURN_NOT_OK_PREPEND(env->DeleteFile(cmeta_path),
123
46.9k
                        "Unable to delete consensus metadata file for tablet " + tablet_id);
124
46.9k
  return Status::OK();
125
46.9k
}
126
127
106M
int64_t ConsensusMetadata::current_term() const {
128
106M
  DCHECK(pb_.has_current_term());
129
106M
  return pb_.current_term();
130
106M
}
131
132
192k
void ConsensusMetadata::set_current_term(int64_t term) {
133
192k
  DCHECK_GE(term, kMinimumTerm);
134
192k
  pb_.set_current_term(term);
135
192k
  UpdateRoleAndTermCache();
136
192k
}
137
138
139
88.8k
bool ConsensusMetadata::has_split_parent_tablet_id() const {
140
88.8k
  return pb_.has_split_parent_tablet_id();
141
88.8k
}
142
143
94
const TabletId& ConsensusMetadata::split_parent_tablet_id() const {
144
94
  DCHECK(pb_.has_split_parent_tablet_id());
145
94
  return pb_.split_parent_tablet_id();
146
94
}
147
148
87
void ConsensusMetadata::set_split_parent_tablet_id(const TabletId& split_parent_tablet_id) {
149
87
  DCHECK(!split_parent_tablet_id.empty());
150
87
  pb_.set_split_parent_tablet_id(split_parent_tablet_id);
151
87
}
152
153
1.12k
bool ConsensusMetadata::has_voted_for() const {
154
1.12k
  return pb_.has_voted_for();
155
1.12k
}
156
157
436
const string& ConsensusMetadata::voted_for() const {
158
436
  DCHECK(pb_.has_voted_for());
159
436
  return pb_.voted_for();
160
436
}
161
162
103k
void ConsensusMetadata::clear_voted_for() {
163
103k
  pb_.clear_voted_for();
164
103k
}
165
166
96.2k
void ConsensusMetadata::set_voted_for(const string& uuid) {
167
96.2k
  DCHECK(!uuid.empty());
168
96.2k
  pb_.set_voted_for(uuid);
169
96.2k
}
170
171
102M
const RaftConfigPB& ConsensusMetadata::committed_config() const {
172
102M
  DCHECK(pb_.has_committed_config());
173
102M
  return pb_.committed_config();
174
102M
}
175
176
99.0k
void ConsensusMetadata::set_committed_config(const RaftConfigPB& config) {
177
99.0k
  *pb_.mutable_committed_config() = config;
178
99.0k
  if (!has_pending_config_) {
179
88.9k
    UpdateActiveRole();
180
88.9k
  }
181
99.0k
}
182
183
9.18M
bool ConsensusMetadata::has_pending_config() const {
184
9.18M
  return has_pending_config_;
185
9.18M
}
186
187
6.14M
const RaftConfigPB& ConsensusMetadata::pending_config() const {
188
6.14M
  DCHECK(has_pending_config_);
189
6.14M
  return pending_config_;
190
6.14M
}
191
192
10.2k
void ConsensusMetadata::clear_pending_config() {
193
10.2k
  has_pending_config_ = false;
194
10.2k
  pending_config_.Clear();
195
10.2k
  UpdateActiveRole();
196
10.2k
}
197
198
10.1k
void ConsensusMetadata::set_pending_config(const RaftConfigPB& config) {
199
10.1k
  has_pending_config_ = true;
200
10.1k
  pending_config_ = config;
201
10.1k
  UpdateActiveRole();
202
10.1k
}
203
204
44.6M
const RaftConfigPB& ConsensusMetadata::active_config() const {
205
44.6M
  if (has_pending_config_) {
206
3.07M
    return pending_config();
207
3.07M
  }
208
41.6M
  return committed_config();
209
41.6M
}
210
211
41.0M
const string& ConsensusMetadata::leader_uuid() const {
212
41.0M
  return leader_uuid_;
213
41.0M
}
214
215
388k
void ConsensusMetadata::set_leader_uuid(const string& uuid) {
216
388k
  leader_uuid_ = uuid;
217
388k
  UpdateActiveRole();
218
388k
}
219
220
0
void ConsensusMetadata::clear_leader_uuid() {
221
0
  set_leader_uuid("");
222
0
}
223
224
108M
PeerRole ConsensusMetadata::active_role() const {
225
108M
  return active_role_;
226
108M
}
227
228
7.95M
ConsensusStatePB ConsensusMetadata::ToConsensusStatePB(ConsensusConfigType type) const {
229
18.4E
  CHECK(type == CONSENSUS_CONFIG_ACTIVE || type == CONSENSUS_CONFIG_COMMITTED)
230
18.4E
      << "Unsupported ConsensusConfigType: " << ConsensusConfigType_Name(type) << ": " << type;
231
7.95M
  ConsensusStatePB cstate;
232
7.95M
  cstate.set_current_term(pb_.current_term());
233
7.95M
  if (type == CONSENSUS_CONFIG_ACTIVE) {
234
703k
    *cstate.mutable_config() = active_config();
235
703k
    cstate.set_leader_uuid(leader_uuid_);
236
7.25M
  } else {
237
7.25M
    *cstate.mutable_config() = committed_config();
238
    // It's possible, though unlikely, that a new node from a pending configuration
239
    // could be elected leader. Do not indicate a leader in this case.
240
7.25M
    if (PREDICT_TRUE(IsRaftConfigVoter(leader_uuid_, cstate.config()))) {
241
5.08M
      cstate.set_leader_uuid(leader_uuid_);
242
5.08M
    }
243
7.25M
  }
244
7.95M
  return cstate;
245
7.95M
}
246
247
101
void ConsensusMetadata::MergeCommittedConsensusStatePB(const ConsensusStatePB& committed_cstate) {
248
101
  if (committed_cstate.current_term() > current_term()) {
249
20
    set_current_term(committed_cstate.current_term());
250
20
    clear_voted_for();
251
20
  }
252
253
101
  set_leader_uuid("");
254
101
  set_committed_config(committed_cstate.config());
255
101
  clear_pending_config();
256
101
}
257
258
300k
Status ConsensusMetadata::Flush() {
259
300k
  MAYBE_FAULT(FLAGS_TEST_fault_crash_before_cmeta_flush);
260
300k
  SCOPED_LOG_SLOW_EXECUTION_PREFIX(WARNING, 500, LogPrefix(), "flushing consensus metadata");
261
  // Sanity test to ensure we never write out a bad configuration.
262
300k
  RETURN_NOT_OK_PREPEND(VerifyRaftConfig(pb_.committed_config(), COMMITTED_QUORUM),
263
300k
                        "Invalid config in ConsensusMetadata, cannot flush to disk");
264
265
  // Create directories if needed.
266
300k
  string dir = fs_manager_->GetConsensusMetadataDir();
267
300k
  bool created_dir = false;
268
300k
  RETURN_NOT_OK_PREPEND(fs_manager_->CreateDirIfMissing(dir, &created_dir),
269
299k
                        "Unable to create consensus metadata root dir");
270
  // fsync() parent dir if we had to create the dir.
271
299k
  if (PREDICT_FALSE(created_dir)) {
272
0
    string parent_dir = DirName(dir);
273
0
    RETURN_NOT_OK_PREPEND(Env::Default()->SyncDir(parent_dir),
274
0
                          "Unable to fsync consensus parent dir " + parent_dir);
275
0
  }
276
277
299k
  string meta_file_path = fs_manager_->GetConsensusMetadataPath(tablet_id_);
278
299k
  RETURN_NOT_OK_PREPEND(pb_util::WritePBContainerToPath(
279
299k
      fs_manager_->env(), meta_file_path, pb_,
280
299k
      pb_util::OVERWRITE,
281
      // Always fsync the consensus metadata.
282
299k
      pb_util::SYNC),
283
299k
          Substitute("Unable to write consensus meta file for tablet $0 to path $1",
284
299k
                     tablet_id_, meta_file_path));
285
299k
  RETURN_NOT_OK(UpdateOnDiskSize());
286
299k
  return Status::OK();
287
299k
}
288
289
ConsensusMetadata::ConsensusMetadata(FsManager* fs_manager,
290
                                     std::string tablet_id,
291
                                     std::string peer_uuid)
292
    : fs_manager_(CHECK_NOTNULL(fs_manager)),
293
      tablet_id_(std::move(tablet_id)),
294
      peer_uuid_(std::move(peer_uuid)),
295
      has_pending_config_(false),
296
      active_role_(PeerRole::UNKNOWN_ROLE),
297
266k
      on_disk_size_(0) {
298
266k
  UpdateRoleAndTermCache();
299
266k
}
300
301
976k
std::string ConsensusMetadata::LogPrefix() const {
302
976k
  return MakeTabletLogPrefix(tablet_id_, peer_uuid_);
303
976k
}
304
305
675k
void ConsensusMetadata::UpdateActiveRole() {
306
675k
  ConsensusStatePB cstate = ToConsensusStatePB(CONSENSUS_CONFIG_ACTIVE);
307
675k
  PeerRole old_role = active_role_;
308
675k
  active_role_ = GetConsensusRole(peer_uuid_, cstate);
309
675k
  UpdateRoleAndTermCache();
310
675k
  LOG_WITH_PREFIX(INFO) << "Updating active role from " << PeerRole_Name(old_role)
311
675k
                        << " to " << PeerRole_Name(active_role_)
312
675k
                        << ". Consensus state: " << cstate.ShortDebugString()
313
675k
                        << ", has_pending_config = " << has_pending_config_;
314
675k
}
315
316
477k
Status ConsensusMetadata::UpdateOnDiskSize() {
317
477k
  string path = fs_manager_->GetConsensusMetadataPath(tablet_id_);
318
477k
  on_disk_size_.store(VERIFY_RESULT(fs_manager_->env()->GetFileSize(path)));
319
477k
  return Status::OK();
320
477k
}
321
322
1.13M
void ConsensusMetadata::UpdateRoleAndTermCache() {
323
779k
  auto new_value = PackRoleAndTerm(active_role_, pb_.has_current_term() ? current_term() : 0);
324
1.13M
  role_and_term_cache_.store(new_value, std::memory_order_release);
325
1.13M
}
326
327
1.77M
std::pair<PeerRole, int64_t> ConsensusMetadata::GetRoleAndTerm() const {
328
1.77M
  const auto packed_role_and_term = role_and_term_cache_.load(std::memory_order_acquire);
329
1.77M
  return std::make_pair(UnpackRole(packed_role_and_term), UnpackTerm(packed_role_and_term));
330
1.77M
}
331
332
230k
const HostPortPB& DesiredHostPort(const RaftPeerPB& peer, const CloudInfoPB& from) {
333
230k
  return DesiredHostPort(
334
230k
      peer.last_known_broadcast_addr(), peer.last_known_private_addr(), peer.cloud_info(), from);
335
230k
}
336
337
109k
void TakeRegistration(ServerRegistrationPB* source, RaftPeerPB* dest) {
338
109k
  dest->mutable_last_known_private_addr()->Swap(source->mutable_private_rpc_addresses());
339
109k
  dest->mutable_last_known_broadcast_addr()->Swap(source->mutable_broadcast_addresses());
340
109k
  dest->mutable_cloud_info()->Swap(source->mutable_cloud_info());
341
109k
}
342
343
14.5k
void CopyRegistration(ServerRegistrationPB source, RaftPeerPB* dest) {
344
14.5k
  TakeRegistration(&source, dest);
345
14.5k
}
346
347
} // namespace consensus
348
} // namespace yb