Loading...
Searching...
No Matches
consensus_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#include <unistd.h>
24
25#include "platform/proto/broadcast.pb.h"
26
27namespace resdb {
28
29namespace {
30
31bool ReplicaExisted(const ReplicaInfo& replica_info,
32 const std::vector<ReplicaInfo>& replicas) {
33 for (auto& rep : replicas) {
34 if (rep.id() == replica_info.id()) {
35 return true;
36 }
37 }
38 return false;
39}
40
41} // namespace
42
44 : config_(config), global_stats_(Stats::GetGlobalStats()) {
46 verifier_ = std::make_unique<SignatureVerifier>(
48 }
49 bc_client_ = GetReplicaClient(config_.GetReplicaInfos(), true);
50}
51
53 bc_client_.reset();
54 Stop();
55}
56
60
62 return bc_client_.get();
63}
64
66 return verifier_ == nullptr ? nullptr : verifier_.get();
67}
68
69bool ConsensusManager::IsReady() const { return is_ready_; }
70
73 if (heartbeat_thread_.joinable()) {
74 heartbeat_thread_.join();
75 }
76}
77
81 heartbeat_thread_ =
82 std::thread(&ConsensusManager::HeartBeat, this); // pass by reference
83 }
84}
85
86// Keep Boardcast the public keys to others.
87void ConsensusManager::HeartBeat() {
88 LOG(INFO) << "heart beat start";
89 int sleep_time = 1;
90 std::mutex mutex;
91 std::condition_variable cv;
92 while (IsRunning()) {
93 auto keys = verifier_->GetAllPublicKeys();
94
95 std::vector<ReplicaInfo> replicas = GetAllReplicas();
96 LOG(ERROR) << "all replicas:" << replicas.size();
97 std::vector<ReplicaInfo> client_replicas = GetClientReplicas();
98 HeartBeatInfo hb_info;
99 for (const auto& key : keys) {
100 *hb_info.add_public_keys() = key;
101 }
102 for (const auto& client : client_replicas) {
103 replicas.push_back(client);
104 }
105 auto client = GetReplicaClient(replicas, false);
106 if (client == nullptr) {
107 continue;
108 }
109
110 // If it is not a client node, broadcost the current primary to the client.
112 .public_key()
113 .public_key_info()
114 .type() == CertificateKeyInfo::REPLICA) {
115 hb_info.set_primary(GetPrimary());
116 hb_info.set_version(GetVersion());
117 }
118 LOG(ERROR) << " server:" << config_.GetSelfInfo().id() << " sends HB"
119 << " is ready:" << is_ready_
120 << " client size:" << client_replicas.size()
121 << " svr size:" << replicas.size();
122
123 Request request;
124 request.set_type(Request::TYPE_HEART_BEAT);
125 request.mutable_region_info()->set_region_id(
126 config_.GetConfigData().self_region_id());
127 hb_info.SerializeToString(request.mutable_data());
128
129 int ret = client->SendHeartBeat(request);
130 if (ret <= 0) {
131 LOG(ERROR) << " server:" << config_.GetSelfInfo().id()
132 << " sends HB fail:" << ret;
133 }
134 std::unique_lock<std::mutex> lk(mutex);
135 cv.wait_for(lk, std::chrono::microseconds(sleep_time * 1000000),
136 [&] { return !IsRunning(); });
137 if (is_ready_) {
138 if (config_.IsTestMode()) {
139 sleep_time = 1;
140 } else {
141 sleep_time = 60 * 2;
142 }
143 }
144 }
145}
146
147// Porcess the packages received from the network.
148// context contains the client socket which can be used for sending response to
149// the client, the signature for the request will be filled inside the context
150// when parsing the message.
151int ConsensusManager::Process(std::unique_ptr<Context> context,
152 std::unique_ptr<DataInfo> request_info) {
153 global_stats_->IncClientCall();
154 // Decode the whole message, it includes the certificate and data.
155 ResDBMessage message;
156 if (!message.ParseFromArray(request_info->buff, request_info->data_len)) {
157 LOG(ERROR) << "parse data info fail";
158 return -1;
159 }
160
161 // Check if the certificate is valid.
162 if (message.has_signature() && verifier_) {
163 bool valid = verifier_->VerifyMessage(message.data(), message.signature());
164 if (!valid) {
165 LOG(ERROR) << "request is not valid:"
166 << message.signature().DebugString();
167 LOG(ERROR) << " msg:" << message.data().size();
168 return -2;
169 }
170 } else {
171 }
172
173 std::unique_ptr<Request> request = std::make_unique<Request>();
174 if (!request->ParseFromString(message.data())) {
175 LOG(ERROR) << "parse data info fail";
176 return -1;
177 }
178
179 std::string tmp;
180 if (!request->SerializeToString(&tmp)) {
181 return -1;
182 }
183
184 // forward the signature to the request so that it can be included in the
185 // request/response set if needed.
186 context->signature = message.signature();
187 // LOG(ERROR) << "======= server:" << config_.GetSelfInfo().id()
188 // << " get request type:" << request->type()
189 // << " from:" << request->sender_id();
190 return Dispatch(std::move(context), std::move(request));
191}
192
193// Dispatch the request if it is a heart beat message from other replica or a
194// cert notification from clients. Otherwise, forward to the worker.
195int ConsensusManager::Dispatch(std::unique_ptr<Context> context,
196 std::unique_ptr<Request> request) {
197 if (request->type() == Request::TYPE_HEART_BEAT) {
198 return ProcessHeartBeat(std::move(context), std::move(request));
199 }
200 return ConsensusCommit(std::move(context), std::move(request));
201}
202
203int ConsensusManager::ProcessHeartBeat(std::unique_ptr<Context> context,
204 std::unique_ptr<Request> request) {
205 std::vector<ReplicaInfo> replicas = GetReplicas();
206 HeartBeatInfo hb_info;
207 if (!hb_info.ParseFromString(request->data())) {
208 LOG(ERROR) << "parse replica info fail\n";
209 return -1;
210 }
211
212 LOG(INFO) << "receive public size:" << hb_info.public_keys().size()
213 << " primary:" << hb_info.primary()
214 << " version:" << hb_info.version()
215 << " from region:" << request->region_info().region_id();
216
217 if (request->region_info().region_id() ==
218 config_.GetConfigData().self_region_id()) {
220 .public_key()
221 .public_key_info()
222 .type() == CertificateKeyInfo::CLIENT) {
223 // TODO count 2f+1 before setting a new primary
224 SetPrimary(hb_info.primary(), hb_info.version());
225 }
226 }
227
228 int replica_num = 0;
229 // Update the public keys received from others.
230 for (const auto& public_key : hb_info.public_keys()) {
231 if (verifier_ && !verifier_->AddPublicKey(public_key)) {
232 LOG(ERROR) << "set public key fail from:"
233 << public_key.public_key_info().node_id();
234 continue;
235 }
236 if (request->region_info().region_id() !=
237 config_.GetConfigData().self_region_id()) {
238 // LOG(ERROR) << "key from other region:"
239 // << request->region_info().region_id();
240 continue;
241 }
242
243 ReplicaInfo info;
244 info.set_ip(public_key.public_key_info().ip());
245 info.set_port(public_key.public_key_info().port());
246 info.set_id(public_key.public_key_info().node_id());
247 if (info.ip().empty()) {
248 LOG(ERROR) << "public doesn't have ip, skip";
249 continue;
250 }
251 // Check whether there is a new replica joining.
252 // TODO notify new replica
253 if (public_key.public_key_info().type() == CertificateKeyInfo::REPLICA) {
254 replica_num++;
255 if (!ReplicaExisted(info, replicas)) {
256 // AddNewReplica(info);
257 }
258 } else {
259 if (!ReplicaExisted(info, clients_)) {
260 AddNewClient(info);
261 }
262 }
263 }
264 if (!is_ready_ && replica_num >= config_.GetMinDataReceiveNum()) {
265 LOG(ERROR) << "============ Server " << config_.GetSelfInfo().id()
266 << " is ready "
267 "=====================";
268 is_ready_ = true;
269 }
270 return 0;
271}
272
273int ConsensusManager::ConsensusCommit(std::unique_ptr<Context> context,
274 std::unique_ptr<Request> request) {
275 return -1;
276}
277
278std::vector<ReplicaInfo> ConsensusManager::GetClientReplicas() {
279 return clients_;
280}
281
282std::vector<ReplicaInfo> ConsensusManager::GetAllReplicas() {
283 auto config_data = config_.GetConfigData();
284 std::vector<ReplicaInfo> ret;
285 for (const auto& r : config_data.region()) {
286 for (const auto& replica : r.replica_info()) {
287 ret.push_back(replica);
288 }
289 }
290 return ret;
291}
292
293void ConsensusManager::BroadCast(const Request& request) {
294 int ret = bc_client_->SendMessage(request);
295 if (ret < 0) {
296 LOG(ERROR) << "broadcast request fail:";
297 }
298}
299
300void ConsensusManager::SendMessage(const google::protobuf::Message& message,
301 int64_t node_id) {
302 std::vector<ReplicaInfo> replicas = GetReplicas();
303 ReplicaInfo target_replica;
304 for (const auto& replica : replicas) {
305 if (replica.id() == node_id) {
306 target_replica = replica;
307 break;
308 }
309 }
310
311 if (target_replica.ip().empty()) {
312 return;
313 }
314
315 int ret = bc_client_->SendMessage(message, target_replica);
316 if (ret < 0) {
317 LOG(ERROR) << "broadcast request fail:";
318 }
319}
320
321std::unique_ptr<ReplicaCommunicator> ConsensusManager::GetReplicaClient(
322 const std::vector<ReplicaInfo>& replicas, bool is_use_long_conn) {
323 return std::make_unique<ReplicaCommunicator>(
324 replicas,
325 verifier_ == nullptr || config_.GetConfigData().not_need_signature()
326 ? nullptr
327 : verifier_.get(),
328 is_use_long_conn, config_.GetOutputWorkerNum(), config_.GetTcpBatchNum());
329}
330
331void ConsensusManager::AddNewReplica(const ReplicaInfo& info) {}
332
333void ConsensusManager::AddNewClient(const ReplicaInfo& info) {
334 clients_.push_back(info);
335 bc_client_->UpdateClientReplicas(clients_);
336}
337
338void ConsensusManager::SetPrimary(uint32_t primary, uint64_t version) {}
339
340uint32_t ConsensusManager::GetPrimary() { return 1; }
341
342uint32_t ConsensusManager::GetVersion() { return 1; }
343
344} // namespace resdb
virtual int Process(std::unique_ptr< Context > context, std::unique_ptr< DataInfo > request_info)
std::vector< ReplicaInfo > GetAllReplicas()
virtual void BroadCast(const Request &request)
int ProcessHeartBeat(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
virtual int ConsensusCommit(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
virtual void SetPrimary(uint32_t primary, uint64_t version)
virtual void SendMessage(const google::protobuf::Message &message, int64_t node_id)
virtual uint32_t GetPrimary()
ConsensusManager(const ResDBConfig &config)
virtual std::vector< ReplicaInfo > GetClientReplicas()
SignatureVerifier * GetSignatureVerifier()
ReplicaCommunicator * GetBroadCastClient()
virtual std::vector< ReplicaInfo > GetReplicas()=0
virtual void AddNewReplica(const ReplicaInfo &info)
virtual int Dispatch(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
void AddNewClient(const ReplicaInfo &info)
std::unique_ptr< SignatureVerifier > verifier_
virtual std::unique_ptr< ReplicaCommunicator > GetReplicaClient(const std::vector< ReplicaInfo > &replicas, bool is_use_long_conn=false)
virtual uint32_t GetVersion()
uint32_t GetOutputWorkerNum() const
int GetMinDataReceiveNum() const
ResConfigData GetConfigData() const
bool IsTestMode() const
uint32_t GetTcpBatchNum() const
CertificateInfo GetPublicKeyCertificateInfo() const
const ReplicaInfo & GetSelfInfo() const
const std::vector< ReplicaInfo > & GetReplicaInfos() const
KeyInfo GetPrivateKey() const
virtual bool IsRunning() const
void IncClientCall()
Definition stats.cpp:215
Stats * global_stats_
Definition keys.py:1
std::unique_ptr< ResDBConfig > config_