1 /** @file
2 
3   I/O classes
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22 
23   @section watermark Watermark
24 
25   Watermarks can be used as an interface between the data transferring
26   layer (VConnection) and the user layer (a state machine).  Watermarks
27   should be used when you need to have at least a certain amount of data
28   to make some determination.  For example, when parsing a string, one
29   might wish to ensure that an entire line will come in before consuming
30   the data.  In such a case, the water_mark should be set to the largest
31   possible size of the string. (appropriate error handling should take
32   care of exessively long strings).
33 
34   In all other cases, especially when all data will be consumed, the
35   water_mark should be set to 0 (the default).
36 
37  */
38 
39 #pragma once
40 #define I_IOBuffer_h
41 
42 #include "tscore/ink_platform.h"
43 #include "tscore/ink_apidefs.h"
44 #include "tscore/Allocator.h"
45 #include "tscore/Ptr.h"
46 #include "tscore/ink_assert.h"
47 #include "tscore/ink_resource.h"
48 
49 struct MIOBufferAccessor;
50 
51 class MIOBuffer;
52 class IOBufferReader;
53 class VIO;
54 
55 // Removing this optimization since this is breaking WMT over HTTP
56 //#define WRITE_AND_TRANSFER
57 
58 inkcoreapi extern int64_t max_iobuffer_size;
59 extern int64_t default_small_iobuffer_size;
60 extern int64_t default_large_iobuffer_size; // matched to size of OS buffers
61 
62 #if !defined(TRACK_BUFFER_USER)
63 #define TRACK_BUFFER_USER 1
64 #endif
65 
66 enum AllocType {
67   NO_ALLOC,
68   FAST_ALLOCATED,
69   XMALLOCED,
70   MEMALIGNED,
71   DEFAULT_ALLOC,
72   CONSTANT,
73 };
74 
75 #define DEFAULT_BUFFER_NUMBER 128
76 #define DEFAULT_HUGE_BUFFER_NUMBER 32
77 #define MAX_MIOBUFFER_READERS 5
78 #define DEFAULT_BUFFER_ALIGNMENT 8192 // should be disk/page size
79 #define DEFAULT_BUFFER_BASE_SIZE 128
80 
81 ////////////////////////////////////////////////
82 // These are defines so that code that used 2 //
83 // for buffer size index when 2 was 2K will   //
84 // still work if it uses BUFFER_SIZE_INDEX_2K //
85 // instead.                                   //
86 ////////////////////////////////////////////////
87 #define BUFFER_SIZE_INDEX_128 0
88 #define BUFFER_SIZE_INDEX_256 1
89 #define BUFFER_SIZE_INDEX_512 2
90 #define BUFFER_SIZE_INDEX_1K 3
91 #define BUFFER_SIZE_INDEX_2K 4
92 #define BUFFER_SIZE_INDEX_4K 5
93 #define BUFFER_SIZE_INDEX_8K 6
94 #define BUFFER_SIZE_INDEX_16K 7
95 #define BUFFER_SIZE_INDEX_32K 8
96 #define BUFFER_SIZE_INDEX_64K 9
97 #define BUFFER_SIZE_INDEX_128K 10
98 #define BUFFER_SIZE_INDEX_256K 11
99 #define BUFFER_SIZE_INDEX_512K 12
100 #define BUFFER_SIZE_INDEX_1M 13
101 #define BUFFER_SIZE_INDEX_2M 14
102 #define MAX_BUFFER_SIZE_INDEX 14
103 #define DEFAULT_BUFFER_SIZES (MAX_BUFFER_SIZE_INDEX + 1)
104 
105 #define BUFFER_SIZE_FOR_INDEX(_i) (DEFAULT_BUFFER_BASE_SIZE * (1 << (_i)))
106 #define DEFAULT_SMALL_BUFFER_SIZE BUFFER_SIZE_INDEX_512
107 #define DEFAULT_LARGE_BUFFER_SIZE BUFFER_SIZE_INDEX_4K
108 #define DEFAULT_TS_BUFFER_SIZE BUFFER_SIZE_INDEX_8K
109 #define DEFAULT_MAX_BUFFER_SIZE BUFFER_SIZE_FOR_INDEX(MAX_BUFFER_SIZE_INDEX)
110 #define MIN_IOBUFFER_SIZE BUFFER_SIZE_INDEX_128
111 #define MAX_IOBUFFER_SIZE (DEFAULT_BUFFER_SIZES - 1)
112 
113 #define BUFFER_SIZE_ALLOCATED(_i) (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_i) || BUFFER_SIZE_INDEX_IS_XMALLOCED(_i))
114 
115 #define BUFFER_SIZE_NOT_ALLOCATED DEFAULT_BUFFER_SIZES
116 #define BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index) (_size_index < 0)
117 #define BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index) (((uint64_t)_size_index) < DEFAULT_BUFFER_SIZES)
118 #define BUFFER_SIZE_INDEX_IS_CONSTANT(_size_index) (_size_index >= DEFAULT_BUFFER_SIZES)
119 
120 #define BUFFER_SIZE_FOR_XMALLOC(_size) (-(_size))
121 #define BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(_size) (-(_size))
122 
123 #define BUFFER_SIZE_FOR_CONSTANT(_size) (_size - DEFAULT_BUFFER_SIZES)
124 #define BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(_size) (_size + DEFAULT_BUFFER_SIZES)
125 
126 inkcoreapi extern Allocator ioBufAllocator[DEFAULT_BUFFER_SIZES];
127 
128 void init_buffer_allocators(int iobuffer_advice);
129 
130 /**
131   A reference counted wrapper around fast allocated or malloced memory.
132   The IOBufferData class provides two basic services around a portion
133   of allocated memory.
134 
135   First, it is a reference counted object and ...
136 
137   @remarks The AllocType enum, is used to define the type of allocation
138   for the memory this IOBufferData object manages.
139 
140   <table>
141     <tr>
142       <td align="center">AllocType</td>
143       <td align="center">Meaning</td>
144     </tr>
145     <tr>
146       <td>NO_ALLOC</td>
147       <td></td>
148     </tr>
149     <tr>
150       <td>FAST_ALLOCATED</td>
151       <td></td>
152     </tr>
153     <tr>
154       <td>XMALLOCED</td>
155       <td></td>
156     </tr>
157     <tr>
158       <td>MEMALIGNED</td>
159       <td></td>
160     </tr>
161     <tr>
162       <td>DEFAULT_ALLOC</td>
163       <td></td>
164     </tr>
165     <tr>
166       <td>CONSTANT</td>
167       <td></td>
168     </tr>
169   </table>
170 
171  */
172 class IOBufferData : public RefCountObj
173 {
174 public:
175   /**
176     The size of the memory allocated by this IOBufferData. Calculates
177     the amount of memory allocated by this IOBufferData.
178 
179     @return number of bytes allocated for the '_data' member.
180 
181   */
182   int64_t block_size();
183 
184   /**
185     Frees the memory managed by this IOBufferData.  Deallocates the
186     memory previously allocated by this IOBufferData object. It frees
187     the memory pointed to by '_data' according to the '_mem_type' and
188     '_size_index' members.
189 
190   */
191   void dealloc();
192 
193   /**
194     Allocates memory and sets this IOBufferData to point to it.
195     Allocates memory according to the size_index and type
196     parameters. Any previously allocated memory pointed to by
197     this IOBufferData is deallocated.
198 
199     @param size_index
200     @param type of allocation to use; see remarks section.
201   */
202   void alloc(int64_t size_index, AllocType type = DEFAULT_ALLOC);
203 
204   /**
205     Provides access to the allocated memory. Returns the address of the
206     allocated memory handled by this IOBufferData.
207 
208     @return address of the memory handled by this IOBufferData.
209 
210   */
211   char *
212   data()
213   {
214     return _data;
215   }
216 
217   /**
218     Cast operator. Provided as a convenience, the cast to a char* applied
219     to the IOBufferData returns the address of the memory handled by the
220     IOBuffer data. In this manner, objects of this class can be used as
221     parameter to functions requiring a char*.
222 
223   */
224   operator char *() { return _data; }
225   /**
226     Frees the IOBufferData object and its underlying memory. Deallocates
227     the memory managed by this IOBufferData and then frees itself. You
228     should not use this object or reference after this call.
229 
230   */
231   void free() override;
232 
233   int64_t _size_index;
234 
235   /**
236     Type of allocation used for the managed memory. Stores the type of
237     allocation used for the memory currently managed by the IOBufferData
238     object. Do not set or modify this value directly. Instead use the
239     alloc or dealloc methods.
240 
241   */
242   AllocType _mem_type = NO_ALLOC;
243 
244   /**
245     Points to the allocated memory. This member stores the address of
246     the allocated memory. You should not modify its value directly,
247     instead use the alloc or dealloc methods.
248 
249   */
250   char *_data = nullptr;
251 
252 #ifdef TRACK_BUFFER_USER
253   const char *_location = nullptr;
254 #endif
255 
256   /**
257     Constructor. Initializes state for a IOBufferData object. Do not use
258     this method. Use one of the functions with the 'new_' prefix instead.
259 
260   */
261   IOBufferData() : _size_index(BUFFER_SIZE_NOT_ALLOCATED) {}
262 
263   // noncopyable, declaration only
264   IOBufferData(const IOBufferData &) = delete;
265   IOBufferData &operator=(const IOBufferData &) = delete;
266 };
267 
268 inkcoreapi extern ClassAllocator<IOBufferData> ioDataAllocator;
269 
270 /**
271   A linkable portion of IOBufferData. IOBufferBlock is a chainable
272   buffer block descriptor. The IOBufferBlock represents both the used
273   and available space in the underlying block. The IOBufferBlock is not
274   sharable between buffers but rather represents what part of the data
275   block is both in use and usable by the MIOBuffer it is attached to.
276 
277 */
278 class IOBufferBlock : public RefCountObj
279 {
280 public:
281   /**
282     Access the actual data. Provides access to rhe underlying data
283     managed by the IOBufferData.
284 
285     @return pointer to the underlying data.
286 
287   */
288   char *
289   buf()
290   {
291     return data->_data;
292   }
293 
294   /**
295     Beginning of the inuse section. Returns the position in the buffer
296     where the inuse area begins.
297 
298     @return pointer to the start of the inuse section.
299 
300   */
301   char *
302   start()
303   {
304     return _start;
305   }
306 
307   /**
308     End of the used space. Returns a pointer to end of the used space
309     in the data buffer represented by this block.
310 
311     @return pointer to the end of the inuse portion of the block.
312 
313   */
314   char *
315   end()
316   {
317     return _end;
318   }
319 
320   /**
321     End of the data buffer. Returns a pointer to end of the data buffer
322     represented by this block.
323 
324   */
325   char *
326   buf_end()
327   {
328     return _buf_end;
329   }
330 
331   /**
332     Size of the inuse area. Returns the size of the current inuse area.
333 
334     @return bytes occupied by the inuse area.
335 
336   */
337   int64_t
338   size()
339   {
340     return (int64_t)(_end - _start);
341   }
342 
343   /**
344     Size of the data available for reading. Returns the size of the data
345     available for reading in the inuse area.
346 
347     @return bytes available for reading from the inuse area.
348 
349   */
350   int64_t
351   read_avail() const
352   {
353     return (int64_t)(_end - _start);
354   }
355 
356   /**
357     Space available in the buffer. Returns the number of bytes that can
358     be written to the data buffer.
359 
360     @return space available for writing in this IOBufferBlock.
361   */
362   int64_t
363   write_avail()
364   {
365     return (int64_t)(_buf_end - _end);
366   }
367 
368   /**
369     Size of the memory allocated by the underlying IOBufferData.
370     Computes the size of the entire block, which includes the used and
371     available areas. It is the memory allocated by the IOBufferData
372     referenced by this IOBufferBlock.
373 
374     @return bytes allocated to the IOBufferData referenced by this
375       IOBufferBlock.
376 
377   */
378   int64_t
379   block_size()
380   {
381     return data->block_size();
382   }
383 
384   /**
385     Decrease the size of the inuse area. Moves forward the start of
386     the inuse area. This also decreases the number of available bytes
387     for reading.
388 
389     @param len bytes to consume or positions to skip for the start of
390       the inuse area.
391 
392   */
393   void consume(int64_t len);
394 
395   /**
396     Increase the inuse area of the block. Adds 'len' bytes to the inuse
397     area of the block. Data should be copied into the data buffer by
398     using end() to find the start of the free space in the data buffer
399     before calling fill()
400 
401     @param len bytes to increase the inuse area. It must be less than
402       or equal to the value of write_avail().
403 
404   */
405   void fill(int64_t len);
406 
407   /**
408     Reset the inuse area. The start and end of the inuse area are reset
409     but the actual IOBufferData referenced by this IOBufferBlock is not
410     modified.  This effectively reduces the number of bytes available
411     for reading to zero, and the number of bytes available for writing
412     to the size of the entire buffer.
413 
414   */
415   void reset();
416 
417   /**
418     Create a copy of the IOBufferBlock. Creates and returns a copy of this
419     IOBufferBlock that references the same data that this IOBufferBlock
420     (it does not allocate an another buffer). The cloned block will not
421     have a writable space since the original IOBufferBlock mantains the
422     ownership for writing data to the block.
423 
424     @return copy of this IOBufferBlock.
425 
426   */
427   IOBufferBlock *clone() const;
428 
429   /**
430     Clear the IOBufferData this IOBufferBlock handles. Clears this
431     IOBufferBlock's reference to the data buffer (IOBufferData). You can
432     use alloc after this call to allocate an IOBufferData associated to
433     this IOBufferBlock.
434 
435   */
436   void clear();
437 
438   /**
439     Allocate a data buffer. Allocates a data buffer for this IOBufferBlock
440     based on index 'i'.  Index values are described in the remarks
441     section in MIOBuffer.
442 
443   */
444   void alloc(int64_t i = default_large_iobuffer_size);
445 
446   /**
447     Clear the IOBufferData this IOBufferBlock handles. Clears this
448     IOBufferBlock's reference to the data buffer (IOBufferData).
449 
450   */
451   void dealloc();
452 
453   /**
454     Set or replace this IOBufferBlock's IOBufferData member. Sets this
455     IOBufferBlock's IOBufferData member to point to the IOBufferData
456     passed in. You can optionally specify the inuse area with the 'len'
457     argument and an offset for the start.
458 
459     @param d new IOBufferData this IOBufferBlock references.
460     @param len in use area to set. It must be less than or equal to the
461       length of the block size *IOBufferData).
462     @param offset bytes to skip from the beginning of the IOBufferData
463       and to mark its start.
464 
465   */
466   void set(IOBufferData *d, int64_t len = 0, int64_t offset = 0);
467   void set_internal(void *b, int64_t len, int64_t asize_index);
468   void realloc_set_internal(void *b, int64_t buf_size, int64_t asize_index);
469   void realloc(void *b, int64_t buf_size);
470   void realloc(int64_t i);
471   void realloc_xmalloc(void *b, int64_t buf_size);
472   void realloc_xmalloc(int64_t buf_size);
473 
474   /**
475     Frees the IOBufferBlock object and its underlying memory.
476     Removes the reference to the IOBufferData object and then frees
477     itself. You should not use this object or reference after this
478     call.
479 
480   */
481   void free() override;
482 
483   char *_start   = nullptr;
484   char *_end     = nullptr;
485   char *_buf_end = nullptr;
486 
487 #ifdef TRACK_BUFFER_USER
488   const char *_location = nullptr;
489 #endif
490 
491   /**
492     The underlying reference to the allocated memory. A reference to a
493     IOBufferData representing the memory allocated to this buffer. Do
494     not set or modify its value directly.
495 
496   */
497   Ptr<IOBufferData> data;
498 
499   /**
500     Reference to another IOBufferBlock. A reference to another
501     IOBufferBlock that allows this object to link to other.
502 
503   */
504   Ptr<IOBufferBlock> next;
505 
506   /**
507     Constructor of a IOBufferBlock. Do not use it to create a new object,
508     instead call new_IOBufferBlock
509 
510   */
511   IOBufferBlock();
512 
513   // noncopyable
514   IOBufferBlock(const IOBufferBlock &) = delete;
515   IOBufferBlock &operator=(const IOBufferBlock &) = delete;
516 };
517 
518 extern inkcoreapi ClassAllocator<IOBufferBlock> ioBlockAllocator;
519 
520 /** A class for holding a chain of IO buffer blocks.
521     This class is intended to be used as a member variable for other classes that
522     need to anchor an IO Buffer chain but don't need the full @c MIOBuffer machinery.
523     That is, the owner is the only reader/writer of the data.
524 
525     This does not handle incremental reads or writes well. The intent is that data is
526     placed in the instance, held for a while, then used and discarded.
527 
528     @note Contrast also with @c IOBufferReader which is similar but requires an
529     @c MIOBuffer as its owner.
530 */
531 class IOBufferChain
532 {
533   using self_type = IOBufferChain; ///< Self reference type.
534 
535 public:
536   /// Default constructor - construct empty chain.
537   IOBufferChain() = default;
538   /// Shallow copy.
539   self_type &operator=(self_type const &that);
540 
541   /// Shallow append.
542   self_type &operator+=(self_type const &that);
543 
544   /// Number of bytes of content.
545   int64_t length() const;
546 
547   /// Copy a chain of @a blocks in to this object up to @a length bytes.
548   /// If @a offset is greater than 0 that many bytes are skipped. Those bytes do not count
549   /// as part of @a length.
550   /// This creates a new chain using existing data blocks. This
551   /// breaks the original chain so that changes there (such as appending blocks)
552   /// is not reflected in this chain.
553   /// @return The number of bytes written to the chain.
554   int64_t write(IOBufferBlock *blocks, int64_t length, int64_t offset = 0);
555 
556   /// Add the content of a buffer block.
557   /// The buffer block is unchanged.
558   int64_t write(IOBufferData *data, int64_t length = 0, int64_t offset = 0);
559 
560   /// Remove @a size bytes of content from the front of the chain.
561   /// @return The actual number of bytes removed.
562   int64_t consume(int64_t size);
563 
564   /// Clear current chain.
565   void clear();
566 
567   /// Get the first block.
568   IOBufferBlock *head();
569   IOBufferBlock const *head() const;
570 
571   /// STL Container support.
572 
573   /// Block iterator.
574   /// @internal The reason for this is to override the increment operator.
575   class const_iterator : public std::forward_iterator_tag
576   {
577     using self_type = const_iterator; ///< Self reference type.
578   protected:
579     /// Current buffer block.
580     IOBufferBlock *_b = nullptr;
581 
582   public:
583     using value_type = const IOBufferBlock; ///< Iterator value type.
584 
585     const_iterator() = default; ///< Default constructor.
586 
587     /// Copy constructor.
588     const_iterator(self_type const &that);
589 
590     /// Assignment.
591     self_type &operator=(self_type const &that);
592 
593     /// Equality.
594     bool operator==(self_type const &that) const;
595     /// Inequality.
596     bool operator!=(self_type const &that) const;
597 
598     value_type &operator*() const;
599     value_type *operator->() const;
600 
601     self_type &operator++();
602     self_type operator++(int);
603   };
604 
605   class iterator : public const_iterator
606   {
607     using self_type = iterator; ///< Self reference type.
608   public:
609     using value_type = IOBufferBlock; ///< Dereferenced type.
610 
611     value_type &operator*() const;
612     value_type *operator->() const;
613   };
614 
615   using value_type = IOBufferBlock;
616 
617   iterator begin();
618   const_iterator begin() const;
619 
620   iterator end();
621   const_iterator end() const;
622 
623 protected:
624   /// Append @a block.
625   void append(IOBufferBlock *block);
626 
627   /// Head of buffer block chain.
628   Ptr<IOBufferBlock> _head;
629   /// Tail of the block chain.
630   IOBufferBlock *_tail = nullptr;
631   /// The amount of data of interest.
632   /// Not necessarily the amount of data in the chain of blocks.
633   int64_t _len = 0;
634 };
635 
636 /**
637   An independent reader from an MIOBuffer. A reader for a set of
638   IOBufferBlocks. The IOBufferReader represents the place where a given
639   consumer of buffer data is reading from. It provides a uniform interface
640   for easily accessing the data contained in a list of IOBufferBlocks
641   associated with the IOBufferReader.
642 
643   IOBufferReaders are the abstraction that determine when data blocks
644   can be removed from the buffer.
645 
646 */
647 class IOBufferReader
648 {
649 public:
650   /**
651     Start of unconsumed data. Returns a pointer to first unconsumed data
652     on the buffer for this reader. A null pointer indicates no data is
653     available. It uses the current start_offset value.
654 
655     @return pointer to the start of the unconsumed data.
656 
657   */
658   char *start();
659 
660   /**
661     End of inuse area of the first block with unconsumed data. Returns a
662     pointer to the end of the first block with unconsumed data for this
663     reader. A nullptr pointer indicates there are no blocks with unconsumed
664     data for this reader.
665 
666     @return pointer to the end of the first block with unconsumed data.
667 
668   */
669   char *end();
670 
671   /**
672     Amount of data available across all of the IOBufferBlocks. Returns the
673     number of unconsumed bytes of data available to this reader across
674     all remaining IOBufferBlocks. It subtracts the current start_offset
675     value from the total.
676 
677     @return bytes of data available across all the buffers.
678 
679   */
680   int64_t read_avail();
681 
682   /** Check if there is more than @a size bytes available to read.
683       @return @c true if more than @a size byte are available.
684   */
685   bool is_read_avail_more_than(int64_t size);
686 
687   /**
688     Number of IOBufferBlocks with data in the block list. Returns the
689     number of IOBufferBlocks on the block list with data remaining for
690     this reader.
691 
692     @return number of blocks with data for this reader.
693 
694   */
695   int block_count();
696 
697   /**
698     Amount of data available in the first buffer with data for this
699     reader.  Returns the number of unconsumed bytes of data available
700     on the first IOBufferBlock with data for this reader.
701 
702     @return number of unconsumed bytes of data available in the first
703       buffer.
704 
705   */
706   int64_t block_read_avail();
707 
708   /** Get a view of the data available to read.
709    *
710    * @return A view encompassing currently available readable data.
711    */
712   std::string_view block_read_view();
713 
714   void skip_empty_blocks();
715 
716   /**
717     Clears all fields in this IOBuffeReader, rendering it unusable. Drops
718     the reference to the IOBufferBlock list, the accesor, MIOBuffer and
719     resets this reader's state. You have to set those fields in order
720     to use this object again.
721 
722   */
723   void clear();
724 
725   /**
726     Instruct the reader to reset the IOBufferBlock list. Resets the
727     reader to the point to the start of the block where new data will
728     be written. After this call, the start_offset field is set to zero
729     and the list of IOBufferBlocks is set using the associated MIOBuffer.
730 
731   */
732   void reset();
733 
734   /**
735     Consume a number of bytes from this reader's IOBufferBlock
736     list. Advances the current position in the IOBufferBlock list of
737     this reader by n bytes.
738 
739     @param n number of bytes to consume. It must be less than or equal
740       to read_avail().
741 
742   */
743   void consume(int64_t n);
744 
745   /**
746     Create another reader with access to the same data as this
747     IOBufferReader. Allocates a new reader with the same state as this
748     IOBufferReader. This means that the new reader will point to the same
749     list of IOBufferBlocks and to the same buffer position as this reader.
750 
751     @return new reader with the same state as this.
752 
753   */
754   IOBufferReader *clone();
755 
756   /**
757     Deallocate this reader. Removes and deallocates this reader from
758     the underlying MIOBuffer. This IOBufferReader object must not be
759     used after this call.
760 
761   */
762   void dealloc();
763 
764   /**
765     Get a pointer to the first block with data. Returns a pointer to
766     the first IOBufferBlock in the block chain with data available for
767     this reader
768 
769     @return pointer to the first IOBufferBlock in the list with data
770       available for this reader.
771 
772   */
773   IOBufferBlock *get_current_block();
774 
775   /**
776     Consult this reader's MIOBuffer writable space. Queries the MIOBuffer
777     associated with this reader about the amount of writable space
778     available without adding any blocks on the buffer and returns true
779     if it is less than the water mark.
780 
781     @return true if the MIOBuffer associated with this IOBufferReader
782       returns true in MIOBuffer::current_low_water().
783 
784   */
785   bool current_low_water();
786 
787   /**
788     Queries the underlying MIOBuffer about. Returns true if the amount
789     of writable space after adding a block on the underlying MIOBuffer
790     is less than its water mark. This function call may add blocks to
791     the MIOBuffer (see MIOBuffer::low_water()).
792 
793     @return result of MIOBuffer::low_water() on the MIOBuffer for
794       this reader.
795 
796   */
797   bool low_water();
798 
799   /**
800     To see if the amount of data available to the reader is greater than
801     the MIOBuffer's water mark. Indicates whether the amount of data
802     available to this reader exceeds the water mark for this reader's
803     MIOBuffer.
804 
805     @return true if the amount of data exceeds the MIOBuffer's water mark.
806 
807   */
808   bool high_water();
809 
810   /**
811     Perform a memchr() across the list of IOBufferBlocks. Returns the
812     offset from the current start point of the reader to the first
813     occurrence of character 'c' in the buffer.
814 
815     @param c character to look for.
816     @param len number of characters to check. If len exceeds the number
817       of bytes available on the buffer or INT64_MAX is passed in, the
818       number of bytes available to the reader is used. It is independent
819       of the offset value.
820     @param offset number of the bytes to skip over before beginning
821       the operation.
822     @return -1 if c is not found, otherwise position of the first
823       ocurrence.
824 
825   */
826   inkcoreapi int64_t memchr(char c, int64_t len = INT64_MAX, int64_t offset = 0);
827 
828   /**
829     Copies and consumes data. Copies len bytes of data from the buffer
830     into the supplied buffer, which must be allocated prior to the call
831     and it must be at large enough for the requested bytes. Once the
832     data is copied, it consumed from the reader.
833 
834     @param buf in which to place the data.
835     @param len bytes to copy and consume. If 'len' exceeds the bytes
836       available to the reader, the number of bytes available is used
837       instead.
838 
839     @return number of bytes copied and consumed.
840 
841   */
842   inkcoreapi int64_t read(void *buf, int64_t len);
843 
844   /**
845     Copy data but do not consume it. Copies 'len' bytes of data from
846     the current buffer into the supplied buffer. The copy skips the
847     number of bytes specified by 'offset' beyond the current point of
848     the reader. It also takes into account the current start_offset value.
849 
850     @param buf in which to place the data. The pointer is modified after
851       the call and points one position after the end of the data copied.
852     @param len bytes to copy. If len exceeds the bytes available to the
853       reader or INT64_MAX is passed in, the number of bytes available is
854       used instead. No data is consumed from the reader in this operation.
855     @param offset bytes to skip from the current position. The parameter
856       is modified after the call.
857     @return pointer to one position after the end of the data copied. The
858       parameter buf is set to this value also.
859 
860   */
861   inkcoreapi char *memcpy(const void *buf, int64_t len = INT64_MAX, int64_t offset = 0);
862 
863   /**
864     Subscript operator. Returns a reference to the character at the
865     specified position. You must ensure that it is within an appropriate
866     range.
867 
868     @param i positions beyond the current point of the reader. It must
869       be less than the number of the bytes available to the reader.
870 
871     @return reference to the character in that position.
872 
873   */
874   char &operator[](int64_t i);
875 
876   MIOBuffer *
877   writer() const
878   {
879     return mbuf;
880   }
881   MIOBuffer *
882   allocated() const
883   {
884     return mbuf;
885   }
886 
887   MIOBufferAccessor *accessor = nullptr; // pointer back to the accessor
888 
889   /**
890     Back pointer to this object's MIOBuffer. A pointer back to the
891     MIOBuffer this reader is allocated from.
892 
893   */
894   MIOBuffer *mbuf = nullptr;
895   Ptr<IOBufferBlock> block;
896 
897   /**
898     Offset beyond the shared start(). The start_offset is used in the
899     calls that copy or consume data and is an offset at the beginning
900     of the available data.
901 
902   */
903   int64_t start_offset = 0;
904   int64_t size_limit   = INT64_MAX;
905 
906   IOBufferReader() {}
907 };
908 
909 /**
910   A multiple reader, single writer memory buffer. MIOBuffers are at
911   the center of all IOCore data transfer. MIOBuffers are the data
912   buffers used to transfer data to and from VConnections. A MIOBuffer
913   points to a list of IOBufferBlocks which in turn point to IOBufferData
914   structures that in turn point to the actual data. MIOBuffer allows one
915   producer and multiple consumers. The buffer fills up according the
916   amount of data outstanding for the slowest consumer. Thus, MIOBuffer
917   implements automatic flow control between readers of different speeds.
918   Data on IOBuffer is immutable. Once written it cannot be modified, only
919   deallocated once all consumers have finished with it. Immutability is
920   necessary since data can be shared between buffers, which means that
921   multiple IOBufferBlock objects may reference the same data but only
922   one will have ownership for writing.
923 
924 */
925 class MIOBuffer
926 {
927 public:
928   /**
929     Increase writer's inuse area. Instructs the writer associated with
930     this MIOBuffer to increase the inuse area of the block by as much as
931     'len' bytes.
932 
933     @param len number of bytes to add to the inuse area of the block.
934 
935   */
936   void fill(int64_t len);
937 
938   /**
939     Adds a block to the end of the block list. The block added to list
940     must be writable by this buffer and must not be writable by any
941     other buffer.
942 
943   */
944   void append_block(IOBufferBlock *b);
945 
946   /**
947     Adds a new block to the end of the block list. The size is determined
948     by asize_index. See the remarks section for a mapping of indexes to
949     buffer block sizes.
950 
951   */
952   void append_block(int64_t asize_index);
953 
954   /**
955     Adds new block to the end of block list using the block size for
956     the buffer specified when the buffer was allocated.
957 
958   */
959   void add_block();
960 
961   /**
962     Adds by reference len bytes of data pointed to by b to the end
963     of the buffer.  b MUST be a pointer to the beginning of  block
964     allocated from the ats_xmalloc() routine. The data will be deallocated
965     by the buffer once all readers on the buffer have consumed it.
966 
967   */
968   void append_xmalloced(void *b, int64_t len);
969 
970   /**
971     Adds by reference len bytes of data pointed to by b to the end of the
972     buffer. b MUST be a pointer to the beginning of  block allocated from
973     ioBufAllocator of the corresponding index for fast_size_index. The
974     data will be deallocated by the buffer once all readers on the buffer
975     have consumed it.
976 
977   */
978   void append_fast_allocated(void *b, int64_t len, int64_t fast_size_index);
979 
980   /**
981     Adds the nbytes worth of data pointed by rbuf to the buffer. The
982     data is copied into the buffer. write() does not respect watermarks
983     or buffer size limits. Users of write must implement their own flow
984     control. Returns the number of bytes added.
985 
986   */
987   inkcoreapi int64_t write(const void *rbuf, int64_t nbytes);
988 
989 #ifdef WRITE_AND_TRANSFER
990   /**
991     Same functionality as write but for the one small difference. The
992     space available in the last block is taken from the original and
993     this space becomes available to the copy.
994 
995   */
996   inkcoreapi int64_t write_and_transfer_left_over_space(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0);
997 #endif
998 
999   /**
1000     Add by data from IOBufferReader r to the this buffer by reference. If
1001     len is INT64_MAX, all available data on the reader is added. If len is
1002     less than INT64_MAX, the smaller of len or the amount of data on the
1003     buffer is added. If offset is greater than zero, than the offset
1004     bytes of data at the front of the reader are skipped. Bytes skipped
1005     by offset reduce the number of bytes available on the reader used
1006     in the amount of data to add computation. write() does not respect
1007     watermarks or buffer size limits. Users of write must implement
1008     their own flow control. Returns the number of bytes added. Each
1009     write() call creates a new IOBufferBlock, even if it is for one
1010     byte. As such, it's necessary to exercise caution in any code that
1011     repeatedly transfers data from one buffer to another, especially if
1012     the data is being read over the network as it may be coming in very
1013     small chunks. Because deallocation of outstanding buffer blocks is
1014     recursive, it's possible to overrun the stack if too many blocks
1015     have been added to the buffer chain. It's imperative that users
1016     both implement their own flow control to prevent too many bytes
1017     from becoming outstanding on a buffer that the write() call is
1018     being used and that care be taken to ensure the transfers are of a
1019     minimum size. Should it be necessary to make a large number of small
1020     transfers, it's preferable to use a interface that copies the data
1021     rather than sharing blocks to prevent a build of blocks on the buffer.
1022 
1023   */
1024   inkcoreapi int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0);
1025 
1026   /** Copy data from the @a chain to this buffer.
1027       New IOBufferBlocks are allocated so this gets a copy of the data that is independent of the source.
1028       @a offset bytes are skipped at the start of the @a chain. The length is bounded by @a len and the
1029       size in the @a chain.
1030 
1031       @return the number of bytes copied.
1032 
1033       @internal I do not like counting @a offset against @a bytes but that's how @c write works...
1034   */
1035   int64_t write(IOBufferChain const *chain, int64_t len = INT64_MAX, int64_t offset = 0);
1036 
1037   int64_t remove_append(IOBufferReader *);
1038 
1039   /**
1040     Returns a pointer to the first writable block on the block chain.
1041     Returns nullptr if there are not currently any writable blocks on the
1042     block list.
1043   */
1044   IOBufferBlock *
1045   first_write_block()
1046   {
1047     if (_writer) {
1048       if (_writer->next && !_writer->write_avail()) {
1049         return _writer->next.get();
1050       }
1051       ink_assert(!_writer->next || !_writer->next->read_avail());
1052       return _writer.get();
1053     }
1054 
1055     return nullptr;
1056   }
1057 
1058   char *
1059   buf()
1060   {
1061     IOBufferBlock *b = first_write_block();
1062     return b ? b->buf() : nullptr;
1063   }
1064 
1065   char *
1066   buf_end()
1067   {
1068     return first_write_block()->buf_end();
1069   }
1070 
1071   char *
1072   start()
1073   {
1074     return first_write_block()->start();
1075   }
1076 
1077   char *
1078   end()
1079   {
1080     return first_write_block()->end();
1081   }
1082 
1083   /**
1084     Returns the amount of space of available for writing on the first
1085     writable block on the block chain (the one that would be reutrned
1086     by first_write_block()).
1087 
1088   */
1089   int64_t block_write_avail();
1090 
1091   /**
1092     Returns the amount of space of available for writing on all writable
1093     blocks currently on the block chain.  Will NOT add blocks to the
1094     block chain.
1095 
1096   */
1097   int64_t current_write_avail();
1098 
1099   /**
1100     Adds blocks for writing if the watermark criteria are met. Returns
1101     the amount of space of available for writing on all writable blocks
1102     on the block chain after a block due to the watermark criteria.
1103 
1104   */
1105   int64_t write_avail();
1106 
1107   /**
1108     Returns the default data block size for this buffer.
1109 
1110   */
1111   int64_t block_size();
1112 
1113   /**
1114     Returns the default data block size for this buffer.
1115 
1116   */
1117   int64_t
1118   total_size()
1119   {
1120     return block_size();
1121   }
1122 
1123   /**
1124     Returns true if amount of the data outstanding on the buffer exceeds
1125     the watermark.
1126 
1127   */
1128   bool
1129   high_water()
1130   {
1131     return max_read_avail() > water_mark;
1132   }
1133 
1134   /**
1135     Returns true if the amount of writable space after adding a block on
1136     the buffer is less than the water mark. Since this function relies
1137     on write_avail() it may add blocks.
1138 
1139   */
1140   bool
1141   low_water()
1142   {
1143     return write_avail() <= water_mark;
1144   }
1145 
1146   /**
1147     Returns true if amount the amount writable space without adding and
1148     blocks on the buffer is less than the water mark.
1149 
1150   */
1151   bool
1152   current_low_water()
1153   {
1154     return current_write_avail() <= water_mark;
1155   }
1156   void set_size_index(int64_t size);
1157 
1158   /**
1159     Allocates a new IOBuffer reader and sets it's its 'accessor' field
1160     to point to 'anAccessor'.
1161 
1162   */
1163   IOBufferReader *alloc_accessor(MIOBufferAccessor *anAccessor);
1164 
1165   /**
1166     Allocates an IOBufferReader for this buffer. IOBufferReaders hold
1167     data on the buffer for different consumers. IOBufferReaders are
1168     REQUIRED when using buffer. alloc_reader() MUST ONLY be a called
1169     on newly allocated buffers. Calling on a buffer with data already
1170     placed on it will result in the reader starting at an indeterminate
1171     place on the buffer.
1172 
1173   */
1174   IOBufferReader *alloc_reader();
1175 
1176   /**
1177     Allocates a new reader on this buffer and places it's starting
1178     point at the same place as reader r. r MUST be a pointer to a reader
1179     previous allocated from this buffer.
1180 
1181   */
1182   IOBufferReader *clone_reader(IOBufferReader *r);
1183 
1184   /**
1185     Deallocates reader e from this buffer. e MUST be a pointer to a reader
1186     previous allocated from this buffer. Reader need to allocated when a
1187     particularly consumer is being removed from the buffer but the buffer
1188     is still in use. Deallocation is not necessary when the buffer is
1189     being freed as all outstanding readers are automatically deallocated.
1190 
1191   */
1192   void dealloc_reader(IOBufferReader *e);
1193 
1194   /**
1195     Deallocates all outstanding readers on the buffer.
1196 
1197   */
1198   void dealloc_all_readers();
1199 
1200   void set(void *b, int64_t len);
1201   void set_xmalloced(void *b, int64_t len);
1202   void alloc(int64_t i = default_large_iobuffer_size);
1203   void alloc_xmalloc(int64_t buf_size);
1204   void append_block_internal(IOBufferBlock *b);
1205   int64_t write(IOBufferBlock const *b, int64_t len, int64_t offset);
1206   int64_t puts(char *buf, int64_t len);
1207 
1208   // internal interface
1209 
1210   bool
1211   empty()
1212   {
1213     return !_writer;
1214   }
1215   int64_t max_read_avail();
1216 
1217   int max_block_count();
1218   void check_add_block();
1219 
1220   IOBufferBlock *get_current_block();
1221 
1222   void
1223   reset()
1224   {
1225     if (_writer) {
1226       _writer->reset();
1227     }
1228     for (auto &reader : readers) {
1229       if (reader.allocated()) {
1230         reader.reset();
1231       }
1232     }
1233   }
1234 
1235   void
1236   init_readers()
1237   {
1238     for (auto &reader : readers) {
1239       if (reader.allocated() && !reader.block) {
1240         reader.block = _writer;
1241       }
1242     }
1243   }
1244 
1245   void
1246   dealloc()
1247   {
1248     _writer = nullptr;
1249     dealloc_all_readers();
1250   }
1251 
1252   void
1253   clear()
1254   {
1255     dealloc();
1256     size_index = BUFFER_SIZE_NOT_ALLOCATED;
1257     water_mark = 0;
1258   }
1259 
1260   void
1261   realloc(int64_t i)
1262   {
1263     _writer->realloc(i);
1264   }
1265   void
1266   realloc(void *b, int64_t buf_size)
1267   {
1268     _writer->realloc(b, buf_size);
1269   }
1270   void
1271   realloc_xmalloc(void *b, int64_t buf_size)
1272   {
1273     _writer->realloc_xmalloc(b, buf_size);
1274   }
1275   void
1276   realloc_xmalloc(int64_t buf_size)
1277   {
1278     _writer->realloc_xmalloc(buf_size);
1279   }
1280 
1281   int64_t size_index;
1282 
1283   /**
1284     Determines when to stop writing or reading. The watermark is the
1285     level to which the producer (filler) is required to fill the buffer
1286     before it can expect the reader to consume any data.  A watermark
1287     of zero means that the reader will consume any amount of data,
1288     no matter how small.
1289 
1290   */
1291   int64_t water_mark;
1292 
1293   Ptr<IOBufferBlock> _writer;
1294   IOBufferReader readers[MAX_MIOBUFFER_READERS];
1295 
1296 #ifdef TRACK_BUFFER_USER
1297   const char *_location = nullptr;
1298 #endif
1299 
1300   MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark);
1301   MIOBuffer(int64_t default_size_index);
1302   MIOBuffer();
1303   ~MIOBuffer();
1304 };
1305 
1306 /**
1307   A wrapper for either a reader or a writer of an MIOBuffer.
1308 
1309 */
1310 struct MIOBufferAccessor {
1311   IOBufferReader *
1312   reader()
1313   {
1314     return entry;
1315   }
1316 
1317   MIOBuffer *
1318   writer()
1319   {
1320     return mbuf;
1321   }
1322 
1323   int64_t
1324   block_size() const
1325   {
1326     return mbuf->block_size();
1327   }
1328 
1329   int64_t
1330   total_size() const
1331   {
1332     return block_size();
1333   }
1334 
1335   void reader_for(IOBufferReader *abuf);
1336   void reader_for(MIOBuffer *abuf);
1337   void writer_for(MIOBuffer *abuf);
1338 
1339   void
1340   clear()
1341   {
1342     mbuf  = nullptr;
1343     entry = nullptr;
1344   }
1345 
1346   MIOBufferAccessor() {}
1347 
1348   ~MIOBufferAccessor();
1349 
1350 #ifdef DEBUG
1351   const char *name = nullptr;
1352 #endif
1353 
1354   // noncopyable
1355   MIOBufferAccessor(const MIOBufferAccessor &) = delete;
1356   MIOBufferAccessor &operator=(const MIOBufferAccessor &) = delete;
1357 
1358 private:
1359   MIOBuffer *mbuf       = nullptr;
1360   IOBufferReader *entry = nullptr;
1361 };
1362 
1363 extern MIOBuffer *new_MIOBuffer_internal(
1364 #ifdef TRACK_BUFFER_USER
1365   const char *loc,
1366 #endif
1367   int64_t size_index = default_large_iobuffer_size);
1368 
1369 #ifdef TRACK_BUFFER_USER
1370 class MIOBuffer_tracker
1371 {
1372   const char *loc;
1373 
1374 public:
1375   MIOBuffer_tracker(const char *_loc) : loc(_loc) {}
1376   MIOBuffer *
1377   operator()(int64_t size_index = default_large_iobuffer_size)
1378   {
1379     return new_MIOBuffer_internal(loc, size_index);
1380   }
1381 };
1382 #endif
1383 
1384 extern MIOBuffer *new_empty_MIOBuffer_internal(
1385 #ifdef TRACK_BUFFER_USER
1386   const char *loc,
1387 #endif
1388   int64_t size_index = default_large_iobuffer_size);
1389 
1390 #ifdef TRACK_BUFFER_USER
1391 class Empty_MIOBuffer_tracker
1392 {
1393   const char *loc;
1394 
1395 public:
1396   Empty_MIOBuffer_tracker(const char *_loc) : loc(_loc) {}
1397   MIOBuffer *
1398   operator()(int64_t size_index = default_large_iobuffer_size)
1399   {
1400     return new_empty_MIOBuffer_internal(loc, size_index);
1401   }
1402 };
1403 #endif
1404 
1405 /// MIOBuffer allocator/deallocator
1406 #ifdef TRACK_BUFFER_USER
1407 #define new_MIOBuffer MIOBuffer_tracker(RES_PATH("memory/IOBuffer/"))
1408 #define new_empty_MIOBuffer Empty_MIOBuffer_tracker(RES_PATH("memory/IOBuffer/"))
1409 #else
1410 #define new_MIOBuffer new_MIOBuffer_internal
1411 #define new_empty_MIOBuffer new_empty_MIOBuffer_internal
1412 #endif
1413 extern void free_MIOBuffer(MIOBuffer *mio);
1414 //////////////////////////////////////////////////////////////////////
1415 
1416 extern IOBufferBlock *new_IOBufferBlock_internal(
1417 #ifdef TRACK_BUFFER_USER
1418   const char *loc
1419 #endif
1420 );
1421 
1422 extern IOBufferBlock *new_IOBufferBlock_internal(
1423 #ifdef TRACK_BUFFER_USER
1424   const char *loc,
1425 #endif
1426   IOBufferData *d, int64_t len = 0, int64_t offset = 0);
1427 
1428 #ifdef TRACK_BUFFER_USER
1429 class IOBufferBlock_tracker
1430 {
1431   const char *loc;
1432 
1433 public:
1434   IOBufferBlock_tracker(const char *_loc) : loc(_loc) {}
1435   IOBufferBlock *
1436   operator()()
1437   {
1438     return new_IOBufferBlock_internal(loc);
1439   }
1440   IOBufferBlock *
1441   operator()(Ptr<IOBufferData> &d, int64_t len = 0, int64_t offset = 0)
1442   {
1443     return new_IOBufferBlock_internal(loc, d.get(), len, offset);
1444   }
1445 };
1446 #endif
1447 
1448 /// IOBufferBlock allocator
1449 #ifdef TRACK_BUFFER_USER
1450 #define new_IOBufferBlock IOBufferBlock_tracker(RES_PATH("memory/IOBuffer/"))
1451 #else
1452 #define new_IOBufferBlock new_IOBufferBlock_internal
1453 #endif
1454 ////////////////////////////////////////////////////////////
1455 
1456 extern IOBufferData *new_IOBufferData_internal(
1457 #ifdef TRACK_BUFFER_USER
1458   const char *location,
1459 #endif
1460   int64_t size_index = default_large_iobuffer_size, AllocType type = DEFAULT_ALLOC);
1461 
1462 extern IOBufferData *new_xmalloc_IOBufferData_internal(
1463 #ifdef TRACK_BUFFER_USER
1464   const char *location,
1465 #endif
1466   void *b, int64_t size);
1467 
1468 extern IOBufferData *new_constant_IOBufferData_internal(
1469 #ifdef TRACK_BUFFER_USER
1470   const char *locaction,
1471 #endif
1472   void *b, int64_t size);
1473 
1474 #ifdef TRACK_BUFFER_USER
1475 class IOBufferData_tracker
1476 {
1477   const char *loc;
1478 
1479 public:
1480   IOBufferData_tracker(const char *_loc) : loc(_loc) {}
1481   IOBufferData *
1482   operator()(int64_t size_index = default_large_iobuffer_size, AllocType type = DEFAULT_ALLOC)
1483   {
1484     return new_IOBufferData_internal(loc, size_index, type);
1485   }
1486 };
1487 #endif
1488 
1489 #ifdef TRACK_BUFFER_USER
1490 #define new_IOBufferData IOBufferData_tracker(RES_PATH("memory/IOBuffer/"))
1491 #define new_xmalloc_IOBufferData(b, size) new_xmalloc_IOBufferData_internal(RES_PATH("memory/IOBuffer/"), (b), (size))
1492 #define new_constant_IOBufferData(b, size) new_constant_IOBufferData_internal(RES_PATH("memory/IOBuffer/"), (b), (size))
1493 #else
1494 #define new_IOBufferData new_IOBufferData_internal
1495 #define new_xmalloc_IOBufferData new_xmalloc_IOBufferData_internal
1496 #define new_constant_IOBufferData new_constant_IOBufferData_internal
1497 #endif
1498 
1499 extern int64_t iobuffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size);
1500 extern int64_t index_to_buffer_size(int64_t idx);
1501 /**
1502   Clone a IOBufferBlock chain. Used to snarf a IOBufferBlock chain
1503   w/o copy.
1504 
1505   @param b head of source IOBufferBlock chain.
1506   @param offset # bytes in the beginning to skip.
1507   @param len bytes to copy from source.
1508   @return ptr to head of new IOBufferBlock chain.
1509 
1510 */
1511 extern IOBufferBlock *iobufferblock_clone(IOBufferBlock *b, int64_t offset, int64_t len);
1512 /**
1513   Skip over specified bytes in chain. Used for dropping references.
1514 
1515   @param b head of source IOBufferBlock chain.
1516   @param poffset originally offset in b, finally offset in returned
1517     IOBufferBlock.
1518   @param plen value of write is subtracted from plen in the function.
1519   @param write bytes to skip.
1520   @return ptr to head of new IOBufferBlock chain.
1521 
1522 */
1523 extern IOBufferBlock *iobufferblock_skip(IOBufferBlock *b, int64_t *poffset, int64_t *plen, int64_t write);
1524 
1525 inline IOBufferChain &
1526 IOBufferChain::operator=(self_type const &that)
1527 {
1528   _head = that._head;
1529   _tail = that._tail;
1530   _len  = that._len;
1531   return *this;
1532 }
1533 
1534 inline IOBufferChain &
1535 IOBufferChain::operator+=(self_type const &that)
1536 {
1537   if (nullptr == _head)
1538     *this = that;
1539   else {
1540     _tail->next = that._head;
1541     _tail       = that._tail;
1542     _len += that._len;
1543   }
1544   return *this;
1545 }
1546 
1547 inline int64_t
1548 IOBufferChain::length() const
1549 {
1550   return _len;
1551 }
1552 
1553 inline IOBufferBlock const *
1554 IOBufferChain::head() const
1555 {
1556   return _head.get();
1557 }
1558 
1559 inline IOBufferBlock *
1560 IOBufferChain::head()
1561 {
1562   return _head.get();
1563 }
1564 
1565 inline void
1566 IOBufferChain::clear()
1567 {
1568   _head = nullptr;
1569   _tail = nullptr;
1570   _len  = 0;
1571 }
1572 
1573 inline IOBufferChain::const_iterator::const_iterator(self_type const &that) : _b(that._b) {}
1574 
1575 inline IOBufferChain::const_iterator &
1576 IOBufferChain::const_iterator::operator=(self_type const &that)
1577 {
1578   _b = that._b;
1579   return *this;
1580 }
1581 
1582 inline bool
1583 IOBufferChain::const_iterator::operator==(self_type const &that) const
1584 {
1585   return _b == that._b;
1586 }
1587 
1588 inline bool
1589 IOBufferChain::const_iterator::operator!=(self_type const &that) const
1590 {
1591   return _b != that._b;
1592 }
1593 
1594 inline IOBufferChain::const_iterator::value_type &IOBufferChain::const_iterator::operator*() const
1595 {
1596   return *_b;
1597 }
1598 
1599 inline IOBufferChain::const_iterator::value_type *IOBufferChain::const_iterator::operator->() const
1600 {
1601   return _b;
1602 }
1603 
1604 inline IOBufferChain::const_iterator &
1605 IOBufferChain::const_iterator::operator++()
1606 {
1607   _b = _b->next.get();
1608   return *this;
1609 }
1610 
1611 inline IOBufferChain::const_iterator
1612 IOBufferChain::const_iterator::operator++(int)
1613 {
1614   self_type pre{*this};
1615   ++*this;
1616   return pre;
1617 }
1618 
1619 inline IOBufferChain::iterator::value_type &IOBufferChain::iterator::operator*() const
1620 {
1621   return *_b;
1622 }
1623 
1624 inline IOBufferChain::iterator::value_type *IOBufferChain::iterator::operator->() const
1625 {
1626   return _b;
1627 }
1628