Loading...
Searching...
No Matches
checkpoint_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
25#include "platform/proto/checkpoint_info.pb.h"
26
27namespace resdb {
28
30 ReplicaCommunicator* replica_communicator,
31 SignatureVerifier* verifier)
32 : config_(config),
33 replica_communicator_(replica_communicator),
34 txn_db_(std::make_unique<ChainState>()),
35 verifier_(verifier),
36 stop_(false),
37 txn_accessor_(config),
38 highest_prepared_seq_(0) {
40 if (config_.GetConfigData().enable_viewchange()) {
42 }
45 std::thread(&CheckPointManager::UpdateStableCheckPointStatus, this);
47 std::thread(&CheckPointManager::UpdateCheckPointStatus, this);
48 }
49 sem_init(&committable_seq_signal_, 0, 0);
50}
51
53
55 stop_ = true;
56 if (checkpoint_thread_.joinable()) {
57 checkpoint_thread_.join();
58 }
59 if (stable_checkpoint_thread_.joinable()) {
61 }
62}
63
64std::string GetHash(const std::string& h1, const std::string& h2) {
66}
67
69
71
73 std::lock_guard<std::mutex> lk(mutex_);
75}
76
78 std::lock_guard<std::mutex> lk(mutex_);
79 return stable_ckpt_;
80}
81
82void CheckPointManager::AddCommitData(std::unique_ptr<Request> request) {
84 data_queue_.Push(std::move(request));
85 } else {
86 txn_db_->Put(std::move(request));
87 }
88}
89
90// check whether there are 2f+1 valid checkpoint proof.
92 const StableCheckPoint& stable_ckpt) {
93 std::string hash = stable_ckpt_.hash();
94 std::set<uint32_t> senders;
95 for (const auto& signature : stable_ckpt_.signatures()) {
96 if (!verifier_->VerifyMessage(hash, signature)) {
97 return false;
98 }
99 senders.insert(signature.node_id());
100 }
101
102 return (static_cast<int>(senders.size()) >= config_.GetMinDataReceiveNum()) ||
103 (stable_ckpt.seq() == 0 && senders.size() == 0);
104}
105
106int CheckPointManager::ProcessCheckPoint(std::unique_ptr<Context> context,
107 std::unique_ptr<Request> request) {
108 CheckPointData checkpoint_data;
109 if (!checkpoint_data.ParseFromString(request->data())) {
110 LOG(ERROR) << "parse checkpont data fail:";
111 return -2;
112 }
113 uint64_t checkpoint_seq = checkpoint_data.seq();
114 uint32_t sender_id = request->sender_id();
115 int water_mark = config_.GetCheckPointWaterMark();
116 if (checkpoint_seq % water_mark) {
117 LOG(ERROR) << "checkpoint seq not invalid:" << checkpoint_seq;
118 return -2;
119 }
120
121 if (verifier_) {
122 // check signatures
123 bool valid = verifier_->VerifyMessage(checkpoint_data.hash(),
124 checkpoint_data.hash_signature());
125 if (!valid) {
126 LOG(ERROR) << "request is not valid:"
127 << checkpoint_data.hash_signature().DebugString();
128 return -2;
129 }
130 }
131
132 {
133 std::lock_guard<std::mutex> lk(mutex_);
134 auto res =
135 sender_ckpt_[std::make_pair(checkpoint_seq, checkpoint_data.hash())]
136 .insert(sender_id);
137 if (res.second) {
138 sign_ckpt_[std::make_pair(checkpoint_seq, checkpoint_data.hash())]
139 .push_back(checkpoint_data.hash_signature());
140 new_data_++;
141 }
142 if (sender_ckpt_[std::make_pair(checkpoint_seq, checkpoint_data.hash())]
143 .size() == 1) {
144 for (auto& hash_ : checkpoint_data.hashs()) {
145 hash_ckpt_[std::make_pair(checkpoint_seq, checkpoint_data.hash())]
146 .push_back(hash_);
147 }
148 }
149 Notify();
150 }
151 return 0;
152}
153
154void CheckPointManager::Notify() {
155 std::lock_guard<std::mutex> lk(cv_mutex_);
156 cv_.notify_all();
157}
158
159bool CheckPointManager::Wait() {
160 int timeout_ms = 1000;
161 std::unique_lock<std::mutex> lk(cv_mutex_);
162 return cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms),
163 [&] { return new_data_ > 0; });
164}
165
166void CheckPointManager::UpdateStableCheckPointStatus() {
167 uint64_t last_committable_seq = 0;
168 while (!stop_) {
169 if (!Wait()) {
170 continue;
171 }
172 uint64_t stable_seq = 0;
173 std::string stable_hash;
174 {
175 std::lock_guard<std::mutex> lk(mutex_);
176 for (auto it : sender_ckpt_) {
177 if (it.second.size() >=
178 static_cast<size_t>(config_.GetMinCheckpointReceiveNum())) {
179 committable_seq_ = it.first.first;
180 committable_hash_ = it.first.second;
181 std::set<uint32_t> senders_ =
183 sem_post(&committable_seq_signal_);
185 last_committable_seq < committable_seq_) {
187 for (auto& replica_ : replicas_) {
188 std::string last_hash;
189 uint64_t last_seq;
190 {
191 std::lock_guard<std::mutex> lk(lt_mutex_);
192 last_hash = last_hash_;
193 // last_seq_ = last_seq > last_committable_seq ? last_seq :
194 // last_committable_seq;
195 last_seq = last_seq_;
196 }
197 if (senders_.count(replica_.id()) &&
198 last_seq < committable_seq_) {
199 // LOG(ERROR) << "GetRequestFromReplica " << last_seq_ + 1 << "
200 // " << committable_seq_;
201 auto requests = txn_accessor_.GetRequestFromReplica(
202 last_seq + 1, committable_seq_, replica_);
203 if (requests.ok()) {
204 bool fail = false;
205 for (auto& request : *requests) {
206 if (SignatureVerifier::CalculateHash(request.data()) !=
207 request.hash()) {
208 LOG(ERROR)
209 << "The hash of the request does not match the data.";
210 fail = true;
211 break;
212 }
213 last_hash = GetHash(last_hash, request.hash());
214 }
215 if (fail) {
216 continue;
217 } else if (last_hash != committable_hash_) {
218 LOG(ERROR) << "The hash of requests returned do not match. "
219 << last_seq + 1 << " " << committable_seq_;
220 } else {
221 last_committable_seq = committable_seq_;
222 for (auto& request : *requests) {
223 if (executor_) {
224 executor_->Commit(std::make_unique<Request>(request));
225 }
226 }
228 // LOG(ERROR) << "[4]";
229 break;
230 }
231 }
232 }
233 }
234 }
235 }
236 if (it.second.size() >=
237 static_cast<size_t>(config_.GetMinDataReceiveNum())) {
238 stable_seq = it.first.first;
239 stable_hash = it.first.second;
240 }
241 }
242 new_data_ = 0;
243 }
244
245 // LOG(ERROR) << "current stable seq:" << current_stable_seq_
246 // << " stable seq:" << stable_seq;
247 std::vector<SignatureInfo> votes;
248 if (current_stable_seq_ < stable_seq) {
249 std::lock_guard<std::mutex> lk(mutex_);
250 votes = sign_ckpt_[std::make_pair(stable_seq, stable_hash)];
251 std::set<uint32_t> senders_ =
252 sender_ckpt_[std::make_pair(stable_seq, stable_hash)];
253
254 auto it = sender_ckpt_.begin();
255 while (it != sender_ckpt_.end()) {
256 if (it->first.first <= stable_seq) {
257 sign_ckpt_.erase(sign_ckpt_.find(it->first));
258 auto tmp = it++;
259 sender_ckpt_.erase(tmp);
260 } else {
261 it++;
262 }
263 }
264 stable_ckpt_.set_seq(stable_seq);
265 stable_ckpt_.set_hash(stable_hash);
266 stable_ckpt_.mutable_signatures()->Clear();
267 for (auto vote : votes) {
268 *stable_ckpt_.add_signatures() = vote;
269 }
270 current_stable_seq_ = stable_seq;
271 // LOG(INFO) << "done. stable seq:" << current_stable_seq_
272 // << " votes:" << stable_ckpt_.DebugString();
273 // LOG(INFO) << "done. stable seq:" << current_stable_seq_;
274 }
276 }
277}
278
280 std::function<void()> timeout_handler) {
281 timeout_handler_ = timeout_handler;
282}
283
289
290void CheckPointManager::UpdateCheckPointStatus() {
291 uint64_t last_ckpt_seq = 0;
292 int water_mark = config_.GetCheckPointWaterMark();
293 int timeout_ms = config_.GetViewchangeCommitTimeout();
294 std::vector<std::string> stable_hashs;
295 std::vector<uint64_t> stable_seqs;
296 while (!stop_) {
297 auto request = data_queue_.Pop(timeout_ms);
298 if (request == nullptr) {
299 // if (last_seq > 0) {
300 // TimeoutHandler();
301 // }
302 continue;
303 }
304 std::string hash_ = request->hash();
305 uint64_t current_seq = request->seq();
306 if (current_seq != last_seq_ + 1) {
307 LOG(ERROR) << "seq invalid:" << last_seq_ << " current:" << current_seq;
308 continue;
309 }
310 {
311 std::lock_guard<std::mutex> lk(lt_mutex_);
312 last_hash_ = GetHash(last_hash_, request->hash());
313 last_seq_++;
314 }
315 txn_db_->Put(std::move(request));
316
317 if (current_seq == last_ckpt_seq + water_mark) {
318 last_ckpt_seq = current_seq;
319 BroadcastCheckPoint(last_ckpt_seq, last_hash_, stable_hashs, stable_seqs);
320 }
321 }
322 return;
323}
324
325void CheckPointManager::BroadcastCheckPoint(
326 uint64_t seq, const std::string& hash,
327 const std::vector<std::string>& stable_hashs,
328 const std::vector<uint64_t>& stable_seqs) {
329 CheckPointData checkpoint_data;
330 std::unique_ptr<Request> checkpoint_request = NewRequest(
331 Request::TYPE_CHECKPOINT, Request(), config_.GetSelfInfo().id());
332 checkpoint_data.set_seq(seq);
333 checkpoint_data.set_hash(hash);
334 if (verifier_) {
335 auto signature_or = verifier_->SignMessage(hash);
336 if (!signature_or.ok()) {
337 LOG(ERROR) << "Sign message fail";
338 return;
339 }
340 *checkpoint_data.mutable_hash_signature() = *signature_or;
341 }
342
343 checkpoint_data.SerializeToString(checkpoint_request->mutable_data());
344 replica_communicator_->BroadCast(*checkpoint_request);
345}
346
348 std::unique_lock<std::mutex> lk(mutex_);
349 signal_.wait(lk, [&] { return !stable_hash_queue_.Empty(); });
350}
351
352std::unique_ptr<std::pair<uint64_t, std::string>>
356
358 std::lock_guard<std::mutex> lk(lt_mutex_);
360}
361
363 std::lock_guard<std::mutex> lk(lt_mutex_);
365}
366
368 std::lock_guard<std::mutex> lk(lt_mutex_);
370}
371
373 std::lock_guard<std::mutex> lk(lt_mutex_);
374 return committable_seq_;
375}
376
377} // namespace resdb
MockReplicaCommunicator replica_communicator_
uint64_t GetMaxSeq()
void SetTimeoutHandler(std::function< void()> timeout_handler)
std::map< std::pair< uint64_t, std::string >, std::set< uint32_t > > sender_ckpt_
SignatureVerifier * verifier_
bool IsValidCheckpointProof(const StableCheckPoint &stable_ckpt)
std::unique_ptr< ChainState > txn_db_
LockFreeQueue< std::pair< uint64_t, std::string > > stable_hash_queue_
ReplicaCommunicator * replica_communicator_
virtual void UpdateStableCheckPointCallback(int64_t current_stable_checkpoint)
CheckPointManager(const ResDBConfig &config, ReplicaCommunicator *replica_communicator, SignatureVerifier *verifier)
std::condition_variable cv_
std::map< std::pair< uint64_t, std::string >, std::vector< SignatureInfo > > sign_ckpt_
std::atomic< uint64_t > highest_prepared_seq_
TransactionExecutor * executor_
std::unique_ptr< std::pair< uint64_t, std::string > > PopStableSeqHash()
std::function< void()> timeout_handler_
int ProcessCheckPoint(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
uint64_t GetStableCheckpoint() override
StableCheckPoint GetStableCheckpointWithVotes()
std::atomic< bool > stop_
std::atomic< uint64_t > current_stable_seq_
void AddCommitData(std::unique_ptr< Request > request)
void SetHighestPreparedSeq(uint64_t seq)
std::map< std::pair< uint64_t, std::string >, std::vector< std::string > > hash_ckpt_
std::condition_variable signal_
LockFreeQueue< Request > data_queue_
void Push(std::unique_ptr< T > data)
std::unique_ptr< T > Pop(int timeout_ms=100)
virtual void BroadCast(const google::protobuf::Message &message)
int GetMinDataReceiveNum() const
ResConfigData GetConfigData() const
int GetCheckPointWaterMark() const
int GetMinCheckpointReceiveNum() const
const ReplicaInfo & GetSelfInfo() const
void EnableCheckPoint(bool is_enable)
const std::vector< ReplicaInfo > & GetReplicaInfos() const
uint32_t GetViewchangeCommitTimeout() const
virtual absl::StatusOr< std::vector< Request > > GetRequestFromReplica(uint64_t min_seq, uint64_t max_seq, const ReplicaInfo &replica)
static std::string CalculateHash(const std::string &str)
virtual absl::StatusOr< SignatureInfo > SignMessage(const std::string &message)
virtual bool VerifyMessage(const std::string &message, const SignatureInfo &sign)
int Commit(std::unique_ptr< Request > request)
MockSignatureVerifier verifier_
std::unique_ptr< Request > NewRequest(Request::Type type, const Request &request, int sender_id)
std::string GetHash(const std::string &h1, const std::string &h2)
std::vector< ReplicaInfo > replicas_
std::unique_ptr< ResDBConfig > config_