LCOV - code coverage report
Current view: top level - envoy/buffer - buffer.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 71 98 72.4 %
Date: 2024-01-05 06:35:25 Functions: 35 81 43.2 %

          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

Generated by: LCOV version 1.15