BIND 10 trac1603bench, updated. b3284a520ea8bcd5dfb32491eeecf2899d27b7e4 [1603bench] Merge branch 'trac1603' into trac1603bench

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Mar 9 07:35:24 UTC 2012


The branch, trac1603bench has been updated
       via  b3284a520ea8bcd5dfb32491eeecf2899d27b7e4 (commit)
       via  b1fb64710cddf53857625d7a871f82775e20d93b (commit)
       via  cd8b0868f1b4bd63f4bc9b661f0afca448e57797 (commit)
       via  c3374ed01863bf7643cddd90f4ef47d338df6225 (commit)
       via  1389eb8fa945be3ffd35d0daff3bcbf17da15549 (commit)
       via  84c6c601a78cdb568b5f7e004d03e20de6b42414 (commit)
       via  55fdccd716864e9f33675546d3b6fcce18027473 (commit)
       via  5434c74a0bf1a4435af9879572143a7b9574f713 (commit)
       via  a62bbb2d56d09aa359be5ba96fff9de9a1e5a36f (commit)
       via  eabc47cf4ee5ff9e3cc92a2e2b7c5b9481fa7bca (commit)
       via  d442b1483e3196ae118fdc982525f15c574e91a0 (commit)
       via  84a7f88f41fd49749deda05aaef7e978bd0fb90f (commit)
       via  dd95b7f18281fd4f06d5f13b5a99ca9e083f774e (commit)
       via  5b91b5ef2cdec92eba172a379a196f2c4c34a675 (commit)
       via  62411740bf363a984e453df37b95bbbdebc443e4 (commit)
       via  79b80617cf3f9c979b5f541d1cb82274631f5fdc (commit)
      from  8896595769911ebd27420ebe6f658f99d80d8cbc (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b3284a520ea8bcd5dfb32491eeecf2899d27b7e4
Merge: 84c6c60 b1fb647
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Mar 8 23:07:46 2012 -0800

    [1603bench] Merge branch 'trac1603' into trac1603bench

commit 84c6c601a78cdb568b5f7e004d03e20de6b42414
Merge: a62bbb2 55fdccd
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Mar 8 21:21:02 2012 -0800

    [1603bench] Merge branch 'trac1603' into trac1603bench

commit a62bbb2d56d09aa359be5ba96fff9de9a1e5a36f
Merge: d442b14 eabc47c
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Mar 8 20:37:16 2012 -0800

    [1603bench] Merge branch 'trac1603' into trac1603bench

commit d442b1483e3196ae118fdc982525f15c574e91a0
Merge: 5b91b5e 84a7f88
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Mar 8 16:57:40 2012 -0800

    [1603bench] Merge branch 'trac1603' into trac1603bench

commit 5b91b5ef2cdec92eba172a379a196f2c4c34a675
Merge: 8896595 6241174
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Mar 8 15:51:50 2012 -0800

    [1603bench] Merge branch 'trac1603' into trac1603bench

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dns/Makefile.am                            |    2 -
 src/lib/dns/benchmarks/Makefile.am                 |    1 +
 src/lib/dns/benchmarks/message_renderer_bench.cc   |    2 +-
 src/lib/dns/{ => benchmarks}/oldmessagerenderer.cc |    2 +-
 src/lib/dns/{ => benchmarks}/oldmessagerenderer.h  |    9 +-
 src/lib/dns/labelsequence.cc                       |   10 +-
 src/lib/dns/labelsequence.h                        |   16 +-
 src/lib/dns/messagerenderer.cc                     |  265 +++++++++++++-------
 src/lib/dns/name.h                                 |    9 -
 src/lib/dns/name_internal.h                        |    9 +-
 src/lib/dns/tests/messagerenderer_unittest.cc      |   17 ++
 src/lib/util/buffer.h                              |   42 ++--
 12 files changed, 243 insertions(+), 141 deletions(-)
 rename src/lib/dns/{ => benchmarks}/oldmessagerenderer.cc (99%)
 rename src/lib/dns/{ => benchmarks}/oldmessagerenderer.h (91%)

-----------------------------------------------------------------------
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index aa6c356..8d1152d 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -95,8 +95,6 @@ libdns___la_SOURCES += labelsequence.h labelsequence.cc
 libdns___la_SOURCES += masterload.h masterload.cc
 libdns___la_SOURCES += message.h message.cc
 libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
-# keep the following two during development for performance comparison
-libdns___la_SOURCES += oldmessagerenderer.h oldmessagerenderer.cc
 libdns___la_SOURCES += name.h name.cc
 libdns___la_SOURCES += name_internal.h
 libdns___la_SOURCES += nsec3hash.h nsec3hash.cc
diff --git a/src/lib/dns/benchmarks/Makefile.am b/src/lib/dns/benchmarks/Makefile.am
index 44a9b19..ff591cc 100644
--- a/src/lib/dns/benchmarks/Makefile.am
+++ b/src/lib/dns/benchmarks/Makefile.am
@@ -18,6 +18,7 @@ rdatarender_bench_LDADD += $(top_builddir)/src/lib/util/libutil.la
 rdatarender_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 
 message_renderer_bench_SOURCES = message_renderer_bench.cc
+message_renderer_bench_SOURCES += oldmessagerenderer.h oldmessagerenderer.cc
 message_renderer_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
 message_renderer_bench_LDADD += $(top_builddir)/src/lib/util/libutil.la
 message_renderer_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/src/lib/dns/benchmarks/message_renderer_bench.cc b/src/lib/dns/benchmarks/message_renderer_bench.cc
index 480f373..33cd65b 100644
--- a/src/lib/dns/benchmarks/message_renderer_bench.cc
+++ b/src/lib/dns/benchmarks/message_renderer_bench.cc
@@ -16,7 +16,7 @@
 
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
-#include <dns/oldmessagerenderer.h>
+#include <oldmessagerenderer.h>
 
 #include <cassert>
 #include <vector>
diff --git a/src/lib/dns/benchmarks/oldmessagerenderer.cc b/src/lib/dns/benchmarks/oldmessagerenderer.cc
new file mode 100644
index 0000000..cd5c4e2
--- /dev/null
+++ b/src/lib/dns/benchmarks/oldmessagerenderer.cc
@@ -0,0 +1,278 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+#include <dns/name.h>
+#include <oldmessagerenderer.h>
+
+#include <cctype>
+#include <cassert>
+#include <set>
+
+using namespace isc::util;
+
+namespace isc {
+namespace dns {
+
+namespace {     // hide internal-only names from the public namespaces
+///
+/// \brief The \c NameCompressNode class represents a pointer to a name
+/// rendered in the internal buffer for the \c MessageRendererImpl object.
+///
+/// A \c MessageRendererImpl object maintains a set of the \c NameCompressNode
+/// objects, and searches the set for the position of the longest match
+/// (ancestor) name against each new name to be rendered into the buffer.
+struct NameCompressNode {
+    NameCompressNode(const OldMessageRenderer& renderer,
+                     const OutputBuffer& buffer, const size_t pos,
+                     const size_t len) :
+        renderer_(renderer), buffer_(buffer), pos_(pos), len_(len) {}
+    /// The renderer that performs name compression using the node.
+    /// This is kept in each node to detect the compression mode
+    /// (case-sensitive or not) in the comparison functor (\c NameCompare).
+    const OldMessageRenderer& renderer_;
+    /// The buffer in which the corresponding name is rendered.
+    const OutputBuffer& buffer_;
+    /// The position (offset from the beginning) in the buffer where the
+    /// name starts.
+    uint16_t pos_;
+    /// The length of the corresponding name.
+    uint16_t len_;
+};
+
+///
+/// \brief The \c NameCompare class is a functor that gives ordering among
+/// \c NameCompressNode objects stored in \c MessageRendererImpl::nodeset_.
+///
+/// Its only public method as a functor, \c operator(), gives the ordering
+/// between two \c NameCompressNode objects in terms of equivalence, that is,
+/// returns whether one is "less than" the other.
+/// For our purpose we only need to distinguish two different names, so the
+/// ordering is different from the canonical DNS name order used in DNSSEC;
+/// basically, it gives the case-insensitive ordering of the two names as their
+/// textual representation.
+struct NameCompare : public std::binary_function<NameCompressNode,
+                                                 NameCompressNode,
+                                                 bool> {
+    ///
+    /// Returns true if n1 < n2 as a result of case-insensitive comparison;
+    /// otherwise return false.
+    ///
+    /// The name corresponding to \c n1 or \c n2 may be compressed, in which
+    /// case we must follow the compression pointer in the associated buffer.
+    /// The helper private method \c nextPosition() gives the position in the
+    /// buffer for the next character, taking into account compression.
+    ///
+    bool operator()(const NameCompressNode& n1,
+                    const NameCompressNode& n2) const
+    {
+        if (n1.len_ < n2.len_) {
+            return (true);
+        } else if (n1.len_ > n2.len_) {
+            return (false);
+        }
+
+        const bool case_sensitive =
+            (n1.renderer_.getCompressMode() == OldMessageRenderer::CASE_SENSITIVE);
+
+        uint16_t pos1 = n1.pos_;
+        uint16_t pos2 = n2.pos_;
+        uint16_t l1 = 0;
+        uint16_t l2 = 0;
+        for (uint16_t i = 0; i < n1.len_; i++, pos1++, pos2++) {
+            pos1 = nextPosition(n1.buffer_, pos1, l1);
+            pos2 = nextPosition(n2.buffer_, pos2, l2);
+            if (case_sensitive) {
+                if (n1.buffer_[pos1] < n2.buffer_[pos2]) {
+                    return (true);
+                } else if (n1.buffer_[pos1] > n2.buffer_[pos2]) {
+                    return (false);
+                }
+            } else {
+                if (tolower(n1.buffer_[pos1]) < tolower(n2.buffer_[pos2])) {
+                    return (true);
+                } else if (tolower(n1.buffer_[pos1]) >
+                           tolower(n2.buffer_[pos2])) {
+                    return (false);
+                }
+            }
+        }
+
+        return (false);
+    }
+
+private:
+    uint16_t nextPosition(const OutputBuffer& buffer,
+                          uint16_t pos, uint16_t& llen) const
+    {
+        if (llen == 0) {
+            size_t i = 0;
+
+            while ((buffer[pos] & Name::COMPRESS_POINTER_MARK8) ==
+                   Name::COMPRESS_POINTER_MARK8) {
+                pos = (buffer[pos] & ~Name::COMPRESS_POINTER_MARK8) *
+                    256 + buffer[pos + 1];
+
+                // This loop should stop as long as the buffer has been
+                // constructed validly and the search/insert argument is based
+                // on a valid name, which is an assumption for this class.
+                // But we'll abort if a bug could cause an infinite loop.
+                i += 2;
+                assert(i < Name::MAX_WIRE);
+            }
+            llen = buffer[pos];
+        } else {
+            --llen;
+        }
+        return (pos);
+    }
+};
+}
+
+///
+/// \brief The \c MessageRendererImpl class is the actual implementation of
+/// \c MessageRenderer.
+///
+/// The implementation is hidden from applications.  We can refer to specific
+/// members of this class only within the implementation source file.
+///
+struct OldMessageRenderer::MessageRendererImpl {
+    /// \brief Constructor from an output buffer.
+    ///
+    MessageRendererImpl() :
+        nbuffer_(Name::MAX_WIRE), msglength_limit_(512),
+        truncated_(false), compress_mode_(OldMessageRenderer::CASE_INSENSITIVE)
+    {}
+    /// A local working buffer to convert each given name into wire format.
+    /// This could be a local variable of the \c writeName() method, but
+    /// we keep it in the class so that we can reuse it and avoid construction
+    /// overhead.
+    OutputBuffer nbuffer_;
+    /// A set of compression pointers.
+    std::set<NameCompressNode, NameCompare> nodeset_;
+    /// The maximum length of rendered data that can fit without
+    /// truncation.
+    uint16_t msglength_limit_;
+    /// A boolean flag that indicates truncation has occurred while rendering
+    /// the data.
+    bool truncated_;
+    /// The name compression mode.
+    CompressMode compress_mode_;
+};
+
+OldMessageRenderer::OldMessageRenderer() :
+    AbstractMessageRenderer(),
+    impl_(new MessageRendererImpl)
+{}
+
+OldMessageRenderer::~OldMessageRenderer() {
+    delete impl_;
+}
+
+void
+OldMessageRenderer::clear() {
+    AbstractMessageRenderer::clear();
+    impl_->nbuffer_.clear();
+    impl_->nodeset_.clear();
+    impl_->msglength_limit_ = 512;
+    impl_->truncated_ = false;
+    impl_->compress_mode_ = CASE_INSENSITIVE;
+}
+
+size_t
+OldMessageRenderer::getLengthLimit() const {
+    return (impl_->msglength_limit_);
+}
+
+void
+OldMessageRenderer::setLengthLimit(const size_t len) {
+    impl_->msglength_limit_ = len;
+}
+
+bool
+OldMessageRenderer::isTruncated() const {
+    return (impl_->truncated_);
+}
+
+void
+OldMessageRenderer::setTruncated() {
+    impl_->truncated_ = true;
+}
+
+OldMessageRenderer::CompressMode
+OldMessageRenderer::getCompressMode() const {
+    return (impl_->compress_mode_);
+}
+
+void
+OldMessageRenderer::setCompressMode(const CompressMode mode) {
+    impl_->compress_mode_ = mode;
+}
+
+void
+OldMessageRenderer::writeName(const Name& name, const bool compress) {
+    impl_->nbuffer_.clear();
+    name.toWire(impl_->nbuffer_);
+
+    unsigned int i;
+    std::set<NameCompressNode, NameCompare>::const_iterator notfound =
+        impl_->nodeset_.end();
+    std::set<NameCompressNode, NameCompare>::const_iterator n = notfound;
+
+    // Find the longest ancestor name in the rendered set that matches the
+    // given name.
+    for (i = 0; i < impl_->nbuffer_.getLength(); i += impl_->nbuffer_[i] + 1) {
+        // skip the trailing null label
+        if (impl_->nbuffer_[i] == 0) {
+            continue;
+        }
+        n = impl_->nodeset_.find(NameCompressNode(*this, impl_->nbuffer_, i,
+                                                  impl_->nbuffer_.getLength() -
+                                                  i));
+        if (n != notfound) {
+            break;
+        }
+    }
+
+    // Record the current offset before extending the buffer.
+    const size_t offset = getLength();
+    // Write uncompress part...
+    writeData(impl_->nbuffer_.getData(),
+              compress ? i : impl_->nbuffer_.getLength());
+    if (compress && n != notfound) {
+        // ...and compression pointer if available.
+        uint16_t pointer = (*n).pos_;
+        pointer |= Name::COMPRESS_POINTER_MARK16;
+        writeUint16(pointer);
+    }
+
+    // Finally, add to the set the newly rendered name and its ancestors that
+    // have not been in the set.
+    for (unsigned int j = 0; j < i; j += impl_->nbuffer_[j] + 1) {
+        if (impl_->nbuffer_[j] == 0) {
+            continue;
+        }
+        if (offset + j > Name::MAX_COMPRESS_POINTER) {
+            break;
+        }
+        impl_->nodeset_.insert(NameCompressNode(*this, getBuffer(),
+                                                offset + j,
+                                                impl_->nbuffer_.getLength() -
+                                                j));
+    }
+}
+
+}
+}
diff --git a/src/lib/dns/benchmarks/oldmessagerenderer.h b/src/lib/dns/benchmarks/oldmessagerenderer.h
new file mode 100644
index 0000000..14e7aee
--- /dev/null
+++ b/src/lib/dns/benchmarks/oldmessagerenderer.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __OLDMESSAGERENDERER_H
+#define __OLDMESSAGERENDERER_H 1
+
+//
+// This is a copy of an older version of MessageRenderer class.  It is kept
+// here to provide a benchmark target.
+//
+
+#include <dns/messagerenderer.h>
+
+namespace isc {
+namespace dns {
+
+class OldMessageRenderer : public AbstractMessageRenderer {
+public:
+    using AbstractMessageRenderer::CASE_INSENSITIVE;
+    using AbstractMessageRenderer::CASE_SENSITIVE;
+
+    /// \brief Constructor from an output buffer.
+    OldMessageRenderer();
+
+    virtual ~OldMessageRenderer();
+    virtual bool isTruncated() const;
+    virtual size_t getLengthLimit() const;
+    virtual CompressMode getCompressMode() const;
+    virtual void setTruncated();
+    virtual void setLengthLimit(size_t len);
+    virtual void setCompressMode(CompressMode mode);
+    virtual void clear();
+    virtual void writeName(const Name& name, bool compress = true);
+private:
+    struct MessageRendererImpl;
+    MessageRendererImpl* impl_;
+};
+}
+}
+#endif // __OLDMESSAGERENDERER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/labelsequence.cc b/src/lib/dns/labelsequence.cc
index f3c2133..0ec450f 100644
--- a/src/lib/dns/labelsequence.cc
+++ b/src/lib/dns/labelsequence.cc
@@ -24,7 +24,7 @@ namespace dns {
 const char*
 LabelSequence::getData(size_t *len) const {
     *len = getDataLength();
-    return (&name_->ndata_[name_->offsets_[first_label_]]);
+    return (&name_.ndata_[name_.offsets_[first_label_]]);
 }
 
 size_t
@@ -35,10 +35,10 @@ LabelSequence::getDataLength() const {
     // the length for the 'previous' label (the root label) plus
     // one (for the root label zero octet)
     if (isAbsolute()) {
-        return (name_->offsets_[last_label_ - 1] -
-                name_->offsets_[first_label_] + 1);
+        return (name_.offsets_[last_label_ - 1] -
+                name_.offsets_[first_label_] + 1);
     } else {
-        return (name_->offsets_[last_label_] - name_->offsets_[first_label_]);
+        return (name_.offsets_[last_label_] - name_.offsets_[first_label_]);
     }
 }
 
@@ -89,7 +89,7 @@ LabelSequence::stripRight(size_t i) {
 
 bool
 LabelSequence::isAbsolute() const {
-    return (last_label_ == name_->offsets_.size());
+    return (last_label_ == name_.offsets_.size());
 }
 
 size_t
diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h
index d371fc5..6b10b67 100644
--- a/src/lib/dns/labelsequence.h
+++ b/src/lib/dns/labelsequence.h
@@ -42,16 +42,6 @@ namespace dns {
 ///
 class LabelSequence {
 public:
-    /// \brief The default constructor
-    ///
-    /// A LabelSequence is expected to be stored in STL containers and
-    /// has to have a default constructor.  A LabelSequence object generated
-    /// by this constructor is only usable as a placeholder; method calls
-    /// on such an object can return a bogus value or result in crash.
-    /// It's caller's responsibility to avoid such invaild usage.
-    LabelSequence() : name_(NULL), first_label_(0), last_label_(0)
-    {}
-
     /// \brief Constructs a LabelSequence for the given name
     ///
     /// \note The associated Name MUST remain in scope during the lifetime
@@ -60,7 +50,7 @@ public:
     /// to the labels in the Name object).
     ///
     /// \param name The Name to construct a LabelSequence for
-    LabelSequence(const Name& name): name_(&name),
+    LabelSequence(const Name& name): name_(name),
                                      first_label_(0),
                                      last_label_(name.getLabelCount())
     {}
@@ -142,7 +132,7 @@ public:
     /// LabelSequence itself.
     ///
     /// \return Reference to the original Name object
-    const Name& getName() const { return (*name_); }
+    const Name& getName() const { return (name_); }
 
     /// \brief Calculate a simple hash for the label sequence.
     ///
@@ -175,7 +165,7 @@ public:
     bool isAbsolute() const;
 
 private:
-    const Name* name_;
+    const Name& name_;
     size_t first_label_;
     size_t last_label_;
 };
diff --git a/src/lib/dns/messagerenderer.cc b/src/lib/dns/messagerenderer.cc
index 33196c0..7591b03 100644
--- a/src/lib/dns/messagerenderer.cc
+++ b/src/lib/dns/messagerenderer.cc
@@ -15,18 +15,128 @@
 #include <exceptions/exceptions.h>
 #include <util/buffer.h>
 #include <dns/name.h>
+#include <dns/name_internal.h>
 #include <dns/labelsequence.h>
 #include <dns/messagerenderer.h>
 
+#include <boost/static_assert.hpp>
+
+#include <limits>
 #include <cassert>
 #include <vector>
 
 using namespace std;
 using namespace isc::util;
+using isc::dns::name::internal::maptolower;
 
 namespace isc {
 namespace dns {
 
+namespace {     // hide internal-only names from the public namespaces
+///
+/// \brief The \c OffsetItem class represents a pointer to a name
+/// rendered in the internal buffer for the \c MessageRendererImpl object.
+///
+/// A \c MessageRendererImpl object maintains a set of \c OffsetItem
+/// objects in a hash table, and searches the table for the position of the
+/// longest match (ancestor) name against each new name to be rendered into
+/// the buffer.
+struct OffsetItem {
+    OffsetItem(size_t pos, size_t len) : pos_(pos), len_(len)
+    {}
+
+    /// The position (offset from the beginning) in the buffer where the
+    /// name starts.
+    uint16_t pos_;
+
+    /// The length of the corresponding sequence (which is a domain name).
+    uint16_t len_;
+};
+
+/// \brief The \c NameCompare class is a functor that checks equality
+/// between the name corresponding to an \c OffsetItem object and the name
+/// consists of labels represented by a \c LabelSequence object.
+///
+/// Template parameter CASE_SENSITIVE determines whether to ignore the case
+/// of the names.  This policy doesn't change throughout the lifetime of
+/// this object, so we separate these using template to avoid unnecessary
+/// condition check.
+template <bool CASE_SENSITIVE>
+struct NameCompare {
+    /// \brief Constructor
+    ///
+    /// \param buffer The buffer for rendering used in the caller renderer
+    /// \param name_buf An input buffer storing the wire-format data of the
+    /// name to be newly rendered (and only that data).
+    NameCompare(const OutputBuffer& buffer, InputBuffer& name_buf) :
+        buffer_(&buffer), name_buf_(&name_buf)
+    {}
+
+    bool operator()(const OffsetItem& item) const {
+        if (item.len_ != name_buf_->getLength()) {
+            return (false);
+        }
+
+        // Compare the name data, character-by-character.
+        // item_pos keeps track of the position in the buffer corresponding to
+        // the character to compare.  item_label_len is the number of
+        // characters in the labels where the character pointed by item_pos
+        // belongs.  When it reaches zero, nextPosition() identifies the
+        // position for the subsequent label, taking into account name
+        // compression, and resets item_label_len to the length of the new
+        // label.
+        name_buf_->setPosition(0); // buffer can be reused, so reset position
+        uint16_t item_pos = item.pos_;
+        uint16_t item_label_len = 0;
+        for (size_t i = 0; i < item.len_; ++i, ++item_pos) {
+            item_pos = nextPosition(*buffer_, item_pos, item_label_len);
+            const unsigned char ch1 = (*buffer_)[item_pos];
+            const unsigned char ch2 = name_buf_->readUint8();
+            if (CASE_SENSITIVE) {
+                if (ch1 != ch2) {
+                    return (false);
+                }
+            } else {
+                if (maptolower[ch1] != maptolower[ch2]) {
+                    return (false);
+                }
+            }
+        }
+
+        return (true);
+    }
+
+private:
+    uint16_t nextPosition(const OutputBuffer& buffer,
+                          uint16_t pos, uint16_t& llen) const
+    {
+        if (llen == 0) {
+            size_t i = 0;
+
+            while ((buffer[pos] & Name::COMPRESS_POINTER_MARK8) ==
+                   Name::COMPRESS_POINTER_MARK8) {
+                pos = (buffer[pos] & ~Name::COMPRESS_POINTER_MARK8) *
+                    256 + buffer[pos + 1];
+
+                // This loop should stop as long as the buffer has been
+                // constructed validly and the search/insert argument is based
+                // on a valid name, which is an assumption for this class.
+                // But we'll abort if a bug could cause an infinite loop.
+                i += 2;
+                assert(i < Name::MAX_WIRE);
+            }
+            llen = buffer[pos];
+        } else {
+            --llen;
+        }
+        return (pos);
+    }
+
+    const OutputBuffer* buffer_;
+    InputBuffer* name_buf_;
+};
+}
+
 ///
 /// \brief The \c MessageRendererImpl class is the actual implementation of
 /// \c MessageRenderer.
@@ -34,79 +144,60 @@ namespace dns {
 /// The implementation is hidden from applications.  We can refer to specific
 /// members of this class only within the implementation source file.
 ///
-/// It internally holds a hash table for LabelSequence objects corresponding
-/// to portions of names rendered in this renderer with their offset from
-/// the beginning to the entire rendered data.  It's used to handle name
-/// compression.
+/// It internally holds a hash table for OffsetItem objects corresponding
+/// to portions of names rendered in this renderer.  The offset information
+/// is used to compress subsequent names to be rendered.
 struct MessageRenderer::MessageRendererImpl {
-    // The size of hash buckets
+    // The size of hash buckets and number of hash entries per bucket for
+    // which space is preallocated and kept reserved for subsequent rendering
+    // to provide better performance.  These values are derived from the
+    // BIND 9 implementation that uses a similar hash table.
     static const size_t BUCKETS = 64;
-    // Number of hash entries per bucket for which space is preallocated and
-    // keep reserved for subsequent rendering, inneding to provide better
-    // performance.
     static const size_t RESERVED_ITEMS = 16;
     static const uint16_t NO_OFFSET = 65535; // used as a marker of 'not found'
 
-    // Structure used as hash entries
-    struct OffsetItem {
-        OffsetItem(const LabelSequence& labels_param, uint16_t offset_param) :
-            labels(labels_param), offset(offset_param)
-        {}
-        LabelSequence labels;
-        uint16_t offset;
-    };
-
+    /// \brief Constructor
     MessageRendererImpl() :
         msglength_limit_(512), truncated_(false),
         compress_mode_(MessageRenderer::CASE_INSENSITIVE)
     {
-        // Reserve some spaces for hash and name placeholders.
+        // Reserve some spaces for hash table items.
         for (size_t i = 0; i < BUCKETS; ++i) {
             table_[i].reserve(RESERVED_ITEMS);
         }
-        names_.reserve(BUCKETS);
     }
 
-    // A helper structure to find the hash entry whose labelsequence is
-    // equal to the search key ("target").
-    struct SequenceComp {
-        SequenceComp(const LabelSequence& target, bool case_sensitive) :
-            target_(target), case_sensitive_(case_sensitive)
-        {}
-        bool operator()(const OffsetItem& item) const {
-            return (item.labels.equals(target_, case_sensitive_));
-        }
-    private:
-        const LabelSequence& target_;
-        bool case_sensitive_;
-    };
-
-    uint16_t findOffset(const LabelSequence& sequence) const {
-        const bool case_sensitive = (compress_mode_ ==
-                                     MessageRenderer::CASE_SENSITIVE);
-        const size_t bucket = (sequence.getHash(case_sensitive) % BUCKETS);
-
+    uint16_t findOffset(const OutputBuffer& buffer,
+                        InputBuffer& name_buf,
+                        size_t bucket_id, bool case_sensitive)
+    {
         // Find a matching entry, if any.  We use some heuristics here: often
         // the same name appers consecutively (like repeating the same owner
         // name for a single RRset), so in case there's a collision in the
         // bucket it will be more likely to find it in the tail side of the
         // bucket.
-        vector<OffsetItem>::const_reverse_iterator found =
-            find_if(table_[bucket].rbegin(), table_[bucket].rend(),
-                    SequenceComp(sequence, case_sensitive));
-        if (found != table_[bucket].rend()) {
-            return (found->offset);
+        vector<OffsetItem>::const_reverse_iterator found;
+        if (case_sensitive) {
+            found = find_if(table_[bucket_id].rbegin(),
+                            table_[bucket_id].rend(),
+                            NameCompare<true>(buffer, name_buf));
+        } else {
+            found = find_if(table_[bucket_id].rbegin(),
+                            table_[bucket_id].rend(),
+                            NameCompare<false>(buffer, name_buf));
+        }
+        if (found != table_[bucket_id].rend()) {
+            return (found->pos_);
         }
         return (NO_OFFSET);
     }
 
-    void addOffset(const LabelSequence& sequence, uint16_t offset) {
-        const bool case_sensitive = (compress_mode_ ==
-                                     MessageRenderer::CASE_SENSITIVE);
-        const size_t bucket = (sequence.getHash(case_sensitive) % BUCKETS);
-        table_[bucket].push_back(OffsetItem(sequence, offset));
+    void addOffset(size_t bucket_id, size_t offset, size_t len) {
+        table_[bucket_id].push_back(OffsetItem(offset, len));
     }
 
+    // The hash table for the (offset + position in the buffer) entries
+    vector<OffsetItem> table_[BUCKETS];
     /// The maximum length of rendered data that can fit without
     /// truncation.
     uint16_t msglength_limit_;
@@ -115,11 +206,6 @@ struct MessageRenderer::MessageRendererImpl {
     bool truncated_;
     /// The name compression mode.
     CompressMode compress_mode_;
-
-    // The hash table for the (LabelSequence * offset) entries
-    vector<OffsetItem> table_[BUCKETS];
-    // Placeholder for names referenced from the stored LabelSequences
-    vector<Name> names_;
 };
 
 MessageRenderer::MessageRenderer() :
@@ -142,19 +228,15 @@ MessageRenderer::clear() {
     // space for possible subsequent use of the renderer.
     for (size_t i = 0; i < MessageRendererImpl::BUCKETS; ++i) {
         if (impl_->table_[i].size() > MessageRendererImpl::RESERVED_ITEMS) {
+            // Trim excessive capacity: reserve() invalidates the excessive
+            // items, and swap ensures the new capacity is only reasonably
+            // large for the reserved space.
             impl_->table_[i].reserve(MessageRendererImpl::RESERVED_ITEMS);
-            vector<MessageRendererImpl::OffsetItem>(impl_->table_[i].begin(),
-                                                    impl_->table_[i].end()).
-                swap(impl_->table_[i]);
+            vector<OffsetItem>(impl_->table_[i].begin(),
+                               impl_->table_[i].end()).swap(impl_->table_[i]);
         }
         impl_->table_[i].clear();
     }
-    if (impl_->names_.size() > MessageRendererImpl::BUCKETS) {
-        impl_->names_.reserve(MessageRendererImpl::BUCKETS);
-        vector<Name>(impl_->names_.begin(), impl_->names_.end()).
-            swap(impl_->names_);
-    }
-    impl_->names_.clear();
 }
 
 size_t
@@ -184,7 +266,7 @@ MessageRenderer::getCompressMode() const {
 
 void
 MessageRenderer::setCompressMode(const CompressMode mode) {
-    if (!impl_->names_.empty()) {
+    if (getLength() != 0) {
         isc_throw(isc::InvalidParameter,
                   "compress mode cannot be changed during rendering");
     }
@@ -198,16 +280,32 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     size_t data_len;
     const char* data;
 
+    // We store hash bucket ID for label sequences derived from the name
+    // in order to avoid calculating the hash twice.  The assert ensures
+    // uint8_t is sufficient for our table.
+    uint8_t bucket_ids[Name::MAX_LABELS];
+    BOOST_STATIC_ASSERT((1 << numeric_limits<uint8_t>::digits) >
+                        MessageRendererImpl::BUCKETS);
+
     // Find the offset in the offset table whose name gives the longest
     // match against the name to be rendered.
     size_t nlabels_uncomp;
     uint16_t ptr_offset = MessageRendererImpl::NO_OFFSET;
+    const bool case_sensitive = (impl_->compress_mode_ ==
+                                 MessageRenderer::CASE_SENSITIVE);
     for (nlabels_uncomp = 0; nlabels_uncomp < nlabels; ++nlabels_uncomp) {
-        if (sequence.getDataLength() == 1) { // trailing dot.
+        data = sequence.getData(&data_len);
+        if (data_len == 1) { // trailing dot.
             ++nlabels_uncomp;
             break;
         }
-        ptr_offset = impl_->findOffset(sequence);
+        bucket_ids[nlabels_uncomp] =
+            (sequence.getHash(impl_->compress_mode_) %
+             MessageRendererImpl::BUCKETS);
+        InputBuffer name_buf(data, data_len);
+        ptr_offset = impl_->findOffset(getBuffer(), name_buf,
+                                       bucket_ids[nlabels_uncomp],
+                                       case_sensitive);
         if (ptr_offset != MessageRendererImpl::NO_OFFSET) {
             break;
         }
@@ -232,27 +330,24 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
         writeUint16(ptr_offset);
     }
 
-    // Finally, add the newly rendered name and its ancestors that
-    // have not been in the set.  We need to make our copy of name and generate
-    // sequence(s) from the copied name because it's not guaranteed that
-    // the caller keeps the name valid after this call.
-    if (nlabels_uncomp > 0) {
-        impl_->names_.push_back(name);
-        LabelSequence saved_sequence(impl_->names_.back());
-        size_t seqlen = saved_sequence.getDataLength();
-        while (nlabels_uncomp-- > 0) {
-            if (seqlen == 1) { // root name doesn't need to be stored.
-                break;
-            }
-            if (offset > Name::MAX_COMPRESS_POINTER) {
-                break;
-            }
-            impl_->addOffset(saved_sequence, offset);
-            saved_sequence.stripLeft(1);
-            const size_t new_seqlen = saved_sequence.getDataLength();
-            offset += (seqlen - new_seqlen);
-            seqlen = new_seqlen;
+    // Finally, record the offset and length for each uncompressed sequence
+    // in the hash table.  The renderer's buffer has just stored the
+    // corresponding data, so we use the rendered data to get the length
+    // of each label of the names.
+    size_t seqlen = name.getLength();
+    for (size_t i = 0; i < nlabels_uncomp; ++i) {
+        const uint8_t label_len = getBuffer()[offset];
+        if (label_len == 0) { // offset for root doesn't need to be stored.
+            break;
+        }
+        if (offset > Name::MAX_COMPRESS_POINTER) {
+            break;
         }
+        // Store the <offset, len> pair to the table.  We already know the
+        // hash value and the bucket ID derived from it.
+        impl_->addOffset(bucket_ids[i], offset, seqlen);
+        offset += (label_len + 1);
+        seqlen -= (label_len + 1);
     }
 }
 
diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h
index 675c0db..ca64d69 100644
--- a/src/lib/dns/name.h
+++ b/src/lib/dns/name.h
@@ -166,15 +166,6 @@ private:
     NameRelation relation_;
 };
 
-// This is effectively a "private" namespace, but exposed publicly so the
-// definitions in it can be shared with the LabelSequence class.  It's not
-// expected to be used
-namespace name {
-namespace internal {
-extern const unsigned char maptolower[];
-}
-}
-
 ///
 /// The \c Name class encapsulates DNS names.
 ///
diff --git a/src/lib/dns/name_internal.h b/src/lib/dns/name_internal.h
index 5c7d698..143ecb3 100644
--- a/src/lib/dns/name_internal.h
+++ b/src/lib/dns/name_internal.h
@@ -16,10 +16,11 @@
 #define __NAME_INTERNAL_H 1
 
 // This is effectively a "private" namespace for the Name class implementation,
-// but exposed publicly so the definitions in it can be shared with the
-// LabelSequence class.  It's not expected to be used even by other modules
-// of this library, much less by normal applications.  This header file is
-// therefore not expected to be installed as part of the library.
+// but exposed publicly so the definitions in it can be shared with other
+// modules of the library (as of its introduction, used by LabelSequence and
+// MessageRenderer).  It's not expected to be used even by normal applications.
+// This header file is therefore not expected to be installed as part of the
+// library.
 namespace isc {
 namespace dns {
 namespace name {
diff --git a/src/lib/dns/oldmessagerenderer.cc b/src/lib/dns/oldmessagerenderer.cc
deleted file mode 100644
index cd1ada5..0000000
--- a/src/lib/dns/oldmessagerenderer.cc
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <exceptions/exceptions.h>
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/oldmessagerenderer.h>
-
-#include <cctype>
-#include <cassert>
-#include <set>
-
-using namespace isc::util;
-
-namespace isc {
-namespace dns {
-
-namespace {     // hide internal-only names from the public namespaces
-///
-/// \brief The \c NameCompressNode class represents a pointer to a name
-/// rendered in the internal buffer for the \c MessageRendererImpl object.
-///
-/// A \c MessageRendererImpl object maintains a set of the \c NameCompressNode
-/// objects, and searches the set for the position of the longest match
-/// (ancestor) name against each new name to be rendered into the buffer.
-struct NameCompressNode {
-    NameCompressNode(const OldMessageRenderer& renderer,
-                     const OutputBuffer& buffer, const size_t pos,
-                     const size_t len) :
-        renderer_(renderer), buffer_(buffer), pos_(pos), len_(len) {}
-    /// The renderer that performs name compression using the node.
-    /// This is kept in each node to detect the compression mode
-    /// (case-sensitive or not) in the comparison functor (\c NameCompare).
-    const OldMessageRenderer& renderer_;
-    /// The buffer in which the corresponding name is rendered.
-    const OutputBuffer& buffer_;
-    /// The position (offset from the beginning) in the buffer where the
-    /// name starts.
-    uint16_t pos_;
-    /// The length of the corresponding name.
-    uint16_t len_;
-};
-
-///
-/// \brief The \c NameCompare class is a functor that gives ordering among
-/// \c NameCompressNode objects stored in \c MessageRendererImpl::nodeset_.
-///
-/// Its only public method as a functor, \c operator(), gives the ordering
-/// between two \c NameCompressNode objects in terms of equivalence, that is,
-/// returns whether one is "less than" the other.
-/// For our purpose we only need to distinguish two different names, so the
-/// ordering is different from the canonical DNS name order used in DNSSEC;
-/// basically, it gives the case-insensitive ordering of the two names as their
-/// textual representation.
-struct NameCompare : public std::binary_function<NameCompressNode,
-                                                 NameCompressNode,
-                                                 bool> {
-    ///
-    /// Returns true if n1 < n2 as a result of case-insensitive comparison;
-    /// otherwise return false.
-    ///
-    /// The name corresponding to \c n1 or \c n2 may be compressed, in which
-    /// case we must follow the compression pointer in the associated buffer.
-    /// The helper private method \c nextPosition() gives the position in the
-    /// buffer for the next character, taking into account compression.
-    ///
-    bool operator()(const NameCompressNode& n1,
-                    const NameCompressNode& n2) const
-    {
-        if (n1.len_ < n2.len_) {
-            return (true);
-        } else if (n1.len_ > n2.len_) {
-            return (false);
-        }
-
-        const bool case_sensitive =
-            (n1.renderer_.getCompressMode() == OldMessageRenderer::CASE_SENSITIVE);
-
-        uint16_t pos1 = n1.pos_;
-        uint16_t pos2 = n2.pos_;
-        uint16_t l1 = 0;
-        uint16_t l2 = 0;
-        for (uint16_t i = 0; i < n1.len_; i++, pos1++, pos2++) {
-            pos1 = nextPosition(n1.buffer_, pos1, l1);
-            pos2 = nextPosition(n2.buffer_, pos2, l2);
-            if (case_sensitive) {
-                if (n1.buffer_[pos1] < n2.buffer_[pos2]) {
-                    return (true);
-                } else if (n1.buffer_[pos1] > n2.buffer_[pos2]) {
-                    return (false);
-                }
-            } else {
-                if (tolower(n1.buffer_[pos1]) < tolower(n2.buffer_[pos2])) {
-                    return (true);
-                } else if (tolower(n1.buffer_[pos1]) >
-                           tolower(n2.buffer_[pos2])) {
-                    return (false);
-                }
-            }
-        }
-
-        return (false);
-    }
-
-private:
-    uint16_t nextPosition(const OutputBuffer& buffer,
-                          uint16_t pos, uint16_t& llen) const
-    {
-        if (llen == 0) {
-            size_t i = 0;
-
-            while ((buffer[pos] & Name::COMPRESS_POINTER_MARK8) ==
-                   Name::COMPRESS_POINTER_MARK8) {
-                pos = (buffer[pos] & ~Name::COMPRESS_POINTER_MARK8) *
-                    256 + buffer[pos + 1];
-
-                // This loop should stop as long as the buffer has been
-                // constructed validly and the search/insert argument is based
-                // on a valid name, which is an assumption for this class.
-                // But we'll abort if a bug could cause an infinite loop.
-                i += 2;
-                assert(i < Name::MAX_WIRE);
-            }
-            llen = buffer[pos];
-        } else {
-            --llen;
-        }
-        return (pos);
-    }
-};
-}
-
-///
-/// \brief The \c MessageRendererImpl class is the actual implementation of
-/// \c MessageRenderer.
-///
-/// The implementation is hidden from applications.  We can refer to specific
-/// members of this class only within the implementation source file.
-///
-struct OldMessageRenderer::MessageRendererImpl {
-    /// \brief Constructor from an output buffer.
-    ///
-    MessageRendererImpl() :
-        nbuffer_(Name::MAX_WIRE), msglength_limit_(512),
-        truncated_(false), compress_mode_(OldMessageRenderer::CASE_INSENSITIVE)
-    {}
-    /// A local working buffer to convert each given name into wire format.
-    /// This could be a local variable of the \c writeName() method, but
-    /// we keep it in the class so that we can reuse it and avoid construction
-    /// overhead.
-    OutputBuffer nbuffer_;
-    /// A set of compression pointers.
-    std::set<NameCompressNode, NameCompare> nodeset_;
-    /// The maximum length of rendered data that can fit without
-    /// truncation.
-    uint16_t msglength_limit_;
-    /// A boolean flag that indicates truncation has occurred while rendering
-    /// the data.
-    bool truncated_;
-    /// The name compression mode.
-    CompressMode compress_mode_;
-};
-
-OldMessageRenderer::OldMessageRenderer() :
-    AbstractMessageRenderer(),
-    impl_(new MessageRendererImpl)
-{}
-
-OldMessageRenderer::~OldMessageRenderer() {
-    delete impl_;
-}
-
-void
-OldMessageRenderer::clear() {
-    AbstractMessageRenderer::clear();
-    impl_->nbuffer_.clear();
-    impl_->nodeset_.clear();
-    impl_->msglength_limit_ = 512;
-    impl_->truncated_ = false;
-    impl_->compress_mode_ = CASE_INSENSITIVE;
-}
-
-size_t
-OldMessageRenderer::getLengthLimit() const {
-    return (impl_->msglength_limit_);
-}
-
-void
-OldMessageRenderer::setLengthLimit(const size_t len) {
-    impl_->msglength_limit_ = len;
-}
-
-bool
-OldMessageRenderer::isTruncated() const {
-    return (impl_->truncated_);
-}
-
-void
-OldMessageRenderer::setTruncated() {
-    impl_->truncated_ = true;
-}
-
-OldMessageRenderer::CompressMode
-OldMessageRenderer::getCompressMode() const {
-    return (impl_->compress_mode_);
-}
-
-void
-OldMessageRenderer::setCompressMode(const CompressMode mode) {
-    impl_->compress_mode_ = mode;
-}
-
-void
-OldMessageRenderer::writeName(const Name& name, const bool compress) {
-    impl_->nbuffer_.clear();
-    name.toWire(impl_->nbuffer_);
-
-    unsigned int i;
-    std::set<NameCompressNode, NameCompare>::const_iterator notfound =
-        impl_->nodeset_.end();
-    std::set<NameCompressNode, NameCompare>::const_iterator n = notfound;
-
-    // Find the longest ancestor name in the rendered set that matches the
-    // given name.
-    for (i = 0; i < impl_->nbuffer_.getLength(); i += impl_->nbuffer_[i] + 1) {
-        // skip the trailing null label
-        if (impl_->nbuffer_[i] == 0) {
-            continue;
-        }
-        n = impl_->nodeset_.find(NameCompressNode(*this, impl_->nbuffer_, i,
-                                                  impl_->nbuffer_.getLength() -
-                                                  i));
-        if (n != notfound) {
-            break;
-        }
-    }
-
-    // Record the current offset before extending the buffer.
-    const size_t offset = getLength();
-    // Write uncompress part...
-    writeData(impl_->nbuffer_.getData(),
-              compress ? i : impl_->nbuffer_.getLength());
-    if (compress && n != notfound) {
-        // ...and compression pointer if available.
-        uint16_t pointer = (*n).pos_;
-        pointer |= Name::COMPRESS_POINTER_MARK16;
-        writeUint16(pointer);
-    }
-
-    // Finally, add to the set the newly rendered name and its ancestors that
-    // have not been in the set.
-    for (unsigned int j = 0; j < i; j += impl_->nbuffer_[j] + 1) {
-        if (impl_->nbuffer_[j] == 0) {
-            continue;
-        }
-        if (offset + j > Name::MAX_COMPRESS_POINTER) {
-            break;
-        }
-        impl_->nodeset_.insert(NameCompressNode(*this, getBuffer(),
-                                                offset + j,
-                                                impl_->nbuffer_.getLength() -
-                                                j));
-    }
-}
-
-}
-}
diff --git a/src/lib/dns/oldmessagerenderer.h b/src/lib/dns/oldmessagerenderer.h
deleted file mode 100644
index 995154b..0000000
--- a/src/lib/dns/oldmessagerenderer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __OLDMESSAGERENDERER_H
-#define __OLDMESSAGERENDERER_H 1
-
-#include <dns/messagerenderer.h>
-
-namespace isc {
-namespace dns {
-
-class OldMessageRenderer : public AbstractMessageRenderer {
-public:
-    using AbstractMessageRenderer::CASE_INSENSITIVE;
-    using AbstractMessageRenderer::CASE_SENSITIVE;
-
-    /// \brief Constructor from an output buffer.
-    OldMessageRenderer();
-
-    virtual ~OldMessageRenderer();
-    virtual bool isTruncated() const;
-    virtual size_t getLengthLimit() const;
-    virtual CompressMode getCompressMode() const;
-    virtual void setTruncated();
-    virtual void setLengthLimit(size_t len);
-    virtual void setCompressMode(CompressMode mode);
-    virtual void clear();
-    virtual void writeName(const Name& name, bool compress = true);
-private:
-    struct MessageRendererImpl;
-    MessageRendererImpl* impl_;
-};
-}
-}
-#endif // __OLDMESSAGERENDERER_H
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/dns/tests/messagerenderer_unittest.cc b/src/lib/dns/tests/messagerenderer_unittest.cc
index 04082f1..928e066 100644
--- a/src/lib/dns/tests/messagerenderer_unittest.cc
+++ b/src/lib/dns/tests/messagerenderer_unittest.cc
@@ -21,12 +21,16 @@
 
 #include <gtest/gtest.h>
 
+#include <boost/lexical_cast.hpp>
+
+#include <string>
 #include <vector>
 
 using isc::UnitTestUtil;
 using isc::dns::Name;
 using isc::dns::MessageRenderer;
 using isc::util::OutputBuffer;
+using boost::lexical_cast;
 
 namespace {
 class MessageRendererTest : public ::testing::Test {
@@ -213,4 +217,17 @@ TEST_F(MessageRendererTest, setBufferErrors) {
     renderer.setBuffer(&new_buffer);
     EXPECT_NO_THROW(renderer.setBuffer(NULL));
 }
+
+TEST_F(MessageRendererTest, manyRRs) {
+    // Render a large number of names, and the confirm the resulting wire
+    // data store the expected names in the correct order (1000 is an
+    // arbitrary choice).
+    for (size_t i = 0; i < 1000; ++i) {
+        renderer.writeName(Name(lexical_cast<std::string>(i) + ".example"));
+    }
+    isc::util::InputBuffer b(renderer.getData(), renderer.getLength());
+    for (size_t i = 0; i < 1000; ++i) {
+        EXPECT_EQ(Name(lexical_cast<std::string>(i) + ".example"), Name(b));
+    }
+}
 }
diff --git a/src/lib/util/buffer.h b/src/lib/util/buffer.h
index 2716bc0..0e91d2e 100644
--- a/src/lib/util/buffer.h
+++ b/src/lib/util/buffer.h
@@ -123,10 +123,10 @@ public:
     /// an exception of class \c isc::dns::InvalidBufferPosition will be thrown.
     /// \param position The new position (offset from the beginning of the
     /// buffer).
-    void setPosition(size_t position)
-    {
-        if (position > len_)
-            isc_throw(InvalidBufferPosition, "position is too large");
+    void setPosition(size_t position) {
+        if (position > len_) {
+            throwError("position is too large");
+        }
         position_ = position;
     }
     //@}
@@ -138,10 +138,9 @@ public:
     ///
     /// If the remaining length of the buffer is smaller than 8-bit, an
     /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
-    uint8_t readUint8()
-    {
+    uint8_t readUint8() {
         if (position_ + sizeof(uint8_t) > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+            throwError("read beyond end of buffer");
         }
 
         return (data_[position_++]);
@@ -151,13 +150,12 @@ public:
     ///
     /// If the remaining length of the buffer is smaller than 16-bit, an
     /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
-    uint16_t readUint16()
-    {
+    uint16_t readUint16() {
         uint16_t data;
         const uint8_t* cp;
 
         if (position_ + sizeof(data) > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+            throwError("read beyond end of buffer");
         }
 
         cp = &data_[position_];
@@ -172,13 +170,12 @@ public:
     ///
     /// If the remaining length of the buffer is smaller than 32-bit, an
     /// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
-    uint32_t readUint32()
-    {
+    uint32_t readUint32() {
         uint32_t data;
         const uint8_t* cp;
 
         if (position_ + sizeof(data) > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+            throwError("read beyond end of buffer");
         }
 
         cp = &data_[position_];
@@ -197,10 +194,9 @@ public:
     /// If the remaining length of the buffer is smaller than the specified
     /// length, an exception of class \c isc::dns::InvalidBufferPosition will
     /// be thrown.
-    void readData(void* data, size_t len)
-    {
+    void readData(void* data, size_t len) {
         if (position_ + len > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+            throwError("read beyond end of buffer");
         }
 
         memcpy(data, &data_[position_], len);
@@ -216,10 +212,9 @@ public:
     /// @param Reference to a buffer (data will be stored there).
     /// @param Size specified number of bytes to read in a vector.
     ///
-    void readVector(std::vector<uint8_t>& data, size_t len)
-    {
+    void readVector(std::vector<uint8_t>& data, size_t len) {
         if (position_ + len > len_) {
-            isc_throw(InvalidBufferPosition, "read beyond end of buffer");
+            throwError("read beyond end of buffer");
         }
 
         data.resize(len);
@@ -227,6 +222,15 @@ public:
     }
 
 private:
+    /// \brief A common helper to throw an exception on invalid operation.
+    ///
+    /// Experiments showed that throwing from each method makes the buffer
+    /// operation thrower, so we consolidate it here, and let the methods
+    /// call this.
+    static void throwError(const char* msg) {
+        isc_throw(InvalidBufferPosition, msg);
+    }
+
     size_t position_;
 
     // XXX: The following must be private, but for a short term workaround with



More information about the bind10-changes mailing list