From 74f6fb5482f2130d816b19e79a2bba0a9f90461e Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 15 Jan 2020 11:44:44 -0800 Subject: [PATCH] quic: make QuicCID more efficient Much of the time, QuicCID is wrapping a `const ngtcp2_cid*`, when that is the case, avoid copying it's value and use the pointer directly. Otherwise, allocate an internal buffer. --- src/quic/node_quic_session.cc | 5 +-- src/quic/node_quic_util-inl.h | 19 +++++------ src/quic/node_quic_util.h | 61 ++++++++++++++++++++++++----------- 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/quic/node_quic_session.cc b/src/quic/node_quic_session.cc index 55c429b6f2..fc0b990e6b 100644 --- a/src/quic/node_quic_session.cc +++ b/src/quic/node_quic_session.cc @@ -1465,7 +1465,6 @@ void QuicSession::AckedStreamDataOffset( // be associated with the new QuicSocket. void QuicSession::AddToSocket(QuicSocket* socket) { socket->AddSession(scid_, BaseObjectPtr(this)); - switch (crypto_context_->side()) { case NGTCP2_CRYPTO_SIDE_SERVER: { socket->AssociateCID(rcid_, scid_); @@ -1475,8 +1474,9 @@ void QuicSession::AddToSocket(QuicSocket* socket) { case NGTCP2_CRYPTO_SIDE_CLIENT: { std::vector cids(ngtcp2_conn_get_num_scid(connection())); ngtcp2_conn_get_scid(connection(), cids.data()); - for (const ngtcp2_cid& cid : cids) + for (const ngtcp2_cid& cid : cids) { socket->AssociateCID(QuicCID(&cid), scid_); + } break; } default: @@ -2748,6 +2748,7 @@ BaseObjectPtr QuicSession::CreateClient( qlog); session->AddToSocket(socket); + return session; } diff --git a/src/quic/node_quic_util-inl.h b/src/quic/node_quic_util-inl.h index 044bcb9dc2..f054c60b8e 100644 --- a/src/quic/node_quic_util-inl.h +++ b/src/quic/node_quic_util-inl.h @@ -33,29 +33,26 @@ QuicPath::QuicPath( size_t QuicCID::Hash::operator()(const QuicCID& token) const { size_t hash = 0; - for (size_t n = 0; n < token.cid_.datalen; n++) - hash ^= std::hash{}(token.cid_.data[n]) + 0x9e3779b9 + + for (size_t n = 0; n < token->datalen; n++) { + hash ^= std::hash{}(token->data[n]) + 0x9e3779b9 + (hash << 6) + (hash >> 2); + } return hash; } bool QuicCID::Compare::operator()( const QuicCID& lcid, const QuicCID& rcid) const { - if (lcid.cid_.datalen != rcid.cid_.datalen) - return false; - return memcmp( - lcid.cid_.data, - rcid.cid_.data, - lcid.cid_.datalen) == 0; + return lcid->datalen != rcid->datalen ? + false : memcmp(lcid->data, rcid->data, lcid->datalen) == 0; } std::string QuicCID::ToHex() const { - std::vector dest(cid_.datalen * 2 + 1); + std::vector dest(ptr_->datalen * 2 + 1); dest[dest.size() - 1] = '\0'; size_t written = StringBytes::hex_encode( - reinterpret_cast(cid_.data), - cid_.datalen, + reinterpret_cast(ptr_->data), + ptr_->datalen, dest.data(), dest.size()); return std::string(dest.data(), written); diff --git a/src/quic/node_quic_util.h b/src/quic/node_quic_util.h index 83a0ab1070..65231e4836 100644 --- a/src/quic/node_quic_util.h +++ b/src/quic/node_quic_util.h @@ -198,12 +198,24 @@ struct QuicPathStorage : public ngtcp2_path_storage { // Simple wrapper for ngtcp2_cid that handles hex encoding class QuicCID : public MemoryRetainer { public: - QuicCID() {} - QuicCID(const QuicCID& cid) : cid_(cid.cid_) {} - explicit QuicCID(const ngtcp2_cid* cid) : cid_(*cid) {} - explicit QuicCID(const ngtcp2_cid& cid) : cid_(cid) {} - QuicCID(const uint8_t* cid, size_t len) { - ngtcp2_cid_init(&cid_, cid, len); + // Empty constructor + QuicCID() : buf_(sizeof(ngtcp2_cid)) { + ptr_ = reinterpret_cast(buf_.data()); + } + + // Copy constructor + QuicCID(const QuicCID& cid) : QuicCID(cid->data, cid->datalen) {} + + // Copy constructor + explicit QuicCID(const ngtcp2_cid& cid) : QuicCID(cid.data, cid.datalen) {} + + // Wrap constructor + explicit QuicCID(const ngtcp2_cid* cid) : ptr_(cid) {} + + QuicCID(const uint8_t* cid, size_t len) : QuicCID() { + ngtcp2_cid* ptr = this->cid(); + ngtcp2_cid_init(ptr, cid, len); + ptr_ = ptr; } struct Hash { @@ -216,28 +228,41 @@ class QuicCID : public MemoryRetainer { inline std::string ToHex() const; + // Copy assignment QuicCID& operator=(const QuicCID& cid) { - cid_ = cid.cid_; - return *this; + if (this == &cid) return *this; + this->~QuicCID(); + return *new(this) QuicCID(std::move(cid)); } - const ngtcp2_cid& operator*() const { return cid_; } - const ngtcp2_cid* operator->() const { return &cid_; } - const ngtcp2_cid* cid() const { return &cid_; } - ngtcp2_cid* cid() { return &cid_; } - operator bool() const { return cid_.datalen > 0; } - const uint8_t* data() const { return cid_.data; } - size_t length() const { return cid_.datalen; } + const ngtcp2_cid& operator*() const { return *ptr_; } + const ngtcp2_cid* operator->() const { return ptr_; } + const ngtcp2_cid* cid() const { return ptr_; } + const uint8_t* data() const { return ptr_->data; } + operator bool() const { return ptr_->datalen > 0; } + size_t length() const { return ptr_->datalen; } + + ngtcp2_cid* cid() { + ngtcp2_cid* cid = reinterpret_cast(buf_.data()); + CHECK_EQ(ptr_, cid); + return cid; + } + + unsigned char* data() { + return reinterpret_cast(cid()->data); + } - unsigned char* data() { return reinterpret_cast(cid_.data); } - void set_length(size_t length) { cid_.datalen = length; } + void set_length(size_t length) { + cid()->datalen = length; + } SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(QuicCID) SET_SELF_SIZE(QuicCID) private: - ngtcp2_cid cid_; + std::vector buf_; + const ngtcp2_cid* ptr_; }; // Simple timer wrapper that is used to implement the internals