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
15
  bool operator==(const RawSlice& rhs) const { return mem_ == rhs.mem_ && len_ == rhs.len_; }
34
  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
  bool operator==(const RawSlice& rhs) const { return mem_ == rhs.mem_ && len_ == rhs.len_; }
45
  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
810298
  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
10
  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
3805571
  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
332
  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
11467982
  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
89
  ssize_t search(const void* data, uint64_t size, size_t start) const {
328
89
    return search(data, size, start, 0);
329
89
  }
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
53173
  T peekInt(uint64_t start = 0) const {
373
53173
    static_assert(Size <= sizeof(T), "requested size is bigger than integer being read");
374

            
375
53173
    if (length() < start + Size) {
376
28
      ExceptionUtil::throwEnvoyException("buffer underflow");
377
28
    }
378

            
379
53173
    constexpr const auto displacement = Endianness == ByteOrder::BigEndian ? sizeof(T) - Size : 0;
380

            
381
53173
    auto result = static_cast<T>(0);
382
53173
    constexpr const auto all_bits_enabled = static_cast<T>(~static_cast<T>(0));
383

            
384
53173
    int8_t* bytes = reinterpret_cast<int8_t*>(std::addressof(result));
385
53173
    copyOut(start, Size, &bytes[displacement]);
386

            
387
53173
    constexpr const auto most_significant_read_byte =
388
53173
        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
53173
    const auto sign_extension_bits =
395
53173
        std::is_signed<T>::value && Size < sizeof(T) && bytes[most_significant_read_byte] < 0
396
53173
            ? static_cast<T>(static_cast<typename std::make_unsigned<T>::type>(all_bits_enabled)
397
6
                             << ((Size % sizeof(T)) * CHAR_BIT))
398
53173
            : static_cast<T>(0);
399

            
400
53173
    return fromEndianness<Endianness>(static_cast<T>(result)) | sign_extension_bits;
401
53173
  }
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
370
  template <typename T, size_t Size = sizeof(T)> T peekLEInt(uint64_t start = 0) const {
409
370
    return peekInt<T, ByteOrder::LittleEndian, Size>(start);
410
370
  }
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
23084
  template <typename T, size_t Size = sizeof(T)> T peekBEInt(uint64_t start = 0) const {
418
23084
    return peekInt<T, ByteOrder::BigEndian, Size>(start);
419
23084
  }
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
7850
  T drainInt() {
428
7850
    const auto result = peekInt<T, Endianness, Size>();
429
7850
    drain(Size);
430
7850
    return result;
431
7850
  }
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
20
  template <typename T, size_t Size = sizeof(T)> T drainLEInt() {
438
20
    return drainInt<T, ByteOrder::LittleEndian, Size>();
439
20
  }
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
6535
  template <typename T, size_t Size = sizeof(T)> T drainBEInt() {
446
6535
    return drainInt<T, ByteOrder::BigEndian, Size>();
447
6535
  }
448

            
449
  /**
450
   * Copy a byte into the buffer.
451
   * @param value supplies the byte to copy into the buffer.
452
   */
453
24152
  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
10714
  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
33209
  void writeInt(T value) {
469
33209
    static_assert(Size <= sizeof(T), "requested size is bigger than integer being written");
470

            
471
33209
    const auto data = toEndianness<Endianness>(value);
472
33209
    constexpr const auto displacement = Endianness == ByteOrder::BigEndian ? sizeof(T) - Size : 0;
473
33209
    add(reinterpret_cast<const char*>(std::addressof(data)) + displacement, Size);
474
33209
  }
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
111
  template <typename T, size_t Size = sizeof(T)> void writeLEInt(T value) {
482
111
    writeInt<ByteOrder::LittleEndian, T, Size>(value);
483
111
  }
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
33098
  template <typename T, size_t Size = sizeof(T)> void writeBEInt(T value) {
491
33098
    writeInt<ByteOrder::BigEndian, T, Size>(value);
492
33098
  }
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(uint64_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 uint64_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
245523
  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
1118629
  ~Reservation() = default;
593

            
594
  /**
595
   * @return an array of `RawSlice` of length `numSlices()`.
596
   */
597
1129535
  RawSlice* slices() { return slices_.data(); }
598
  const RawSlice* slices() const { return slices_.data(); }
599

            
600
  /**
601
   * @return the number of slices present.
602
   */
603
1131027
  uint64_t numSlices() const { return slices_.size(); }
604

            
605
  /**
606
   * @return the total length of the Reservation.
607
   */
608
1107122
  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
1118649
  void commit(uint64_t length) {
618
1118649
    ENVOY_BUG(length <= length_, "commit() length must be <= size of the Reservation");
619
1118649
    ASSERT(length == 0 || !slices_.empty(),
620
1118649
           "Reservation.commit() called on empty Reservation; possible double-commit().");
621
1118649
    buffer_.commit(length, absl::MakeSpan(slices_), std::move(slices_owner_));
622
1118649
    length_ = 0;
623
1118649
    slices_.clear();
624
1118649
    ASSERT(slices_owner_ == nullptr);
625
1118649
  }
626

            
627
  // Tuned to allow reads of 128k, using 16k slices.
628
  static constexpr uint32_t MAX_SLICES_ = 8;
629

            
630
private:
631
1118574
  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
1118589
  static Reservation bufferImplUseOnlyConstruct(Instance& buffer) { return {buffer}; }
651
1118599
  decltype(slices_)& bufferImplUseOnlySlices() { return slices_; }
652
1118602
  ReservationSlicesOwnerPtr& bufferImplUseOnlySlicesOwner() { return slices_owner_; }
653
1118622
  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
2001320
  ReservationSingleSlice(ReservationSingleSlice&&) = default;
665
4689305
  ~ReservationSingleSlice() = default;
666

            
667
  /**
668
   * @return the slice in the Reservation.
669
   */
670
2692227
  RawSlice slice() const { return slice_; }
671

            
672
  /**
673
   * @return the total length of the Reservation.
674
   */
675
2
  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
885730
  void commit(uint64_t length) {
685
885730
    ENVOY_BUG(length <= slice_.len_, "commit() length must be <= size of the Reservation");
686
885730
    ASSERT(length == 0 || slice_.mem_ != nullptr,
687
885730
           "Reservation.commit() called on empty Reservation; possible double-commit().");
688
885730
    buffer_.commit(length, absl::MakeSpan(&slice_, 1), std::move(slice_owner_));
689
885730
    slice_ = {nullptr, 0};
690
885730
    ASSERT(slice_owner_ == nullptr);
691
885730
  }
692

            
693
private:
694
2688108
  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
2688101
  static ReservationSingleSlice bufferImplUseOnlyConstruct(Instance& buffer) { return {buffer}; }
712
2686892
  RawSlice& bufferImplUseOnlySlice() { return slice_; }
713
2686353
  ReservationSlicesOwnerPtr& bufferImplUseOnlySliceOwner() { return slice_owner_; }
714
};
715

            
716
} // namespace Buffer
717
} // namespace Envoy