vitastor/src/stub_osd.cpp

219 lines
7.0 KiB
C++
Raw Normal View History

// Copyright (c) Vitaliy Filippov, 2019+
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
/**
* Stub "OSD" to test & compare network performance with sync read/write and io_uring
*
* Core i7-6700HQ laptop
*
* stub_osd:
* randwrite Q1 S1: 36900 iops
* randwrite Q32 S32: 71000 iops
* randwrite Q32 S32 (multi-fsync fix): 113000 iops
* randread Q1: 67300 iops
* randread Q32: 144000 iops
*
* io_uring osd with #define OSD_STUB:
* randwrite Q1 S1: 30000 iops
* randwrite Q32 S32: 78600 iops
* randwrite Q32 S32 (multi-fsync fix): 125000 iops
* randread Q1: 50700 iops
* randread Q32: 86100 iops
*
* It seems io_uring is fine :)
*/
#include <sys/types.h>
2021-12-31 00:10:51 +03:00
#include <sys/mman.h>
#include <sys/socket.h>
2021-12-31 00:10:51 +03:00
#include <poll.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdexcept>
2021-12-19 01:14:20 +03:00
#include "addr_util.h"
#include "rw_blocking.h"
#include "osd_ops.h"
2021-12-19 01:14:20 +03:00
int bind_stub(std::string bind_address, int bind_port);
2021-12-31 00:10:51 +03:00
void run_stub(int peer_fd, int peer_data_fd);
int main(int narg, char *args[])
{
int listen_fd = bind_stub("0.0.0.0", 11203);
2021-12-31 00:10:51 +03:00
int listen_data_fd = bind_stub("0.0.0.0", 11204);
/* int mss = 8192;
if (setsockopt(listen_data_fd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss)) < 0)
{
throw std::runtime_error(std::string("setsockopt TCP_MAXSEG: ") + strerror(errno));
}
int rcvlowat = 4096;
if (setsockopt(listen_data_fd, SOL_SOCKET, SO_RCVLOWAT, &rcvlowat, sizeof(rcvlowat)) < 0)
{
throw std::runtime_error(std::string("setsockopt SO_RCVLOWAT: ") + strerror(errno));
}*/
// Accept new connections
2021-12-19 01:14:20 +03:00
sockaddr addr;
2021-12-31 00:10:51 +03:00
socklen_t peer_addr_size;
int peer_fd, peer_data_fd;
const int one = 1;
while (1)
{
printf("stub_osd: waiting for 1 client\n");
2021-12-31 00:10:51 +03:00
peer_addr_size = sizeof(addr);
peer_fd = accept(listen_fd, (sockaddr*)&addr, &peer_addr_size);
if (peer_fd == -1)
{
if (errno == EAGAIN)
continue;
else
throw std::runtime_error(std::string("accept: ") + strerror(errno));
}
setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
2021-12-31 00:10:51 +03:00
printf("stub_osd: new client %d: connection from %s\n", peer_fd,
addr_to_string(*((sockaddr*)&addr)).c_str());
printf("stub_osd: waiting for 1 data connection\n");
peer_addr_size = sizeof(addr);
peer_data_fd = accept(listen_data_fd, (sockaddr*)&addr, &peer_addr_size);
if (peer_data_fd == -1)
{
if (errno == EAGAIN)
continue;
else
throw std::runtime_error(std::string("accept: ") + strerror(errno));
}
setsockopt(peer_data_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
printf("stub_osd: new client %d: data connection from %s\n", peer_data_fd,
addr_to_string(*((sockaddr*)&addr)).c_str());
run_stub(peer_fd, peer_data_fd);
close(peer_data_fd);
close(peer_fd);
2021-12-31 00:10:51 +03:00
printf("stub_osd: client %d / data %d disconnected\n", peer_fd, peer_data_fd);
// Try to accept next connection
}
return 0;
}
2021-12-19 01:14:20 +03:00
int bind_stub(std::string bind_address, int bind_port)
{
int listen_backlog = 128;
2021-12-31 00:10:51 +03:00
sockaddr_storage addr = { 0 };
if (!string_to_addr(bind_address, 0, bind_port, (sockaddr*)&addr))
2021-12-19 01:14:20 +03:00
{
throw std::runtime_error("bind address "+bind_address+" is not valid");
}
2021-12-31 00:10:51 +03:00
int listen_fd = socket(addr.ss_family, SOCK_STREAM, 0);
if (listen_fd < 0)
{
throw std::runtime_error(std::string("socket: ") + strerror(errno));
}
int enable = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
2021-12-31 00:10:51 +03:00
if (bind(listen_fd, (sockaddr*)&addr, addr.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) < 0)
{
close(listen_fd);
throw std::runtime_error(std::string("bind: ") + strerror(errno));
}
if (listen(listen_fd, listen_backlog) < 0)
{
close(listen_fd);
throw std::runtime_error(std::string("listen: ") + strerror(errno));
}
return listen_fd;
}
2021-12-31 00:10:51 +03:00
void run_stub(int peer_fd, int peer_data_fd)
{
osd_any_op_t op;
2021-12-12 23:12:34 +03:00
osd_any_reply_t reply = { 0 };
2021-12-31 00:10:51 +03:00
unsigned bufsize = 4*1024*1024;
void *buf = mmap(NULL, bufsize, PROT_READ, MAP_SHARED, peer_data_fd, 0);
if (buf == MAP_FAILED)
{
throw std::runtime_error(std::string("mmap: ") + strerror(errno));
}
while (1)
{
int r = read_blocking(peer_fd, op.buf, OSD_PACKET_SIZE);
if (r < OSD_PACKET_SIZE)
{
break;
}
if (op.hdr.magic != SECONDARY_OSD_OP_MAGIC)
{
printf("client %d: bad magic number in operation header\n", peer_fd);
break;
}
reply.hdr.magic = SECONDARY_OSD_REPLY_MAGIC;
reply.hdr.id = op.hdr.id;
reply.hdr.opcode = op.hdr.opcode;
if (op.hdr.opcode == OSD_OP_SEC_READ)
{
reply.hdr.retval = op.sec_rw.len;
2021-12-31 00:10:51 +03:00
void *buf = malloc(op.sec_rw.len);
r = write_blocking(peer_fd, reply.buf, OSD_PACKET_SIZE);
if (r == OSD_PACKET_SIZE)
2021-12-31 00:10:51 +03:00
r = write_blocking(peer_data_fd, buf, op.sec_rw.len);
free(buf);
if (r < op.sec_rw.len)
break;
}
else if (op.hdr.opcode == OSD_OP_SEC_WRITE || op.hdr.opcode == OSD_OP_SEC_WRITE_STABLE)
{
2021-12-31 00:10:51 +03:00
struct pollfd pfd = { .fd = peer_data_fd, .events = POLLIN };
poll(&pfd, 1, 10000);
struct tcp_zerocopy_receive zc = { .address = (uint64_t)buf, .length = op.sec_rw.len };
socklen_t zc_len = sizeof(zc);
r = getsockopt(peer_data_fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, &zc, &zc_len);
r = r == -1 ? 0 : zc.length;
if (r > 0)
{
uint64_t hash = 0;
for (int k = 0; k < r/8; k++)
hash ^= ((uint64_t*)buf)[k];
printf("ZCTR: op=%lx r=%d len=%d skip=%d hash=%lx\n", op.hdr.id, r, zc.length, zc.recv_skip_hint, hash);
}
if (r < op.sec_rw.len)
{
int rest = op.sec_rw.len - r;
void *buf = malloc(rest);
r += read_blocking(peer_data_fd, buf, rest);
free(buf);
}
reply.hdr.retval = op.sec_rw.len;
if (r == op.sec_rw.len)
r = write_blocking(peer_fd, reply.buf, OSD_PACKET_SIZE);
else
r = 0;
if (r < OSD_PACKET_SIZE)
break;
}
else if (op.hdr.opcode == OSD_OP_TEST_SYNC_STAB_ALL)
{
reply.hdr.retval = 0;
r = write_blocking(peer_fd, reply.buf, OSD_PACKET_SIZE);
if (r < OSD_PACKET_SIZE)
break;
}
else
{
printf("client %d: unsupported stub opcode: %lu\n", peer_fd, op.hdr.opcode);
break;
}
}
}