Loading...
Searching...
No Matches
performance_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"
25
26namespace resdb {
27
29 uint64_t time_) {
30 this->hash = hash_;
31 this->timeout_time = time_;
32}
33
39
41 const PerformanceClientTimeout& other) const {
42 return timeout_time > other.timeout_time;
43}
44
46 const ResDBConfig& config, ReplicaCommunicator* replica_communicator,
47 SystemInfo* system_info, SignatureVerifier* verifier)
48 : config_(config),
49 replica_communicator_(replica_communicator),
50 collector_pool_(std::make_unique<LockFreeCollectorPool>(
51 "response", config_.GetMaxProcessTxn(), nullptr)),
52 context_pool_(std::make_unique<LockFreeCollectorPool>(
53 "context", config_.GetMaxProcessTxn(), nullptr)),
54 batch_queue_("user request"),
55 system_info_(system_info),
56 verifier_(verifier) {
57 stop_ = false;
58 eval_started_ = false;
59 eval_ready_future_ = eval_ready_promise_.get_future();
60 if (config_.GetPublicKeyCertificateInfo()
61 .public_key()
62 .public_key_info()
63 .type() == CertificateKeyInfo::CLIENT) {
64 for (int i = 0; i < 2; ++i) {
65 user_req_thread_[i] =
66 std::thread(&PerformanceManager::BatchProposeMsg, this);
67 }
68 }
69
70 checking_timeout_thread_ =
71 std::thread(&PerformanceManager::MonitoringClientTimeOut, this);
72 global_stats_ = Stats::GetGlobalStats();
73 for (size_t i = 0; i <= config_.GetReplicaNum(); i++) {
74 send_num_.push_back(0);
75 }
76 total_num_ = 0;
77 timeout_length_ = 10000000; // 10s
78}
79
81 stop_ = true;
82 for (int i = 0; i < 16; ++i) {
83 if (user_req_thread_[i].joinable()) {
84 user_req_thread_[i].join();
85 }
86 }
87 if (checking_timeout_thread_.joinable()) {
88 checking_timeout_thread_.join();
89 }
90}
91
92// use system info
93int PerformanceManager::GetPrimary() { return system_info_->GetPrimaryId(); }
94
95std::unique_ptr<Request> PerformanceManager::GenerateUserRequest() {
96 std::unique_ptr<Request> request = std::make_unique<Request>();
97 request->set_data(data_func_());
98 return request;
99}
100
101void PerformanceManager::SetDataFunc(std::function<std::string()> func) {
102 data_func_ = std::move(func);
103}
104
106 if (eval_started_) {
107 return 0;
108 }
109 eval_started_ = true;
110 for (int i = 0; i < 60000000000; ++i) {
111 std::unique_ptr<QueueItem> queue_item = std::make_unique<QueueItem>();
112 queue_item->context = nullptr;
113 queue_item->user_request = GenerateUserRequest();
114 batch_queue_.Push(std::move(queue_item));
115 if (i == 20000000) {
116 eval_ready_promise_.set_value(true);
117 }
118 }
119 LOG(WARNING) << "start eval done";
120 return 0;
121}
122
123// =================== response ========================
124// handle the response message. If receive f+1 commit messages, send back to the
125// user.
126int PerformanceManager::ProcessResponseMsg(std::unique_ptr<Context> context,
127 std::unique_ptr<Request> request) {
128 std::unique_ptr<Request> response;
129 std::string hash = request->hash();
130 int32_t primary_id = request->primary_id();
131 uint64_t seq = request->seq();
132 // Add the response message, and use the call back to collect the received
133 // messages.
134 // The callback will be triggered if it received f+1 messages.
135 if (request->ret() == -2) {
136 // LOG(INFO) << "get response fail:" << request->ret();
137 // send_num_--;
138 RemoveWaitingResponseRequest(hash);
139 return 0;
140 }
142 AddResponseMsg(context->signature, std::move(request),
143 [&](const Request& request,
145 response = std::make_unique<Request>(request);
146 return;
147 });
148
150 BatchUserResponse batch_response;
151 if (batch_response.ParseFromString(response->data())) {
152 if (seq > highest_seq_) {
153 highest_seq_ = seq;
154 if (highest_seq_primary_id_ != primary_id) {
155 system_info_->SetPrimary(primary_id);
156 highest_seq_primary_id_ = primary_id;
157 }
158 }
159 SendResponseToClient(batch_response);
160 RemoveWaitingResponseRequest(hash);
161 } else {
162 LOG(ERROR) << "parse response fail:";
163 }
164 }
165 return ret == CollectorResultCode::INVALID ? -2 : 0;
166}
167
168bool PerformanceManager::MayConsensusChangeStatus(
169 int type, int received_count, std::atomic<TransactionStatue>* status) {
170 switch (type) {
171 case Request::TYPE_RESPONSE:
172 // if receive f+1 response results, ack to the caller.
173 if (*status == TransactionStatue::None &&
174 config_.GetMinClientReceiveNum() <= received_count) {
176 return status->compare_exchange_strong(
177 old_status, TransactionStatue::EXECUTED, std::memory_order_acq_rel,
178 std::memory_order_acq_rel);
179 }
180 break;
181 }
182 return false;
183}
184
185CollectorResultCode PerformanceManager::AddResponseMsg(
186 const SignatureInfo& signature, std::unique_ptr<Request> request,
187 std::function<void(const Request&,
189 response_call_back) {
190 if (request == nullptr) {
192 }
193
194 int type = request->type();
195 uint64_t seq = request->seq();
196 int resp_received_count = 0;
197 int ret = collector_pool_->GetCollector(seq)->AddRequest(
198 std::move(request), signature, false,
199 [&](const Request& request, int received_count,
201 std::atomic<TransactionStatue>* status, bool force) {
202 if (MayConsensusChangeStatus(type, received_count, status)) {
203 resp_received_count = 1;
204 response_call_back(request, data);
205 }
206 });
207 if (ret != 0) {
209 }
210 if (resp_received_count > 0) {
211 collector_pool_->Update(seq);
213 }
215}
216
217void PerformanceManager::SendResponseToClient(
218 const BatchUserResponse& batch_response) {
219 uint64_t create_time = batch_response.createtime();
220 uint64_t local_id = batch_response.local_id();
221 if (create_time > 0) {
222 uint64_t run_time = GetCurrentTime() - create_time;
223 global_stats_->AddLatency(run_time);
224 } else {
225 LOG(ERROR) << "seq:" << local_id << " no resp";
226 }
227 {
228 // std::lock_guard<std::mutex> lk(mutex_);
229 if (send_num_[batch_response.primary_id()] > 0) {
230 send_num_[batch_response.primary_id()]--;
231 }
232 }
233
234 if (config_.IsPerformanceRunning()) {
235 return;
236 }
237}
238
239// =================== request ========================
240int PerformanceManager::BatchProposeMsg() {
241 LOG(WARNING) << "batch wait time:" << config_.ClientBatchWaitTimeMS()
242 << " batch num:" << config_.ClientBatchNum()
243 << " max txn:" << config_.GetMaxProcessTxn();
244 std::vector<std::unique_ptr<QueueItem>> batch_req;
245 eval_ready_future_.get();
246 while (!stop_) {
247 // std::lock_guard<std::mutex> lk(mutex_);
248 if (send_num_[GetPrimary()] >= config_.GetMaxProcessTxn()) {
249 usleep(100000);
250 continue;
251 }
252 if (batch_req.size() < config_.ClientBatchNum()) {
253 std::unique_ptr<QueueItem> item =
254 batch_queue_.Pop(config_.ClientBatchWaitTimeMS());
255 if (item == nullptr) {
256 continue;
257 }
258 batch_req.push_back(std::move(item));
259 if (batch_req.size() < config_.ClientBatchNum()) {
260 continue;
261 }
262 }
263 int ret = DoBatch(batch_req);
264 batch_req.clear();
265 if (ret != 0) {
266 Response response;
267 response.set_result(Response::ERROR);
268 for (size_t i = 0; i < batch_req.size(); ++i) {
269 if (batch_req[i]->context && batch_req[i]->context->client) {
270 int ret = batch_req[i]->context->client->SendRawMessage(response);
271 if (ret) {
272 LOG(ERROR) << "send resp" << response.DebugString()
273 << " fail ret:" << ret;
274 }
275 }
276 }
277 }
278 }
279 return 0;
280}
281
282int PerformanceManager::DoBatch(
283 const std::vector<std::unique_ptr<QueueItem>>& batch_req) {
284 auto new_request =
285 NewRequest(Request::TYPE_NEW_TXNS, Request(), config_.GetSelfInfo().id());
286 if (new_request == nullptr) {
287 return -2;
288 }
289 std::vector<std::unique_ptr<Context>> context_list;
290
291 BatchUserRequest batch_request;
292 for (size_t i = 0; i < batch_req.size(); ++i) {
293 BatchUserRequest::UserRequest* req = batch_request.add_user_requests();
294 *req->mutable_request() = *batch_req[i]->user_request.get();
295 if (batch_req[i]->context) {
296 *req->mutable_signature() = batch_req[i]->context->signature;
297 }
298 req->set_id(i);
299 }
300
301 batch_request.set_createtime(GetCurrentTime());
302 batch_request.SerializeToString(new_request->mutable_data());
303 if (verifier_) {
304 auto signature_or = verifier_->SignMessage(new_request->data());
305 if (!signature_or.ok()) {
306 LOG(ERROR) << "Sign message fail";
307 return -2;
308 }
309 *new_request->mutable_data_signature() = *signature_or;
310 }
311
312 new_request->set_hash(SignatureVerifier::CalculateHash(new_request->data()));
313 new_request->set_proxy_id(config_.GetSelfInfo().id());
314
315 replica_communicator_->SendMessage(*new_request, GetPrimary());
316 global_stats_->BroadCastMsg();
317 send_num_[GetPrimary()]++;
318 if (total_num_++ == 1000000) {
319 stop_ = true;
320 LOG(WARNING) << "total num is done:" << total_num_;
321 }
322 if (total_num_ % 10000 == 0) {
323 LOG(WARNING) << "total num is :" << total_num_;
324 }
325 global_stats_->IncClientCall();
326 AddWaitingResponseRequest(std::move(new_request));
327 return 0;
328}
329
330void PerformanceManager::AddWaitingResponseRequest(
331 std::unique_ptr<Request> request) {
332 if (!config_.GetConfigData().enable_viewchange()) {
333 return;
334 }
335 pm_lock_.lock();
336 uint64_t time = GetCurrentTime() + this->timeout_length_;
337 client_timeout_min_heap_.push(
338 PerformanceClientTimeout(request->hash(), time));
339 waiting_response_batches_.insert(
340 make_pair(request->hash(), std::move(request)));
341 pm_lock_.unlock();
342 sem_post(&request_sent_signal_);
343}
344
345void PerformanceManager::RemoveWaitingResponseRequest(std::string hash) {
346 if (!config_.GetConfigData().enable_viewchange()) {
347 return;
348 }
349 pm_lock_.lock();
350 if (waiting_response_batches_.find(hash) != waiting_response_batches_.end()) {
351 waiting_response_batches_.erase(waiting_response_batches_.find(hash));
352 }
353 pm_lock_.unlock();
354}
355
356bool PerformanceManager::CheckTimeOut(std::string hash) {
357 pm_lock_.lock();
358 bool value =
359 (waiting_response_batches_.find(hash) != waiting_response_batches_.end());
360 pm_lock_.unlock();
361 return value;
362}
363
364std::unique_ptr<Request> PerformanceManager::GetTimeOutRequest(
365 std::string hash) {
366 pm_lock_.lock();
367 auto value = std::move(waiting_response_batches_.find(hash)->second);
368 pm_lock_.unlock();
369 return value;
370}
371
372void PerformanceManager::MonitoringClientTimeOut() {
373 while (!stop_) {
374 sem_wait(&request_sent_signal_);
375 pm_lock_.lock();
376 if (client_timeout_min_heap_.empty()) {
377 pm_lock_.unlock();
378 continue;
379 }
380 auto client_timeout = client_timeout_min_heap_.top();
381 client_timeout_min_heap_.pop();
382 pm_lock_.unlock();
383
384 if (client_timeout.timeout_time > GetCurrentTime()) {
385 usleep(client_timeout.timeout_time - GetCurrentTime());
386 }
387
388 if (CheckTimeOut(client_timeout.hash)) {
389 auto request = GetTimeOutRequest(client_timeout.hash);
390 if (request) {
391 LOG(ERROR) << "Client Request Timeout " << client_timeout.hash;
392 replica_communicator_->BroadCast(*request);
393 }
394 }
395 }
396}
397
398} // namespace resdb
std::string data
MockReplicaCommunicator replica_communicator_
void Push(std::unique_ptr< T > data)
std::unique_ptr< T > Pop(int timeout_ms=100)
PerformanceClientTimeout(std::string hash_, uint64_t time_)
bool operator<(const PerformanceClientTimeout &other) const
int ProcessResponseMsg(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
PerformanceManager(const ResDBConfig &config, ReplicaCommunicator *replica_communicator, SystemInfo *system_info, SignatureVerifier *verifier)
void SetDataFunc(std::function< std::string()> func)
virtual void BroadCast(const google::protobuf::Message &message)
virtual int SendMessage(const google::protobuf::Message &message)
int GetMinClientReceiveNum() const
size_t GetReplicaNum() const
ResConfigData GetConfigData() const
uint32_t GetMaxProcessTxn() const
uint32_t ClientBatchNum() const
CertificateInfo GetPublicKeyCertificateInfo() const
const ReplicaInfo & GetSelfInfo() const
uint32_t ClientBatchWaitTimeMS() const
static std::string CalculateHash(const std::string &str)
virtual absl::StatusOr< SignatureInfo > SignMessage(const std::string &message)
void BroadCastMsg()
Definition stats.cpp:261
static Stats * GetGlobalStats(int sleep_seconds=5)
Definition stats.cpp:29
void AddLatency(uint64_t run_time)
Definition stats.cpp:301
void IncClientCall()
Definition stats.cpp:215
uint32_t GetPrimaryId() const
void SetPrimary(uint32_t id)
std::list< std::unique_ptr< RequestInfo > > CollectorDataType
SystemInfo system_info_
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_