Skip to content

Commit ead61aa

Browse files
committed
quic: improve packet definition
Handful of additional improvements to the Packet class. Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode:Opus 4.6
1 parent 9b9bf0c commit ead61aa

File tree

3 files changed

+58
-85
lines changed

3 files changed

+58
-85
lines changed

src/quic/arena.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ class ArenaPool final : public MemoryRetainer {
5555
// Construct T in an acquired slot with forwarded args.
5656
// Returns an empty Ptr only on allocation failure.
5757
template <typename... Args>
58-
Ptr Acquire(Args&&... args);
58+
[[nodiscard]] Ptr Acquire(Args&&... args);
5959

6060
// Construct T with (extra_data_ptr, extra_bytes, ...args).
6161
// Use this for types whose constructor accepts a trailing data
6262
// buffer as its first two parameters.
6363
template <typename... Args>
64-
Ptr AcquireExtra(Args&&... args);
64+
[[nodiscard]] Ptr AcquireExtra(Args&&... args);
6565

6666
// Release a raw T* previously detached via Ptr::release().
6767
// Calls ~T() and returns the slot to the pool's free list.
@@ -199,7 +199,7 @@ class ArenaPool<T>::Ptr final {
199199
// Detach ownership. The caller takes responsibility for eventually
200200
// calling ArenaPool<T>::Release(ptr) to destruct T and return
201201
// the slot to the pool.
202-
T* release() noexcept {
202+
[[nodiscard]] T* release() noexcept {
203203
if (!slot_) return nullptr;
204204
T* obj = ObjectFromSlot(slot_);
205205
slot_ = nullptr;

src/quic/packet.cc

Lines changed: 6 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
#include "packet.h"
1616
#include "tokens.h"
1717

18-
namespace node {
19-
namespace quic {
18+
namespace node::quic {
2019

2120
namespace {
2221
static constexpr size_t kRandlen = NGTCP2_MIN_STATELESS_RESET_RANDLEN * 5;
@@ -43,57 +42,12 @@ Packet::Packet(uint8_t* data,
4342
size_t capacity,
4443
Listener* listener,
4544
const SocketAddress& destination)
46-
: req_{},
45+
: data_(data),
46+
capacity_(capacity),
47+
length_(capacity),
4748
listener_(listener),
4849
destination_(destination),
49-
data_(data),
50-
capacity_(capacity),
51-
length_(capacity) {}
52-
53-
const SocketAddress& Packet::destination() const {
54-
return destination_;
55-
}
56-
57-
Packet::Listener* Packet::listener() const {
58-
return listener_;
59-
}
60-
61-
size_t Packet::length() const {
62-
return length_;
63-
}
64-
65-
size_t Packet::capacity() const {
66-
return capacity_;
67-
}
68-
69-
uint8_t* Packet::data() {
70-
return data_;
71-
}
72-
73-
const uint8_t* Packet::data() const {
74-
return data_;
75-
}
76-
77-
Packet::operator uv_buf_t() const {
78-
return uv_buf_init(reinterpret_cast<char*>(data_), length_);
79-
}
80-
81-
Packet::operator ngtcp2_vec() const {
82-
return ngtcp2_vec{data_, length_};
83-
}
84-
85-
void Packet::Truncate(size_t len) {
86-
DCHECK_LE(len, capacity_);
87-
length_ = len;
88-
}
89-
90-
uv_udp_send_t* Packet::req() {
91-
return &req_;
92-
}
93-
94-
Packet* Packet::FromReq(uv_udp_send_t* req) {
95-
return ContainerOf(&Packet::req_, req);
96-
}
50+
req_{} {}
9751

9852
std::string Packet::ToString() const {
9953
std::string res = "Packet(";
@@ -264,8 +218,7 @@ Packet::Ptr Packet::CreateVersionNegotiationPacket(
264218
return packet;
265219
}
266220

267-
} // namespace quic
268-
} // namespace node
221+
} // namespace node::quic
269222

270223
#endif // OPENSSL_NO_QUIC
271224
#endif // HAVE_OPENSSL && HAVE_QUIC

src/quic/packet.h

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include <ngtcp2/ngtcp2.h>
66
#include <node_sockaddr.h>
77
#include <uv.h>
8-
#include <v8.h>
98
#include <string>
109
#include "arena.h"
1110
#include "cid.h"
@@ -39,6 +38,10 @@ struct PathDescriptor final {
3938
//
4039
// Packets are always encrypted; their content is opaque. We leave it
4140
// entirely up to ngtcp2 how to encode QUIC frames into the packet.
41+
//
42+
// Member layout is ordered so that fields touched on the hot path
43+
// (data_, capacity_, length_, listener_) share the first cache line.
44+
// The uv_udp_send_t (320 bytes, only touched by libuv) is placed last.
4245
class Packet final {
4346
public:
4447
using Ptr = ArenaPool<Packet>::Ptr;
@@ -58,49 +61,61 @@ class Packet final {
5861

5962
DISALLOW_COPY_AND_MOVE(Packet)
6063

61-
const SocketAddress& destination() const;
62-
Listener* listener() const;
63-
size_t length() const;
64-
size_t capacity() const;
65-
uint8_t* data();
66-
const uint8_t* data() const;
67-
operator uv_buf_t() const;
68-
operator ngtcp2_vec() const;
64+
// --- Inline accessors (hot path) ---
65+
66+
uint8_t* data() { return data_; }
67+
const uint8_t* data() const { return data_; }
68+
size_t length() const { return length_; }
69+
size_t capacity() const { return capacity_; }
70+
const SocketAddress& destination() const { return destination_; }
71+
Listener* listener() const { return listener_; }
72+
uv_udp_send_t* req() { return &req_; }
73+
74+
operator uv_buf_t() const {
75+
return uv_buf_init(reinterpret_cast<char*>(data_), length_);
76+
}
77+
operator ngtcp2_vec() const { return ngtcp2_vec{data_, length_}; }
6978

7079
// Modify the logical size of the packet after ngtcp2 has written
7180
// to it. len must be <= capacity().
72-
void Truncate(size_t len);
73-
74-
uv_udp_send_t* req();
81+
void Truncate(size_t len) {
82+
DCHECK_LE(len, capacity_);
83+
length_ = len;
84+
}
7585

7686
// Recover Packet* from a uv_udp_send_t* in the libuv send callback.
77-
static Packet* FromReq(uv_udp_send_t* req);
87+
static Packet* FromReq(uv_udp_send_t* req) {
88+
return ContainerOf(&Packet::req_, req);
89+
}
7890

7991
// --- Static factory methods ---
8092
// These create fully-formed packets for specific QUIC operations.
8193
// They acquire from the endpoint's packet pool and return Ptr.
8294
// An empty Ptr indicates failure.
8395

84-
static Ptr CreateRetryPacket(Endpoint& endpoint,
85-
const PathDescriptor& path_descriptor,
86-
const TokenSecret& token_secret);
96+
[[nodiscard]] static Ptr CreateRetryPacket(
97+
Endpoint& endpoint,
98+
const PathDescriptor& path_descriptor,
99+
const TokenSecret& token_secret);
87100

88-
static Ptr CreateConnectionClosePacket(Endpoint& endpoint,
89-
const SocketAddress& destination,
90-
ngtcp2_conn* conn,
91-
const QuicError& error);
101+
[[nodiscard]] static Ptr CreateConnectionClosePacket(
102+
Endpoint& endpoint,
103+
const SocketAddress& destination,
104+
ngtcp2_conn* conn,
105+
const QuicError& error);
92106

93-
static Ptr CreateImmediateConnectionClosePacket(
107+
[[nodiscard]] static Ptr CreateImmediateConnectionClosePacket(
94108
Endpoint& endpoint,
95109
const PathDescriptor& path_descriptor,
96110
const QuicError& reason);
97111

98-
static Ptr CreateStatelessResetPacket(Endpoint& endpoint,
99-
const PathDescriptor& path_descriptor,
100-
const TokenSecret& token_secret,
101-
size_t source_len);
112+
[[nodiscard]] static Ptr CreateStatelessResetPacket(
113+
Endpoint& endpoint,
114+
const PathDescriptor& path_descriptor,
115+
const TokenSecret& token_secret,
116+
size_t source_len);
102117

103-
static Ptr CreateVersionNegotiationPacket(
118+
[[nodiscard]] static Ptr CreateVersionNegotiationPacket(
104119
Endpoint& endpoint, const PathDescriptor& path_descriptor);
105120

106121
// --- Diagnostic label: zero cost in release builds ---
@@ -113,12 +128,17 @@ class Packet final {
113128
std::string ToString() const;
114129

115130
private:
116-
uv_udp_send_t req_;
117-
Listener* listener_;
118-
SocketAddress destination_;
131+
// Hot fields first — all on cache line 0 during the fill loop.
119132
uint8_t* data_;
120133
size_t capacity_;
121134
size_t length_;
135+
Listener* listener_;
136+
137+
// Touched at send time.
138+
SocketAddress destination_;
139+
140+
// Only touched by libuv during uv_udp_send and in the send callback.
141+
uv_udp_send_t req_;
122142

123143
#ifdef DEBUG
124144
const char* diagnostic_label_ = nullptr;

0 commit comments

Comments
 (0)