You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2017/10/19 12:36:43 UTC

[trafficserver] branch master updated: Add MIOBufferWriter class which writes to an MIOBuffer instance.

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 88431a4  Add MIOBufferWriter class which writes to an MIOBuffer instance.
88431a4 is described below

commit 88431a42abf1df769ceeb826bc4faea26fddbd0d
Author: Walt Karas <wk...@yahoo-inc.com>
AuthorDate: Thu Sep 21 22:40:52 2017 +0000

    Add MIOBufferWriter class which writes to an MIOBuffer instance.
---
 .gitignore                                         |   1 +
 iocore/eventsystem/I_MIOBufferWriter.h             | 174 +++++++++++++++++
 iocore/eventsystem/Makefile.am                     |   9 +-
 .../eventsystem/unit-tests/test_MIOBufferWriter.cc | 217 +++++++++++++++++++++
 4 files changed, 400 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 2d9b5e0..885d6b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,6 +92,7 @@ iocore/net/test_UDPNet
 iocore/aio/test_AIO
 iocore/eventsystem/test_Buffer
 iocore/eventsystem/test_Event
+iocore/eventsystem/test_MIOBufferWriter
 iocore/hostdb/test_RefCountCache
 
 proxy/config/records.config.default
diff --git a/iocore/eventsystem/I_MIOBufferWriter.h b/iocore/eventsystem/I_MIOBufferWriter.h
new file mode 100644
index 0000000..3943fc8
--- /dev/null
+++ b/iocore/eventsystem/I_MIOBufferWriter.h
@@ -0,0 +1,174 @@
+#if !defined I_MIOBUFFERWRITER_H_
+#define I_MIOBUFFERWRITER_H_
+
+/** @file
+
+    Buffer Writer for an MIOBuffer.
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#include <cstring>
+
+#include <ts/ink_assert.h>
+#include <ts/BufferWriter.h>
+
+#if !defined(UNIT_TEST_BUFFER_WRITER)
+#include <I_IOBuffer.h>
+#endif
+
+class MIOBufferWriter : public ts::BufferWriter
+{
+public:
+  MIOBufferWriter(MIOBuffer &miob) : _miob(miob) {}
+
+  MIOBufferWriter &
+  write(const void *data_, size_t length) override
+  {
+    const char *data = static_cast<const char *>(data_);
+
+    while (length) {
+      IOBufferBlock *iobbPtr = _miob.first_write_block();
+
+      if (!iobbPtr) {
+        addBlock();
+
+        iobbPtr = _miob.first_write_block();
+
+        ink_assert(iobbPtr);
+      }
+
+      size_t writeSize = iobbPtr->write_avail();
+
+      if (length < writeSize) {
+        writeSize = length;
+      }
+
+      std::memcpy(iobbPtr->end(), data, writeSize);
+      iobbPtr->fill(writeSize);
+
+      data += writeSize;
+      length -= writeSize;
+
+      _numWritten += writeSize;
+    }
+
+    return *this;
+  }
+
+  MIOBufferWriter &
+  write(char c) override
+  {
+    return write(&c, 1);
+  }
+
+  bool
+  error() const override
+  {
+    return false;
+  }
+
+  char *
+  auxBuffer() override
+  {
+    IOBufferBlock *iobbPtr = _miob.first_write_block();
+
+    if (!iobbPtr) {
+      return nullptr;
+    }
+
+    return iobbPtr->end();
+  }
+
+  size_t
+  auxBufferCapacity() const
+  {
+    IOBufferBlock *iobbPtr = _miob.first_write_block();
+
+    if (!iobbPtr) {
+      return 0;
+    }
+
+    return iobbPtr->write_avail();
+  }
+
+  // Write the first n characters that have been placed in the auxiliary buffer.  This call invalidates the auxiliary buffer.
+  // This function should not be called if no auxiliary buffer is available.
+  //
+  MIOBufferWriter &
+  write(size_t n) override
+  {
+    if (n) {
+      IOBufferBlock *iobbPtr = _miob.first_write_block();
+
+      ink_assert(iobbPtr and (n <= size_t(iobbPtr->write_avail())));
+
+      iobbPtr->fill(n);
+
+      _numWritten += n;
+    }
+
+    return *this;
+  }
+
+  // No fixed limit on capacity.
+  //
+  size_t
+  capacity() const override
+  {
+    return (~size_t(0));
+  }
+
+  size_t
+  extent() const override
+  {
+    return _numWritten;
+  }
+
+  // Not useful in this derived class.
+  //
+  BufferWriter &clip(size_t) override { return *this; }
+
+  // Not useful in this derived class.
+  //
+  BufferWriter &extend(size_t) override { return *this; }
+
+  // This must not be called for this derived class.
+  //
+  const char *
+  data() const override
+  {
+    ink_assert(false);
+    return nullptr;
+  }
+
+protected:
+  MIOBuffer &_miob;
+
+private:
+  size_t _numWritten = 0;
+
+  virtual void
+  addBlock()
+  {
+    _miob.add_block();
+  }
+};
+
+#endif // include once
diff --git a/iocore/eventsystem/Makefile.am b/iocore/eventsystem/Makefile.am
index 20835e6..c1d24f0 100644
--- a/iocore/eventsystem/Makefile.am
+++ b/iocore/eventsystem/Makefile.am
@@ -68,7 +68,8 @@ libinkevent_a_SOURCES = \
   UnixEvent.cc \
   UnixEventProcessor.cc
 
-check_PROGRAMS = test_Buffer test_Event
+check_PROGRAMS = test_Buffer test_Event \
+  test_MIOBufferWriter
 
 test_LD_FLAGS = \
   @AM_LDFLAGS@ \
@@ -117,6 +118,12 @@ test_Event_LDFLAGS = $(test_LD_FLAGS)
 test_Buffer_LDADD = $(test_LD_ADD)
 test_Event_LDADD = $(test_LD_ADD)
 
+test_MIOBufferWriter_CPPFLAGS = $(AM_CPPFLAGS)\
+  -I$(abs_top_srcdir)/tests/include
+
+test_MIOBufferWriter_SOURCES = \
+  unit-tests/test_MIOBufferWriter.cc
+
 include $(top_srcdir)/build/tidy.mk
 
 tidy-local: $(DIST_SOURCES)
diff --git a/iocore/eventsystem/unit-tests/test_MIOBufferWriter.cc b/iocore/eventsystem/unit-tests/test_MIOBufferWriter.cc
new file mode 100644
index 0000000..5665359
--- /dev/null
+++ b/iocore/eventsystem/unit-tests/test_MIOBufferWriter.cc
@@ -0,0 +1,217 @@
+/** @file
+
+    Catch-based unit tests for MIOBufferWriter class.
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+
+#include <cstdint>
+
+struct IOBufferBlock {
+  std::int64_t write_avail();
+
+  char *end();
+
+  void fill(int64_t);
+};
+
+struct MIOBuffer {
+  IOBufferBlock *first_write_block();
+
+  void add_block();
+};
+
+#define UNIT_TEST_BUFFER_WRITER
+#include "I_MIOBufferWriter.h"
+
+IOBufferBlock iobb[1];
+int iobbIdx{0};
+
+const int BlockSize = 11 * 11;
+char block[BlockSize];
+int blockUsed{0};
+
+std::int64_t
+IOBufferBlock::write_avail()
+{
+  REQUIRE(this == (iobb + iobbIdx));
+  return BlockSize - blockUsed;
+}
+
+char *
+IOBufferBlock::end()
+{
+  REQUIRE(this == (iobb + iobbIdx));
+  return block + blockUsed;
+}
+
+void
+IOBufferBlock::fill(int64_t len)
+{
+  static std::uint8_t dataCheck;
+
+  REQUIRE(this == (iobb + iobbIdx));
+
+  while (len-- and (blockUsed < BlockSize)) {
+    REQUIRE(block[blockUsed] == static_cast<char>(dataCheck));
+
+    ++blockUsed;
+
+    dataCheck += 7;
+  }
+
+  REQUIRE(len == -1);
+}
+
+MIOBuffer theMIOBuffer;
+
+IOBufferBlock *
+MIOBuffer::first_write_block()
+{
+  REQUIRE(this == &theMIOBuffer);
+
+  REQUIRE(blockUsed <= BlockSize);
+
+  if (blockUsed == BlockSize) {
+    return nullptr;
+  }
+
+  return iobb + iobbIdx;
+}
+
+void
+MIOBuffer::add_block()
+{
+  REQUIRE(this == &theMIOBuffer);
+
+  REQUIRE(blockUsed == BlockSize);
+
+  blockUsed = 0;
+
+  ++iobbIdx;
+}
+
+std::string
+genData(int numBytes)
+{
+  static std::uint8_t genData;
+
+  std::string s(numBytes, ' ');
+
+  for (int i{0}; i < numBytes; ++i) {
+    s[i] = genData;
+    genData += 7;
+  }
+
+  return s;
+}
+
+void
+writeOnce(MIOBufferWriter &bw, std::size_t len)
+{
+  static bool toggle;
+
+  std::string s{genData(len)};
+
+  if (len == 1) {
+    bw.write(s[0]);
+
+  } else if (toggle) {
+    std::size_t cap{bw.auxBufferCapacity()};
+
+    if (cap >= len) {
+      memcpy(bw.auxBuffer(), s.data(), len);
+      bw.write(len);
+
+    } else {
+      memcpy(bw.auxBuffer(), s.data(), cap);
+      bw.write(cap);
+      bw.write(s.data() + cap, len - cap);
+    }
+  } else {
+    bw.write(s.data(), len);
+  }
+
+  toggle = !toggle;
+
+  REQUIRE(bw.auxBufferCapacity() <= BlockSize);
+}
+
+class InkAssertExcept
+{
+};
+
+TEST_CASE("MIOBufferWriter", "[MIOBW]")
+{
+  MIOBufferWriter bw(theMIOBuffer);
+
+  REQUIRE(bw.auxBufferCapacity() == BlockSize);
+
+  writeOnce(bw, 0);
+  writeOnce(bw, 1);
+  writeOnce(bw, 1);
+  writeOnce(bw, 1);
+  writeOnce(bw, 10);
+  writeOnce(bw, 1000);
+  writeOnce(bw, 1);
+  writeOnce(bw, 0);
+  writeOnce(bw, 1);
+  writeOnce(bw, 2000);
+  writeOnce(bw, 69);
+  writeOnce(bw, 666);
+
+  for (int i = 0; i < 3000; i += 13) {
+    writeOnce(bw, i);
+  }
+
+  writeOnce(bw, 0);
+  writeOnce(bw, 1);
+
+  REQUIRE(bw.extent() == ((iobbIdx * BlockSize) + blockUsed));
+
+// These tests don't work properly with clang for some reason.
+#if !defined(__clang__)
+
+  try {
+    bw.write(bw.auxBufferCapacity() + 1);
+    REQUIRE(false);
+
+  } catch (InkAssertExcept) {
+    REQUIRE(true);
+  }
+
+  try {
+    bw.data();
+    REQUIRE(false);
+
+  } catch (InkAssertExcept) {
+    REQUIRE(true);
+  }
+
+#endif
+}
+
+void
+_ink_assert(const char *a, const char *f, int l)
+{
+  throw InkAssertExcept();
+}

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].