Line data Source code
1 : #pragma once
2 :
3 : #include <cstdint>
4 : #include <functional>
5 : #include <memory>
6 : #include <string>
7 :
8 : #include "envoy/api/os_sys_calls.h"
9 : #include "envoy/common/exception.h"
10 : #include "envoy/common/platform.h"
11 : #include "envoy/common/pure.h"
12 : #include "envoy/http/stream_reset_handler.h"
13 :
14 : #include "source/common/common/assert.h"
15 : #include "source/common/common/byte_order.h"
16 : #include "source/common/common/utility.h"
17 :
18 : #include "absl/container/inlined_vector.h"
19 : #include "absl/strings/string_view.h"
20 : #include "absl/types/optional.h"
21 : #include "absl/types/span.h"
22 :
23 : namespace Envoy {
24 : namespace Buffer {
25 :
26 : /**
27 : * A raw memory data slice including location and length.
28 : */
29 : struct RawSlice {
30 : void* mem_ = nullptr;
31 : size_t len_ = 0;
32 :
33 0 : bool operator==(const RawSlice& rhs) const { return mem_ == rhs.mem_ && len_ == rhs.len_; }
34 0 : bool operator!=(const RawSlice& rhs) const { return !(*this == rhs); }
35 : };
36 :
37 : /**
38 : * A const raw memory data slice including the location and length.
39 : */
40 : struct ConstRawSlice {
41 : const void* mem_ = nullptr;
42 : size_t len_ = 0;
43 :
44 0 : bool operator==(const RawSlice& rhs) const { return mem_ == rhs.mem_ && len_ == rhs.len_; }
45 0 : bool operator!=(const RawSlice& rhs) const { return !(*this == rhs); }
46 : };
47 :
48 : using RawSliceVector = absl::InlinedVector<RawSlice, 16>;
49 :
50 : /**
51 : * A wrapper class to facilitate passing in externally owned data to a buffer via addBufferFragment.
52 : * When the buffer no longer needs the data passed in through a fragment, it calls done() on it.
53 : */
54 : class BufferFragment {
55 : public:
56 3147 : virtual ~BufferFragment() = default;
57 : /**
58 : * @return const void* a pointer to the referenced data.
59 : */
60 : virtual const void* data() const PURE;
61 :
62 : /**
63 : * @return size_t the size of the referenced data.
64 : */
65 : virtual size_t size() const PURE;
66 :
67 : /**
68 : * Called by a buffer when the referenced data is no longer needed.
69 : */
70 : virtual void done() PURE;
71 : };
72 :
73 : /**
74 : * A class to facilitate extracting buffer slices from a buffer instance.
75 : */
76 : class SliceData {
77 : public:
78 0 : virtual ~SliceData() = default;
79 :
80 : /**
81 : * @return a mutable view of the slice data.
82 : */
83 : virtual absl::Span<uint8_t> getMutableData() PURE;
84 : };
85 :
86 : using SliceDataPtr = std::unique_ptr<SliceData>;
87 :
88 : class Reservation;
89 : class ReservationSingleSlice;
90 :
91 : // Base class for an object to manage the ownership for slices in a `Reservation` or
92 : // `ReservationSingleSlice`.
93 : class ReservationSlicesOwner {
94 : public:
95 8894 : virtual ~ReservationSlicesOwner() = default;
96 : };
97 :
98 : using ReservationSlicesOwnerPtr = std::unique_ptr<ReservationSlicesOwner>;
99 :
100 : /**
101 : * An interface for accounting for the usage for byte tracking in buffers.
102 : *
103 : * Currently this is only used by L7 streams to track the amount of memory
104 : * allocated in buffers by the stream.
105 : */
106 : class BufferMemoryAccount {
107 : public:
108 0 : virtual ~BufferMemoryAccount() = default;
109 :
110 : /**
111 : * Charges the account for using the specified amount of memory.
112 : *
113 : * @param amount the amount to debit.
114 : */
115 : virtual void charge(uint64_t amount) PURE;
116 :
117 : /**
118 : * Called to credit the account for an amount of memory
119 : * is no longer used.
120 : *
121 : * @param amount the amount to credit.
122 : */
123 : virtual void credit(uint64_t amount) PURE;
124 :
125 : /**
126 : * Clears the associated downstream with this account.
127 : * After this has been called, calls to reset the downstream become no-ops.
128 : * Must be called before downstream is deleted.
129 : */
130 : virtual void clearDownstream() PURE;
131 :
132 : /**
133 : * Reset the downstream stream associated with this account. Resetting the downstream stream
134 : * should trigger a reset of the corresponding upstream stream if it exists.
135 : */
136 : virtual void resetDownstream() PURE;
137 : };
138 :
139 : using BufferMemoryAccountSharedPtr = std::shared_ptr<BufferMemoryAccount>;
140 :
141 : /**
142 : * A basic buffer abstraction.
143 : */
144 : class Instance {
145 : public:
146 2223154 : virtual ~Instance() = default;
147 :
148 : /**
149 : * Register function to call when the last byte in the last slice of this
150 : * buffer has fully drained. Note that slices may be transferred to
151 : * downstream buffers, drain trackers are transferred along with the bytes
152 : * they track so the function is called only after the last byte is drained
153 : * from all buffers.
154 : */
155 : virtual void addDrainTracker(std::function<void()> drain_tracker) PURE;
156 :
157 : /**
158 : * Binds the account to be charged for resources used by the buffer. This
159 : * should only be called when the buffer is empty as existing slices
160 : * within the buffer won't retroactively get tagged.
161 : *
162 : * @param account a shared_ptr to the account to charge.
163 : */
164 : virtual void bindAccount(BufferMemoryAccountSharedPtr account) PURE;
165 :
166 : /**
167 : * Copy data into the buffer (deprecated, use absl::string_view variant
168 : * instead).
169 : * TODO(htuch): Cleanup deprecated call sites.
170 : * @param data supplies the data address.
171 : * @param size supplies the data size.
172 : */
173 : virtual void add(const void* data, uint64_t size) PURE;
174 :
175 : /**
176 : * Add externally owned data into the buffer. No copying is done. fragment is not owned. When
177 : * the fragment->data() is no longer needed, fragment->done() is called.
178 : * @param fragment the externally owned data to add to the buffer.
179 : */
180 : virtual void addBufferFragment(BufferFragment& fragment) PURE;
181 :
182 : /**
183 : * Copy a string into the buffer.
184 : * @param data supplies the string to copy.
185 : */
186 : virtual void add(absl::string_view data) PURE;
187 :
188 : /**
189 : * Copy another buffer into this buffer.
190 : * @param data supplies the buffer to copy.
191 : */
192 : virtual void add(const Instance& data) PURE;
193 :
194 : /**
195 : * Prepend a string_view to the buffer.
196 : * @param data supplies the string_view to copy.
197 : */
198 : virtual void prepend(absl::string_view data) PURE;
199 :
200 : /**
201 : * Prepend data from another buffer to this buffer.
202 : * The supplied buffer is drained after this operation.
203 : * @param data supplies the buffer to copy.
204 : */
205 : virtual void prepend(Instance& data) PURE;
206 :
207 : /**
208 : * Copy out a section of the buffer.
209 : * @param start supplies the buffer index to start copying from.
210 : * @param size supplies the size of the output buffer.
211 : * @param data supplies the output buffer to fill.
212 : */
213 : virtual void copyOut(size_t start, uint64_t size, void* data) const PURE;
214 :
215 : /**
216 : * Copy out a section of the buffer to dynamic array of slices.
217 : * @param size supplies the size of the data that will be copied.
218 : * @param slices supplies the output slices to fill.
219 : * @param num_slice supplies the number of slices to fill.
220 : * @return the number of bytes copied.
221 : */
222 : virtual uint64_t copyOutToSlices(uint64_t size, Buffer::RawSlice* slices,
223 : uint64_t num_slice) const PURE;
224 :
225 : /**
226 : * Drain data from the buffer.
227 : * @param size supplies the length of data to drain.
228 : */
229 : virtual void drain(uint64_t size) PURE;
230 :
231 : /**
232 : * Fetch the raw buffer slices.
233 : * @param max_slices supplies an optional limit on the number of slices to fetch, for performance.
234 : * @return RawSliceVector with non-empty slices in the buffer.
235 : */
236 : virtual RawSliceVector
237 : getRawSlices(absl::optional<uint64_t> max_slices = absl::nullopt) const PURE;
238 :
239 : /**
240 : * Fetch the valid data pointer and valid data length of the first non-zero-length
241 : * slice in the buffer.
242 : * @return RawSlice the first non-empty slice in the buffer, or {nullptr, 0} if the buffer
243 : * is empty.
244 : */
245 : virtual RawSlice frontSlice() const PURE;
246 :
247 : /**
248 : * Transfer ownership of the front slice to the caller. Must only be called if the
249 : * buffer is not empty otherwise the implementation will have undefined behavior.
250 : * If the underlying slice is immutable then the implementation must create and return
251 : * a mutable slice that has a copy of the immutable data.
252 : * @return pointer to SliceData object that wraps the front slice
253 : */
254 : virtual SliceDataPtr extractMutableFrontSlice() PURE;
255 :
256 : /**
257 : * @return uint64_t the total length of the buffer (not necessarily contiguous in memory).
258 : */
259 : virtual uint64_t length() const PURE;
260 :
261 : /**
262 : * @return a pointer to the first byte of data that has been linearized out to size bytes.
263 : */
264 : virtual void* linearize(uint32_t size) PURE;
265 :
266 : /**
267 : * Move a buffer into this buffer. As little copying is done as possible.
268 : * @param rhs supplies the buffer to move.
269 : */
270 : virtual void move(Instance& rhs) PURE;
271 :
272 : /**
273 : * Move a portion of a buffer into this buffer. As little copying is done as possible.
274 : * @param rhs supplies the buffer to move.
275 : * @param length supplies the amount of data to move.
276 : */
277 : virtual void move(Instance& rhs, uint64_t length) PURE;
278 :
279 : /**
280 : * Move a portion of a buffer into this buffer. If reset_drain_trackers_and_accounting is true,
281 : * then any drain trackers on the source buffer are also called and cleared so that the
282 : * connection originating the source buffer (e.g. an internal listener connection) may be deleted
283 : * without causing a use-after-free.
284 : * @param rhs supplies the buffer to move.
285 : * @param length supplies the amount of data to move.
286 : * @param reset_drain_trackers_and_accounting whether the drain trackers on the source buffers
287 : * should be cleared, so that the source buffer is deletable.
288 : */
289 : virtual void move(Instance& rhs, uint64_t length, bool reset_drain_trackers_and_accounting) PURE;
290 :
291 : /**
292 : * Reserve space in the buffer for reading into. The amount of space reserved is determined
293 : * based on buffer settings and performance considerations.
294 : * @return a `Reservation`, on which `commit()` can be called, or which can
295 : * be destructed to discard any resources in the `Reservation`.
296 : */
297 : virtual Reservation reserveForRead() PURE;
298 :
299 : /**
300 : * Reserve space in the buffer in a single slice.
301 : * @param length the exact length of the reservation.
302 : * @param separate_slice specifies whether the reserved space must be in a separate slice
303 : * from any other data in this buffer.
304 : * @return a `ReservationSingleSlice` which has exactly one slice in it.
305 : */
306 : virtual ReservationSingleSlice reserveSingleSlice(uint64_t length,
307 : bool separate_slice = false) PURE;
308 :
309 : /**
310 : * Search for an occurrence of data within the buffer.
311 : * @param data supplies the data to search for.
312 : * @param size supplies the length of the data to search for.
313 : * @param start supplies the starting index to search from.
314 : * @param length limits the search to specified number of bytes starting from start index.
315 : * When length value is zero, entire length of data from starting index to the end is searched.
316 : * @return the index where the match starts or -1 if there is no match.
317 : */
318 : virtual ssize_t search(const void* data, uint64_t size, size_t start, size_t length) const PURE;
319 :
320 : /**
321 : * Search for an occurrence of data within entire buffer.
322 : * @param data supplies the data to search for.
323 : * @param size supplies the length of the data to search for.
324 : * @param start supplies the starting index to search from.
325 : * @return the index where the match starts or -1 if there is no match.
326 : */
327 310 : ssize_t search(const void* data, uint64_t size, size_t start) const {
328 310 : return search(data, size, start, 0);
329 310 : }
330 :
331 : /**
332 : * Search for an occurrence of data at the start of a buffer.
333 : * @param data supplies the data to search for.
334 : * @return true if this buffer starts with data, false otherwise.
335 : */
336 : virtual bool startsWith(absl::string_view data) const PURE;
337 :
338 : /**
339 : * Constructs a flattened string from a buffer.
340 : * @return the flattened string.
341 : */
342 : virtual std::string toString() const PURE;
343 :
344 : /**
345 : * Copy an integer out of the buffer.
346 : * @param start supplies the buffer index to start copying from.
347 : * @param Size how many bytes to read out of the buffer.
348 : * @param Endianness specifies the byte order to use when decoding the integer.
349 : * @details Size parameter: Some protocols have integer fields whose size in bytes won't match the
350 : * size in bytes of C++'s integer types. Take a 3-byte integer field for example, which we want to
351 : * represent as a 32-bit (4 bytes) integer. One option to deal with that situation is to read 4
352 : * bytes from the buffer and ignore 1. There are a few problems with that solution, though.
353 : * * The first problem is buffer underflow: there may not be more than Size bytes available
354 : * (say, last field in the payload), so that's an edge case to take into consideration.
355 : * * The second problem is draining the buffer after reading. With the above solution we cannot
356 : * read and discard in one go. We'd need to peek 4 bytes, ignore 1 and then drain 3. That not
357 : * only looks hacky since the sizes don't match, but also produces less terse code and
358 : * requires the caller to propagate that logic to all call sites. Things complicate even further
359 : * when endianness is taken into consideration: should the most or least-significant bytes be
360 : * padded? Dealing with this situation requires a high level of care and attention to detail.
361 : * Properly calculating which bytes to discard and how to displace the data is not only error
362 : * prone, but also shifts to the caller a burden that could be solved in a much more generic,
363 : * transparent and well tested manner.
364 : * * The last problem in the list is sign extension, which should be properly handled when
365 : * reading signed types with negative values. To make matters easier, the optional Size parameter
366 : * can be specified in those situations where there's a need to read less bytes than a C++'s
367 : * integer size in bytes. For the most common case when one needs to read exactly as many bytes as
368 : * the size of C++'s integer, this parameter can simply be omitted and it will be automatically
369 : * deduced from the size of the type T
370 : */
371 : template <typename T, ByteOrder Endianness = ByteOrder::Host, size_t Size = sizeof(T)>
372 14052 : T peekInt(uint64_t start = 0) const {
373 14052 : static_assert(Size <= sizeof(T), "requested size is bigger than integer being read");
374 :
375 14052 : if (length() < start + Size) {
376 0 : ExceptionUtil::throwEnvoyException("buffer underflow");
377 0 : }
378 :
379 14052 : constexpr const auto displacement = Endianness == ByteOrder::BigEndian ? sizeof(T) - Size : 0;
380 :
381 14052 : auto result = static_cast<T>(0);
382 14052 : constexpr const auto all_bits_enabled = static_cast<T>(~static_cast<T>(0));
383 :
384 14052 : int8_t* bytes = reinterpret_cast<int8_t*>(std::addressof(result));
385 14052 : copyOut(start, Size, &bytes[displacement]);
386 :
387 14052 : constexpr const auto most_significant_read_byte =
388 14052 : Endianness == ByteOrder::BigEndian ? displacement : Size - 1;
389 :
390 : // If Size == sizeof(T), we need to make sure we don't generate an invalid left shift
391 : // (e.g. int32 << 32), even though we know that that branch of the conditional will.
392 : // not be taken. Size % sizeof(T) gives us the correct left shift when Size < sizeof(T),
393 : // and generates a left shift of 0 bits when Size == sizeof(T)
394 14052 : const auto sign_extension_bits =
395 14052 : std::is_signed<T>::value && Size < sizeof(T) && bytes[most_significant_read_byte] < 0
396 14052 : ? static_cast<T>(static_cast<typename std::make_unsigned<T>::type>(all_bits_enabled)
397 0 : << ((Size % sizeof(T)) * CHAR_BIT))
398 14052 : : static_cast<T>(0);
399 :
400 14052 : return fromEndianness<Endianness>(static_cast<T>(result)) | sign_extension_bits;
401 14052 : }
402 :
403 : /**
404 : * Copy a little endian integer out of the buffer.
405 : * @param start supplies the buffer index to start copying from.
406 : * @param Size how many bytes to read out of the buffer.
407 : */
408 244 : template <typename T, size_t Size = sizeof(T)> T peekLEInt(uint64_t start = 0) const {
409 244 : return peekInt<T, ByteOrder::LittleEndian, Size>(start);
410 244 : }
411 :
412 : /**
413 : * Copy a big endian integer out of the buffer.
414 : * @param start supplies the buffer index to start copying from.
415 : * @param Size how many bytes to read out of the buffer.
416 : */
417 13792 : template <typename T, size_t Size = sizeof(T)> T peekBEInt(uint64_t start = 0) const {
418 13792 : return peekInt<T, ByteOrder::BigEndian, Size>(start);
419 13792 : }
420 :
421 : /**
422 : * Copy an integer out of the buffer and drain the read data.
423 : * @param Size how many bytes to read out of the buffer.
424 : * @param Endianness specifies the byte order to use when decoding the integer.
425 : */
426 : template <typename T, ByteOrder Endianness = ByteOrder::Host, size_t Size = sizeof(T)>
427 16 : T drainInt() {
428 16 : const auto result = peekInt<T, Endianness, Size>();
429 16 : drain(Size);
430 16 : return result;
431 16 : }
432 :
433 : /**
434 : * Copy a little endian integer out of the buffer and drain the read data.
435 : * @param Size how many bytes to read out of the buffer.
436 : */
437 16 : template <typename T, size_t Size = sizeof(T)> T drainLEInt() {
438 16 : return drainInt<T, ByteOrder::LittleEndian, Size>();
439 16 : }
440 :
441 : /**
442 : * Copy a big endian integer out of the buffer and drain the read data.
443 : * @param Size how many bytes to read out of the buffer.
444 : */
445 0 : template <typename T, size_t Size = sizeof(T)> T drainBEInt() {
446 0 : return drainInt<T, ByteOrder::BigEndian, Size>();
447 0 : }
448 :
449 : /**
450 : * Copy a byte into the buffer.
451 : * @param value supplies the byte to copy into the buffer.
452 : */
453 0 : void writeByte(uint8_t value) { add(std::addressof(value), 1); }
454 :
455 : /**
456 : * Copy value as a byte into the buffer.
457 : * @param value supplies the byte to copy into the buffer.
458 : */
459 0 : template <typename T> void writeByte(T value) { writeByte(static_cast<uint8_t>(value)); }
460 :
461 : /**
462 : * Copy an integer into the buffer.
463 : * @param value supplies the integer to copy into the buffer.
464 : * @param Size how many bytes to write from the requested integer.
465 : * @param Endianness specifies the byte order to use when encoding the integer.
466 : */
467 : template <ByteOrder Endianness = ByteOrder::Host, typename T, size_t Size = sizeof(T)>
468 0 : void writeInt(T value) {
469 0 : static_assert(Size <= sizeof(T), "requested size is bigger than integer being written");
470 :
471 0 : const auto data = toEndianness<Endianness>(value);
472 0 : constexpr const auto displacement = Endianness == ByteOrder::BigEndian ? sizeof(T) - Size : 0;
473 0 : add(reinterpret_cast<const char*>(std::addressof(data)) + displacement, Size);
474 0 : }
475 :
476 : /**
477 : * Copy an integer into the buffer in little endian byte order.
478 : * @param value supplies the integer to copy into the buffer.
479 : * @param Size how many bytes to write from the requested integer.
480 : */
481 0 : template <typename T, size_t Size = sizeof(T)> void writeLEInt(T value) {
482 0 : writeInt<ByteOrder::LittleEndian, T, Size>(value);
483 0 : }
484 :
485 : /**
486 : * Copy an integer into the buffer in big endian byte order.
487 : * @param value supplies the integer to copy into the buffer.
488 : * @param Size how many bytes to write from the requested integer.
489 : */
490 0 : template <typename T, size_t Size = sizeof(T)> void writeBEInt(T value) {
491 0 : writeInt<ByteOrder::BigEndian, T, Size>(value);
492 0 : }
493 :
494 : /**
495 : * Copy multiple string type fragments to the buffer.
496 : * @param fragments A sequence of string views with variable length.
497 : * @return The total size of the data copied to the buffer.
498 : */
499 : virtual size_t addFragments(absl::Span<const absl::string_view> fragments) PURE;
500 :
501 : /**
502 : * Set the buffer's high watermark. The buffer's low watermark is implicitly set to half the high
503 : * watermark. Setting the high watermark to 0 disables watermark functionality.
504 : * @param watermark supplies the buffer high watermark size threshold, in bytes.
505 : * @param watermark supplies the overflow multiplier, in bytes.
506 : * If set to non-zero, overflow callbacks will be called if the
507 : * buffered data exceeds watermark * overflow_multiplier.
508 : */
509 : virtual void setWatermarks(uint32_t watermark, uint32_t overflow_multiplier = 0) PURE;
510 :
511 : /**
512 : * Returns the configured high watermark. A return value of 0 indicates that watermark
513 : * functionality is disabled.
514 : */
515 : virtual uint32_t highWatermark() const PURE;
516 : /**
517 : * Determine if the buffer watermark trigger condition is currently set. The watermark trigger is
518 : * set when the buffer size exceeds the configured high watermark and is cleared once the buffer
519 : * size drops to the low watermark.
520 : * @return true if the buffer size once exceeded the high watermark and hasn't since dropped to
521 : * the low watermark.
522 : */
523 : virtual bool highWatermarkTriggered() const PURE;
524 :
525 : private:
526 : friend Reservation;
527 : friend ReservationSingleSlice;
528 :
529 : /**
530 : * Called by a `Reservation` to commit `length` bytes of the
531 : * reservation.
532 : */
533 : virtual void commit(uint64_t length, absl::Span<RawSlice> slices,
534 : ReservationSlicesOwnerPtr slices_owner) PURE;
535 : };
536 :
537 : using InstancePtr = std::unique_ptr<Instance>;
538 :
539 : /**
540 : * An abstract factory for creating watermarked buffers and buffer memory
541 : * accounts. The factory also supports tracking active memory accounts.
542 : */
543 : class WatermarkFactory {
544 : public:
545 4972 : virtual ~WatermarkFactory() = default;
546 :
547 : /**
548 : * Creates and returns a unique pointer to a new buffer.
549 : * @param below_low_watermark supplies a function to call if the buffer goes under a configured
550 : * low watermark.
551 : * @param above_high_watermark supplies a function to call if the buffer goes over a configured
552 : * high watermark.
553 : * @return a newly created InstancePtr.
554 : */
555 : virtual InstancePtr createBuffer(std::function<void()> below_low_watermark,
556 : std::function<void()> above_high_watermark,
557 : std::function<void()> above_overflow_watermark) PURE;
558 :
559 : /**
560 : * Create and returns a buffer memory account.
561 : *
562 : * @param reset_handler supplies the stream_reset_handler the account will
563 : * invoke to reset the stream.
564 : * @return a BufferMemoryAccountSharedPtr of the newly created account or
565 : * nullptr if tracking is disabled.
566 : */
567 : virtual BufferMemoryAccountSharedPtr createAccount(Http::StreamResetHandler& reset_handler) PURE;
568 :
569 : /**
570 : * Goes through the tracked accounts, resetting the accounts and their
571 : * corresponding stream depending on the pressure.
572 : *
573 : * @param pressure scaled threshold pressure used to compute the buckets to
574 : * reset internally.
575 : * @return the number of streams reset
576 : */
577 : virtual uint64_t resetAccountsGivenPressure(float pressure) PURE;
578 : };
579 :
580 : using WatermarkFactoryPtr = std::unique_ptr<WatermarkFactory>;
581 : using WatermarkFactorySharedPtr = std::shared_ptr<WatermarkFactory>;
582 :
583 : /**
584 : * Holds an in-progress addition to a buffer.
585 : *
586 : * @note For performance reasons, this class is passed by value to
587 : * avoid an extra allocation, so it cannot have any virtual methods.
588 : */
589 : class Reservation final {
590 : public:
591 : Reservation(Reservation&&) = default;
592 7250 : ~Reservation() = default;
593 :
594 : /**
595 : * @return an array of `RawSlice` of length `numSlices()`.
596 : */
597 7679 : RawSlice* slices() { return slices_.data(); }
598 0 : const RawSlice* slices() const { return slices_.data(); }
599 :
600 : /**
601 : * @return the number of slices present.
602 : */
603 7490 : uint64_t numSlices() const { return slices_.size(); }
604 :
605 : /**
606 : * @return the total length of the Reservation.
607 : */
608 7249 : uint64_t length() const { return length_; }
609 :
610 : /**
611 : * Commits some or all of the data in the reservation.
612 : * @param length supplies the number of bytes to commit. This must be
613 : * less than or equal to the size of the `Reservation`.
614 : *
615 : * @note No other methods should be called on the object after `commit()` is called.
616 : */
617 7246 : void commit(uint64_t length) {
618 7246 : ENVOY_BUG(length <= length_, "commit() length must be <= size of the Reservation");
619 7246 : ASSERT(length == 0 || !slices_.empty(),
620 7246 : "Reservation.commit() called on empty Reservation; possible double-commit().");
621 7246 : buffer_.commit(length, absl::MakeSpan(slices_), std::move(slices_owner_));
622 7246 : length_ = 0;
623 7246 : slices_.clear();
624 7246 : ASSERT(slices_owner_ == nullptr);
625 7246 : }
626 :
627 : // Tuned to allow reads of 128k, using 16k slices.
628 : static constexpr uint32_t MAX_SLICES_ = 8;
629 :
630 : private:
631 7250 : Reservation(Instance& buffer) : buffer_(buffer) {}
632 :
633 : // The buffer that created this `Reservation`.
634 : Instance& buffer_;
635 :
636 : // The combined length of all slices in the Reservation.
637 : uint64_t length_;
638 :
639 : // The RawSlices in the reservation, usable by operations such as `::readv()`.
640 : absl::InlinedVector<RawSlice, MAX_SLICES_> slices_;
641 :
642 : // An owner that can be set by the creator of the `Reservation` to free slices upon
643 : // destruction.
644 : ReservationSlicesOwnerPtr slices_owner_;
645 :
646 : public:
647 : // The following are for use only by implementations of Buffer. Because c++
648 : // doesn't allow inheritance of friendship, these are just trying to make
649 : // misuse easy to spot in a code review.
650 7250 : static Reservation bufferImplUseOnlyConstruct(Instance& buffer) { return {buffer}; }
651 7249 : decltype(slices_)& bufferImplUseOnlySlices() { return slices_; }
652 6009 : ReservationSlicesOwnerPtr& bufferImplUseOnlySlicesOwner() { return slices_owner_; }
653 7249 : void bufferImplUseOnlySetLength(uint64_t length) { length_ = length; }
654 : };
655 :
656 : /**
657 : * Holds an in-progress addition to a buffer, holding only a single slice.
658 : *
659 : * @note For performance reasons, this class is passed by value to
660 : * avoid an extra allocation, so it cannot have any virtual methods.
661 : */
662 : class ReservationSingleSlice final {
663 : public:
664 1344 : ReservationSingleSlice(ReservationSingleSlice&&) = default;
665 4332 : ~ReservationSingleSlice() = default;
666 :
667 : /**
668 : * @return the slice in the Reservation.
669 : */
670 3190 : RawSlice slice() const { return slice_; }
671 :
672 : /**
673 : * @return the total length of the Reservation.
674 : */
675 202 : uint64_t length() const { return slice_.len_; }
676 :
677 : /**
678 : * Commits some or all of the data in the reservation.
679 : * @param length supplies the number of bytes to commit. This must be
680 : * less than or equal to the size of the `Reservation`.
681 : *
682 : * @note No other methods should be called on the object after `commit()` is called.
683 : */
684 1892 : void commit(uint64_t length) {
685 1892 : ENVOY_BUG(length <= slice_.len_, "commit() length must be <= size of the Reservation");
686 1892 : ASSERT(length == 0 || slice_.mem_ != nullptr,
687 1892 : "Reservation.commit() called on empty Reservation; possible double-commit().");
688 1892 : buffer_.commit(length, absl::MakeSpan(&slice_, 1), std::move(slice_owner_));
689 1892 : slice_ = {nullptr, 0};
690 1892 : ASSERT(slice_owner_ == nullptr);
691 1892 : }
692 :
693 : private:
694 2988 : ReservationSingleSlice(Instance& buffer) : buffer_(buffer) {}
695 :
696 : // The buffer that created this `Reservation`.
697 : Instance& buffer_;
698 :
699 : // The RawSlice in the reservation, usable by anything needing the raw pointer
700 : // and length to read into.
701 : RawSlice slice_{};
702 :
703 : // An owner that can be set by the creator of the `ReservationSingleSlice` to free the slice upon
704 : // destruction.
705 : ReservationSlicesOwnerPtr slice_owner_;
706 :
707 : public:
708 : // The following are for use only by implementations of Buffer. Because c++
709 : // doesn't allow inheritance of friendship, these are just trying to make
710 : // misuse easy to spot in a code review.
711 2988 : static ReservationSingleSlice bufferImplUseOnlyConstruct(Instance& buffer) { return {buffer}; }
712 2988 : RawSlice& bufferImplUseOnlySlice() { return slice_; }
713 2887 : ReservationSlicesOwnerPtr& bufferImplUseOnlySliceOwner() { return slice_owner_; }
714 : };
715 :
716 : } // namespace Buffer
717 : } // namespace Envoy
|