ppd/modules/reqgen.cc
2023-01-17 21:22:43 +01:00

346 lines
7.3 KiB
C++

#include "google/protobuf/stubs/common.h"
#include "options.h"
#include <msg.pb.h>
#include <stdint.h>
#include <sstream>
#include <sys/_stdint.h>
#include <unistd.h>
#include <util.h>
#ifdef WITH_ROCKSDB
#include <rocksdb/db.h>
#endif
#include "reqgen.h"
////////////////
// TOUCH Generator
////////////////
touch_gen::touch_gen(const int conn_id, std::unordered_map<std::string, std::string>* args) : req_gen(conn_id)
{
this->ugen = createGenerator("uniform:100");
if (this->ugen == NULL) {
E("Failed to create ugen for touch_gen\n");
}
if (args->find(PARAM_GEN) == args->end()) {
this->wgen = createGenerator(PARAM_GEN_DEFAULT);
} else {
this->wgen = createGenerator(args->at(PARAM_GEN));
}
if (this->wgen == NULL) {
E("Failed to create wgen for touch_gen\n");
}
if (args->find(PARAM_UPDATE) == args->end()) {
this->update_ratio = PARAM_UPDATE_DEFAULT;
} else {
this->update_ratio = atoi(args->at(PARAM_UPDATE).c_str());
}
}
touch_gen::~touch_gen()
{
delete wgen;
delete ugen;
}
int touch_gen::send_req(int fd)
{
ppd_touch_req req;
if (options.master_mode) {
req.set_touch_cnt(0);
} else {
req.set_touch_cnt(this->wgen->generate());
}
if (this->ugen->generate() < this->update_ratio) {
req.set_inc(1);
} else {
req.set_inc(0);
}
if (!req.SerializeToArray(this->send_buf, MAX_SEND_BUF_SIZE)) {
E("Failed to serialize to array for fd %d", fd);
}
return writemsg(fd, this->send_buf, this->MAX_SEND_BUF_SIZE, this->send_buf, req.ByteSizeLong());
}
int touch_gen::read_resp(int fd)
{
ppd_touch_resp resp;
struct ppd_msg * msg = (struct ppd_msg *)this->send_buf;
if (readmsg(fd, this->send_buf, MAX_SEND_BUF_SIZE) < 0) {
E("Readbuf failed for fd %d\n", fd);
}
resp.ParseFromArray(msg->payload, msg->size);
return resp.status();
}
////////////////
// ECHO Generator
////////////////
int echo_gen::delay_table[DT_SZ];
std::atomic<int> echo_gen::delay_table_populated = ATOMIC_VAR_INIT(0);
void
echo_gen::populate_delay_table()
{
int idx = 0;
int expected = 0;
// hack
if (echo_gen::DT_SZ != 100) {
E("Delay table size isn't 100");
}
/* 95 + 4 + 1 = 100 */
if (!delay_table_populated.compare_exchange_weak(expected, 1)) {
return;
}
delay_table[idx++] = 200;
for(int i = 0; i < 4; i++) {
delay_table[idx++] = 50;
}
for(int i = 0; i < 95; i++) {
delay_table[idx++] = 10;
}
}
echo_gen::echo_gen(const int conn_id, std::unordered_map<std::string, std::string>* args) : req_gen(conn_id)
{
if (args->find(PARAM_GEN) == args->end()) {
this->wgen = createGenerator(PARAM_GEN_DEFAULT);
} else {
this->wgen = createGenerator(args->at(PARAM_GEN));
}
if (this->wgen == NULL) {
E("Failed to create wgen for echo_gen");
}
if (args->find(PARAM_CDELAY) == args->end()) {
this->cdelay = PARAM_CDELAY_DEFAULT;
} else {
this->cdelay = atoi(args->at(PARAM_CDELAY).c_str());
}
if (args->find(PARAM_SIZE) == args->end()) {
this->data_sz = PARAM_SIZE_DEFAULT;
} else {
this->data_sz = atoi(args->at(PARAM_SIZE).c_str());
}
if (this->cdelay) {
populate_delay_table();
}
}
echo_gen::~echo_gen()
{
delete wgen;
}
int echo_gen::get_delay()
{
if (cdelay) {
return delay_table[conn_id % DT_SZ];
} else {
return this->wgen->generate();
}
}
int echo_gen::send_req(int fd)
{
ppd_echo_req req;
if (options.master_mode) {
req.set_enable_delay(0);
req.set_data_size(PARAM_SIZE_DEFAULT);
} else {
req.set_enable_delay(get_delay());
req.set_data_size(this->data_sz);
}
if (!req.SerializeToArray(this->send_buf, MAX_SEND_BUF_SIZE)) {
E("Failed to serialize to array for fd %d\n", fd);
}
this->send_sz = req.ByteSizeLong() + sizeof(struct ppd_msg);
return writemsg(fd, this->send_buf, MAX_SEND_BUF_SIZE, this->send_buf, req.ByteSizeLong());
}
int echo_gen::read_resp(int fd)
{
ppd_echo_resp resp;
struct ppd_msg * msg = (struct ppd_msg *)this->send_buf;
if (readmsg(fd, this->send_buf, MAX_SEND_BUF_SIZE) < 0) {
E("Readbuf failed for fd %d\n", fd);
}
resp.ParseFromArray(msg->payload, msg->size);
this->recv_sz = msg->size + sizeof(struct ppd_msg);
return resp.status();
}
int echo_gen::get_send_sz()
{
return this->send_sz;
}
int echo_gen::get_recv_sz()
{
return this->recv_sz;
}
////////////////
// HTTP Generator
////////////////
char http_gen::cons_buf[CONS_SZ];
http_gen::http_gen(const int conn_id, const std::string& host, std::unordered_map<std::string, std::string>* args) : req_gen(conn_id)
{
// hack
method = "GET";
headers.insert({"Host", host});
headers.insert({"Connection", "keep-alive"});
major_ver = 1;
minor_ver = 1;
uri = "/";
}
http_gen::~http_gen()
{
}
std::string
http_gen::build_req()
{
std::stringstream ss;
ss << method << ' ' \
<< uri << ' ' \
<< "HTTP/" + std::to_string(major_ver) + "." + std::to_string(minor_ver) \
<< "\r\n";
for(auto &i : headers) {
ss << i.first.c_str() << ": " << i.second.c_str() << "\r\n";
}
ss << "\r\n";
return ss.str();
}
int http_gen::send_req(int fd)
{
std::string req = build_req();
//V("Sending Request: %s\n", req.c_str());
return writebuf(fd, (void*)req.c_str(), req.length());
}
int http_gen::read_resp(int fd)
{
// hack
// consume everything
return read(fd, cons_buf, CONS_SZ);;
}
#ifdef WITH_ROCKSDB
////////////////
// RDB Generator
////////////////
rdb_gen::rdb_gen(const int conn_id, std::unordered_map<std::string, std::string>* args) : req_gen(conn_id), rand(1000 + conn_id)
{
this->key = AllocateKey(&this->key_guard, KEY_SIZE);
std::vector<double> ratio {GET_RATIO, PUT_RATIO, SEEK_RATIO};
this->query.Initiate(ratio);
gen_exp.InitiateExpDistribution(TOTAL_KEYS, KEYRANGE_DIST_A, KEYRANGE_DIST_B, KEYRANGE_DIST_C, KEYRANGE_DIST_D);
}
rdb_gen::~rdb_gen()
{
}
int rdb_gen::send_req(int fd)
{
int status;
ppd_rdb_req req;
int64_t ini_rand = GetRandomKey(&this->rand);
int64_t key_rand = gen_exp.DistGetKeyID(ini_rand, this->KEYRANGE_DIST_A, this->KEYRANGE_DIST_B);
int64_t rand_v = ini_rand % TOTAL_KEYS;
double u = (double)rand_v / TOTAL_KEYS;
int query_type = options.master_mode ? 0 : query.GetType(rand_v);
GenerateKeyFromInt(key_rand, TOTAL_KEYS, KEY_SIZE, &this->key);
V("SENDING KEY: %s.\n", this->key.data());
switch (query_type) {
case 0: {
// get query
req.set_op(PPD_RDB_OP_GET);
req.set_key(this->key.data(), this->key.size());
break;
}
case 1: {
// put query
int val_sz = ParetoCdfInversion(u, VALUE_THETA, VALUE_K, VALUE_SIGMA);
rocksdb::Slice val = gen.Generate((unsigned int)val_sz);
req.set_op(PPD_RDB_OP_PUT);
req.set_key(this->key.data(), this->key.size());
req.set_val(val.data(), val.size());
break;
}
case 2: {
// seek query
int64_t scan_length = ParetoCdfInversion(u, ITER_THETA, ITER_K, ITER_SIGMA);
req.set_op(PPD_RDB_OP_SEEK);
req.set_key(this->key.data(), this->key.size());
req.set_optarg(scan_length);
break;
}
default: {
E("Unsupported query type %d", query_type);
}
}
if (!req.SerializeToArray(this->send_buf, MAX_SEND_BUF_SIZE)) {
E("Failed to serialize protobuf");
}
status = writemsg(fd, this->send_buf, MAX_SEND_BUF_SIZE, this->send_buf, req.ByteSizeLong());
return status;
}
int rdb_gen::read_resp(int fd)
{
ppd_rdb_resp resp;
struct ppd_msg * msg = (struct ppd_msg *)this->send_buf;
if (readmsg(fd, this->send_buf, MAX_SEND_BUF_SIZE) < 0) {
E("Readbuf failed for fd %d", fd);
}
resp.ParseFromArray(msg->payload, msg->size);
return resp.status();
}
#endif