Loading...
Searching...
No Matches
viewchange_manager.cpp
Go to the documentation of this file.
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
21
22#include <glog/logging.h>
23
24#include "common/utils/utils.h"
26#include "platform/proto/viewchange_message.pb.h"
27
28namespace resdb {
29
31 : proxy_id(0), is_complaining(false), timeout_length_(10000000) {}
32
34 : proxy_id(proxy_id), is_complaining(false), timeout_length_(10000000) {}
35
36std::shared_ptr<ViewChangeTimeout> ComplaningClients::SetComplaining(
37 std::string hash, uint64_t view) {
38 this->complain_state_lock.lock();
39 this->is_complaining = true;
40 auto info = std::make_shared<ViewChangeTimeout>(
43 this->viewchange_timeout_set.insert(hash);
44 this->complain_state_lock.unlock();
45 return info;
46}
47
49 this->complain_state_lock.lock();
50 uint value = this->viewchange_timeout_set.count(hash);
51 this->complain_state_lock.unlock();
52 return value;
53}
54
56 this->complain_state_lock.lock();
57 this->viewchange_timeout_set.erase(hash);
58 this->complain_state_lock.unlock();
59}
60
62 this->complain_state_lock.lock();
63 this->viewchange_timeout_set.erase(hash);
64 this->complain_state_lock.unlock();
65}
66
67// A manager to address View change process.
68// All stuff here will be addressed in sequential by using mutex
69// to make things simplier.
71 CheckPointManager* checkpoint_manager,
72 MessageManager* message_manager,
73 SystemInfo* system_info,
74 ReplicaCommunicator* replica_communicator,
75 SignatureVerifier* verifier)
76 : config_(config),
77 checkpoint_manager_(checkpoint_manager),
78 message_manager_(message_manager),
79 system_info_(system_info),
80 replica_communicator_(replica_communicator),
81 verifier_(verifier),
82 status_(ViewChangeStatus::NONE),
83 started_(false),
84 stop_(false) {
86 if (config_.GetConfigData().enable_viewchange()) {
87 collector_pool_ = message_manager->GetCollectorPool();
88 sem_init(&viewchange_timer_signal_, 0, 0);
90 std::thread(&ViewChangeManager::MonitoringViewChangeTimeOut, this);
92 std::thread(&ViewChangeManager::MonitoringCheckpointState, this);
93 }
94}
95
105
107 if (started_) {
108 return;
109 }
110 started_ = true;
111
113 .public_key()
114 .public_key_info()
115 .type() == CertificateKeyInfo::CLIENT) {
116 LOG(ERROR) << "client type not process view change";
117 return;
118 }
119
121 // LOG(ERROR) << "checkpoint timeout";
125 // If the new view msg expires after receiving enough view
126 // messages, trigger a new primary.
128 }
129 // std::lock_guard<std::mutex> lk(status_mutex_);
130 if (ChangeStatue(ViewChangeStatus::READY_VIEW_CHANGE)) {
131 SendViewChangeMsg();
132 auto viewchange_timer = std::make_shared<ViewChangeTimeout>(
134 config_.GetSelfInfo().id(), "null", GetCurrentTime(),
136 std::lock_guard<std::mutex> lk(vc_mutex_);
140 viewchange_timer);
141 sem_post(&viewchange_timer_signal_);
142 }
143 }
144 });
145}
146
147bool ViewChangeManager::ChangeStatue(ViewChangeStatus status) {
150 status_ = status;
151 }
152 } else {
153 status_ = status;
154 }
155 return status_ == status;
156}
157
161
162bool ViewChangeManager::IsValidViewChangeMsg(
163 const ViewChangeMessage& view_change_message) {
164 if (view_change_message.view_number() <= system_info_->GetCurrentView()) {
165 LOG(ERROR) << "View number is not greater than current view:"
166 << view_change_message.view_number() << "("
167 << system_info_->GetCurrentView() << ")";
168 return false;
169 }
170
172 view_change_message.stable_ckpt())) {
173 LOG(ERROR) << "stable checkpoint invalid";
174 return false;
175 }
176
177 uint64_t stable_seq = view_change_message.stable_ckpt().seq();
178
179 for (const auto& prepared_msg : view_change_message.prepared_msg()) {
180 if (prepared_msg.seq() <= stable_seq) {
181 continue;
182 }
183 // If there is less than 2f+1 proof, reject.
184 if (prepared_msg.proof_size() < config_.GetMinDataReceiveNum()) {
185 LOG(ERROR) << "proof[" << prepared_msg.proof_size()
186 << "] not enough:" << config_.GetMinDataReceiveNum();
187 return false;
188 }
189 for (const auto& proof : prepared_msg.proof()) {
190 if (proof.request().seq() != prepared_msg.seq()) {
191 LOG(ERROR) << "proof seq not match";
192 return false;
193 }
194 std::string data;
195 proof.request().SerializeToString(&data);
196 if (!verifier_->VerifyMessage(data, proof.signature())) {
197 LOG(ERROR) << "proof signature not valid";
198 return false;
199 }
200 }
201 }
202 return true;
203}
204
205uint32_t ViewChangeManager::AddRequest(
206 const ViewChangeMessage& viewchange_message, uint32_t sender) {
207 std::lock_guard<std::mutex> lk(vc_mutex_);
208 viewchange_request_[viewchange_message.view_number()][sender] =
209 viewchange_message;
210 return viewchange_request_[viewchange_message.view_number()].size();
211}
212
213bool ViewChangeManager::IsNextPrimary(uint64_t view_number) {
214 std::lock_guard<std::mutex> lk(mutex_);
215 const std::vector<ReplicaInfo>& replicas = config_.GetReplicaInfos();
216 return config_.GetReplicaInfos()[(view_number - 1) % replicas.size()].id() ==
217 config_.GetSelfInfo().id();
218}
219
220void ViewChangeManager::SetCurrentViewAndNewPrimary(uint64_t view_number) {
221 system_info_->SetCurrentView(view_number);
222
223 const std::vector<ReplicaInfo>& replicas = config_.GetReplicaInfos();
224 uint32_t id =
225 config_.GetReplicaInfos()[(view_number - 1) % replicas.size()].id();
227}
228
229std::vector<std::unique_ptr<Request>> ViewChangeManager::GetPrepareMsg(
230 const NewViewMessage& new_view_message, bool need_sign) {
231 std::map<uint64_t, Request> prepared_msg; // <sequence, digest>
232 for (const auto& msg : new_view_message.viewchange_messages()) {
233 for (const auto& msg : msg.prepared_msg()) {
234 uint64_t seq = msg.seq();
235 prepared_msg[seq] = msg.proof(0).request();
236 }
237 }
238
239 uint64_t min_s = std::numeric_limits<uint64_t>::max();
240 for (const auto& msg : new_view_message.viewchange_messages()) {
241 min_s = std::min(min_s, msg.stable_ckpt().seq());
242 }
243
244 uint64_t max_seq = 1;
245 if (prepared_msg.size() > 0) {
246 max_seq = (--prepared_msg.end())->first;
247 }
248
249 LOG(INFO) << "[GP] min_s: " << min_s << " max_seq: " << max_seq;
250
251 std::vector<std::unique_ptr<Request>> redo_request;
252 // Resent all the request with the current view number.
253 for (auto i = min_s + 1; i <= max_seq; ++i) {
254 if (prepared_msg.find(i) == prepared_msg.end()) {
255 // for sequence hole, create a new request with empty data and
256 // sign by the new primary.
257 std::unique_ptr<Request> user_request = resdb::NewRequest(
258 Request::TYPE_PRE_PREPARE, Request(), config_.GetSelfInfo().id());
259 user_request->set_seq(i);
260 user_request->set_current_view(new_view_message.view_number());
261 user_request->set_hash("null" + std::to_string(i));
262
263 if (verifier_ && need_sign) {
264 std::string data;
265 auto signature_or = verifier_->SignMessage(data);
266 if (!signature_or.ok()) {
267 LOG(ERROR) << "Sign message fail";
268 continue;
269 }
270 *user_request->mutable_data_signature() = *signature_or;
271 }
272 redo_request.push_back(std::move(user_request));
273 } else {
274 std::unique_ptr<Request> commit_request = resdb::NewRequest(
275 Request::TYPE_COMMIT, prepared_msg[i], config_.GetSelfInfo().id());
276 commit_request->set_seq(i);
277 commit_request->set_current_view(new_view_message.view_number());
278 redo_request.push_back(std::move(commit_request));
279 }
280 }
281
282 return redo_request;
283}
284
285int ViewChangeManager::ProcessNewView(std::unique_ptr<Context> context,
286 std::unique_ptr<Request> request) {
287 NewViewMessage new_view_message;
288 if (!new_view_message.ParseFromString(request->data())) {
289 LOG(ERROR) << "Parsing new_view_msg failed.";
290 return -2;
291 }
292 LOG(INFO) << "Received NEW-VIEW for view " << new_view_message.view_number();
293 // Check if new view is from next expected primary
294 if (new_view_message.view_number() !=
296 LOG(ERROR) << "View number " << new_view_message.view_number()
297 << " is not the same as expected: "
299 return -2;
300 }
301
302 uint64_t min_s = std::numeric_limits<uint64_t>::max(), max_s = 0;
303 // Verify each view change message as the new primary does.
304 for (const auto& msg : new_view_message.viewchange_messages()) {
305 min_s = std::min(min_s, msg.stable_ckpt().seq());
306 max_s = std::max(max_s, msg.stable_ckpt().seq());
307 if (!IsValidViewChangeMsg(msg)) {
308 LOG(ERROR) << "view change message in the new-view message is invalid";
309 return -2;
310 }
311 }
312
313 // check the re-calculated request is the same as the one in the request.
314 auto request_list = GetPrepareMsg(new_view_message, false);
315 if (request_list.size() !=
316 static_cast<size_t>(new_view_message.request_size())) {
317 LOG(ERROR) << "redo request list size not match:" << request_list.size()
318 << "- " << new_view_message.request_size();
319 return -2;
320 }
321
322 std::set<uint64_t> seq_set;
323 // only check the data.
324 for (size_t i = 0; i < request_list.size(); ++i) {
325 if (request_list[i]->data() != new_view_message.request(i).data()) {
326 LOG(ERROR) << "data not match";
327 return -2;
328 }
329 seq_set.insert(request_list[i]->seq());
330 }
331
332 LOG(ERROR) << "min_s: " << min_s << " max_s: " << max_s;
333
334 // Check if all the sequences in the committed list exist.
335 for (uint64_t i = min_s + 1; i <= max_s; i++) {
336 if (seq_set.find(i) == seq_set.end()) {
337 LOG(ERROR) << "Committed msg :" << i << " does exist";
338 return -2;
339 }
340 }
341
342 uint64_t max_seq = seq_set.empty() ? max_s : *(--seq_set.end());
343
344 SetCurrentViewAndNewPrimary(new_view_message.view_number());
345 message_manager_->SetNextSeq(max_seq + 1);
346 LOG(INFO) << "SetNexSeq: " << max_seq + 1;
347
348 // All is fine.
349 for (size_t i = 0; i < request_list.size(); ++i) {
350 if (new_view_message.request(i).type() ==
351 static_cast<int>(Request::TYPE_PRE_PREPARE)) {
352 new_view_message.request(i);
353 auto non_proposed_hashes =
354 collector_pool_->GetCollector(new_view_message.request(i).seq())
356 for (auto& hash : non_proposed_hashes) {
358 }
359 replica_communicator_->SendMessage(new_view_message.request(i),
361 } else {
362 if (new_view_message.request(i).seq() >
365 new_view_message.request(i).seq());
366 }
367 replica_communicator_->BroadCast(new_view_message.request(i));
368 }
369 }
370
371 ChangeStatue(ViewChangeStatus::NONE);
372 return config_.GetSelfInfo().id() == system_info_->GetPrimaryId() ? -4 : 0;
373}
374
375int ViewChangeManager::ProcessViewChange(std::unique_ptr<Context> context,
376 std::unique_ptr<Request> request) {
377 ViewChangeMessage viewchange_message;
378 if (!viewchange_message.ParseFromString(request->data())) {
379 LOG(ERROR) << "pase view change data fail";
380 return -2;
381 }
382
383 if (!IsValidViewChangeMsg(viewchange_message)) {
384 LOG(ERROR) << "view change msg not valid from:" << request->sender_id();
385 return -2;
386 }
387
388 LOG(ERROR) << "ViewChange message from " << request->sender_id();
389
390 size_t request_size = AddRequest(viewchange_message, request->sender_id());
391 if (request_size >= config_.GetMinDataReceiveNum()) {
392 // process new view
393 if (IsNextPrimary(viewchange_message.view_number())) {
394 std::lock_guard<std::mutex> lk(mutex_);
395 SendNewViewMsg(viewchange_message.view_number());
396 } else {
397 auto newview_timer = std::make_shared<ViewChangeTimeout>(
399 config_.GetSelfInfo().id(), "null", GetCurrentTime(),
401 std::lock_guard<std::mutex> lk(vc_mutex_);
405 newview_timer);
406 sem_post(&viewchange_timer_signal_);
407 }
408 }
410 }
411 return 0;
412}
413
414void ViewChangeManager::SendNewViewMsg(uint64_t view_number) {
415 if (new_view_is_sent_) {
416 return;
417 }
418 new_view_is_sent_ = true;
419
420 // PBFT Paper - Primary determines the sequence number min-s of the latest
421 // stable checkpoint in V and the highest sequence number max-s in a prepare
422 // message in V
423 // uint64_t min_s = std::numeric_limits<uint64_t>::max();
424
425 std::lock_guard<std::mutex> lk(vc_mutex_);
426 auto requests = viewchange_request_[view_number];
427
428 NewViewMessage new_view_message;
429 new_view_message.set_view_number(view_number);
430
431 std::map<uint64_t, std::string> new_view_request; // <sequence, digest>
432 for (auto& it : requests) {
433 ViewChangeMessage& msg = it.second;
434 LOG(ERROR) << "msg.view_number(): " << msg.view_number()
435 << " view_number: " << view_number << " sender: " << it.first
436 << " msg.stable_ckpt(): " << msg.stable_ckpt().seq();
437 msg.set_view_number(view_number);
438 *new_view_message.add_viewchange_messages() = msg;
439 }
440
441 // Get the redo message from the primary. This could not be done
442 // in each replica because the primary has to signed some empty
443 // request if needed.
444
445 std::vector<std::unique_ptr<Request>> request_list =
446 GetPrepareMsg(new_view_message);
447 for (const auto& request : request_list) {
448 *new_view_message.add_request() = *request;
449 }
450
451 // Broadcast my new view request.
452 std::unique_ptr<Request> request =
453 NewRequest(Request::TYPE_NEWVIEW, Request(), config_.GetSelfInfo().id());
454 new_view_message.SerializeToString(request->mutable_data());
456}
457
458void ViewChangeManager::SendViewChangeMsg() {
459 // PBFT Paper - <VIEW-CHANGE, v + x, n, C, P)
460 ViewChangeMessage view_change_message;
461 // v + x (view number of the next expected primary)
462 view_change_message.set_view_number(system_info_->GetCurrentView() +
464
465 LOG(ERROR) << "current view: " << system_info_->GetCurrentView()
466 << " view number: " << view_change_message.view_number()
467 << " view_change_counter_ " << view_change_counter_;
468 assert(view_change_message.view_number() ==
470
471 // n (sequence number of the latest checkpoint) and C (proof for the stable
472 // checkpoint)
473 *view_change_message.mutable_stable_ckpt() =
475
476 // P - P is a set containing a set Pm for each request m that prepared at i
477 // with a sequence number higher than n.
479 LOG(INFO) << "Check prepared or committed txns from "
480 << view_change_message.stable_ckpt().seq() + 1 << " to " << max_seq;
481
482 for (int i = view_change_message.stable_ckpt().seq() + 1; i <= max_seq; ++i) {
483 // seq i has been prepared or committed.
486 std::vector<RequestInfo> proof_info =
488 assert(proof_info.size() >= config_.GetMinDataReceiveNum());
489 auto txn = view_change_message.add_prepared_msg();
490 txn->set_seq(i);
491 for (const auto& info : proof_info) {
492 auto proof = txn->add_proof();
493 *proof->mutable_request() = *info.request;
494 *proof->mutable_signature() = info.signature;
495 }
496 }
497 }
498
499 // Broadcast my view change request.
500 std::unique_ptr<Request> request = NewRequest(
501 Request::TYPE_VIEWCHANGE, Request(), config_.GetSelfInfo().id());
502 view_change_message.SerializeToString(request->mutable_data());
504}
505
506void ViewChangeManager::AddComplaintTimer(uint64_t proxy_id, std::string hash) {
507 std::lock_guard<std::mutex> lk(vc_mutex_);
508 if (complaining_clients_.count(proxy_id) == 0) {
509 complaining_clients_[proxy_id].set_proxy_id(proxy_id);
510 }
511 auto complaint_ = complaining_clients_[proxy_id].SetComplaining(
513 if (viewchange_timeout_min_heap_[proxy_id].size() <
515 viewchange_timeout_min_heap_[proxy_id].push(complaint_);
516 sem_post(&viewchange_timer_signal_);
517 } else {
518 // LOG(INFO) << "The number of complaints reaches the maximum value";
519 }
520}
521
522void ViewChangeManager::MonitoringViewChangeTimeOut() {
523 while (!stop_) {
524 // [DK3] After timer is out, the client will check if the corresponding
525 // client request has recevied sufficient valid responses
526 sem_wait(&viewchange_timer_signal_);
527 vc_mutex_.lock();
528 bool empty = true;
529 std::shared_ptr<ViewChangeTimeout> viewchange_timeout;
530 for (auto& heap : viewchange_timeout_min_heap_) {
531 if (!heap.second.empty()) {
532 viewchange_timeout = heap.second.top();
533 heap.second.pop();
534 vc_mutex_.unlock();
535 empty = false;
536 break;
537 }
538 }
539 if (empty) {
540 vc_mutex_.unlock();
541 continue;
542 }
543 auto current_time = GetCurrentTime();
544 if (viewchange_timeout->timeout_time > current_time) {
545 usleep(viewchange_timeout->timeout_time - current_time);
546 }
547 // [DK3] if not enough responses are received, the client broadcasts the
548 // client request to all replicas
549 if (viewchange_timeout->type == ViewChangeTimerType::TYPE_NEWVIEW) {
551 viewchange_timeout->view == system_info_->GetCurrentView()) {
552 // [DK12] if the replicas cannot receive a newview message in a timely
553 // manner, they will enter the next view and starts a new round of
554 // viewchange. SetCurrentViewAndNewPrimary(viewchange_timeout->view +
555 // 1);
556 LOG(ERROR) << "It is time to start a new viewchange";
558 }
559 } else if (viewchange_timeout->type ==
561 // [DK9] if the primary cannot get enough viewchange messages before the
562 // timer is out, then it broadcasts its viewchanges messages and starts
563 // the timer again.
565 viewchange_timeout->view == system_info_->GetCurrentView()) {
566 LOG(ERROR) << "It is time to rebroacast viewchange messages";
569 }
570 } else if (viewchange_timeout->type ==
572 // [DK7] if the primary does not broadcast the request in a timely manner,
573 // the replica starts a viewchange
574 if (complaining_clients_[viewchange_timeout->proxy_id]
575 .CountViewChangeTimeout(viewchange_timeout->hash)) {
576 complaining_clients_[viewchange_timeout->proxy_id]
577 .EraseViewChangeTimeout(viewchange_timeout->hash);
578 }
579 std::lock_guard<std::mutex> lk(status_mutex_);
581 viewchange_timeout->view == system_info_->GetCurrentView()) {
582 if (viewchange_timeout->start_time >=
584 viewchange_timeout->proxy_id)) {
585 LOG(ERROR) << "It is time to start a viewchange";
588 }
589 }
590 }
591 }
592}
593
594void ViewChangeManager::MonitoringCheckpointState() {
595 uint64_t last_seq_value = 0;
596 while (!stop_) {
599 if (last_seq_value != value) {
600 last_seq_value = value;
601 if (IsInViewChange()) {
602 ChangeStatue(ViewChangeStatus::NONE);
603 }
604 }
605 }
606}
607
611
612} // namespace resdb
std::string data
MockReplicaCommunicator replica_communicator_
void SetTimeoutHandler(std::function< void()> timeout_handler)
bool IsValidCheckpointProof(const StableCheckPoint &stable_ckpt)
StableCheckPoint GetStableCheckpointWithVotes()
void SetHighestPreparedSeq(uint64_t seq)
void EraseViewChangeTimeout(std::string hash)
uint CountViewChangeTimeout(std::string hash)
std::shared_ptr< ViewChangeTimeout > SetComplaining(std::string hash, uint64_t view)
std::set< std::string > viewchange_timeout_set
void ReleaseComplaining(std::string hash)
void EraseProposed(const std::string &hash)
TransactionCollector * GetCollector(uint64_t seq)
TransactionStatue GetTransactionState(uint64_t seq)
uint64_t GetLastCommittedTime(uint64_t proxy_id)
std::vector< RequestInfo > GetPreparedProof(uint64_t seq)
void SetNextSeq(uint64_t seq)
LockFreeCollectorPool * GetCollectorPool()
virtual void BroadCast(const google::protobuf::Message &message)
virtual int SendMessage(const google::protobuf::Message &message)
int GetMinDataReceiveNum() const
ResConfigData GetConfigData() const
CertificateInfo GetPublicKeyCertificateInfo() const
const ReplicaInfo & GetSelfInfo() const
const std::vector< ReplicaInfo > & GetReplicaInfos() const
uint32_t GetMaxClientComplaintNum() const
virtual absl::StatusOr< SignatureInfo > SignMessage(const std::string &message)
virtual bool VerifyMessage(const std::string &message, const SignatureInfo &sign)
void SetCurrentView(uint64_t)
uint32_t GetPrimaryId() const
void SetPrimary(uint32_t id)
uint64_t GetCurrentView() const
std::vector< std::string > GetAllStoredHash()
int ProcessViewChange(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
DuplicateManager * duplicate_manager_
std::map< uint64_t, std::map< uint32_t, ViewChangeMessage > > viewchange_request_
int ProcessNewView(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
MessageManager * message_manager_
std::map< uint64_t, std::priority_queue< std::shared_ptr< ViewChangeTimeout > > > viewchange_timeout_min_heap_
SignatureVerifier * verifier_
std::atomic< bool > started_
std::map< uint64_t, ComplaningClients > complaining_clients_
ViewChangeManager(const ResDBConfig &config, CheckPointManager *checkpoint_manager, MessageManager *message_manager, SystemInfo *system_info, ReplicaCommunicator *replica_communicator, SignatureVerifier *verifier)
ReplicaCommunicator * replica_communicator_
void SetDuplicateManager(DuplicateManager *manager)
LockFreeCollectorPool * collector_pool_
CheckPointManager * checkpoint_manager_
void AddComplaintTimer(uint64_t proxy_id, std::string hash)
std::thread server_checking_timeout_thread_
CheckPointManager checkpoint_manager_
SystemInfo system_info_
std::unique_ptr< MessageManager > message_manager_
MockSignatureVerifier verifier_
std::unique_ptr< Request > NewRequest(Request::Type type, const Request &request, int sender_id)
uint64_t GetCurrentTime()
Definition utils.cpp:36
std::unique_ptr< ResDBConfig > config_