nghttpx: Fix bugs and crash when affinity is enabled

This commit is contained in:
Tatsuhiro Tsujikawa 2016-06-09 23:17:41 +09:00
parent 143d0b69b7
commit f9897f8ccd
9 changed files with 52 additions and 14 deletions

View File

@ -302,4 +302,6 @@ APIDownstreamConnection::get_downstream_addr_group() const {
return nullptr; return nullptr;
} }
DownstreamAddr *APIDownstreamConnection::get_addr() const { return nullptr; }
} // namespace shrpx } // namespace shrpx

View File

@ -55,6 +55,7 @@ public:
virtual bool poolable() const; virtual bool poolable() const;
virtual DownstreamAddrGroup *get_downstream_addr_group() const; virtual DownstreamAddrGroup *get_downstream_addr_group() const;
virtual DownstreamAddr *get_addr() const;
int send_reply(unsigned int http_status, int api_status); int send_reply(unsigned int http_status, int api_status);

View File

@ -669,8 +669,18 @@ void ClientHandler::pool_downstream_connection(
<< " in group " << group; << " in group " << group;
} }
auto &dconn_pool = group->shared_addr->dconn_pool; auto &shared_addr = group->shared_addr;
dconn_pool.add_downstream_connection(std::move(dconn));
if (shared_addr->affinity == AFFINITY_NONE) {
auto &dconn_pool = group->shared_addr->dconn_pool;
dconn_pool.add_downstream_connection(std::move(dconn));
return;
}
auto addr = dconn->get_addr();
auto &dconn_pool = addr->dconn_pool;
dconn_pool->add_downstream_connection(std::move(dconn));
} }
void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn) { void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn) {
@ -715,7 +725,6 @@ Http2Session *ClientHandler::select_http2_session_with_affinity(
if (addr->http2_extra_freelist.size()) { if (addr->http2_extra_freelist.size()) {
auto session = addr->http2_extra_freelist.head; auto session = addr->http2_extra_freelist.head;
session->remove_from_freelist();
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "Use Http2Session " << session CLOG(INFO, this) << "Use Http2Session " << session
@ -727,8 +736,8 @@ Http2Session *ClientHandler::select_http2_session_with_affinity(
CLOG(INFO, this) << "Maximum streams are reached for Http2Session(" CLOG(INFO, this) << "Maximum streams are reached for Http2Session("
<< session << ")."; << session << ").";
} }
} else {
session->add_to_avail_freelist(); session->remove_from_freelist();
} }
return session; return session;
} }
@ -740,7 +749,7 @@ Http2Session *ClientHandler::select_http2_session_with_affinity(
CLOG(INFO, this) << "Create new Http2Session " << session; CLOG(INFO, this) << "Create new Http2Session " << session;
} }
session->add_to_avail_freelist(); session->add_to_extra_freelist();
return session; return session;
} }

View File

@ -35,6 +35,7 @@ class ClientHandler;
class Upstream; class Upstream;
class Downstream; class Downstream;
struct DownstreamAddrGroup; struct DownstreamAddrGroup;
struct DownstreamAddr;
class DownstreamConnection { class DownstreamConnection {
public: public:
@ -61,6 +62,7 @@ public:
virtual bool poolable() const = 0; virtual bool poolable() const = 0;
virtual DownstreamAddrGroup *get_downstream_addr_group() const = 0; virtual DownstreamAddrGroup *get_downstream_addr_group() const = 0;
virtual DownstreamAddr *get_addr() const = 0;
void set_client_handler(ClientHandler *client_handler); void set_client_handler(ClientHandler *client_handler);
ClientHandler *get_client_handler(); ClientHandler *get_client_handler();

View File

@ -543,4 +543,6 @@ Http2DownstreamConnection::get_downstream_addr_group() const {
return http2session_->get_downstream_addr_group(); return http2session_->get_downstream_addr_group();
} }
DownstreamAddr *Http2DownstreamConnection::get_addr() const { return nullptr; }
} // namespace shrpx } // namespace shrpx

View File

@ -65,6 +65,7 @@ public:
virtual bool poolable() const { return false; } virtual bool poolable() const { return false; }
virtual DownstreamAddrGroup *get_downstream_addr_group() const; virtual DownstreamAddrGroup *get_downstream_addr_group() const;
virtual DownstreamAddr *get_addr() const;
int send(); int send();

View File

@ -562,6 +562,24 @@ int HttpDownstreamConnection::end_upload_data() {
return 0; return 0;
} }
namespace {
void remove_from_pool(HttpDownstreamConnection *dconn) {
auto group = dconn->get_downstream_addr_group();
auto &shared_addr = group->shared_addr;
if (shared_addr->affinity == AFFINITY_NONE) {
auto &dconn_pool =
dconn->get_downstream_addr_group()->shared_addr->dconn_pool;
dconn_pool.remove_downstream_connection(dconn);
return;
}
auto addr = dconn->get_addr();
auto &dconn_pool = addr->dconn_pool;
dconn_pool->remove_downstream_connection(dconn);
}
} // namespace
namespace { namespace {
void idle_readcb(struct ev_loop *loop, ev_io *w, int revents) { void idle_readcb(struct ev_loop *loop, ev_io *w, int revents) {
auto conn = static_cast<Connection *>(w->data); auto conn = static_cast<Connection *>(w->data);
@ -569,9 +587,8 @@ void idle_readcb(struct ev_loop *loop, ev_io *w, int revents) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
DCLOG(INFO, dconn) << "Idle connection EOF"; DCLOG(INFO, dconn) << "Idle connection EOF";
} }
auto &dconn_pool =
dconn->get_downstream_addr_group()->shared_addr->dconn_pool; remove_from_pool(dconn);
dconn_pool.remove_downstream_connection(dconn);
// dconn was deleted // dconn was deleted
} }
} // namespace } // namespace
@ -583,9 +600,8 @@ void idle_timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
DCLOG(INFO, dconn) << "Idle connection timeout"; DCLOG(INFO, dconn) << "Idle connection timeout";
} }
auto &dconn_pool =
dconn->get_downstream_addr_group()->shared_addr->dconn_pool; remove_from_pool(dconn);
dconn_pool.remove_downstream_connection(dconn);
// dconn was deleted // dconn was deleted
} }
} // namespace } // namespace

View File

@ -65,6 +65,7 @@ public:
virtual bool poolable() const; virtual bool poolable() const;
virtual DownstreamAddrGroup *get_downstream_addr_group() const; virtual DownstreamAddrGroup *get_downstream_addr_group() const;
virtual DownstreamAddr *get_addr() const;
int read_clear(); int read_clear();
int write_clear(); int write_clear();
@ -80,8 +81,6 @@ public:
int noop(); int noop();
DownstreamAddr *get_addr() const;
private: private:
Connection conn_; Connection conn_;
std::function<int(HttpDownstreamConnection &)> do_read_, do_write_, std::function<int(HttpDownstreamConnection &)> do_read_, do_write_,

View File

@ -96,6 +96,9 @@ struct DownstreamAddr {
// Http2Session object created for this address. This list chains // Http2Session object created for this address. This list chains
// all Http2Session objects that is not in group scope // all Http2Session objects that is not in group scope
// http2_avail_freelist, and is not reached in maximum concurrency. // http2_avail_freelist, and is not reached in maximum concurrency.
//
// If session affinity is enabled, http2_avail_freelist is not used,
// and this list is solely used.
DList<Http2Session> http2_extra_freelist; DList<Http2Session> http2_extra_freelist;
// true if Http2Session for this address is in group scope // true if Http2Session for this address is in group scope
// SharedDownstreamAddr.http2_avail_freelist // SharedDownstreamAddr.http2_avail_freelist
@ -129,6 +132,9 @@ struct SharedDownstreamAddr {
// coalesce as much stream as possible in one Http2Session to fully // coalesce as much stream as possible in one Http2Session to fully
// utilize TCP connection. // utilize TCP connection.
// //
// If session affinity is enabled, this list is not used. Per
// address http2_extra_freelist is used instead.
//
// TODO Verify that this approach performs better in performance // TODO Verify that this approach performs better in performance
// wise. // wise.
DList<Http2Session> http2_avail_freelist; DList<Http2Session> http2_avail_freelist;