trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a..@apache.org
Subject [trafficserver] branch master updated: IOBufferChain: A class for holding an IO buffer block chain.
Date Mon, 04 Jun 2018 14:02:03 GMT
This is an automated email from the ASF dual-hosted git repository.

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 7621f3e  IOBufferChain: A class for holding an IO buffer block chain.
7621f3e is described below

commit 7621f3edd123ddd2490ec4c07e1f266d78095d6c
Author: Alan M. Carroll <amc@apache.org>
AuthorDate: Tue May 15 14:51:56 2018 -0500

    IOBufferChain: A class for holding an IO buffer block chain.
---
 iocore/eventsystem/IOBuffer.cc  | 103 +++++++++++++++++-
 iocore/eventsystem/I_IOBuffer.h | 236 +++++++++++++++++++++++++++++++++++++++-
 iocore/eventsystem/P_IOBuffer.h |   2 +-
 3 files changed, 334 insertions(+), 7 deletions(-)

diff --git a/iocore/eventsystem/IOBuffer.cc b/iocore/eventsystem/IOBuffer.cc
index e92dc94..5d80d49 100644
--- a/iocore/eventsystem/IOBuffer.cc
+++ b/iocore/eventsystem/IOBuffer.cc
@@ -136,11 +136,21 @@ MIOBuffer::write_and_transfer_left_over_space(IOBufferReader *r, int64_t
alen, i
 #endif
 
 int64_t
-MIOBuffer::write(IOBufferReader *r, int64_t alen, int64_t offset)
+MIOBuffer::write(IOBufferReader *r, int64_t len, int64_t offset)
 {
-  int64_t len      = alen;
-  IOBufferBlock *b = r->block.get();
-  offset += r->start_offset;
+  return this->write(r->block.get(), len, offset + r->start_offset);
+}
+
+int64_t
+MIOBuffer::write(IOBufferChain const *chain, int64_t len, int64_t offset)
+{
+  return this->write(chain->head(), std::min(len, chain->length()), offset);
+}
+
+int64_t
+MIOBuffer::write(IOBufferBlock const *b, int64_t alen, int64_t offset)
+{
+  int64_t len = alen;
 
   while (b && len > 0) {
     int64_t max_bytes = b->read_avail();
@@ -279,6 +289,91 @@ IOBufferReader::memcpy(const void *ap, int64_t len, int64_t offset)
   return p;
 }
 
+int64_t
+IOBufferChain::write(IOBufferBlock *blocks, int64_t length, int64_t offset)
+{
+  int64_t n = length;
+
+  while (blocks && n > 0) {
+    int64_t block_bytes = blocks->read_avail();
+    if (block_bytes <= offset) { // skip the entire block
+      offset -= block_bytes;
+    } else {
+      int64_t bytes     = std::min(n, block_bytes - offset);
+      IOBufferBlock *bb = blocks->clone();
+      if (offset) {
+        bb->consume(offset);
+        block_bytes -= offset; // bytes really available to use.
+        offset = 0;
+      }
+      if (block_bytes > n)
+        bb->_end -= (block_bytes - n);
+      // Attach the cloned block since its data will be kept.
+      this->append(bb);
+      n -= bytes;
+    }
+    blocks = blocks->next.get();
+  }
+
+  length -= n; // actual bytes written to chain.
+  _len += length;
+  return length;
+}
+
+int64_t
+IOBufferChain::write(IOBufferData *data, int64_t length, int64_t offset)
+{
+  int64_t zret     = 0;
+  IOBufferBlock *b = new_IOBufferBlock();
+
+  if (length < 0)
+    length = 0;
+
+  b->set(data, length, offset);
+  this->append(b);
+
+  zret = b->read_avail();
+  _len += zret;
+  return zret;
+}
+
+void
+IOBufferChain::append(IOBufferBlock *block)
+{
+  if (nullptr == _tail) {
+    _head = block;
+    _tail = block;
+  } else {
+    _tail->next = block;
+    _tail       = block;
+  }
+}
+
+int64_t
+IOBufferChain::consume(int64_t size)
+{
+  int64_t zret = 0;
+  int64_t bytes;
+  size = std::min(size, _len);
+
+  while (_head != nullptr && size > 0 && (bytes = _head->read_avail())
> 0) {
+    if (size >= bytes) {
+      _head = _head->next;
+      zret += bytes;
+      size -= bytes;
+    } else {
+      _head->consume(size);
+      zret += size;
+      size = 0;
+    }
+  }
+  _len -= zret;
+  if (_head == nullptr || _len == 0) {
+    _head = nullptr, _tail = nullptr, _len = 0;
+  }
+  return zret;
+}
+
 //-- MIOBufferWriter
 MIOBufferWriter &
 MIOBufferWriter::write(const void *data_, size_t length)
diff --git a/iocore/eventsystem/I_IOBuffer.h b/iocore/eventsystem/I_IOBuffer.h
index 2105d7d..1f1b9ad 100644
--- a/iocore/eventsystem/I_IOBuffer.h
+++ b/iocore/eventsystem/I_IOBuffer.h
@@ -357,7 +357,7 @@ public:
 
   */
   int64_t
-  read_avail()
+  read_avail() const
   {
     return (int64_t)(_end - _start);
   }
@@ -433,7 +433,7 @@ public:
     @return copy of this IOBufferBlock.
 
   */
-  IOBufferBlock *clone();
+  IOBufferBlock *clone() const;
 
   /**
     Clear the IOBufferData this IOBufferBlock handles. Clears this
@@ -526,6 +526,122 @@ public:
 
 extern inkcoreapi ClassAllocator<IOBufferBlock> ioBlockAllocator;
 
+/** A class for holding a chain of IO buffer blocks.
+    This class is intended to be used as a member variable for other classes that
+    need to anchor an IO Buffer chain but don't need the full @c MIOBuffer machinery.
+    That is, the owner is the only reader/writer of the data.
+
+    This does not handle incremental reads or writes well. The intent is that data is
+    placed in the instance, held for a while, then used and discarded.
+
+    @note Contrast also with @c IOBufferReader which is similar but requires an
+    @c MIOBuffer as its owner.
+*/
+class IOBufferChain
+{
+  using self_type = IOBufferChain; ///< Self reference type.
+
+public:
+  /// Default constructor - construct empty chain.
+  IOBufferChain() = default;
+  /// Shallow copy.
+  self_type &operator=(self_type const &that);
+
+  /// Shallow append.
+  self_type &operator+=(self_type const &that);
+
+  /// Number of bytes of content.
+  int64_t length() const;
+
+  /// Copy a chain of @a blocks in to this object up to @a length bytes.
+  /// If @a offset is greater than 0 that many bytes are skipped. Those bytes do not count
+  /// as part of @a length.
+  /// This creates a new chain using existing data blocks. This
+  /// breaks the original chain so that changes there (such as appending blocks)
+  /// is not reflected in this chain.
+  /// @return The number of bytes written to the chain.
+  int64_t write(IOBufferBlock *blocks, int64_t length, int64_t offset = 0);
+
+  /// Add the content of a buffer block.
+  /// The buffer block is unchanged.
+  int64_t write(IOBufferData *data, int64_t length = 0, int64_t offset = 0);
+
+  /// Remove @a size bytes of content from the front of the chain.
+  /// @return The actual number of bytes removed.
+  int64_t consume(int64_t size);
+
+  /// Clear current chain.
+  void clear();
+
+  /// Get the first block.
+  IOBufferBlock *head();
+  IOBufferBlock const *head() const;
+
+  /// STL Container support.
+
+  /// Block iterator.
+  /// @internal The reason for this is to override the increment operator.
+  class const_iterator : public std::forward_iterator_tag
+  {
+    using self_type = const_iterator; ///< Self reference type.
+  protected:
+    /// Current buffer block.
+    IOBufferBlock *_b = nullptr;
+
+  public:
+    using value_type = const IOBufferBlock; ///< Iterator value type.
+
+    const_iterator() = default; ///< Default constructor.
+
+    /// Copy constructor.
+    const_iterator(self_type const &that);
+
+    /// Assignment.
+    self_type &operator=(self_type const &that);
+
+    /// Equality.
+    bool operator==(self_type const &that) const;
+    /// Inequality.
+    bool operator!=(self_type const &that) const;
+
+    value_type &operator*() const;
+    value_type *operator->() const;
+
+    self_type &operator++();
+    self_type operator++(int);
+  };
+
+  class iterator : public const_iterator
+  {
+    using self_type = iterator; ///< Self reference type.
+  public:
+    using value_type = IOBufferBlock; ///< Dereferenced type.
+
+    value_type &operator*() const;
+    value_type *operator->() const;
+  };
+
+  using value_type = IOBufferBlock;
+
+  iterator begin();
+  const_iterator begin() const;
+
+  iterator end();
+  const_iterator end() const;
+
+protected:
+  /// Append @a block.
+  void append(IOBufferBlock *block);
+
+  /// Head of buffer block chain.
+  Ptr<IOBufferBlock> _head;
+  /// Tail of the block chain.
+  IOBufferBlock *_tail = nullptr;
+  /// The amount of data of interest.
+  /// Not necessarily the amount of data in the chain of blocks.
+  int64_t _len = 0;
+};
+
 /**
   An independent reader from an MIOBuffer. A reader for a set of
   IOBufferBlocks. The IOBufferReader represents the place where a given
@@ -910,6 +1026,17 @@ public:
   */
   inkcoreapi int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0);
 
+  /** Copy data from the @a chain to this buffer.
+      New IOBufferBlocks are allocated so this gets a copy of the data that is independent
of the source.
+      @a offset bytes are skipped at the start of the @a chain. The length is bounded by
@a len and the
+      size in the @a chain.
+
+      @return the number of bytes copied.
+
+      @internal I do not like counting @a offset against @a bytes but that's how @c write
works...
+  */
+  int64_t write(IOBufferChain const *chain, int64_t len = INT64_MAX, int64_t offset = 0);
+
   int64_t remove_append(IOBufferReader *);
 
   /**
@@ -1078,6 +1205,7 @@ public:
   void alloc(int64_t i = default_large_iobuffer_size);
   void alloc_xmalloc(int64_t buf_size);
   void append_block_internal(IOBufferBlock *b);
+  int64_t write(IOBufferBlock const *b, int64_t len, int64_t offset);
   int64_t puts(char *buf, int64_t len);
 
   // internal interface
@@ -1404,3 +1532,107 @@ extern IOBufferBlock *iobufferblock_clone(IOBufferBlock *b, int64_t
offset, int6
 
 */
 extern IOBufferBlock *iobufferblock_skip(IOBufferBlock *b, int64_t *poffset, int64_t *plen,
int64_t write);
+
+inline IOBufferChain &
+IOBufferChain::operator=(self_type const &that)
+{
+  _head = that._head;
+  _tail = that._tail;
+  _len  = that._len;
+  return *this;
+}
+
+inline IOBufferChain &
+IOBufferChain::operator+=(self_type const &that)
+{
+  if (nullptr == _head)
+    *this = that;
+  else {
+    _tail->next = that._head;
+    _tail       = that._tail;
+    _len += that._len;
+  }
+  return *this;
+}
+
+inline int64_t
+IOBufferChain::length() const
+{
+  return _len;
+}
+
+inline IOBufferBlock const *
+IOBufferChain::head() const
+{
+  return _head.get();
+}
+
+inline IOBufferBlock *
+IOBufferChain::head()
+{
+  return _head.get();
+}
+
+inline void
+IOBufferChain::clear()
+{
+  _head = nullptr;
+  _tail = nullptr;
+  _len  = 0;
+}
+
+inline IOBufferChain::const_iterator::const_iterator(self_type const &that) : _b(that._b)
{}
+
+inline IOBufferChain::const_iterator &
+IOBufferChain::const_iterator::operator=(self_type const &that)
+{
+  _b = that._b;
+  return *this;
+}
+
+inline bool
+IOBufferChain::const_iterator::operator==(self_type const &that) const
+{
+  return _b == that._b;
+}
+
+inline bool
+IOBufferChain::const_iterator::operator!=(self_type const &that) const
+{
+  return _b != that._b;
+}
+
+inline IOBufferChain::const_iterator::value_type &IOBufferChain::const_iterator::operator*()
const
+{
+  return *_b;
+}
+
+inline IOBufferChain::const_iterator::value_type *IOBufferChain::const_iterator::operator->()
const
+{
+  return _b;
+}
+
+inline IOBufferChain::const_iterator &
+IOBufferChain::const_iterator::operator++()
+{
+  _b = _b->next.get();
+  return *this;
+}
+
+inline IOBufferChain::const_iterator
+IOBufferChain::const_iterator::operator++(int)
+{
+  self_type pre{*this};
+  ++*this;
+  return pre;
+}
+
+inline IOBufferChain::iterator::value_type &IOBufferChain::iterator::operator*() const
+{
+  return *_b;
+}
+
+inline IOBufferChain::iterator::value_type *IOBufferChain::iterator::operator->() const
+{
+  return _b;
+}
diff --git a/iocore/eventsystem/P_IOBuffer.h b/iocore/eventsystem/P_IOBuffer.h
index b348c74..cfbba65 100644
--- a/iocore/eventsystem/P_IOBuffer.h
+++ b/iocore/eventsystem/P_IOBuffer.h
@@ -453,7 +453,7 @@ IOBufferBlock::clear()
 }
 
 TS_INLINE IOBufferBlock *
-IOBufferBlock::clone()
+IOBufferBlock::clone() const
 {
 #ifdef TRACK_BUFFER_USER
   IOBufferBlock *b = new_IOBufferBlock_internal(_location);

-- 
To stop receiving notification emails like this one, please contact
amc@apache.org.

Mime
View raw message