Loading...
Searching...
No Matches
commitment.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#include <unistd.h>
24
25#include "common/utils/utils.h"
27
28namespace resdb {
29
31 MessageManager* message_manager,
32 ReplicaCommunicator* replica_communicator,
33 SignatureVerifier* verifier)
34 : config_(config),
35 message_manager_(message_manager),
36 stop_(false),
37 replica_communicator_(replica_communicator),
38 verifier_(verifier) {
41 duplicate_manager_ = std::make_unique<DuplicateManager>(config);
43}
44
46 stop_ = true;
47 if (executed_thread_.joinable()) {
48 executed_thread_.join();
49 }
50}
51
53 std::function<bool(const Request& request)> func) {
54 pre_verify_func_ = func;
55}
56
57void Commitment::SetNeedCommitQC(bool need_qc) { need_qc_ = need_qc; }
58
59// Handle the user request and send a pre-prepare message to others.
60// TODO if not a primary, redicet to the primary replica.
61int Commitment::ProcessNewRequest(std::unique_ptr<Context> context,
62 std::unique_ptr<Request> user_request) {
63 if (context == nullptr || context->signature.signature().empty()) {
64 LOG(ERROR) << "user request doesn't contain signature, reject";
65 return -2;
66 }
67
68 if (uint64_t seq =
69 duplicate_manager_->CheckIfExecuted(user_request->hash())) {
70 LOG(ERROR) << "This request is already executed with seq: " << seq;
71 user_request->set_seq(seq);
72 message_manager_->SendResponse(std::move(user_request));
73 return -2;
74 }
75
77 // LOG(ERROR) << "current node is not primary. primary:"
78 // << message_manager_->GetCurrentPrimary()
79 // << " seq:" << user_request->seq()
80 // << " hash:" << user_request->hash();
83 {
84 std::lock_guard<std::mutex> lk(rc_mutex_);
86 std::make_pair(std::move(context), std::move(user_request)));
87 }
88
89 return -3;
90 }
91
92 /*
93 if(SignatureVerifier::CalculateHash(user_request->data()) !=
94 user_request->hash()){ LOG(ERROR) << "the hash and data of the user request
95 don't match, reject"; return -2;
96 }
97 */
98
99 // check signatures
100 bool valid = verifier_->VerifyMessage(user_request->data(),
101 user_request->data_signature());
102 if (!valid) {
103 LOG(ERROR) << "request is not valid:"
104 << user_request->data_signature().DebugString();
105 LOG(ERROR) << " msg:" << user_request->data().size();
106 return -2;
107 }
108
109 if (pre_verify_func_ && !pre_verify_func_(*user_request)) {
110 LOG(ERROR) << " check by the user func fail";
111 return -2;
112 }
113
115 if (duplicate_manager_->CheckAndAddProposed(user_request->hash())) {
116 LOG(ERROR) << "duplicate check fail:";
117 return -2;
118 }
119 auto seq = message_manager_->AssignNextSeq();
120
121 // Artificially make the primary stop proposing new trasactions.
122
123 if (!seq.ok()) {
124 duplicate_manager_->EraseProposed(user_request->hash());
126 Request request;
127 request.set_type(Request::TYPE_RESPONSE);
128 request.set_sender_id(config_.GetSelfInfo().id());
129 request.set_proxy_id(user_request->proxy_id());
130 request.set_ret(-2);
131 request.set_hash(user_request->hash());
132
133 replica_communicator_->SendMessage(request, request.proxy_id());
134 return -2;
135 }
136
137 user_request->set_type(Request::TYPE_PRE_PREPARE);
138 user_request->set_current_view(message_manager_->GetCurrentView());
139 user_request->set_seq(*seq);
140 user_request->set_sender_id(config_.GetSelfInfo().id());
141 user_request->set_primary_id(config_.GetSelfInfo().id());
142
143 replica_communicator_->BroadCast(*user_request);
144
145 return 0;
146}
147
148// Receive the pre-prepare message from the primary.
149// TODO check whether the sender is the primary.
150int Commitment::ProcessProposeMsg(std::unique_ptr<Context> context,
151 std::unique_ptr<Request> request) {
152 if (context == nullptr || context->signature.signature().empty()) {
153 LOG(ERROR) << "user request doesn't contain signature, reject";
154 return -2;
155 }
156 if (request->is_recovery()) {
157 if (static_cast<int64_t>(request->seq()) >=
159 message_manager_->SetNextSeq(request->seq() + 1);
160 }
161 return message_manager_->AddConsensusMsg(context->signature,
162 std::move(request));
163 }
164
165 if (request->sender_id() != message_manager_->GetCurrentPrimary()) {
166 LOG(ERROR) << "the request is not from primary. sender:"
167 << request->sender_id() << " seq:" << request->seq();
168 return -2;
169 }
170
171 /*
172 if(request->hash() != "null" + std::to_string(request->seq())
173 && SignatureVerifier::CalculateHash(request->data()) != request->hash())
174 { LOG(ERROR) << "the hash and data of the request don't match, reject";
175 return -2;
176 }
177 */
178
179 if (request->sender_id() != config_.GetSelfInfo().id()) {
180 if (pre_verify_func_ && !pre_verify_func_(*request)) {
181 LOG(ERROR) << " check by the user func fail";
182 return -2;
183 }
184 BatchUserRequest batch_request;
185 batch_request.ParseFromString(request->data());
186 batch_request.clear_createtime();
187 std::string data;
188 batch_request.SerializeToString(&data);
189 // check signatures
190 bool valid =
191 verifier_->VerifyMessage(request->data(), request->data_signature());
192 if (!valid) {
193 LOG(ERROR) << "request is not valid:"
194 << request->data_signature().DebugString();
195 LOG(ERROR) << " msg:" << request->data().size();
196 return -2;
197 }
198 if (duplicate_manager_->CheckAndAddProposed(request->hash())) {
199 LOG(INFO) << "The request is already proposed, reject";
200 return -2;
201 }
202 }
203
205 std::unique_ptr<Request> prepare_request = resdb::NewRequest(
206 Request::TYPE_PREPARE, *request, config_.GetSelfInfo().id());
207 prepare_request->clear_data();
208
209 // Add request to message_manager.
210 // If it has received enough same requests(2f+1), broadcast the prepare
211 // message.
213 message_manager_->AddConsensusMsg(context->signature, std::move(request));
215 replica_communicator_->BroadCast(*prepare_request);
216 }
217 return ret == CollectorResultCode::INVALID ? -2 : 0;
218}
219
220// If receive 2f+1 prepare message, broadcast a commit message.
221int Commitment::ProcessPrepareMsg(std::unique_ptr<Context> context,
222 std::unique_ptr<Request> request) {
223 if (context == nullptr || context->signature.signature().empty()) {
224 LOG(ERROR) << "user request doesn't contain signature, reject";
225 return -2;
226 }
227 if (request->is_recovery()) {
228 return message_manager_->AddConsensusMsg(context->signature,
229 std::move(request));
230 }
232 std::unique_ptr<Request> commit_request = resdb::NewRequest(
233 Request::TYPE_COMMIT, *request, config_.GetSelfInfo().id());
234 commit_request->mutable_data_signature()->Clear();
235 // Add request to message_manager.
236 // If it has received enough same requests(2f+1), broadcast the commit
237 // message.
238 uint64_t seq_ = request->seq();
240 message_manager_->AddConsensusMsg(context->signature, std::move(request));
244 }
245 // If need qc, sign the data
246 if (need_qc_ && verifier_) {
247 auto signature_or = verifier_->SignMessage(commit_request->hash());
248 if (!signature_or.ok()) {
249 LOG(ERROR) << "Sign message fail";
250 return -2;
251 }
252 *commit_request->mutable_data_signature() = *signature_or;
253 // LOG(ERROR) << "sign hash"
254 // << commit_request->data_signature().DebugString();
255 }
256 replica_communicator_->BroadCast(*commit_request);
257 }
258 return ret == CollectorResultCode::INVALID ? -2 : 0;
259}
260
261// If receive 2f+1 commit message, commit the request.
262int Commitment::ProcessCommitMsg(std::unique_ptr<Context> context,
263 std::unique_ptr<Request> request) {
264 if (context == nullptr || context->signature.signature().empty()) {
265 LOG(ERROR) << "user request doesn't contain signature, reject"
266 << " context:" << (context == nullptr);
267 return -2;
268 }
269 if (request->is_recovery()) {
270 return message_manager_->AddConsensusMsg(context->signature,
271 std::move(request));
272 }
274 // Add request to message_manager.
275 // If it has received enough same requests(2f+1), message manager will
276 // commit the request.
278 message_manager_->AddConsensusMsg(context->signature, std::move(request));
279 return ret == CollectorResultCode::INVALID ? -2 : 0;
280}
281
282// =========== private threads ===========================
283// If the transaction is executed, send back to the proxy.
285 while (!stop_) {
286 auto batch_resp = message_manager_->GetResponseMsg();
287 if (batch_resp == nullptr) {
288 continue;
289 }
290 Request request;
291 request.set_hash(batch_resp->hash());
292 request.set_seq(batch_resp->seq());
293 request.set_type(Request::TYPE_RESPONSE);
294 request.set_sender_id(config_.GetSelfInfo().id());
295 request.set_current_view(batch_resp->current_view());
296 request.set_proxy_id(batch_resp->proxy_id());
297 request.set_primary_id(batch_resp->primary_id());
298 // LOG(ERROR)<<"send back to proxy:"<<batch_resp->proxy_id();
299 batch_resp->SerializeToString(request.mutable_data());
300 replica_communicator_->SendMessage(request, request.proxy_id());
301 }
302 return 0;
303}
304
308
309} // namespace resdb
std::string data
MockReplicaCommunicator replica_communicator_
ResDBConfig config_
Definition commitment.h:63
MessageManager * message_manager_
Definition commitment.h:64
std::thread executed_thread_
Definition commitment.h:65
ReplicaCommunicator * replica_communicator_
Definition commitment.h:67
virtual int ProcessCommitMsg(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
std::atomic< bool > stop_
Definition commitment.h:66
DuplicateManager * GetDuplicateManager()
virtual int PostProcessExecutedMsg()
Commitment(const ResDBConfig &config, MessageManager *message_manager, ReplicaCommunicator *replica_communicator, SignatureVerifier *verifier)
virtual ~Commitment()
std::mutex rc_mutex_
Definition commitment.h:55
virtual int ProcessNewRequest(std::unique_ptr< Context > context, std::unique_ptr< Request > user_request)
Stats * global_stats_
Definition commitment.h:70
SignatureVerifier * verifier_
Definition commitment.h:69
virtual int ProcessProposeMsg(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
void SetPreVerifyFunc(std::function< bool(const Request &request)> func)
std::function< bool(const Request &request)> pre_verify_func_
Definition commitment.h:72
std::queue< std::pair< std::unique_ptr< Context >, std::unique_ptr< Request > > > request_complained_
Definition commitment.h:53
virtual int ProcessPrepareMsg(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
void SetNeedCommitQC(bool need_qc)
std::unique_ptr< DuplicateManager > duplicate_manager_
Definition commitment.h:76
void SetDuplicateManager(DuplicateManager *manager)
absl::StatusOr< uint64_t > AssignNextSeq()
void SendResponse(std::unique_ptr< Request > request)
uint64_t GetCurrentView() const
void SetHighestPreparedSeq(uint64_t seq)
CollectorResultCode AddConsensusMsg(const SignatureInfo &signature, std::unique_ptr< Request > request)
int64_t GetCurrentPrimary() const
std::unique_ptr< BatchUserResponse > GetResponseMsg()
void SetNextSeq(uint64_t seq)
virtual void BroadCast(const google::protobuf::Message &message)
virtual int SendMessage(const google::protobuf::Message &message)
const ReplicaInfo & GetSelfInfo() const
virtual absl::StatusOr< SignatureInfo > SignMessage(const std::string &message)
virtual bool VerifyMessage(const std::string &message, const SignatureInfo &sign)
void SeqFail()
Definition stats.cpp:272
static Stats * GetGlobalStats(int sleep_seconds=5)
Definition stats.cpp:29
void IncClientRequest()
Definition stats.cpp:222
void IncPrepare()
Definition stats.cpp:236
void IncCommit()
Definition stats.cpp:243
void IncPropose()
Definition stats.cpp:229
std::unique_ptr< MessageManager > message_manager_
MockSignatureVerifier verifier_
std::unique_ptr< Request > NewRequest(Request::Type type, const Request &request, int sender_id)
std::unique_ptr< ResDBConfig > config_