Loading...
Searching...
No Matches
response_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 {
28 ReplicaCommunicator* replica_communicator,
29 SystemInfo* system_info,
30 SignatureVerifier* verifier)
31 : config_(config),
32 replica_communicator_(replica_communicator),
33 collector_pool_(std::make_unique<LockFreeCollectorPool>(
34 "response", config_.GetMaxProcessTxn(), nullptr)),
35 context_pool_(std::make_unique<LockFreeCollectorPool>(
36 "context", config_.GetMaxProcessTxn(), nullptr)),
37 batch_queue_("user request"),
38 system_info_(system_info),
39 verifier_(verifier) {
40 stop_ = false;
41 local_id_ = 1;
42
43 if (config_.GetPublicKeyCertificateInfo()
44 .public_key()
45 .public_key_info()
46 .type() == CertificateKeyInfo::CLIENT ||
47 config_.IsTestMode()) {
48 user_req_thread_ = std::thread(&ResponseManager::BatchProposeMsg, this);
49 }
50 global_stats_ = Stats::GetGlobalStats();
51 send_num_ = 0;
52}
53
55 stop_ = true;
56 if (user_req_thread_.joinable()) {
57 user_req_thread_.join();
58 }
59}
60
61// use system info
62int ResponseManager::GetPrimary() { return system_info_->GetPrimaryId(); }
63
65 std::vector<std::unique_ptr<Context>> context_list, uint64_t id) {
66 return context_pool_->GetCollector(id)->SetContextList(
67 id, std::move(context_list));
68}
69
70std::vector<std::unique_ptr<Context>> ResponseManager::FetchContextList(
71 uint64_t id) {
72 auto context = context_pool_->GetCollector(id)->FetchContextList(id);
73 context_pool_->Update(id);
74 return context;
75}
76
77int ResponseManager::NewUserRequest(std::unique_ptr<Context> context,
78 std::unique_ptr<Request> user_request) {
79 if (!user_request->need_response()) {
80 context->client = nullptr;
81 }
82
83 std::unique_ptr<QueueItem> queue_item = std::make_unique<QueueItem>();
84 queue_item->context = std::move(context);
85 queue_item->user_request = std::move(user_request);
86
87 batch_queue_.Push(std::move(queue_item));
88 return 0;
89}
90
91// =================== response ========================
92// handle the response message. If receive f+1 commit messages, send back to the
93// caller.
94int ResponseManager::ProcessResponseMsg(std::unique_ptr<Context> context,
95 std::unique_ptr<Request> request) {
96 std::unique_ptr<Request> response;
97 // Add the response message, and use the call back to collect the received
98 // messages.
99 // The callback will be triggered if it received f+1 messages.
100 if (request->ret() == -2) {
101 LOG(ERROR) << "get response fail:" << request->ret();
102 send_num_--;
103 return 0;
104 }
106 AddResponseMsg(context->signature, std::move(request),
107 [&](const Request& request,
109 response = std::make_unique<Request>(request);
110 return;
111 });
112
114 BatchUserResponse batch_response;
115 if (batch_response.ParseFromString(response->data())) {
116 SendResponseToClient(batch_response);
117 } else {
118 LOG(ERROR) << "parse response fail:";
119 }
120 }
121 return ret == CollectorResultCode::INVALID ? -2 : 0;
122}
123
124bool ResponseManager::MayConsensusChangeStatus(
125 int type, int received_count, std::atomic<TransactionStatue>* status) {
126 switch (type) {
127 case Request::TYPE_RESPONSE:
128 // if receive f+1 response results, ack to the caller.
129 if (*status == TransactionStatue::None &&
130 config_.GetMinClientReceiveNum() <= received_count) {
132 return status->compare_exchange_strong(
133 old_status, TransactionStatue::EXECUTED, std::memory_order_acq_rel,
134 std::memory_order_acq_rel);
135 }
136 break;
137 }
138 return false;
139}
140
141CollectorResultCode ResponseManager::AddResponseMsg(
142 const SignatureInfo& signature, std::unique_ptr<Request> request,
143 std::function<void(const Request&,
145 response_call_back) {
146 if (request == nullptr) {
148 }
149
150 int type = request->type();
151 uint64_t seq = request->seq();
152 int resp_received_count = 0;
153 int ret = collector_pool_->GetCollector(seq)->AddRequest(
154 std::move(request), signature, false,
155 [&](const Request& request, int received_count,
157 std::atomic<TransactionStatue>* status, bool force) {
158 if (MayConsensusChangeStatus(type, received_count, status)) {
159 resp_received_count = 1;
160 response_call_back(request, data);
161 }
162 });
163 if (ret != 0) {
165 }
166 if (resp_received_count > 0) {
167 collector_pool_->Update(seq);
169 }
171}
172
173void ResponseManager::SendResponseToClient(
174 const BatchUserResponse& batch_response) {
175 uint64_t create_time = batch_response.createtime();
176 uint64_t local_id = batch_response.local_id();
177 if (create_time > 0) {
178 uint64_t run_time = GetCurrentTime() - create_time;
179 global_stats_->AddLatency(run_time);
180 } else {
181 LOG(ERROR) << "seq:" << local_id << " no resp";
182 }
183 send_num_--;
184
185 if (config_.IsPerformanceRunning()) {
186 return;
187 }
188
189 std::vector<std::unique_ptr<Context>> context_list =
190 FetchContextList(batch_response.local_id());
191 if (context_list.empty()) {
192 LOG(ERROR) << "context list is empty. local id:"
193 << batch_response.local_id();
194 return;
195 }
196
197 for (size_t i = 0; i < context_list.size(); ++i) {
198 auto& context = context_list[i];
199 if (context->client == nullptr) {
200 LOG(ERROR) << " no channel:";
201 continue;
202 }
203 int ret = context->client->SendRawMessageData(batch_response.response(i));
204 if (ret) {
205 LOG(ERROR) << "send resp fail ret:" << ret;
206 }
207 }
208}
209
210// =================== request ========================
211int ResponseManager::BatchProposeMsg() {
212 LOG(INFO) << "batch wait time:" << config_.ClientBatchWaitTimeMS()
213 << " batch num:" << config_.ClientBatchNum();
214 std::vector<std::unique_ptr<QueueItem>> batch_req;
215 while (!stop_) {
216 if (send_num_ > config_.GetMaxProcessTxn()) {
217 LOG(ERROR) << "send num too high, wait:" << send_num_;
218 usleep(100);
219 continue;
220 }
221 if (batch_req.size() < config_.ClientBatchNum()) {
222 std::unique_ptr<QueueItem> item =
223 batch_queue_.Pop(config_.ClientBatchWaitTimeMS());
224 if (item != nullptr) {
225 batch_req.push_back(std::move(item));
226 if (batch_req.size() < config_.ClientBatchNum()) {
227 continue;
228 }
229 }
230 }
231 if (batch_req.empty()) {
232 continue;
233 }
234 int ret = DoBatch(batch_req);
235 batch_req.clear();
236 if (ret != 0) {
237 Response response;
238 response.set_result(Response::ERROR);
239 for (size_t i = 0; i < batch_req.size(); ++i) {
240 if (batch_req[i]->context && batch_req[i]->context->client) {
241 int ret = batch_req[i]->context->client->SendRawMessage(response);
242 if (ret) {
243 LOG(ERROR) << "send resp" << response.DebugString()
244 << " fail ret:" << ret;
245 }
246 }
247 }
248 }
249 }
250 return 0;
251}
252
253int ResponseManager::DoBatch(
254 const std::vector<std::unique_ptr<QueueItem>>& batch_req) {
255 auto new_request =
256 NewRequest(Request::TYPE_NEW_TXNS, Request(), config_.GetSelfInfo().id());
257 if (new_request == nullptr) {
258 return -2;
259 }
260 std::vector<std::unique_ptr<Context>> context_list;
261
262 BatchUserRequest batch_request;
263 for (size_t i = 0; i < batch_req.size(); ++i) {
264 BatchUserRequest::UserRequest* req = batch_request.add_user_requests();
265 *req->mutable_request() = *batch_req[i]->user_request.get();
266 *req->mutable_signature() = batch_req[i]->context->signature;
267 req->set_id(i);
268 context_list.push_back(std::move(batch_req[i]->context));
269 }
270
271 if (!config_.IsPerformanceRunning()) {
272 LOG(ERROR) << "add context list:" << new_request->seq()
273 << " list size:" << context_list.size();
274 batch_request.set_local_id(local_id_);
275 int ret = AddContextList(std::move(context_list), local_id_++);
276 if (ret != 0) {
277 LOG(ERROR) << "add context list fail:";
278 return ret;
279 }
280 }
281 batch_request.set_createtime(GetCurrentTime());
282 std::string data;
283 batch_request.SerializeToString(&data);
284 if (verifier_) {
285 auto signature_or = verifier_->SignMessage(data);
286 if (!signature_or.ok()) {
287 LOG(ERROR) << "Sign message fail";
288 return -2;
289 }
290 *new_request->mutable_data_signature() = *signature_or;
291 }
292
293 batch_request.SerializeToString(new_request->mutable_data());
294 new_request->set_hash(SignatureVerifier::CalculateHash(new_request->data()));
295 new_request->set_proxy_id(config_.GetSelfInfo().id());
296 replica_communicator_->SendMessage(*new_request, GetPrimary());
297 send_num_++;
298 LOG(INFO) << "send msg to primary:" << GetPrimary()
299 << " batch size:" << batch_req.size();
300 return 0;
301}
302
303} // namespace resdb
std::string data
MockReplicaCommunicator replica_communicator_
void Push(std::unique_ptr< T > data)
std::unique_ptr< T > Pop(int timeout_ms=100)
virtual int SendMessage(const google::protobuf::Message &message)
int GetMinClientReceiveNum() const
bool IsTestMode() const
uint32_t GetMaxProcessTxn() const
uint32_t ClientBatchNum() const
CertificateInfo GetPublicKeyCertificateInfo() const
const ReplicaInfo & GetSelfInfo() const
uint32_t ClientBatchWaitTimeMS() const
std::vector< std::unique_ptr< Context > > FetchContextList(uint64_t id)
ResponseManager(const ResDBConfig &config, ReplicaCommunicator *replica_communicator, SystemInfo *system_info, SignatureVerifier *verifier)
int ProcessResponseMsg(std::unique_ptr< Context > context, std::unique_ptr< Request > request)
int AddContextList(std::vector< std::unique_ptr< Context > > context, uint64_t id)
int NewUserRequest(std::unique_ptr< Context > context, std::unique_ptr< Request > user_request)
static std::string CalculateHash(const std::string &str)
virtual absl::StatusOr< SignatureInfo > SignMessage(const std::string &message)
static Stats * GetGlobalStats(int sleep_seconds=5)
Definition stats.cpp:29
void AddLatency(uint64_t run_time)
Definition stats.cpp:301
uint32_t GetPrimaryId() const
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_