forked from vitalif/vitastor
Remove io_uring usage from osd_http and timerfd_manager
For better future interoperability with external event loops such as QEMU's onetrace-sqes
parent
f57731f8ca
commit
a61ede9951
22
osd.cpp
22
osd.cpp
|
@ -43,7 +43,7 @@ osd_t::osd_t(blockstore_config_t & config, blockstore_t *bs, ring_loop_t *ringlo
|
||||||
throw std::runtime_error(std::string("epoll_create: ") + strerror(errno));
|
throw std::runtime_error(std::string("epoll_create: ") + strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
this->tfd = new timerfd_manager_t(ringloop);
|
this->tfd = new timerfd_manager_t([this](int fd, std::function<void(int, int)> handler) { set_fd_handler(fd, handler); });
|
||||||
this->tfd->set_timer(print_stats_interval*1000, true, [this](int timer_id)
|
this->tfd->set_timer(print_stats_interval*1000, true, [this](int timer_id)
|
||||||
{
|
{
|
||||||
print_stats();
|
print_stats();
|
||||||
|
@ -236,6 +236,26 @@ void osd_t::loop()
|
||||||
ringloop->submit();
|
ringloop->submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void osd_t::set_fd_handler(int fd, std::function<void(int, int)> handler)
|
||||||
|
{
|
||||||
|
if (handler != NULL)
|
||||||
|
{
|
||||||
|
epoll_event ev;
|
||||||
|
ev.data.fd = fd;
|
||||||
|
ev.events = EPOLLOUT | EPOLLIN | EPOLLRDHUP | EPOLLET;
|
||||||
|
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("epoll_ctl: ") + strerror(errno));
|
||||||
|
}
|
||||||
|
epoll_handlers[fd] = handler;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||||
|
epoll_handlers.erase(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void osd_t::handle_epoll_events()
|
void osd_t::handle_epoll_events()
|
||||||
{
|
{
|
||||||
io_uring_sqe *sqe = ringloop->get_sqe();
|
io_uring_sqe *sqe = ringloop->get_sqe();
|
||||||
|
|
1
osd.h
1
osd.h
|
@ -327,6 +327,7 @@ class osd_t
|
||||||
|
|
||||||
// event loop, socket read/write
|
// event loop, socket read/write
|
||||||
void loop();
|
void loop();
|
||||||
|
void set_fd_handler(int fd, std::function<void(int, int)> handler);
|
||||||
void handle_epoll_events();
|
void handle_epoll_events();
|
||||||
void read_requests();
|
void read_requests();
|
||||||
void handle_read(ring_data_t *data, int peer_fd);
|
void handle_read(ring_data_t *data, int peer_fd);
|
||||||
|
|
191
osd_http.cpp
191
osd_http.cpp
|
@ -21,10 +21,7 @@ static bool ws_parse_frame(std::string & buf, int & type, std::string & res);
|
||||||
// FIXME: Use keepalive
|
// FIXME: Use keepalive
|
||||||
struct http_co_t
|
struct http_co_t
|
||||||
{
|
{
|
||||||
ring_loop_t *ringloop;
|
|
||||||
timerfd_manager_t *tfd;
|
timerfd_manager_t *tfd;
|
||||||
int epoll_fd;
|
|
||||||
std::map<int, std::function<void(int, int)>> *epoll_handlers;
|
|
||||||
|
|
||||||
int request_timeout = 0;
|
int request_timeout = 0;
|
||||||
std::string host;
|
std::string host;
|
||||||
|
@ -40,12 +37,10 @@ struct http_co_t
|
||||||
int peer_fd = -1;
|
int peer_fd = -1;
|
||||||
int timeout_id = -1;
|
int timeout_id = -1;
|
||||||
int epoll_events = 0;
|
int epoll_events = 0;
|
||||||
ring_data_t *send_data = NULL, *read_data = NULL;
|
|
||||||
int sent = 0;
|
int sent = 0;
|
||||||
std::vector<char> rbuf;
|
std::vector<char> rbuf;
|
||||||
iovec read_iov, send_iov;
|
iovec read_iov, send_iov;
|
||||||
msghdr read_msg = { 0 }, send_msg = { 0 };
|
msghdr read_msg = { 0 }, send_msg = { 0 };
|
||||||
int waiting_read_sqe = 0, waiting_send_sqe = 0;
|
|
||||||
|
|
||||||
std::function<void(const http_response_t*)> callback;
|
std::function<void(const http_response_t*)> callback;
|
||||||
|
|
||||||
|
@ -74,9 +69,6 @@ void osd_t::http_request(const std::string & host, const std::string & request,
|
||||||
const http_options_t & options, std::function<void(const http_response_t *response)> callback)
|
const http_options_t & options, std::function<void(const http_response_t *response)> callback)
|
||||||
{
|
{
|
||||||
http_co_t *handler = new http_co_t();
|
http_co_t *handler = new http_co_t();
|
||||||
handler->ringloop = ringloop;
|
|
||||||
handler->epoll_fd = epoll_fd;
|
|
||||||
handler->epoll_handlers = &epoll_handlers;
|
|
||||||
handler->request_timeout = options.timeout < 0 ? 0 : (options.timeout == 0 ? DEFAULT_TIMEOUT : options.timeout);
|
handler->request_timeout = options.timeout < 0 ? 0 : (options.timeout == 0 ? DEFAULT_TIMEOUT : options.timeout);
|
||||||
handler->want_streaming = options.want_streaming;
|
handler->want_streaming = options.want_streaming;
|
||||||
handler->tfd = tfd;
|
handler->tfd = tfd;
|
||||||
|
@ -124,9 +116,6 @@ websocket_t* osd_t::open_websocket(const std::string & host, const std::string &
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"\r\n";
|
"\r\n";
|
||||||
http_co_t *handler = new http_co_t();
|
http_co_t *handler = new http_co_t();
|
||||||
handler->ringloop = ringloop;
|
|
||||||
handler->epoll_fd = epoll_fd;
|
|
||||||
handler->epoll_handlers = &epoll_handlers;
|
|
||||||
handler->request_timeout = timeout < 0 ? -1 : (timeout == 0 ? DEFAULT_TIMEOUT : timeout);
|
handler->request_timeout = timeout < 0 ? -1 : (timeout == 0 ? DEFAULT_TIMEOUT : timeout);
|
||||||
handler->want_streaming = false;
|
handler->want_streaming = false;
|
||||||
handler->tfd = tfd;
|
handler->tfd = tfd;
|
||||||
|
@ -155,28 +144,9 @@ http_co_t::~http_co_t()
|
||||||
tfd->clear_timer(timeout_id);
|
tfd->clear_timer(timeout_id);
|
||||||
timeout_id = -1;
|
timeout_id = -1;
|
||||||
}
|
}
|
||||||
if (read_data)
|
|
||||||
{
|
|
||||||
// Ignore CQE result
|
|
||||||
read_data->callback = [](ring_data_t *data) {};
|
|
||||||
}
|
|
||||||
else if (waiting_read_sqe)
|
|
||||||
{
|
|
||||||
ringloop->cancel_wait_sqe(waiting_read_sqe);
|
|
||||||
}
|
|
||||||
if (send_data)
|
|
||||||
{
|
|
||||||
// Ignore CQE result
|
|
||||||
send_data->callback = [](ring_data_t *data) {};
|
|
||||||
}
|
|
||||||
else if (waiting_send_sqe)
|
|
||||||
{
|
|
||||||
ringloop->cancel_wait_sqe(waiting_send_sqe);
|
|
||||||
}
|
|
||||||
if (peer_fd >= 0)
|
if (peer_fd >= 0)
|
||||||
{
|
{
|
||||||
epoll_handlers->erase(peer_fd);
|
tfd->set_fd_handler(peer_fd, NULL);
|
||||||
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, peer_fd, NULL);
|
|
||||||
close(peer_fd);
|
close(peer_fd);
|
||||||
peer_fd = -1;
|
peer_fd = -1;
|
||||||
}
|
}
|
||||||
|
@ -231,7 +201,7 @@ void http_co_t::start_connection()
|
||||||
delete this;
|
delete this;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(*epoll_handlers)[peer_fd] = [this](int peer_fd, int epoll_events)
|
tfd->set_fd_handler(peer_fd, [this](int peer_fd, int epoll_events)
|
||||||
{
|
{
|
||||||
this->epoll_events |= epoll_events;
|
this->epoll_events |= epoll_events;
|
||||||
if (state == HTTP_CO_CONNECTING)
|
if (state == HTTP_CO_CONNECTING)
|
||||||
|
@ -249,17 +219,7 @@ void http_co_t::start_connection()
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
// Add FD to epoll (EPOLLOUT for tracking connect() result)
|
|
||||||
epoll_event ev;
|
|
||||||
ev.data.fd = peer_fd;
|
|
||||||
ev.events = EPOLLOUT | EPOLLIN | EPOLLRDHUP | EPOLLET;
|
|
||||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, peer_fd, &ev) < 0)
|
|
||||||
{
|
|
||||||
parsed.error_code = errno;
|
|
||||||
delete this;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
epoll_events = 0;
|
epoll_events = 0;
|
||||||
// Finally call connect
|
// Finally call connect
|
||||||
r = ::connect(peer_fd, (sockaddr*)&addr, sizeof(addr));
|
r = ::connect(peer_fd, (sockaddr*)&addr, sizeof(addr));
|
||||||
|
@ -301,96 +261,83 @@ void http_co_t::handle_connect_result()
|
||||||
|
|
||||||
void http_co_t::submit_read()
|
void http_co_t::submit_read()
|
||||||
{
|
{
|
||||||
if (!read_data && !waiting_read_sqe)
|
int res;
|
||||||
|
again:
|
||||||
|
if (rbuf.size() != READ_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
if (rbuf.size() != READ_BUFFER_SIZE)
|
rbuf.resize(READ_BUFFER_SIZE);
|
||||||
{
|
}
|
||||||
rbuf.resize(READ_BUFFER_SIZE);
|
read_iov = { .iov_base = rbuf.data(), .iov_len = READ_BUFFER_SIZE };
|
||||||
}
|
read_msg.msg_iov = &read_iov;
|
||||||
io_uring_sqe *sqe = ringloop->get_sqe();
|
read_msg.msg_iovlen = 1;
|
||||||
if (!sqe)
|
epoll_events = epoll_events & ~EPOLLIN;
|
||||||
{
|
res = recvmsg(peer_fd, &read_msg, 0);
|
||||||
waiting_read_sqe = ringloop->wait_sqe([this]() { waiting_read_sqe = 0; submit_read(); });
|
if (res < 0)
|
||||||
return;
|
{
|
||||||
}
|
res = -errno;
|
||||||
read_data = ((ring_data_t*)sqe->user_data);
|
}
|
||||||
read_iov = { .iov_base = rbuf.data(), .iov_len = READ_BUFFER_SIZE };
|
if (res == -EAGAIN)
|
||||||
read_msg.msg_iov = &read_iov;
|
{
|
||||||
read_msg.msg_iovlen = 1;
|
res = 0;
|
||||||
epoll_events = epoll_events & ~EPOLLIN;
|
}
|
||||||
read_data->callback = [this](ring_data_t *data)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
read_data = NULL;
|
delete this;
|
||||||
if (data->res == -EAGAIN)
|
return;
|
||||||
{
|
}
|
||||||
data->res = 0;
|
response += std::string(rbuf.data(), res);
|
||||||
}
|
if (res == READ_BUFFER_SIZE)
|
||||||
if (data->res < 0)
|
{
|
||||||
{
|
goto again;
|
||||||
delete this;
|
}
|
||||||
return;
|
if (!handle_read())
|
||||||
}
|
{
|
||||||
response += std::string(rbuf.data(), data->res);
|
return;
|
||||||
if (data->res == READ_BUFFER_SIZE)
|
}
|
||||||
{
|
if (res < READ_BUFFER_SIZE && (epoll_events & (EPOLLRDHUP|EPOLLERR)))
|
||||||
submit_read();
|
{
|
||||||
}
|
delete this;
|
||||||
if (!handle_read())
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (data->res < READ_BUFFER_SIZE && (epoll_events & (EPOLLRDHUP|EPOLLERR)))
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
my_uring_prep_recvmsg(sqe, peer_fd, &read_msg, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_co_t::submit_send()
|
void http_co_t::submit_send()
|
||||||
{
|
{
|
||||||
if (sent < request.size() && !send_data && !waiting_send_sqe)
|
int res;
|
||||||
|
again:
|
||||||
|
if (sent < request.size())
|
||||||
{
|
{
|
||||||
io_uring_sqe *sqe = ringloop->get_sqe();
|
|
||||||
if (!sqe)
|
|
||||||
{
|
|
||||||
waiting_send_sqe = ringloop->wait_sqe([this]() { waiting_send_sqe = 0; submit_send(); });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
send_data = ((ring_data_t*)sqe->user_data);
|
|
||||||
send_iov = (iovec){ .iov_base = (void*)(request.c_str()+sent), .iov_len = request.size()-sent };
|
send_iov = (iovec){ .iov_base = (void*)(request.c_str()+sent), .iov_len = request.size()-sent };
|
||||||
send_msg.msg_iov = &send_iov;
|
send_msg.msg_iov = &send_iov;
|
||||||
send_msg.msg_iovlen = 1;
|
send_msg.msg_iovlen = 1;
|
||||||
send_data->callback = [this](ring_data_t *data)
|
res = sendmsg(peer_fd, &send_msg, 0);
|
||||||
|
if (res < 0)
|
||||||
{
|
{
|
||||||
send_data = NULL;
|
res = -errno;
|
||||||
if (data->res == -EAGAIN)
|
}
|
||||||
{
|
if (res == -EAGAIN)
|
||||||
data->res = 0;
|
{
|
||||||
}
|
res = 0;
|
||||||
else if (data->res < 0)
|
}
|
||||||
{
|
else if (res < 0)
|
||||||
delete this;
|
{
|
||||||
return;
|
delete this;
|
||||||
}
|
return;
|
||||||
sent += data->res;
|
}
|
||||||
if (state == HTTP_CO_SENDING_REQUEST)
|
sent += res;
|
||||||
{
|
if (state == HTTP_CO_SENDING_REQUEST)
|
||||||
if (sent >= request.size())
|
{
|
||||||
state = HTTP_CO_REQUEST_SENT;
|
if (sent >= request.size())
|
||||||
else
|
state = HTTP_CO_REQUEST_SENT;
|
||||||
submit_send();
|
else
|
||||||
}
|
goto again;
|
||||||
else if (state == HTTP_CO_WEBSOCKET)
|
}
|
||||||
{
|
else if (state == HTTP_CO_WEBSOCKET)
|
||||||
request = request.substr(sent);
|
{
|
||||||
sent = 0;
|
request = request.substr(sent);
|
||||||
submit_send();
|
sent = 0;
|
||||||
}
|
goto again;
|
||||||
};
|
}
|
||||||
my_uring_prep_sendmsg(sqe, peer_fd, &send_msg, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,29 @@
|
||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
#include "timerfd_manager.h"
|
#include "timerfd_manager.h"
|
||||||
|
|
||||||
timerfd_manager_t::timerfd_manager_t(ring_loop_t *ringloop)
|
timerfd_manager_t::timerfd_manager_t(std::function<void(int, std::function<void(int, int)>)> set_fd_handler)
|
||||||
{
|
{
|
||||||
|
this->set_fd_handler = set_fd_handler;
|
||||||
wait_state = 0;
|
wait_state = 0;
|
||||||
timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||||
if (timerfd < 0)
|
if (timerfd < 0)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(std::string("timerfd_create: ") + strerror(errno));
|
throw std::runtime_error(std::string("timerfd_create: ") + strerror(errno));
|
||||||
}
|
}
|
||||||
consumer.loop = [this]() { loop(); };
|
set_fd_handler(timerfd, [this](int fd, int events)
|
||||||
ringloop->register_consumer(&consumer);
|
{
|
||||||
this->ringloop = ringloop;
|
handle_readable();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
timerfd_manager_t::~timerfd_manager_t()
|
timerfd_manager_t::~timerfd_manager_t()
|
||||||
{
|
{
|
||||||
ringloop->unregister_consumer(&consumer);
|
set_fd_handler(timerfd, NULL);
|
||||||
close(timerfd);
|
close(timerfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +53,6 @@ int timerfd_manager_t::set_timer(uint64_t millis, bool repeat, std::function<voi
|
||||||
});
|
});
|
||||||
inc_timer(timers[timers.size()-1]);
|
inc_timer(timers[timers.size()-1]);
|
||||||
set_nearest();
|
set_nearest();
|
||||||
set_wait();
|
|
||||||
return timer_id;
|
return timer_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +73,6 @@ void timerfd_manager_t::clear_timer(int timer_id)
|
||||||
nearest--;
|
nearest--;
|
||||||
}
|
}
|
||||||
set_nearest();
|
set_nearest();
|
||||||
set_wait();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,53 +123,25 @@ void timerfd_manager_t::set_nearest()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void timerfd_manager_t::loop()
|
void timerfd_manager_t::handle_readable()
|
||||||
{
|
{
|
||||||
if (!(wait_state & 1) && timers.size())
|
uint64_t n;
|
||||||
|
size_t res = read(timerfd, &n, 8);
|
||||||
|
if (res == 8 && nearest >= 0)
|
||||||
{
|
{
|
||||||
set_nearest();
|
int nearest_id = timers[nearest].id;
|
||||||
}
|
auto cb = timers[nearest].callback;
|
||||||
set_wait();
|
if (timers[nearest].repeat)
|
||||||
}
|
|
||||||
|
|
||||||
void timerfd_manager_t::set_wait()
|
|
||||||
{
|
|
||||||
if ((wait_state & 3) == 1)
|
|
||||||
{
|
|
||||||
io_uring_sqe *sqe = ringloop->get_sqe();
|
|
||||||
if (!sqe)
|
|
||||||
{
|
{
|
||||||
return;
|
inc_timer(timers[nearest]);
|
||||||
}
|
}
|
||||||
ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
else
|
||||||
my_uring_prep_poll_add(sqe, timerfd, POLLIN);
|
|
||||||
data->callback = [this](ring_data_t *data)
|
|
||||||
{
|
{
|
||||||
if (data->res < 0)
|
timers.erase(timers.begin()+nearest, timers.begin()+nearest+1);
|
||||||
{
|
}
|
||||||
throw std::runtime_error(std::string("waiting for timer failed: ") + strerror(-data->res));
|
cb(nearest_id);
|
||||||
}
|
nearest = -1;
|
||||||
uint64_t n;
|
|
||||||
read(timerfd, &n, 8);
|
|
||||||
if (nearest >= 0)
|
|
||||||
{
|
|
||||||
int nearest_id = timers[nearest].id;
|
|
||||||
auto cb = timers[nearest].callback;
|
|
||||||
if (timers[nearest].repeat)
|
|
||||||
{
|
|
||||||
inc_timer(timers[nearest]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timers.erase(timers.begin()+nearest, timers.begin()+nearest+1);
|
|
||||||
}
|
|
||||||
cb(nearest_id);
|
|
||||||
nearest = -1;
|
|
||||||
}
|
|
||||||
wait_state = 0;
|
|
||||||
set_nearest();
|
|
||||||
set_wait();
|
|
||||||
};
|
|
||||||
wait_state = 3;
|
|
||||||
}
|
}
|
||||||
|
wait_state = 0;
|
||||||
|
set_nearest();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "ringloop.h"
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
struct timerfd_timer_t
|
struct timerfd_timer_t
|
||||||
{
|
{
|
||||||
|
@ -19,16 +20,15 @@ class timerfd_manager_t
|
||||||
int nearest = -1;
|
int nearest = -1;
|
||||||
int id = 1;
|
int id = 1;
|
||||||
std::vector<timerfd_timer_t> timers;
|
std::vector<timerfd_timer_t> timers;
|
||||||
ring_loop_t *ringloop;
|
|
||||||
ring_consumer_t consumer;
|
|
||||||
|
|
||||||
void inc_timer(timerfd_timer_t & t);
|
void inc_timer(timerfd_timer_t & t);
|
||||||
void set_nearest();
|
void set_nearest();
|
||||||
void set_wait();
|
|
||||||
void loop();
|
|
||||||
public:
|
public:
|
||||||
timerfd_manager_t(ring_loop_t *ringloop);
|
std::function<void(int, std::function<void(int, int)>)> set_fd_handler;
|
||||||
|
|
||||||
|
timerfd_manager_t(std::function<void(int, std::function<void(int, int)>)> set_fd_handler);
|
||||||
~timerfd_manager_t();
|
~timerfd_manager_t();
|
||||||
int set_timer(uint64_t millis, bool repeat, std::function<void(int)> callback);
|
int set_timer(uint64_t millis, bool repeat, std::function<void(int)> callback);
|
||||||
void clear_timer(int timer_id);
|
void clear_timer(int timer_id);
|
||||||
|
void handle_readable();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue