Compare commits

..

7 Commits

Author SHA1 Message Date
83939f5a22 Test ZCTR 2022-01-01 02:30:25 +03:00
ec2852c598 Add minsize_1 test 2021-12-28 10:54:36 +03:00
b9f5c2a823 Support zero-copy send in fio_sec_osd to allow testing it
Prelimilary results:
- CPU usage drops significantly. For example, in T1Q8 128K write test against
  stub_uring_osd with 10G network and Athlon X4 860k CPU it drops from 100% to 30%
- Latency becomes slightly worse. In T1Q1 4K write test in the same environment
  latency increases from 56 to 63 us.
- Small write throughput also becomes slightly worse. In T1Q128 4K write test
  against stub iops decreases from 138k to ~110k (unstable, fluctuates 100k..120k).
  Note that this is without io_uring, of course.
2021-12-27 02:12:44 +03:00
e9d2f79aa7 Support reading bitmaps in fio_sec_osd 2021-12-27 02:12:44 +03:00
0785bdf8b3 Release 0.6.11
- Slightly reduce journaling write amplification (requires no_same_sector_overwrites=false)
- Fix listen_backlog (it was 0) because it could more than halve OSD socket send speed
- Support IPv6 OSD addresses
- Do not try to initialize client in simple-offsets
- Fix OSDs sometimes marking PGs incomplete instead of trying to connect with peers
- Allow to configure OSD placement in node_placement
- Allow to run with 4k sector size block devices. Natural, but it was forbidden
2021-12-26 21:11:24 +03:00
b57e44748b Send 4 byte bitmap in stub_uring_osd 2021-12-25 11:38:13 +03:00
1bbe62f29c Fix uninitialized listen_backlog which was leading to REALLY SLOW send speeds!!! 2021-12-25 11:38:13 +03:00
24 changed files with 310 additions and 137 deletions

View File

@@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 2.8)
project(vitastor) project(vitastor)
set(VERSION "0.6.10") set(VERSION "0.6.11")
add_subdirectory(src) add_subdirectory(src)

View File

@@ -1,4 +1,4 @@
VERSION ?= v0.6.10 VERSION ?= v0.6.11
all: build push all: build push

View File

@@ -49,7 +49,7 @@ spec:
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true allowPrivilegeEscalation: true
image: vitalif/vitastor-csi:v0.6.10 image: vitalif/vitastor-csi:v0.6.11
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"

View File

@@ -116,7 +116,7 @@ spec:
privileged: true privileged: true
capabilities: capabilities:
add: ["SYS_ADMIN"] add: ["SYS_ADMIN"]
image: vitalif/vitastor-csi:v0.6.10 image: vitalif/vitastor-csi:v0.6.11
args: args:
- "--node=$(NODE_ID)" - "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)" - "--endpoint=$(CSI_ENDPOINT)"

View File

@@ -5,7 +5,7 @@ package vitastor
const ( const (
vitastorCSIDriverName = "csi.vitastor.io" vitastorCSIDriverName = "csi.vitastor.io"
vitastorCSIDriverVersion = "0.6.10" vitastorCSIDriverVersion = "0.6.11"
) )
// Config struct fills the parameters of request or user input // Config struct fills the parameters of request or user input

2
debian/changelog vendored
View File

@@ -1,4 +1,4 @@
vitastor (0.6.10-1) unstable; urgency=medium vitastor (0.6.11-1) unstable; urgency=medium
* RDMA support * RDMA support
* Bugfixes * Bugfixes

View File

@@ -33,8 +33,8 @@ RUN set -e -x; \
mkdir -p /root/packages/vitastor-$REL; \ mkdir -p /root/packages/vitastor-$REL; \
rm -rf /root/packages/vitastor-$REL/*; \ rm -rf /root/packages/vitastor-$REL/*; \
cd /root/packages/vitastor-$REL; \ cd /root/packages/vitastor-$REL; \
cp -r /root/vitastor vitastor-0.6.10; \ cp -r /root/vitastor vitastor-0.6.11; \
cd vitastor-0.6.10; \ cd vitastor-0.6.11; \
ln -s /root/fio-build/fio-*/ ./fio; \ ln -s /root/fio-build/fio-*/ ./fio; \
FIO=$(head -n1 fio/debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \ FIO=$(head -n1 fio/debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \
ls /usr/include/linux/raw.h || cp ./debian/raw.h /usr/include/linux/raw.h; \ ls /usr/include/linux/raw.h || cp ./debian/raw.h /usr/include/linux/raw.h; \
@@ -47,8 +47,8 @@ RUN set -e -x; \
rm -rf a b; \ rm -rf a b; \
echo "dep:fio=$FIO" > debian/fio_version; \ echo "dep:fio=$FIO" > debian/fio_version; \
cd /root/packages/vitastor-$REL; \ cd /root/packages/vitastor-$REL; \
tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_0.6.10.orig.tar.xz vitastor-0.6.10; \ tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_0.6.11.orig.tar.xz vitastor-0.6.11; \
cd vitastor-0.6.10; \ cd vitastor-0.6.11; \
V=$(head -n1 debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \ V=$(head -n1 debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \
DEBFULLNAME="Vitaliy Filippov <vitalif@yourcmc.ru>" dch -D $REL -v "$V""$REL" "Rebuild for $REL"; \ DEBFULLNAME="Vitaliy Filippov <vitalif@yourcmc.ru>" dch -D $REL -v "$V""$REL" "Rebuild for $REL"; \
DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --jobs=auto -sa; \ DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --jobs=auto -sa; \

View File

@@ -50,7 +50,7 @@ from cinder.volume import configuration
from cinder.volume import driver from cinder.volume import driver
from cinder.volume import volume_utils from cinder.volume import volume_utils
VERSION = '0.6.10' VERSION = '0.6.11'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)

View File

@@ -25,4 +25,4 @@ rm fio
mv fio-copy fio mv fio-copy fio
FIO=`rpm -qi fio | perl -e 'while(<>) { /^Epoch[\s:]+(\S+)/ && print "$1:"; /^Version[\s:]+(\S+)/ && print $1; /^Release[\s:]+(\S+)/ && print "-$1"; }'` FIO=`rpm -qi fio | perl -e 'while(<>) { /^Epoch[\s:]+(\S+)/ && print "$1:"; /^Version[\s:]+(\S+)/ && print $1; /^Release[\s:]+(\S+)/ && print "-$1"; }'`
perl -i -pe 's/(Requires:\s*fio)([^\n]+)?/$1 = '$FIO'/' $VITASTOR/rpm/vitastor-el$EL.spec perl -i -pe 's/(Requires:\s*fio)([^\n]+)?/$1 = '$FIO'/' $VITASTOR/rpm/vitastor-el$EL.spec
tar --transform 's#^#vitastor-0.6.10/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-0.6.10$(rpm --eval '%dist').tar.gz * tar --transform 's#^#vitastor-0.6.11/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-0.6.11$(rpm --eval '%dist').tar.gz *

View File

@@ -34,7 +34,7 @@ ADD . /root/vitastor
RUN set -e; \ RUN set -e; \
cd /root/vitastor/rpm; \ cd /root/vitastor/rpm; \
sh build-tarball.sh; \ sh build-tarball.sh; \
cp /root/vitastor-0.6.10.el7.tar.gz ~/rpmbuild/SOURCES; \ cp /root/vitastor-0.6.11.el7.tar.gz ~/rpmbuild/SOURCES; \
cp vitastor-el7.spec ~/rpmbuild/SPECS/vitastor.spec; \ cp vitastor-el7.spec ~/rpmbuild/SPECS/vitastor.spec; \
cd ~/rpmbuild/SPECS/; \ cd ~/rpmbuild/SPECS/; \
rpmbuild -ba vitastor.spec; \ rpmbuild -ba vitastor.spec; \

View File

@@ -1,11 +1,11 @@
Name: vitastor Name: vitastor
Version: 0.6.10 Version: 0.6.11
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-0.6.10.el7.tar.gz Source0: vitastor-0.6.11.el7.tar.gz
BuildRequires: liburing-devel >= 0.6 BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel

View File

@@ -33,7 +33,7 @@ ADD . /root/vitastor
RUN set -e; \ RUN set -e; \
cd /root/vitastor/rpm; \ cd /root/vitastor/rpm; \
sh build-tarball.sh; \ sh build-tarball.sh; \
cp /root/vitastor-0.6.10.el8.tar.gz ~/rpmbuild/SOURCES; \ cp /root/vitastor-0.6.11.el8.tar.gz ~/rpmbuild/SOURCES; \
cp vitastor-el8.spec ~/rpmbuild/SPECS/vitastor.spec; \ cp vitastor-el8.spec ~/rpmbuild/SPECS/vitastor.spec; \
cd ~/rpmbuild/SPECS/; \ cd ~/rpmbuild/SPECS/; \
rpmbuild -ba vitastor.spec; \ rpmbuild -ba vitastor.spec; \

View File

@@ -1,11 +1,11 @@
Name: vitastor Name: vitastor
Version: 0.6.10 Version: 0.6.11
Release: 1%{?dist} Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1 License: Vitastor Network Public License 1.1
URL: https://vitastor.io/ URL: https://vitastor.io/
Source0: vitastor-0.6.10.el8.tar.gz Source0: vitastor-0.6.11.el8.tar.gz
BuildRequires: liburing-devel >= 0.6 BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel BuildRequires: gperftools-devel

View File

@@ -15,7 +15,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif() endif()
add_definitions(-DVERSION="0.6.10") add_definitions(-DVERSION="0.6.11")
add_definitions(-Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -I ${CMAKE_SOURCE_DIR}/src) add_definitions(-Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -I ${CMAKE_SOURCE_DIR}/src)
if (${WITH_ASAN}) if (${WITH_ASAN})
add_definitions(-fsanitize=address -fno-omit-frame-pointer) add_definitions(-fsanitize=address -fno-omit-frame-pointer)
@@ -111,12 +111,11 @@ if (${WITH_FIO})
# libfio_vitastor_sec.so # libfio_vitastor_sec.so
add_library(fio_vitastor_sec SHARED add_library(fio_vitastor_sec SHARED
fio_sec_osd.cpp fio_sec_osd.cpp
rw_blocking.cpp
addr_util.cpp
) )
target_link_libraries(fio_vitastor_sec target_link_libraries(fio_vitastor_sec
vitastor_common
tcmalloc_minimal tcmalloc_minimal
${LIBURING_LIBRARIES}
${IBVERBS_LIBRARIES}
) )
endif (${WITH_FIO}) endif (${WITH_FIO})

View File

@@ -29,23 +29,23 @@
#include <unordered_map> #include <unordered_map>
#include "addr_util.h" #include "addr_util.h"
#include "epoll_manager.h" #include "rw_blocking.h"
#include "ringloop.h"
#include "messenger.h"
#include "osd_ops.h" #include "osd_ops.h"
#include "fio_headers.h" #include "fio_headers.h"
struct op_buf_t
{
osd_any_op_t buf;
io_u* fio_op;
};
struct sec_data struct sec_data
{ {
epoll_manager_t *epmgr;
ring_loop_t *ringloop;
osd_messenger_t *msgr;
ring_consumer_t looper;
void *bitmap_buf;
int connect_fd; int connect_fd;
uint64_t op_id; int data_fd;
/* block_size = 1 << block_order (128KB by default) */ /* block_size = 1 << block_order (128KB by default) */
uint64_t block_order = 17, block_size = 1 << 17; uint64_t block_order = 17, block_size = 1 << 17;
std::unordered_map<uint64_t, op_buf_t*> queue;
bool last_sync = false; bool last_sync = false;
/* The list of completed io_u structs. */ /* The list of completed io_u structs. */
std::vector<io_u*> completed; std::vector<io_u*> completed;
@@ -60,6 +60,7 @@ struct sec_options
int single_primary = 0; int single_primary = 0;
int trace = 0; int trace = 0;
int block_order = 17; int block_order = 17;
int zerocopy_send = 0;
}; };
static struct fio_option options[] = { static struct fio_option options[] = {
@@ -110,6 +111,16 @@ static struct fio_option options[] = {
.category = FIO_OPT_C_ENGINE, .category = FIO_OPT_C_ENGINE,
.group = FIO_OPT_G_FILENAME, .group = FIO_OPT_G_FILENAME,
}, },
{
.name = "zerocopy_send",
.lname = "Use zero-copy send",
.type = FIO_OPT_BOOL,
.off1 = offsetof(struct sec_options, zerocopy_send),
.help = "Use zero-copy send (MSG_ZEROCOPY)",
.def = "0",
.category = FIO_OPT_C_ENGINE,
.group = FIO_OPT_G_FILENAME,
},
{ {
.name = NULL, .name = NULL,
}, },
@@ -118,6 +129,9 @@ static struct fio_option options[] = {
static int sec_setup(struct thread_data *td) static int sec_setup(struct thread_data *td)
{ {
sec_data *bsd; sec_data *bsd;
//fio_file *f;
//int r;
//int64_t size;
bsd = new sec_data; bsd = new sec_data;
if (!bsd) if (!bsd)
@@ -134,6 +148,8 @@ static int sec_setup(struct thread_data *td)
td->o.open_files++; td->o.open_files++;
} }
//f = td->files[0];
//f->real_file_size = size;
return 0; return 0;
} }
@@ -142,10 +158,7 @@ static void sec_cleanup(struct thread_data *td)
sec_data *bsd = (sec_data*)td->io_ops_data; sec_data *bsd = (sec_data*)td->io_ops_data;
if (bsd) if (bsd)
{ {
delete bsd->msgr; close(bsd->data_fd);
delete bsd->epmgr;
delete bsd->ringloop;
free(bsd->bitmap_buf);
close(bsd->connect_fd); close(bsd->connect_fd);
delete bsd; delete bsd;
} }
@@ -159,65 +172,67 @@ static int sec_init(struct thread_data *td)
bsd->block_order = o->block_order == 0 ? 17 : o->block_order; bsd->block_order = o->block_order == 0 ? 17 : o->block_order;
bsd->block_size = 1 << o->block_order; bsd->block_size = 1 << o->block_order;
sockaddr addr; struct sockaddr_storage addr = { 0 };
if (!string_to_addr(std::string(o->host ? o->host : "127.0.0.1"), false, o->port > 0 ? o->port : 11203, &addr)) if (!string_to_addr(o->host ? o->host : "127.0.0.1", false, o->port > 0 ? o->port : 11203, (struct sockaddr*)&addr))
{ {
fprintf(stderr, "server address: %s is not valid\n", o->host ? o->host : "127.0.0.1"); fprintf(stderr, "server address: %s is not valid\n", o->host ? o->host : "127.0.0.1");
return 1; return 1;
} }
bsd->connect_fd = socket(addr.sa_family, SOCK_STREAM, 0); bsd->connect_fd = socket(addr.ss_family, SOCK_STREAM, 0);
if (bsd->connect_fd < 0) if (bsd->connect_fd < 0)
{ {
perror("socket"); perror("socket");
return 1; return 1;
} }
if (connect(bsd->connect_fd, (sockaddr*)&addr, sizeof(addr)) < 0) if (connect(bsd->connect_fd, (sockaddr*)&addr, addr.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) < 0)
{ {
perror("connect"); perror("connect");
return 1; return 1;
} }
int one = 1; int one = 1;
setsockopt(bsd->connect_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); setsockopt(bsd->connect_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
if (o->zerocopy_send)
fcntl(bsd->connect_fd, F_SETFL, fcntl(bsd->connect_fd, F_GETFL, 0) | O_NONBLOCK);
json11::Json cfg = json11::Json::object{ { "use_rdma", 0 } };
bsd->bitmap_buf = malloc(4096);
bsd->ringloop = new ring_loop_t(512);
bsd->epmgr = new epoll_manager_t(bsd->ringloop);
bsd->msgr = new osd_messenger_t();
bsd->msgr->tfd = bsd->epmgr->tfd;
bsd->msgr->ringloop = bsd->ringloop;
bsd->msgr->repeer_pgs = [](osd_num_t){};
bsd->msgr->parse_config(cfg);
bsd->msgr->init();
bsd->looper.loop = [bsd]()
{ {
bsd->msgr->read_requests(); if (setsockopt(bsd->connect_fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one)) < 0)
bsd->msgr->send_replies();
bsd->ringloop->submit();
};
bsd->ringloop->register_consumer(&bsd->looper);
int peer_fd = bsd->connect_fd;
bsd->msgr->clients[peer_fd] = new osd_client_t();
bsd->msgr->clients[peer_fd]->peer_addr = addr;
bsd->msgr->clients[peer_fd]->peer_port = ntohs(((sockaddr_in*)&addr)->sin_port);
bsd->msgr->clients[peer_fd]->peer_fd = peer_fd;
bsd->msgr->clients[peer_fd]->peer_state = PEER_CONNECTED;
bsd->msgr->clients[peer_fd]->connect_timeout_id = -1;
bsd->msgr->clients[peer_fd]->osd_num = 1;
bsd->msgr->clients[peer_fd]->in_buf = malloc_or_die(bsd->msgr->receive_buffer_size);
bsd->epmgr->tfd->set_fd_handler(peer_fd, true, [msgr = bsd->msgr](int peer_fd, int epoll_events)
{ {
// Either OUT (connected) or HUP perror("setsockopt zerocopy");
msgr->handle_peer_epoll(peer_fd, epoll_events); return 1;
}); }
bsd->msgr->osd_peer_fds[1] = peer_fd; }
if (!string_to_addr(o->host ? o->host : "127.0.0.1", false, 1 + (o->port > 0 ? o->port : 11203), (sockaddr*)&addr))
{
fprintf(stderr, "server address: %s is not valid\n", o->host ? o->host : "127.0.0.1");
return 1;
}
bsd->data_fd = socket(addr.ss_family, SOCK_STREAM, 0);
if (bsd->data_fd < 0)
{
perror("socket");
return 1;
}
/* int mss = 4096;
if (setsockopt(bsd->data_fd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss)) < 0)
{
perror("setsockopt TCP_MAXSEG");
return 1;
}*/
if (connect(bsd->data_fd, (sockaddr*)&addr, addr.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) < 0)
{
perror("connect");
return 1;
}
setsockopt(bsd->data_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
if (o->zerocopy_send)
{
if (setsockopt(bsd->data_fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one)) < 0)
{
perror("setsockopt zerocopy");
return 1;
}
}
// FIXME: read config (block size) from OSD // FIXME: read config (block size) from OSD
@@ -238,12 +253,9 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
} }
io->engine_data = bsd; io->engine_data = bsd;
op_buf_t *op_buf = new op_buf_t;
osd_op_t *oo = new osd_op_t(); op_buf->fio_op = io;
oo->op_type = OSD_OP_OUT; osd_any_op_t &op = op_buf->buf;
oo->peer_fd = bsd->connect_fd;
osd_any_op_t & op = oo->req;
op.hdr.magic = SECONDARY_OSD_OP_MAGIC; op.hdr.magic = SECONDARY_OSD_OP_MAGIC;
op.hdr.id = n; op.hdr.id = n;
@@ -260,9 +272,6 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
op.sec_rw.version = UINT64_MAX; // last unstable op.sec_rw.version = UINT64_MAX; // last unstable
op.sec_rw.offset = io->offset % bsd->block_size; op.sec_rw.offset = io->offset % bsd->block_size;
op.sec_rw.len = io->xfer_buflen; op.sec_rw.len = io->xfer_buflen;
op.sec_rw.attr_len = 4;
oo->bitmap = bsd->bitmap_buf;
oo->bitmap_len = 4;
} }
else else
{ {
@@ -271,7 +280,6 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
op.rw.offset = io->offset; op.rw.offset = io->offset;
op.rw.len = io->xfer_buflen; op.rw.len = io->xfer_buflen;
} }
oo->iov.push_back(io->xfer_buf, io->xfer_buflen);
bsd->last_sync = false; bsd->last_sync = false;
break; break;
case DDIR_WRITE: case DDIR_WRITE:
@@ -293,7 +301,6 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
op.rw.offset = io->offset; op.rw.offset = io->offset;
op.rw.len = io->xfer_buflen; op.rw.len = io->xfer_buflen;
} }
oo->iov.push_back(io->xfer_buf, io->xfer_buflen);
bsd->last_sync = false; bsd->last_sync = false;
break; break;
case DDIR_SYNC: case DDIR_SYNC:
@@ -315,21 +322,6 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
return FIO_Q_COMPLETED; return FIO_Q_COMPLETED;
} }
oo->callback = [td, io](osd_op_t *oo)
{
sec_options *opt = (sec_options*)td->eo;
sec_data *bsd = (sec_data*)td->io_ops_data;
if (opt->trace)
{
printf("--- %s # %ld %ld\n", io->ddir == DDIR_READ ? "READ" :
(io->ddir == DDIR_WRITE ? "WRITE" : "SYNC"), oo->reply.hdr.id, oo->reply.hdr.retval);
}
io->error = oo->reply.hdr.retval < 0 ? -oo->reply.hdr.retval : 0;
bsd->completed.push_back(io);
delete oo;
};
bsd->msgr->outbox_push(oo);
if (opt->trace) if (opt->trace)
{ {
printf("+++ %s # %d\n", io->ddir == DDIR_READ ? "READ" : printf("+++ %s # %d\n", io->ddir == DDIR_READ ? "READ" :
@@ -339,6 +331,22 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
io->error = 0; io->error = 0;
bsd->inflight++; bsd->inflight++;
bsd->op_n++; bsd->op_n++;
bsd->queue[n] = op_buf;
if (io->ddir == DDIR_WRITE)
{
// It may make you laugh but ZCTR is only stable if we write data before header :-) O_o
if (write_blocking(bsd->data_fd, io->xfer_buf, io->xfer_buflen) != io->xfer_buflen)
{
perror("write");
exit(1);
}
}
if (write_blocking(bsd->connect_fd, op.buf, OSD_PACKET_SIZE) != OSD_PACKET_SIZE)
{
perror("write");
exit(1);
}
if (io->error != 0) if (io->error != 0)
return FIO_Q_COMPLETED; return FIO_Q_COMPLETED;
@@ -347,13 +355,72 @@ static enum fio_q_status sec_queue(struct thread_data *td, struct io_u *io)
static int sec_getevents(struct thread_data *td, unsigned int min, unsigned int max, const struct timespec *t) static int sec_getevents(struct thread_data *td, unsigned int min, unsigned int max, const struct timespec *t)
{ {
sec_options *opt = (sec_options*)td->eo;
sec_data *bsd = (sec_data*)td->io_ops_data; sec_data *bsd = (sec_data*)td->io_ops_data;
// FIXME timeout, at least poll. Now it's the stupidest implementation possible
osd_any_reply_t reply;
while (bsd->completed.size() < min) while (bsd->completed.size() < min)
{ {
bsd->ringloop->loop(); read_blocking(bsd->connect_fd, reply.buf, OSD_PACKET_SIZE);
if (bsd->completed.size() >= min) if (reply.hdr.magic != SECONDARY_OSD_REPLY_MAGIC)
break; {
bsd->ringloop->wait(); fprintf(stderr, "bad reply: magic = %lx instead of %lx\n", reply.hdr.magic, SECONDARY_OSD_REPLY_MAGIC);
exit(1);
}
auto it = bsd->queue.find(reply.hdr.id);
if (it == bsd->queue.end())
{
fprintf(stderr, "bad reply: op id %lx missing in local queue\n", reply.hdr.id);
exit(1);
}
io_u* io = it->second->fio_op;
delete it->second;
bsd->queue.erase(it);
if (io->ddir == DDIR_READ)
{
if (reply.hdr.retval != io->xfer_buflen)
{
fprintf(stderr, "Short read: retval = %ld instead of %llu\n", reply.hdr.retval, io->xfer_buflen);
exit(1);
}
if (reply.sec_rw.attr_len > 0)
{
if (reply.sec_rw.attr_len <= 8)
{
uint64_t bitmap = 0;
read_blocking(bsd->connect_fd, &bitmap, reply.sec_rw.attr_len);
}
else
{
void *bitmap = malloc(reply.sec_rw.attr_len);
read_blocking(bsd->connect_fd, bitmap, reply.sec_rw.attr_len);
free(bitmap);
}
}
read_blocking(bsd->data_fd, io->xfer_buf, io->xfer_buflen);
}
else if (io->ddir == DDIR_WRITE)
{
if (reply.hdr.retval != io->xfer_buflen)
{
fprintf(stderr, "Short write: retval = %ld instead of %llu\n", reply.hdr.retval, io->xfer_buflen);
exit(1);
}
}
else if (io->ddir == DDIR_SYNC)
{
if (reply.hdr.retval != 0)
{
fprintf(stderr, "Sync failed: retval = %ld\n", reply.hdr.retval);
exit(1);
}
}
if (opt->trace)
{
printf("--- %s # %ld\n", io->ddir == DDIR_READ ? "READ" :
(io->ddir == DDIR_WRITE ? "WRITE" : "SYNC"), reply.hdr.id);
}
bsd->completed.push_back(io);
} }
return bsd->completed.size(); return bsd->completed.size();
} }

View File

@@ -120,6 +120,7 @@ struct osd_messenger_t
protected: protected:
int keepalive_timer_id = -1; int keepalive_timer_id = -1;
uint32_t receive_buffer_size = 0;
int peer_connect_interval = 0; int peer_connect_interval = 0;
int peer_connect_timeout = 0; int peer_connect_timeout = 0;
int osd_idle_timeout = 0; int osd_idle_timeout = 0;
@@ -141,8 +142,6 @@ protected:
std::vector<std::function<void()>> set_immediate; std::vector<std::function<void()>> set_immediate;
public: public:
uint32_t receive_buffer_size = 0;
timerfd_manager_t *tfd; timerfd_manager_t *tfd;
ring_loop_t *ringloop; ring_loop_t *ringloop;
// osd_num_t is only for logging and asserts // osd_num_t is only for logging and asserts
@@ -173,11 +172,10 @@ public:
bool connect_rdma(int peer_fd, std::string rdma_address, uint64_t client_max_msg); bool connect_rdma(int peer_fd, std::string rdma_address, uint64_t client_max_msg);
#endif #endif
void handle_peer_epoll(int peer_fd, int epoll_events);
protected: protected:
void try_connect_peer(uint64_t osd_num); void try_connect_peer(uint64_t osd_num);
void try_connect_peer_addr(osd_num_t peer_osd, const char *peer_host, int peer_port); void try_connect_peer_addr(osd_num_t peer_osd, const char *peer_host, int peer_port);
void handle_peer_epoll(int peer_fd, int epoll_events);
void handle_connect_epoll(int peer_fd); void handle_connect_epoll(int peer_fd);
void on_connect_peer(osd_num_t peer_osd, int peer_fd); void on_connect_peer(osd_num_t peer_osd, int peer_fd);
void check_peer_config(osd_client_t *cl); void check_peer_config(osd_client_t *cl);

View File

@@ -102,7 +102,7 @@ class osd_t
bool no_rebalance = false; bool no_rebalance = false;
bool no_recovery = false; bool no_recovery = false;
std::string bind_address; std::string bind_address;
int bind_port, listen_backlog; int bind_port, listen_backlog = 128;
// FIXME: Implement client queue depth limit // FIXME: Implement client queue depth limit
int client_queue_depth = 128; int client_queue_depth = 128;
bool allow_test_ops = false; bool allow_test_ops = false;

View File

@@ -4,6 +4,8 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "rw_blocking.h" #include "rw_blocking.h"
@@ -123,3 +125,41 @@ int writev_blocking(int fd, iovec *iov, int iovcnt)
} }
return done; return done;
} }
int sendv_blocking(int fd, iovec *iov, int iovcnt, int flags)
{
struct msghdr msg = { 0 };
int v = 0;
int done = 0;
while (v < iovcnt)
{
msg.msg_iov = iov+v;
msg.msg_iovlen = iovcnt-v;
ssize_t r = sendmsg(fd, &msg, flags);
if (r < 0)
{
if (errno != EAGAIN && errno != EPIPE)
{
perror("sendmsg");
exit(1);
}
continue;
}
done += r;
while (v < iovcnt)
{
if (iov[v].iov_len > r)
{
iov[v].iov_len -= r;
iov[v].iov_base += r;
break;
}
else
{
r -= iov[v].iov_len;
v++;
}
}
}
return done;
}

View File

@@ -10,3 +10,4 @@ int read_blocking(int fd, void *read_buf, size_t remaining);
int write_blocking(int fd, void *write_buf, size_t remaining); int write_blocking(int fd, void *write_buf, size_t remaining);
int readv_blocking(int fd, iovec *iov, int iovcnt); int readv_blocking(int fd, iovec *iov, int iovcnt);
int writev_blocking(int fd, iovec *iov, int iovcnt); int writev_blocking(int fd, iovec *iov, int iovcnt);
int sendv_blocking(int fd, iovec *iov, int iovcnt, int flags);

View File

@@ -24,7 +24,9 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/mman.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <poll.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@@ -43,19 +45,32 @@
int bind_stub(std::string bind_address, int bind_port); int bind_stub(std::string bind_address, int bind_port);
void run_stub(int peer_fd); void run_stub(int peer_fd, int peer_data_fd);
int main(int narg, char *args[]) int main(int narg, char *args[])
{ {
int listen_fd = bind_stub("0.0.0.0", 11203); int listen_fd = bind_stub("0.0.0.0", 11203);
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 // Accept new connections
sockaddr addr; sockaddr addr;
socklen_t peer_addr_size = sizeof(addr); socklen_t peer_addr_size;
int peer_fd; int peer_fd, peer_data_fd;
const int one = 1;
while (1) while (1)
{ {
printf("stub_osd: waiting for 1 client\n"); printf("stub_osd: waiting for 1 client\n");
peer_fd = accept(listen_fd, &addr, &peer_addr_size); peer_addr_size = sizeof(addr);
peer_fd = accept(listen_fd, (sockaddr*)&addr, &peer_addr_size);
if (peer_fd == -1) if (peer_fd == -1)
{ {
if (errno == EAGAIN) if (errno == EAGAIN)
@@ -63,15 +78,27 @@ int main(int narg, char *args[])
else else
throw std::runtime_error(std::string("accept: ") + strerror(errno)); throw std::runtime_error(std::string("accept: ") + strerror(errno));
} }
printf("stub_osd: new client %d: connection from %s\n", peer_fd,
addr_to_string(addr).c_str());
int one = 1;
setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
run_stub(peer_fd); printf("stub_osd: new client %d: connection from %s\n", peer_fd,
close(peer_fd); addr_to_string(*((sockaddr*)&addr)).c_str());
printf("stub_osd: client %d disconnected\n", peer_fd); printf("stub_osd: waiting for 1 data connection\n");
// Try to accept next connection
peer_addr_size = sizeof(addr); 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);
printf("stub_osd: client %d / data %d disconnected\n", peer_fd, peer_data_fd);
// Try to accept next connection
} }
return 0; return 0;
} }
@@ -80,13 +107,13 @@ int bind_stub(std::string bind_address, int bind_port)
{ {
int listen_backlog = 128; int listen_backlog = 128;
sockaddr addr; sockaddr_storage addr = { 0 };
if (!string_to_addr(bind_address, 0, bind_port, &addr)) if (!string_to_addr(bind_address, 0, bind_port, (sockaddr*)&addr))
{ {
throw std::runtime_error("bind address "+bind_address+" is not valid"); throw std::runtime_error("bind address "+bind_address+" is not valid");
} }
int listen_fd = socket(addr.sa_family, SOCK_STREAM, 0); int listen_fd = socket(addr.ss_family, SOCK_STREAM, 0);
if (listen_fd < 0) if (listen_fd < 0)
{ {
throw std::runtime_error(std::string("socket: ") + strerror(errno)); throw std::runtime_error(std::string("socket: ") + strerror(errno));
@@ -94,7 +121,7 @@ int bind_stub(std::string bind_address, int bind_port)
int enable = 1; int enable = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
if (bind(listen_fd, &addr, sizeof(addr)) < 0) if (bind(listen_fd, (sockaddr*)&addr, addr.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) < 0)
{ {
close(listen_fd); close(listen_fd);
throw std::runtime_error(std::string("bind: ") + strerror(errno)); throw std::runtime_error(std::string("bind: ") + strerror(errno));
@@ -109,11 +136,16 @@ int bind_stub(std::string bind_address, int bind_port)
return listen_fd; return listen_fd;
} }
void run_stub(int peer_fd) void run_stub(int peer_fd, int peer_data_fd)
{ {
osd_any_op_t op; osd_any_op_t op;
osd_any_reply_t reply = { 0 }; osd_any_reply_t reply = { 0 };
void *buf = NULL; 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) while (1)
{ {
int r = read_blocking(peer_fd, op.buf, OSD_PACKET_SIZE); int r = read_blocking(peer_fd, op.buf, OSD_PACKET_SIZE);
@@ -132,19 +164,36 @@ void run_stub(int peer_fd)
if (op.hdr.opcode == OSD_OP_SEC_READ) if (op.hdr.opcode == OSD_OP_SEC_READ)
{ {
reply.hdr.retval = op.sec_rw.len; reply.hdr.retval = op.sec_rw.len;
buf = malloc(op.sec_rw.len); void *buf = malloc(op.sec_rw.len);
r = write_blocking(peer_fd, reply.buf, OSD_PACKET_SIZE); r = write_blocking(peer_fd, reply.buf, OSD_PACKET_SIZE);
if (r == OSD_PACKET_SIZE) if (r == OSD_PACKET_SIZE)
r = write_blocking(peer_fd, buf, op.sec_rw.len); r = write_blocking(peer_data_fd, buf, op.sec_rw.len);
free(buf); free(buf);
if (r < op.sec_rw.len) if (r < op.sec_rw.len)
break; break;
} }
else if (op.hdr.opcode == OSD_OP_SEC_WRITE || op.hdr.opcode == OSD_OP_SEC_WRITE_STABLE) else if (op.hdr.opcode == OSD_OP_SEC_WRITE || op.hdr.opcode == OSD_OP_SEC_WRITE_STABLE)
{ {
buf = malloc(op.sec_rw.len); struct pollfd pfd = { .fd = peer_data_fd, .events = POLLIN };
r = read_blocking(peer_fd, buf, op.sec_rw.len); 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); free(buf);
}
reply.hdr.retval = op.sec_rw.len; reply.hdr.retval = op.sec_rw.len;
if (r == op.sec_rw.len) if (r == op.sec_rw.len)
r = write_blocking(peer_fd, reply.buf, OSD_PACKET_SIZE); r = write_blocking(peer_fd, reply.buf, OSD_PACKET_SIZE);
@@ -166,5 +215,4 @@ void run_stub(int peer_fd)
break; break;
} }
} }
free(buf);
} }

View File

@@ -110,8 +110,10 @@ void stub_exec_op(osd_messenger_t *msgr, osd_op_t *op)
if (op->req.hdr.opcode == OSD_OP_SEC_READ) if (op->req.hdr.opcode == OSD_OP_SEC_READ)
{ {
op->reply.hdr.retval = op->req.sec_rw.len; op->reply.hdr.retval = op->req.sec_rw.len;
op->buf = malloc(op->req.sec_rw.len); op->buf = memalign_or_die(MEM_ALIGNMENT, op->req.sec_rw.len);
op->iov.push_back(op->buf, op->req.sec_rw.len); op->iov.push_back(op->buf, op->req.sec_rw.len);
op->reply.sec_rw.attr_len = 4;
op->bitmap = op->buf;
} }
else if (op->req.hdr.opcode == OSD_OP_SEC_WRITE || op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE) else if (op->req.hdr.opcode == OSD_OP_SEC_WRITE || op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE)
{ {

View File

@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: Vitastor Name: Vitastor
Description: Vitastor client library Description: Vitastor client library
Version: 0.6.10 Version: 0.6.11
Libs: -L${libdir} -lvitastor_client Libs: -L${libdir} -lvitastor_client
Cflags: -I${includedir} Cflags: -I${includedir}

View File

@@ -5,6 +5,7 @@
OSD_SIZE=${OSD_SIZE:-1024} OSD_SIZE=${OSD_SIZE:-1024}
PG_COUNT=${PG_COUNT:-1} PG_COUNT=${PG_COUNT:-1}
PG_SIZE=${PG_SIZE:-3} PG_SIZE=${PG_SIZE:-3}
PG_MINSIZE=${PG_MINSIZE:-2}
OSD_COUNT=${OSD_COUNT:-3} OSD_COUNT=${OSD_COUNT:-3}
SCHEME=${SCHEME:-ec} SCHEME=${SCHEME:-ec}
@@ -25,9 +26,9 @@ if [ -n "$GLOBAL_CONF" ]; then
fi fi
if [ "$SCHEME" = "replicated" ]; then if [ "$SCHEME" = "replicated" ]; then
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"replicated","pg_size":'$PG_SIZE',"pg_minsize":'$((PG_SIZE-1))',"pg_count":'$PG_COUNT',"failure_domain":"osd"}}' $ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"replicated","pg_size":'$PG_SIZE',"pg_minsize":'$PG_MINSIZE',"pg_count":'$PG_COUNT',"failure_domain":"osd"}}'
else else
$ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"xor","pg_size":'$PG_SIZE',"pg_minsize":'$((PG_SIZE-1))',"parity_chunks":1,"pg_count":'$PG_COUNT',"failure_domain":"osd"}}' $ETCDCTL put /vitastor/config/pools '{"1":{"name":"testpool","scheme":"xor","pg_size":'$PG_SIZE',"pg_minsize":'$PG_MINSIZE',"parity_chunks":1,"pg_count":'$PG_COUNT',"failure_domain":"osd"}}'
fi fi
sleep 2 sleep 2

17
tests/test_minsize_1.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash -ex
PG_MINSIZE=1
SCHEME=replicated
. `dirname $0`/run_3osds.sh
kill -INT $OSD1_PID
kill -INT $OSD2_PID
sleep 5
if ! ($ETCDCTL get /vitastor/pg/state/1/ --prefix --print-value-only | jq -s -e '[ .[] | select(.state == ["active", "degraded"]) ] | length == '$PG_COUNT); then
format_error "FAILED: $PG_COUNT PG(s) NOT ACTIVE+DEGRADED"
fi
format_green OK