chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
file(GLOB SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/tools/rpc_press/*.cpp")
|
||||
add_executable(rpc_press ${SOURCES})
|
||||
target_link_libraries(rpc_press PRIVATE brpc-static ${DYNAMIC_LIB})
|
||||
install(TARGETS rpc_press RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
@@ -0,0 +1,28 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import json
|
||||
import urllib2
|
||||
data = { "message" : "hello world" }
|
||||
request_json = json.dumps(data)
|
||||
req = urllib2.Request("http://127.0.0.1:8000/EchoService/Echo")
|
||||
try:
|
||||
response = urllib2.urlopen(req, request_json, 1)
|
||||
print response.read()
|
||||
except urllib2.HTTPError as e:
|
||||
print e.exception.code
|
||||
@@ -0,0 +1,130 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#include "info_thread.h"
|
||||
|
||||
namespace brpc {
|
||||
|
||||
InfoThread::InfoThread()
|
||||
: _stop(false)
|
||||
, _tid(0) {
|
||||
pthread_mutex_init(&_mutex, NULL);
|
||||
pthread_cond_init(&_cond, NULL);
|
||||
}
|
||||
|
||||
InfoThread::~InfoThread() {
|
||||
pthread_mutex_destroy(&_mutex);
|
||||
pthread_cond_destroy(&_cond);
|
||||
}
|
||||
|
||||
void InfoThread::run() {
|
||||
int64_t i = 0;
|
||||
int64_t last_sent_count = 0;
|
||||
int64_t last_succ_count = 0;
|
||||
int64_t last_error_count = 0;
|
||||
int64_t start_time = butil::cpuwide_time_us();
|
||||
while (!_stop) {
|
||||
int64_t end_time = 0;
|
||||
while (!_stop &&
|
||||
(end_time = butil::cpuwide_time_us()) < start_time + 1000000L) {
|
||||
BAIDU_SCOPED_LOCK(_mutex);
|
||||
if (!_stop) {
|
||||
timespec ts = butil::microseconds_to_timespec(end_time);
|
||||
pthread_cond_timedwait(&_cond, &_mutex, &ts);
|
||||
}
|
||||
}
|
||||
start_time = butil::cpuwide_time_us();
|
||||
char buf[64];
|
||||
const time_t tm_s = start_time / 1000000L;
|
||||
struct tm lt;
|
||||
strftime(buf, sizeof(buf), "%Y/%m/%d-%H:%M:%S",
|
||||
localtime_r(&tm_s, <));
|
||||
|
||||
const int64_t cur_sent_count = _options.sent_count->get_value();
|
||||
const int64_t cur_succ_count = _options.latency_recorder->count();
|
||||
const int64_t cur_error_count = _options.error_count->get_value();
|
||||
printf("%s\tsent:%-10dsuccess:%-10derror:%-6dtotal_error:%-10lldtotal_sent:%-10lld\n",
|
||||
buf,
|
||||
(int)(cur_sent_count - last_sent_count),
|
||||
(int)(cur_succ_count - last_succ_count),
|
||||
(int)(cur_error_count - last_error_count),
|
||||
(long long)cur_error_count,
|
||||
(long long)cur_sent_count);
|
||||
last_sent_count = cur_sent_count;
|
||||
last_succ_count = cur_succ_count;
|
||||
last_error_count = cur_error_count;
|
||||
|
||||
if (_stop || ++i % 10 == 0) {
|
||||
printf("[Latency]\n"
|
||||
" avg %10lld us\n"
|
||||
" 50%% %10lld us\n"
|
||||
" 70%% %10lld us\n"
|
||||
" 90%% %10lld us\n"
|
||||
" 95%% %10lld us\n"
|
||||
" 97%% %10lld us\n"
|
||||
" 99%% %10lld us\n"
|
||||
" 99.9%% %10lld us\n"
|
||||
" 99.99%% %10lld us\n"
|
||||
" max %10lld us\n",
|
||||
(long long)_options.latency_recorder->latency(),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.5),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.7),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.9),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.95),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.97),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.99),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.999),
|
||||
(long long)_options.latency_recorder->latency_percentile(0.9999),
|
||||
(long long)_options.latency_recorder->max_latency());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void* run_info_thread(void* arg) {
|
||||
((InfoThread*)arg)->run();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool InfoThread::start(const InfoThreadOptions& options) {
|
||||
if (options.latency_recorder == NULL ||
|
||||
options.error_count == NULL ||
|
||||
options.sent_count == NULL) {
|
||||
LOG(ERROR) << "Some required options are NULL";
|
||||
return false;
|
||||
}
|
||||
_options = options;
|
||||
_stop = false;
|
||||
if (pthread_create(&_tid, NULL, run_info_thread, this) != 0) {
|
||||
LOG(ERROR) << "Fail to create info_thread";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InfoThread::stop() {
|
||||
{
|
||||
BAIDU_SCOPED_LOCK(_mutex);
|
||||
if (_stop) {
|
||||
return;
|
||||
}
|
||||
_stop = true;
|
||||
pthread_cond_signal(&_cond);
|
||||
}
|
||||
pthread_join(_tid, NULL);
|
||||
}
|
||||
|
||||
} // namespace brpc
|
||||
@@ -0,0 +1,55 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#ifndef BRPC_RPC_REPLAY_INFO_THREAD_H
|
||||
#define BRPC_RPC_REPLAY_INFO_THREAD_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <bvar/bvar.h>
|
||||
|
||||
namespace brpc {
|
||||
|
||||
struct InfoThreadOptions {
|
||||
bvar::LatencyRecorder* latency_recorder;
|
||||
bvar::Adder<int64_t>* sent_count;
|
||||
bvar::Adder<int64_t>* error_count;
|
||||
|
||||
InfoThreadOptions()
|
||||
: latency_recorder(NULL)
|
||||
, sent_count(NULL)
|
||||
, error_count(NULL) {}
|
||||
};
|
||||
|
||||
class InfoThread {
|
||||
public:
|
||||
InfoThread();
|
||||
~InfoThread();
|
||||
void run();
|
||||
bool start(const InfoThreadOptions&);
|
||||
void stop();
|
||||
|
||||
private:
|
||||
bool _stop;
|
||||
InfoThreadOptions _options;
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_cond_t _cond;
|
||||
pthread_t _tid;
|
||||
};
|
||||
|
||||
} // namespace brpc
|
||||
|
||||
#endif //BRPC_RPC_REPLAY_INFO_THREAD_H
|
||||
@@ -0,0 +1,229 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <butil/logging.h>
|
||||
#include <json2pb/pb_to_json.h>
|
||||
#include <json2pb/json_to_pb.h>
|
||||
#include "pb_util.h"
|
||||
#include "json_loader.h"
|
||||
#include <errno.h>
|
||||
|
||||
namespace brpc {
|
||||
|
||||
class JsonLoader::Reader {
|
||||
public:
|
||||
explicit Reader(int fd2)
|
||||
: _fd(fd2)
|
||||
, _brace_depth(0)
|
||||
, _quoted(false)
|
||||
, _quote_char(0)
|
||||
{}
|
||||
|
||||
explicit Reader(const std::string& jsons)
|
||||
: _fd(-1)
|
||||
, _brace_depth(0)
|
||||
, _quoted(false)
|
||||
, _quote_char(0) {
|
||||
_file_buf.append(jsons);
|
||||
}
|
||||
|
||||
bool get_next_json(butil::IOBuf* json1);
|
||||
bool read_some();
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
int _brace_depth;
|
||||
bool _quoted; // quoted by " or '
|
||||
char _quote_char;
|
||||
butil::IOPortal _file_buf;
|
||||
};
|
||||
|
||||
// Load data from the file.
|
||||
bool JsonLoader::Reader::read_some() {
|
||||
if (_fd < 0) { // loading from a string.
|
||||
return false;
|
||||
}
|
||||
ssize_t nr = _file_buf.append_from_file_descriptor(_fd, 65536);
|
||||
if (nr < 0) {
|
||||
if (errno == EINTR) {
|
||||
return read_some();
|
||||
}
|
||||
PLOG(ERROR) << "Fail to read fd=" << _fd;
|
||||
return false;
|
||||
} else if (nr == 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore json only with spaces and newline
|
||||
static bool possibly_valid_json(const butil::IOBuf& json) {
|
||||
butil::IOBufAsZeroCopyInputStream it(json);
|
||||
const void* data = NULL;
|
||||
for (int size = 0; it.Next(&data, &size); ) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
char c = ((const char*)data)[i];
|
||||
if (!isspace(c) && c != '\n') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Separate jsons with closed braces.
|
||||
bool JsonLoader::Reader::get_next_json(butil::IOBuf* json1) {
|
||||
if (_file_buf.empty()) {
|
||||
if (!read_some()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
json1->clear();
|
||||
while (1) {
|
||||
butil::IOBufAsZeroCopyInputStream it(_file_buf);
|
||||
const void* data = NULL;
|
||||
int size = 0;
|
||||
int total_size = 0;
|
||||
int skipped = 0;
|
||||
for (; it.Next(&data, &size); total_size += size) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
const char c = ((const char*)data)[i];
|
||||
if (_brace_depth == 0) {
|
||||
// skip any character until the first left brace is found.
|
||||
if (c != '{') {
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (c) {
|
||||
case '{':
|
||||
if (!_quoted) {
|
||||
++_brace_depth;
|
||||
} else {
|
||||
VLOG(1) << "Quoted left brace";
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
if (!_quoted) {
|
||||
--_brace_depth;
|
||||
if (_brace_depth == 0) {
|
||||
// the braces are closed, a complete object.
|
||||
_file_buf.cutn(json1, total_size + i + 1);
|
||||
json1->pop_front(skipped);
|
||||
return possibly_valid_json(*json1);
|
||||
} else if (_brace_depth < 0) {
|
||||
LOG(ERROR) << "More right braces than left braces";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
VLOG(1) << "Quoted right brace";
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (_quoted) {
|
||||
if (_quote_char == '"') {
|
||||
_quoted = false;
|
||||
}
|
||||
} else {
|
||||
_quoted = true;
|
||||
_quote_char = '"';
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
if (_quoted) {
|
||||
if (_quote_char == '\'') {
|
||||
_quoted = false;
|
||||
}
|
||||
} else {
|
||||
_quoted = true;
|
||||
_quote_char = '\'';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// just skip
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!_file_buf.empty()) {
|
||||
json1->append(_file_buf);
|
||||
_file_buf.clear();
|
||||
}
|
||||
if (!read_some()) {
|
||||
json1->pop_front(skipped);
|
||||
if (!json1->empty()) {
|
||||
return possibly_valid_json(*json1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonLoader::JsonLoader(google::protobuf::compiler::Importer* importer,
|
||||
google::protobuf::DynamicMessageFactory* factory,
|
||||
const std::string& service_name,
|
||||
const std::string& method_name)
|
||||
: _importer(importer)
|
||||
, _factory(factory)
|
||||
, _service_name(service_name)
|
||||
, _method_name(method_name)
|
||||
{
|
||||
_request_prototype = pbrpcframework::get_prototype_by_name(
|
||||
_service_name, _method_name, true, _importer, _factory);
|
||||
}
|
||||
|
||||
void JsonLoader::load_messages(
|
||||
JsonLoader::Reader* ctx,
|
||||
std::deque<google::protobuf::Message*>* out_msgs) {
|
||||
out_msgs->clear();
|
||||
butil::IOBuf request_json;
|
||||
while (ctx->get_next_json(&request_json)) {
|
||||
VLOG(1) << "Load " << out_msgs->size() + 1 << "-th json=`"
|
||||
<< request_json << '\'';
|
||||
std::string error;
|
||||
google::protobuf::Message* request = _request_prototype->New();
|
||||
butil::IOBufAsZeroCopyInputStream wrapper(request_json);
|
||||
if (!json2pb::JsonToProtoMessage(&wrapper, request, &error)) {
|
||||
LOG(WARNING) << "Fail to convert to pb: " << error << ", json=`"
|
||||
<< request_json << '\'';
|
||||
delete request;
|
||||
continue;
|
||||
}
|
||||
out_msgs->push_back(request);
|
||||
LOG_IF(INFO, (out_msgs->size() % 10000) == 0)
|
||||
<< "Loaded " << out_msgs->size() << " jsons";
|
||||
}
|
||||
}
|
||||
|
||||
void JsonLoader::load_messages(
|
||||
int fd,
|
||||
std::deque<google::protobuf::Message*>* out_msgs) {
|
||||
JsonLoader::Reader ctx(fd);
|
||||
load_messages(&ctx, out_msgs);
|
||||
}
|
||||
|
||||
void JsonLoader::load_messages(
|
||||
const std::string& jsons,
|
||||
std::deque<google::protobuf::Message*>* out_msgs) {
|
||||
JsonLoader::Reader ctx(jsons);
|
||||
load_messages(&ctx, out_msgs);
|
||||
}
|
||||
|
||||
} // namespace brpc
|
||||
@@ -0,0 +1,63 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#ifndef BRPC_JSON_LOADER_H
|
||||
#define BRPC_JSON_LOADER_H
|
||||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/compiler/importer.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <butil/iobuf.h>
|
||||
|
||||
namespace brpc {
|
||||
|
||||
// This utility loads pb messages in json format from a file or string.
|
||||
class JsonLoader {
|
||||
public:
|
||||
JsonLoader(google::protobuf::compiler::Importer* importer,
|
||||
google::protobuf::DynamicMessageFactory* factory,
|
||||
const std::string& service_name,
|
||||
const std::string& method_name);
|
||||
~JsonLoader() {}
|
||||
|
||||
// TODO(gejun): messages should be lazily loaded.
|
||||
|
||||
// Load jsons from fd or string, convert them into pb messages, then insert
|
||||
// them into `out_msgs'.
|
||||
void load_messages(int fd, std::deque<google::protobuf::Message*>* out_msgs);
|
||||
void load_messages(const std::string& jsons,
|
||||
std::deque<google::protobuf::Message*>* out_msgs);
|
||||
|
||||
private:
|
||||
class Reader;
|
||||
|
||||
void load_messages(
|
||||
JsonLoader::Reader* ctx,
|
||||
std::deque<google::protobuf::Message*>* out_msgs);
|
||||
|
||||
google::protobuf::compiler::Importer* _importer;
|
||||
google::protobuf::DynamicMessageFactory* _factory;
|
||||
std::string _service_name;
|
||||
std::string _method_name;
|
||||
const google::protobuf::Message* _request_prototype;
|
||||
};
|
||||
|
||||
} // namespace brpc
|
||||
|
||||
#endif // BRPC_JSON_LOADER_H
|
||||
@@ -0,0 +1,72 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#include <butil/logging.h>
|
||||
#include "pb_util.h"
|
||||
|
||||
using google::protobuf::ServiceDescriptor;
|
||||
using google::protobuf::Descriptor;
|
||||
using google::protobuf::DescriptorPool;
|
||||
using google::protobuf::MessageFactory;
|
||||
using google::protobuf::Message;
|
||||
using google::protobuf::MethodDescriptor;
|
||||
using google::protobuf::compiler::Importer;
|
||||
using google::protobuf::DynamicMessageFactory;
|
||||
using google::protobuf::DynamicMessageFactory;
|
||||
using std::string;
|
||||
|
||||
namespace pbrpcframework {
|
||||
|
||||
const MethodDescriptor* find_method_by_name(const string& service_name,
|
||||
const string& method_name,
|
||||
Importer* importer) {
|
||||
const ServiceDescriptor* descriptor =
|
||||
importer->pool()->FindServiceByName(service_name);
|
||||
if (NULL == descriptor) {
|
||||
LOG(FATAL) << "Fail to find service=" << service_name;
|
||||
return NULL;
|
||||
}
|
||||
return descriptor->FindMethodByName(method_name);
|
||||
}
|
||||
|
||||
const Message* get_prototype_by_method_descriptor(
|
||||
const MethodDescriptor* descripter,
|
||||
bool is_input,
|
||||
DynamicMessageFactory* factory) {
|
||||
if (NULL == descripter) {
|
||||
LOG(FATAL) <<"Param[descripter] is NULL";
|
||||
return NULL;
|
||||
}
|
||||
const Descriptor* message_descriptor = NULL;
|
||||
if (is_input) {
|
||||
message_descriptor = descripter->input_type();
|
||||
} else {
|
||||
message_descriptor = descripter->output_type();
|
||||
}
|
||||
return factory->GetPrototype(message_descriptor);
|
||||
}
|
||||
|
||||
const Message* get_prototype_by_name(const string& service_name,
|
||||
const string& method_name, bool is_input,
|
||||
Importer* importer,
|
||||
DynamicMessageFactory* factory){
|
||||
const MethodDescriptor* descripter = find_method_by_name(
|
||||
service_name, method_name, importer);
|
||||
return get_prototype_by_method_descriptor(descripter, is_input, factory);
|
||||
}
|
||||
|
||||
} // pbrpcframework
|
||||
@@ -0,0 +1,44 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#ifndef UTIL_PB_UTIL_H
|
||||
#define UTIL_PB_UTIL_H
|
||||
#include "google/protobuf/message.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/compiler/importer.h>
|
||||
|
||||
namespace pbrpcframework {
|
||||
const google::protobuf::MethodDescriptor* find_method_by_name(
|
||||
const std::string& service_name,
|
||||
const std::string& method_name,
|
||||
google::protobuf::compiler::Importer* importer);
|
||||
|
||||
const google::protobuf::Message* get_prototype_by_method_descriptor(
|
||||
const google::protobuf::MethodDescriptor* descripter,
|
||||
bool is_input,
|
||||
google::protobuf::DynamicMessageFactory* factory);
|
||||
|
||||
const google::protobuf::Message* get_prototype_by_name(
|
||||
const std::string& service_name,
|
||||
const std::string& method_name,
|
||||
bool is_input,
|
||||
google::protobuf::compiler::Importer* importer,
|
||||
google::protobuf::DynamicMessageFactory* factory);
|
||||
}
|
||||
#endif //UTIL_PB_UTIL_H
|
||||
@@ -0,0 +1,129 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/compiler/importer.h>
|
||||
#include <brpc/server.h>
|
||||
#include <butil/logging.h>
|
||||
#include <butil/string_splitter.h>
|
||||
#include <string.h>
|
||||
#include "rpc_press_impl.h"
|
||||
|
||||
DEFINE_int32(dummy_port, 8888, "Port of dummy server");
|
||||
DEFINE_string(proto, "", " user's proto files with path");
|
||||
DEFINE_string(inc, "", "Include paths for proto, separated by semicolon(;)");
|
||||
DEFINE_string(method, "example.EchoService.Echo", "The full method name");
|
||||
DEFINE_string(server, "0.0.0.0:8002", "ip:port of the server when -load_balancer is empty, the naming service otherwise");
|
||||
DEFINE_string(input, "", "The file containing requests in json format");
|
||||
DEFINE_string(output, "", "The file containing responses in json format");
|
||||
DEFINE_string(lb_policy, "", "The load balancer algorithm: rr, random, la, p2c, c_murmurhash, c_md5");
|
||||
DEFINE_int32(thread_num, 0, "Number of threads to send requests. 0: automatically chosen according to -qps");
|
||||
DEFINE_string(protocol, "baidu_std", "baidu_std hulu_pbrpc sofa_pbrpc http public_pbrpc nova_pbrpc ubrpc_compack...");
|
||||
DEFINE_string(connection_type, "", "Type of connections: single, pooled, short");
|
||||
DEFINE_int32(timeout_ms, 1000, "RPC timeout in milliseconds");
|
||||
DEFINE_int32(connection_timeout_ms, 500, " connection timeout in milliseconds");
|
||||
DEFINE_int32(max_retry, 3, "Maximum retry times by RPC framework");
|
||||
DEFINE_int32(request_compress_type, 0, "Snappy:1 Gzip:2 Zlib:3 LZ4:4 None:0");
|
||||
DEFINE_int32(response_compress_type, 0, "Snappy:1 Gzip:2 Zlib:3 LZ4:4 None:0");
|
||||
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
|
||||
DEFINE_int32(duration, 0, "how many seconds the press keep");
|
||||
DEFINE_int32(qps, 100 , "how many calls per seconds");
|
||||
DEFINE_bool(pretty, true, "output pretty jsons");
|
||||
|
||||
bool set_press_options(pbrpcframework::PressOptions* options){
|
||||
size_t dot_pos = FLAGS_method.find_last_of('.');
|
||||
if (dot_pos == std::string::npos) {
|
||||
LOG(ERROR) << "-method must be in form of: package.service.method";
|
||||
return false;
|
||||
}
|
||||
options->service = FLAGS_method.substr(0, dot_pos);
|
||||
options->method = FLAGS_method.substr(dot_pos + 1);
|
||||
options->lb_policy = FLAGS_lb_policy;
|
||||
options->test_req_rate = FLAGS_qps;
|
||||
if (FLAGS_thread_num > 0) {
|
||||
options->test_thread_num = FLAGS_thread_num;
|
||||
} else {
|
||||
if (FLAGS_qps <= 0) { // unlimited qps
|
||||
options->test_thread_num = 50;
|
||||
} else {
|
||||
options->test_thread_num = FLAGS_qps / 10000;
|
||||
if (options->test_thread_num < 1) {
|
||||
options->test_thread_num = 1;
|
||||
}
|
||||
if (options->test_thread_num > 50) {
|
||||
options->test_thread_num = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int rate_limit_per_thread = 1000000;
|
||||
double req_rate_per_thread = options->test_req_rate / options->test_thread_num;
|
||||
if (req_rate_per_thread > rate_limit_per_thread) {
|
||||
LOG(ERROR) << "req_rate: " << (int64_t) req_rate_per_thread << " is too large in one thread. The rate limit is "
|
||||
<< rate_limit_per_thread << " in one thread";
|
||||
return false;
|
||||
}
|
||||
|
||||
options->input = FLAGS_input;
|
||||
options->output = FLAGS_output;
|
||||
options->connection_type = FLAGS_connection_type;
|
||||
options->connect_timeout_ms = FLAGS_connection_timeout_ms;
|
||||
options->timeout_ms = FLAGS_timeout_ms;
|
||||
options->max_retry = FLAGS_max_retry;
|
||||
options->protocol = FLAGS_protocol;
|
||||
options->request_compress_type = FLAGS_request_compress_type;
|
||||
options->response_compress_type = FLAGS_response_compress_type;
|
||||
options->attachment_size = FLAGS_attachment_size;
|
||||
options->host = FLAGS_server;
|
||||
options->proto_file = FLAGS_proto;
|
||||
options->proto_includes = FLAGS_inc;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Parse gflags. We recommend you to use gflags as well
|
||||
GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
|
||||
// set global log option
|
||||
|
||||
if (FLAGS_dummy_port >= 0) {
|
||||
brpc::StartDummyServerAt(FLAGS_dummy_port);
|
||||
}
|
||||
|
||||
pbrpcframework::PressOptions options;
|
||||
if (!set_press_options(&options)) {
|
||||
return -1;
|
||||
}
|
||||
pbrpcframework::RpcPress* rpc_press = new pbrpcframework::RpcPress;
|
||||
if (0 != rpc_press->init(&options)) {
|
||||
LOG(FATAL) << "Fail to init rpc_press";
|
||||
return -1;
|
||||
}
|
||||
|
||||
rpc_press->start();
|
||||
if (FLAGS_duration <= 0) {
|
||||
while (!brpc::IsAskedToQuit()) {
|
||||
sleep(1);
|
||||
}
|
||||
} else {
|
||||
sleep(FLAGS_duration);
|
||||
}
|
||||
rpc_press->stop();
|
||||
// NOTE(gejun): Can't delete rpc_press on exit. It's probably
|
||||
// used by concurrently running done.
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <bthread/bthread.h>
|
||||
#include <butil/file_util.h> // butil::FilePath
|
||||
#include <butil/time.h>
|
||||
#include <brpc/channel.h>
|
||||
#include <brpc/controller.h>
|
||||
#include <butil/logging.h>
|
||||
#include <json2pb/pb_to_json.h>
|
||||
#include "json_loader.h"
|
||||
#include "rpc_press_impl.h"
|
||||
|
||||
using google::protobuf::Message;
|
||||
using google::protobuf::Closure;
|
||||
|
||||
namespace pbrpcframework {
|
||||
|
||||
class ImportErrorPrinter
|
||||
: public google::protobuf::compiler::MultiFileErrorCollector {
|
||||
public:
|
||||
// Line and column numbers are zero-based. A line number of -1 indicates
|
||||
// an error with the entire file (e.g. "not found").
|
||||
virtual void AddError(const std::string& filename, int line,
|
||||
int /*column*/, const std::string& message) {
|
||||
LOG_AT(ERROR, filename.c_str(), line) << message;
|
||||
}
|
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 5026000
|
||||
void RecordError(absl::string_view filename, int line, int column,
|
||||
absl::string_view message) override {
|
||||
LOG_AT(ERROR, filename.data(), line) << message;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int PressClient::init() {
|
||||
brpc::ChannelOptions rpc_options;
|
||||
rpc_options.connect_timeout_ms = _options->connect_timeout_ms;
|
||||
rpc_options.timeout_ms = _options->timeout_ms;
|
||||
rpc_options.max_retry = _options->max_retry;
|
||||
rpc_options.protocol = _options->protocol;
|
||||
rpc_options.connection_type = _options->connection_type;
|
||||
if (_options->attachment_size > 0) {
|
||||
_attachment.clear();
|
||||
_attachment.assign(_options->attachment_size, 'a');
|
||||
}
|
||||
if (_rpc_client.Init(_options->host.c_str(), _options->lb_policy.c_str(),
|
||||
&rpc_options) != 0){
|
||||
LOG(ERROR) << "Fail to initialize channel";
|
||||
return -1;
|
||||
}
|
||||
_method_descriptor = find_method_by_name(
|
||||
_options->service, _options->method, _importer);
|
||||
if (NULL == _method_descriptor) {
|
||||
LOG(ERROR) << "Fail to find method=" << _options->service << '.'
|
||||
<< _options->method;
|
||||
return -1;
|
||||
}
|
||||
_response_prototype = get_prototype_by_method_descriptor(
|
||||
_method_descriptor, false, _factory);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PressClient::call_method(brpc::Controller* cntl, Message* request,
|
||||
Message* response, Closure* done) {
|
||||
if (!_attachment.empty()) {
|
||||
cntl->request_attachment().append(_attachment);
|
||||
}
|
||||
_rpc_client.CallMethod(_method_descriptor, cntl, request, response, done);
|
||||
}
|
||||
|
||||
RpcPress::RpcPress()
|
||||
: _pbrpc_client(NULL)
|
||||
, _started(false)
|
||||
, _stop(false)
|
||||
, _output_json(NULL) {
|
||||
}
|
||||
|
||||
RpcPress::~RpcPress() {
|
||||
if (_output_json) {
|
||||
fclose(_output_json);
|
||||
_output_json = NULL;
|
||||
}
|
||||
delete _importer;
|
||||
}
|
||||
|
||||
int RpcPress::init(const PressOptions* options) {
|
||||
if (NULL == options) {
|
||||
LOG(ERROR) << "Param[options] is NULL" ;
|
||||
return -1;
|
||||
}
|
||||
_options = *options;
|
||||
|
||||
// Import protos.
|
||||
if (_options.proto_file.empty()) {
|
||||
LOG(ERROR) << "-proto is required";
|
||||
return -1;
|
||||
}
|
||||
int pos = _options.proto_file.find_last_of('/');
|
||||
std::string proto_file(_options.proto_file.substr(pos + 1));
|
||||
std::string proto_path(_options.proto_file.substr(0, pos));
|
||||
google::protobuf::compiler::DiskSourceTree sourceTree;
|
||||
// look up .proto file in the same directory
|
||||
sourceTree.MapPath("", proto_path.c_str());
|
||||
// Add paths in -inc
|
||||
if (!_options.proto_includes.empty()) {
|
||||
butil::StringSplitter sp(_options.proto_includes.c_str(), ';');
|
||||
for (; sp; ++sp) {
|
||||
sourceTree.MapPath("", std::string(sp.field(), sp.length()));
|
||||
}
|
||||
}
|
||||
ImportErrorPrinter error_printer;
|
||||
_importer = new google::protobuf::compiler::Importer(&sourceTree, &error_printer);
|
||||
if (_importer->Import(proto_file.c_str()) == NULL) {
|
||||
LOG(ERROR) << "Fail to import " << proto_file;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_pbrpc_client = new PressClient(&_options, _importer, &_factory);
|
||||
|
||||
if (!_options.output.empty()) {
|
||||
butil::File::Error error;
|
||||
butil::FilePath path(_options.output);
|
||||
butil::FilePath dir = path.DirName();
|
||||
if (!butil::CreateDirectoryAndGetError(dir, &error)) {
|
||||
LOG(ERROR) << "Fail to create directory=`" << dir.value()
|
||||
<< "', " << error;
|
||||
return -1;
|
||||
}
|
||||
_output_json = fopen(_options.output.c_str(), "w");
|
||||
LOG_IF(ERROR, !_output_json) << "Fail to open " << _options.output;
|
||||
}
|
||||
|
||||
int ret = _pbrpc_client->init();
|
||||
if (0 != ret) {
|
||||
LOG(ERROR) << "Fail to initialize rpc client";
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (_options.input.empty()) {
|
||||
LOG(ERROR) << "-input is empty";
|
||||
return -1;
|
||||
}
|
||||
brpc::JsonLoader json_util(_importer, &_factory,
|
||||
_options.service, _options.method);
|
||||
if (butil::PathExists(butil::FilePath(_options.input))) {
|
||||
int fd = open(_options.input.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
PLOG(ERROR) << "Fail to open " << _options.input;
|
||||
return -1;
|
||||
}
|
||||
json_util.load_messages(fd, &_msgs);
|
||||
} else {
|
||||
json_util.load_messages(_options.input, &_msgs);
|
||||
}
|
||||
if (_msgs.empty()) {
|
||||
LOG(ERROR) << "Fail to load requests";
|
||||
return -1;
|
||||
}
|
||||
LOG(INFO) << "Loaded " << _msgs.size() << " requests";
|
||||
_latency_recorder.expose("rpc_press");
|
||||
_error_count.expose("rpc_press_error_count");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* RpcPress::sync_call_thread(void* arg) {
|
||||
((RpcPress*)arg)->sync_client();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RpcPress::handle_response(brpc::Controller* cntl,
|
||||
Message* request,
|
||||
Message* response,
|
||||
int64_t start_time){
|
||||
if (!cntl->Failed()){
|
||||
int64_t rpc_call_time_us = butil::cpuwide_time_us() - start_time;
|
||||
_latency_recorder << rpc_call_time_us;
|
||||
|
||||
if (_output_json) {
|
||||
std::string response_json;
|
||||
std::string error;
|
||||
if (!json2pb::ProtoMessageToJson(*response, &response_json, &error)) {
|
||||
LOG(WARNING) << "Fail to convert to json: " << error;
|
||||
}
|
||||
fprintf(_output_json, "%s\n", response_json.c_str());
|
||||
}
|
||||
} else {
|
||||
LOG(WARNING) << "error_code=" << cntl->ErrorCode() << ", "
|
||||
<< cntl->ErrorText();
|
||||
_error_count << 1;
|
||||
}
|
||||
delete response;
|
||||
delete cntl;
|
||||
}
|
||||
|
||||
static butil::atomic<int> g_thread_count(0);
|
||||
|
||||
void RpcPress::sync_client() {
|
||||
double req_rate = _options.test_req_rate / _options.test_thread_num;
|
||||
//max make up time is 5 s
|
||||
if (_msgs.empty()) {
|
||||
LOG(ERROR) << "nothing to send!";
|
||||
return;
|
||||
}
|
||||
const int thread_index = g_thread_count.fetch_add(1, butil::memory_order_relaxed);
|
||||
int msg_index = thread_index;
|
||||
int64_t last_expected_time = butil::monotonic_time_ns();
|
||||
const int64_t interval = (int64_t) (1000000000L / req_rate);
|
||||
// the max tolerant delay between end_time and expected_time. 10ms or 10 intervals
|
||||
int64_t max_tolerant_delay = std::max((int64_t) 10000000L, 10 * interval);
|
||||
while (!_stop) {
|
||||
brpc::Controller* cntl = new brpc::Controller;
|
||||
msg_index = (msg_index + _options.test_thread_num) % _msgs.size();
|
||||
Message* request = _msgs[msg_index];
|
||||
Message* response = _pbrpc_client->get_output_message();
|
||||
const int64_t start_time = butil::cpuwide_time_us();
|
||||
google::protobuf::Closure* done = brpc::NewCallback<
|
||||
RpcPress,
|
||||
RpcPress*,
|
||||
brpc::Controller*,
|
||||
Message*,
|
||||
Message*, int64_t>
|
||||
(this, &RpcPress::handle_response, cntl, request, response, start_time);
|
||||
const brpc::CallId cid1 = cntl->call_id();
|
||||
_pbrpc_client->call_method(cntl, request, response, done);
|
||||
_sent_count << 1;
|
||||
|
||||
if (_options.test_req_rate <= 0) {
|
||||
brpc::Join(cid1);
|
||||
} else {
|
||||
int64_t end_time = butil::monotonic_time_ns();
|
||||
int64_t expected_time = last_expected_time + interval;
|
||||
if (end_time < expected_time) {
|
||||
usleep((expected_time - end_time)/1000);
|
||||
}
|
||||
if (end_time - expected_time > max_tolerant_delay) {
|
||||
expected_time = end_time;
|
||||
}
|
||||
last_expected_time = expected_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RpcPress::start() {
|
||||
_ttid.resize(_options.test_thread_num);
|
||||
int ret = 0;
|
||||
for (int i = 0; i < _options.test_thread_num; i++) {
|
||||
if ((ret = pthread_create(&_ttid[i], NULL, sync_call_thread, this)) != 0) {
|
||||
LOG(ERROR) << "Fail to create sending threads";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
brpc::InfoThreadOptions info_thr_opt;
|
||||
info_thr_opt.latency_recorder = &_latency_recorder;
|
||||
info_thr_opt.error_count = &_error_count;
|
||||
info_thr_opt.sent_count = &_sent_count;
|
||||
if (!_info_thr.start(info_thr_opt)) {
|
||||
LOG(ERROR) << "Fail to create stats thread";
|
||||
return -1;
|
||||
}
|
||||
_started = true;
|
||||
return 0;
|
||||
}
|
||||
int RpcPress::stop() {
|
||||
if (!_started) {
|
||||
return -1;
|
||||
}
|
||||
_stop = true;
|
||||
for (size_t i = 0; i < _ttid.size(); i++) {
|
||||
pthread_join(_ttid[i], NULL);
|
||||
}
|
||||
_info_thr.stop();
|
||||
return 0;
|
||||
}
|
||||
} //namespace
|
||||
@@ -0,0 +1,141 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#ifndef PBRPCPRESS_PBRPC_PRESS_H
|
||||
#define PBRPCPRESS_PBRPC_PRESS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <deque>
|
||||
#include <google/protobuf/compiler/importer.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <bvar/bvar.h>
|
||||
#include <brpc/channel.h>
|
||||
#include "info_thread.h"
|
||||
#include "pb_util.h"
|
||||
|
||||
namespace pbrpcframework {
|
||||
class JsonUtil;
|
||||
|
||||
struct PressOptions {
|
||||
std::string service; //service name (packet.rpcservice)
|
||||
std::string method; //method name (rpc service method)
|
||||
int server_type; // server type: 0 = hulu server, 1 = old pbrpc server, 2 = sofa server
|
||||
double test_req_rate; // 0 = no limit
|
||||
int test_thread_num;
|
||||
std::string input;
|
||||
std::string output;
|
||||
std::string host; // server's ip:port, used by hulu server and sofa server
|
||||
std::string channel; // server's channel, used by old pbrpc server
|
||||
//comcfg::Configure conf;
|
||||
std::string conf_dir;
|
||||
std::string conf_file;
|
||||
std::string connection_type; // connection type 0:SINGLE 1:POOLED 2:SHORT
|
||||
int connect_timeout_ms; // connection timeout in milliseconds
|
||||
int timeout_ms; // RPC timeout in milliseconds
|
||||
int max_retry; // Maximum retry times by RPC framework
|
||||
std::string protocol;
|
||||
int request_compress_type; // Snappy:1 Gzip:2 Zlib:3 LZ4:4 None:0
|
||||
int response_compress_type; // Snappy:1 Gzip:2 Zlib:3 LZ4:4 None:0
|
||||
int attachment_size; // Snappy:1 Gzip:2 Zlib:3 LZ4:4 None:0
|
||||
bool auth;// Enable Giano authentication
|
||||
std::string auth_group;
|
||||
std::string lb_policy; // "rr", "Policy of load balance rr ||random"
|
||||
std::string proto_file;
|
||||
std::string proto_includes;
|
||||
|
||||
PressOptions() :
|
||||
server_type(0),
|
||||
test_req_rate(0),
|
||||
test_thread_num(1),
|
||||
connect_timeout_ms(1000),
|
||||
timeout_ms(1000),
|
||||
max_retry(3),
|
||||
request_compress_type(0),
|
||||
response_compress_type(0),
|
||||
attachment_size(0),
|
||||
auth(false)
|
||||
{}
|
||||
};
|
||||
|
||||
class PressClient {
|
||||
public:
|
||||
PressClient(const PressOptions* options,
|
||||
google::protobuf::compiler::Importer* importer,
|
||||
google::protobuf::DynamicMessageFactory* factory) {
|
||||
_method_descriptor = NULL;
|
||||
_response_prototype = NULL;
|
||||
_options = options;
|
||||
_importer = importer;
|
||||
_factory = factory;
|
||||
|
||||
}
|
||||
|
||||
google::protobuf::Message* get_output_message() {
|
||||
return _response_prototype->New();
|
||||
}
|
||||
|
||||
int init();
|
||||
void call_method(brpc::Controller* cntl,
|
||||
google::protobuf::Message* request,
|
||||
google::protobuf::Message* response,
|
||||
google::protobuf::Closure* done);
|
||||
public:
|
||||
brpc::Channel _rpc_client;
|
||||
std::string _attachment;
|
||||
const PressOptions* _options;
|
||||
const google::protobuf::MethodDescriptor* _method_descriptor;
|
||||
const google::protobuf::Message* _response_prototype;
|
||||
google::protobuf::compiler::Importer* _importer;
|
||||
google::protobuf::DynamicMessageFactory* _factory;
|
||||
};
|
||||
|
||||
class RpcPress {
|
||||
public:
|
||||
RpcPress();
|
||||
~RpcPress();
|
||||
int init(const PressOptions* options);
|
||||
int start();
|
||||
int stop();
|
||||
const PressOptions* options() { return &_options; }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(RpcPress);
|
||||
|
||||
bool new_pbrpc_press_client_by_client_type(int client_type);
|
||||
void sync_client();
|
||||
void handle_response(brpc::Controller* cntl,
|
||||
google::protobuf::Message* request,
|
||||
google::protobuf::Message* response,
|
||||
int64_t start_time_ns);
|
||||
static void* sync_call_thread(void* arg);
|
||||
|
||||
bvar::LatencyRecorder _latency_recorder;
|
||||
bvar::Adder<int64_t> _error_count;
|
||||
bvar::Adder<int64_t> _sent_count;
|
||||
std::deque<google::protobuf::Message*> _msgs;
|
||||
PressClient* _pbrpc_client;
|
||||
PressOptions _options;
|
||||
bool _started;
|
||||
bool _stop;
|
||||
FILE* _output_json;
|
||||
google::protobuf::compiler::Importer* _importer;
|
||||
google::protobuf::DynamicMessageFactory _factory;
|
||||
std::vector<pthread_t> _ttid;
|
||||
brpc::InfoThread _info_thr;
|
||||
};
|
||||
}
|
||||
#endif // PBRPCPRESS_PBRPC_PRESS_H
|
||||
Reference in New Issue
Block a user