BIND 10 trac2096, updated. db4962ad778838b6872fa1516a3e2e6c3e2579be [2096] a bit more editorial cleanups: typo in class name, some blank lines
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Aug 23 21:13:24 UTC 2012
The branch, trac2096 has been updated
via db4962ad778838b6872fa1516a3e2e6c3e2579be (commit)
via 83979200b23f48735babe19b6359660222b2c525 (commit)
via bddce14fdd3f92879bad0fa6f88772e5575b7c02 (commit)
via 04c050cb0c48cfb1b4e0f0303c098e47d5da7c2b (commit)
from a57188382f9187c8096f198cf2fbf281c5419f2b (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 db4962ad778838b6872fa1516a3e2e6c3e2579be
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Aug 23 14:12:59 2012 -0700
[2096] a bit more editorial cleanups: typo in class name, some blank lines
commit 83979200b23f48735babe19b6359660222b2c525
Merge: bddce14 a571883
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Aug 23 14:06:59 2012 -0700
[2096] Merge development and review branch for trac2096
Fixing conflicts in
src/lib/datasrc/memory/rdata_encoder.h
src/lib/datasrc/memory/rdata_reader.cc
src/lib/datasrc/memory/rdata_reader.h
src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
commit bddce14fdd3f92879bad0fa6f88772e5575b7c02
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Aug 15 21:29:48 2012 -0700
[2096] added a simple benchmark test for RdataReader.
for fair comparison, slightly different implementations are used for now,
so the reader.h/cc were copied from the parent directory and modified.
commit 04c050cb0c48cfb1b4e0f0303c098e47d5da7c2b
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Aug 15 16:45:47 2012 -0700
[2096] trivial (mostly) editorial fixes
- spacing
- typo, comment/doc wording/grammar fixes
- avoid having too long lines
- empty line for readability
- indentation
also fixed one real bug where a temporary Name object is passed to
LabelSequence constructor.
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 1 +
src/lib/datasrc/memory/Makefile.am | 2 +-
src/lib/datasrc/memory/benchmarks/Makefile.am | 18 ++
src/lib/datasrc/memory/benchmarks/rdata_reader.cc | 225 +++++++++++++
src/lib/datasrc/memory/benchmarks/rdata_reader.h | 296 +++++++++++++++++
.../memory/benchmarks/rdata_reader_bench.cc | 334 ++++++++++++++++++++
src/lib/datasrc/memory/rdata_encoder.h | 3 +-
src/lib/datasrc/memory/rdata_reader.cc | 4 +-
src/lib/datasrc/memory/rdata_reader.h | 9 +-
.../memory/tests/rdata_serialization_unittest.cc | 24 +-
10 files changed, 896 insertions(+), 20 deletions(-)
create mode 100644 src/lib/datasrc/memory/benchmarks/Makefile.am
create mode 100644 src/lib/datasrc/memory/benchmarks/rdata_reader.cc
create mode 100644 src/lib/datasrc/memory/benchmarks/rdata_reader.h
create mode 100644 src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index e75cbd8..e7b17ed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1165,6 +1165,7 @@ AC_CONFIG_FILES([Makefile
src/lib/datasrc/Makefile
src/lib/datasrc/memory/Makefile
src/lib/datasrc/memory/tests/Makefile
+ src/lib/datasrc/memory/benchmarks/Makefile
src/lib/datasrc/tests/Makefile
src/lib/datasrc/tests/testdata/Makefile
src/lib/xfr/Makefile
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index e8a78ea..0ec2add 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . tests benchmarks
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
diff --git a/src/lib/datasrc/memory/benchmarks/Makefile.am b/src/lib/datasrc/memory/benchmarks/Makefile.am
new file mode 100644
index 0000000..6741d7f
--- /dev/null
+++ b/src/lib/datasrc/memory/benchmarks/Makefile.am
@@ -0,0 +1,18 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+noinst_PROGRAMS = rdata_reader_bench
+
+rdata_reader_bench_SOURCES = rdata_reader_bench.cc
+rdata_reader_bench_SOURCES += rdata_reader.cc rdata_reader.h
+
+rdata_reader_bench_LDADD = $(top_builddir)/src/lib/datasrc/memory/libdatasrc_memory.la
+rdata_reader_bench_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
diff --git a/src/lib/datasrc/memory/benchmarks/rdata_reader.cc b/src/lib/datasrc/memory/benchmarks/rdata_reader.cc
new file mode 100644
index 0000000..c13a80a
--- /dev/null
+++ b/src/lib/datasrc/memory/benchmarks/rdata_reader.cc
@@ -0,0 +1,225 @@
+// Copyright (C) 2012 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 "rdata_reader.h"
+
+using namespace isc::dns;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+void
+RdataReader2::emptyNameAction(const LabelSequence&, unsigned) {
+ // Do nothing here. On purpose, it's not unfinished.
+}
+
+void
+RdataReader2::emptyDataAction(const uint8_t*, size_t) {
+ // Do nothing here. On purpose, it's not unfinished.
+}
+
+RdataReader2::Result::Result(const LabelSequence& label,
+ unsigned attributes) :
+ label_(label),
+ data_(NULL),
+ size_(0),
+ type_(NAME),
+ compressible_((attributes & NAMEATTR_COMPRESSIBLE) != 0),
+ additional_((attributes & NAMEATTR_ADDITIONAL) != 0)
+{}
+
+RdataReader2::Result::Result(const uint8_t* data, size_t size) :
+ label_(Name::ROOT_NAME()),
+ data_(data),
+ size_(size),
+ type_(DATA),
+ compressible_(false),
+ additional_(false)
+{}
+
+RdataReader2::RdataReader2(const RRClass& rrclass, const RRType& rrtype,
+ const uint8_t* data,
+ size_t rdata_count, size_t sig_count,
+ const NameAction& name_action,
+ const DataAction& data_action) :
+ name_action_(name_action),
+ data_action_(data_action),
+ spec_(getRdataEncodeSpec(rrclass, rrtype)),
+ var_count_total_(spec_.varlen_count * rdata_count),
+ sig_count_(sig_count),
+ spec_count_(spec_.field_count * rdata_count),
+ // The casts, well, C++ decided it doesn't like completely valid
+ // and explicitly allowed cast in C, so we need to fool it through
+ // void.
+ lengths_(static_cast<const uint16_t*>(
+ static_cast<const void*>(data))), // The lenghts are stored first
+ // And the data just after all the lengths
+ data_(data + (var_count_total_ + sig_count_) * sizeof(uint16_t)),
+ sigs_(NULL)
+{
+ rewind();
+}
+
+void
+RdataReader2::rewind() {
+ data_pos_ = 0;
+ spec_pos_ = 0;
+ length_pos_ = 0;
+ sig_data_pos_ = 0;
+ sig_pos_ = 0;
+}
+
+RdataReader2::Result
+RdataReader2::next() {
+ if (spec_pos_ < spec_count_) {
+ const RdataFieldSpec& spec(spec_.fields[(spec_pos_++) %
+ spec_.field_count]);
+ if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
+ const LabelSequence sequence(data_ + data_pos_);
+ data_pos_ += sequence.getSerializedLength();
+ return (Result(sequence, spec.name_attributes));
+ } else {
+ const size_t length(spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
+ spec.fixeddata_len : lengths_[length_pos_++]);
+ const Result result(data_ + data_pos_, length);
+ data_pos_ += length;
+ return (result);
+ }
+ } else {
+ sigs_ = data_ + data_pos_;
+ return (Result());
+ }
+}
+
+void
+RdataReader2::iterate() {
+ while (spec_pos_ < spec_count_) {
+ const RdataFieldSpec& spec(spec_.fields[(spec_pos_++) %
+ spec_.field_count]);
+ if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
+ const LabelSequence sequence(data_ + data_pos_);
+ data_pos_ += sequence.getSerializedLength();
+ name_action_(sequence, spec.name_attributes);
+ } else {
+ const size_t length(spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
+ spec.fixeddata_len : lengths_[length_pos_++]);
+ const Result result(data_ + data_pos_, length);
+ data_pos_ += length;
+ data_action_(result.data(), result.size());
+ }
+ }
+ sigs_ = data_ + data_pos_;
+}
+
+RdataReader2::Result
+RdataReader2::nextSig() {
+ if (sig_pos_ < sig_count_) {
+ if (sigs_ == NULL) {
+ // We didn't find where the signatures start yet. We do it
+ // by iterating the whole data and then returning the state
+ // back.
+ const size_t data_pos = data_pos_;
+ const size_t spec_pos = spec_pos_;
+ const size_t length_pos = length_pos_;
+ // When the next() gets to the last item, it sets the sigs_
+ while (next()) {}
+ assert(sigs_ != NULL);
+ // Return the state
+ data_pos_ = data_pos;
+ spec_pos_ = spec_pos;
+ length_pos_ = length_pos;
+ }
+ // Extract the result
+ const Result result(sigs_ + sig_data_pos_, lengths_[var_count_total_ +
+ sig_pos_]);
+ // Move the position of iterator.
+ sig_data_pos_ += lengths_[var_count_total_ + sig_pos_];
+ ++sig_pos_;
+ // Call the callback
+ data_action_(result.data(), result.size());
+ return (result);
+ } else {
+ return (Result());
+ }
+}
+
+void
+RdataReader2::iterateSig() {
+ while (sig_pos_ < sig_count_) {
+ if (sigs_ == NULL) {
+ // We didn't find where the signatures start yet. We do it
+ // by iterating the whole data and then returning the state
+ // back.
+ const size_t data_pos = data_pos_;
+ const size_t spec_pos = spec_pos_;
+ const size_t length_pos = length_pos_;
+ // When the next() gets to the last item, it sets the sigs_
+ while (next()) {}
+ assert(sigs_ != NULL);
+ // Return the state
+ data_pos_ = data_pos;
+ spec_pos_ = spec_pos;
+ length_pos_ = length_pos;
+ }
+ // Extract the result
+ const Result result(sigs_ + sig_data_pos_, lengths_[var_count_total_ +
+ sig_pos_]);
+ // Move the position of iterator.
+ sig_data_pos_ += lengths_[var_count_total_ + sig_pos_];
+ ++sig_pos_;
+ // Call the callback
+ data_action_(result.data(), result.size());
+ }
+}
+
+size_t
+RdataReader2::getSize() const {
+ size_t storage_size = 0; // this will be the end result
+ size_t data_pos = 0;
+ size_t length_pos = 0;
+
+ // Go over all data fields, adding their lengths to storage_size
+ for (size_t spec_pos = 0; spec_pos < spec_count_; ++spec_pos) {
+ const RdataFieldSpec& spec =
+ spec_.fields[spec_pos % spec_.field_count];
+ if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
+ const size_t seq_len =
+ LabelSequence(data_ + data_pos).getSerializedLength();
+ data_pos += seq_len;
+ storage_size += seq_len;
+ } else {
+ const size_t data_len =
+ (spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
+ spec.fixeddata_len : lengths_[length_pos++]);
+ data_pos += data_len;
+ storage_size += data_len;
+ }
+ }
+ // Same for all RRSIG data
+ for (size_t sig_pos = 0; sig_pos < sig_count_; ++sig_pos) {
+ const size_t sig_data_len = lengths_[length_pos++];
+ storage_size += sig_data_len;
+ }
+
+ // Finally, add the size for 16-bit length fields
+ storage_size += (var_count_total_ * sizeof(uint16_t) +
+ sig_count_ * sizeof(uint16_t));
+
+ return (storage_size);
+}
+
+}
+}
+}
diff --git a/src/lib/datasrc/memory/benchmarks/rdata_reader.h b/src/lib/datasrc/memory/benchmarks/rdata_reader.h
new file mode 100644
index 0000000..f9a717b
--- /dev/null
+++ b/src/lib/datasrc/memory/benchmarks/rdata_reader.h
@@ -0,0 +1,296 @@
+// Copyright (C) 2012 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 DATASRC_MEMORY_RDATA_READER_H
+#define DATASRC_MEMORY_RDATA_READER_H 1
+
+#include <datasrc/memory/rdata_field.h>
+
+#include <boost/function.hpp>
+
+#include <dns/labelsequence.h>
+#include <dns/name.h>
+
+namespace isc {
+// Some forward declarations
+namespace dns{
+class RRClass;
+class RRType;
+}
+
+namespace datasrc {
+namespace memory {
+
+/// \brief Class to read serialized rdata
+///
+/// This class allows you to read the data encoded by RdataEncoder.
+/// It is rather low-level -- it provides sequence of data fields
+/// and names. It does not give you convenient Rdata or RRset class.
+///
+/// It allows two types of operation. First one is by providing callbacks
+/// to the constructor and then iterating by repeatedly calling next(), or
+/// calling iterate() once. The callbacks are then called with each part of
+/// the data.
+///
+/// \code
+/// void handleLabel(const dns::LabelSequence& label, unsigned int flags) {
+/// ...
+/// }
+/// void handleData(const uint8_t* data, size_t size) {
+/// ...
+/// }
+///
+/// RdataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
+/// handleLabel, handleData);
+/// reader.iterate();
+/// \endcode
+///
+/// The other way is to use the return value of next() and loop through
+/// it manually. It has the inconvenience of having the type condition, but
+/// the code is in one place. The used way is matter of personal preferrence,
+/// there's no much difference on the technical side.
+///
+/// \code
+/// RdataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
+/// &handleLabel, handleData);
+/// RdataReader::Result data;
+/// while (data = reader.next()) {
+/// switch (data.type()) {
+/// case RdataReader::NAME:
+/// ...
+/// break;
+/// case RdataReader::DATA:
+/// ...
+/// break;
+/// default: assert(0); // Can not happen
+/// }
+/// }
+/// \endcode
+///
+/// \note It is caller's responsibility to pass valid data here. This means
+/// the data returned by RdataEncoder and the corresponding class and type.
+/// If this is not the case, all the kinds of pointer hell might get loose.
+class RdataReader2 {
+public:
+ /// \brief Function called on each name encountered in the data.
+ typedef boost::function<void(const dns::LabelSequence&, unsigned)>
+ NameAction;
+
+ /// \brief Function called on each data field in the data.
+ typedef boost::function<void(const uint8_t*, size_t)> DataAction;
+
+ /// \brief a NameAction that does nothing.
+ ///
+ /// This is a NameAction function that does nothing. It is used
+ /// as a default in the constructor.
+ static void emptyNameAction(const dns::LabelSequence& label,
+ unsigned attributes);
+
+ /// \brief a DataAction that does nothing.
+ ///
+ /// This is a DataAction function that does nothing. It is used
+ /// as a default in the constructor.
+ static void emptyDataAction(const uint8_t* data, size_t size);
+
+ /// \brief Constructor
+ ///
+ /// This constructs the reader on top of some serialized data.
+ /// It does not copy the data, you have to make sure the data
+ /// is valid for the whole life of this object and that they
+ /// don't change.
+ ///
+ /// \param rrclass The class the encoded rdata belongs to.
+ /// \param rrtype The type of the encode rdata.
+ /// \param data The actual data.
+ /// \param rdata_count The number of Rdata encoded in the data.
+ /// \param sig_count The number of RRSig rdata bundled with the data.
+ /// \param name_action The callback to be called on each encountered name.
+ /// \param data_action The callback to be called on each data chunk.
+ RdataReader2(const dns::RRClass& rrclass, const dns::RRType& rrtype,
+ const uint8_t* data, size_t rdata_count, size_t sig_count,
+ const NameAction& name_action = &emptyNameAction,
+ const DataAction& data_action = &emptyDataAction);
+
+ /// \brief The type of data returned from this iteration.
+ enum DataType {
+ NAME, ///< This iteration returns domain label
+ DATA, ///< This iteration returns unstructuder data
+ END ///< No more data to return
+ };
+
+ /// \brief Data from one iteration
+ ///
+ /// Each time you call next() or nextSig(), it returns some data.
+ /// This holds the data.
+ ///
+ /// It is valid only for as long as the RdataReader that returned it.
+ ///
+ /// All the methods can be called under any circumstances. However,
+ /// if the required property is not valid for the given type (eg.
+ /// when calling size() on type() == NAME), it returns some "empty"
+ /// value (0, NULL, or the like).
+ class Result {
+ public:
+ /// \brief Default constructor
+ ///
+ /// It creates an empty result (with no data) of type END.
+ Result() :
+ // TODO: Do we maybe want to have a static one to copy
+ // instead of constructing new one from the root Name?
+ label_(dns::Name::ROOT_NAME()),
+ data_(NULL),
+ size_(0),
+ type_(END),
+ compressible_(false),
+ additional_(false)
+ {}
+
+ /// \brief Constructor from a domain label
+ ///
+ /// Creates the NAME type result. Used internally from RdataReader.
+ ///
+ /// \param label The label to hold
+ /// \param attributes The attributes, as stored by the serialized
+ /// data.
+ Result(const dns::LabelSequence& label, unsigned attributes);
+
+ /// \brief Constructor from data
+ ///
+ /// Creates the DATA type result. Used internally from RdataReader.
+ ///
+ /// \param data The data pointer to hold.
+ /// \param size The size to hold.
+ Result(const uint8_t* data, size_t size);
+
+ /// \brief The type of data returned.
+ DataType type() const { return (type_); }
+
+ /// \brief The raw data.
+ ///
+ /// This is only valid if type() == DATA.
+ const uint8_t* data() const { return (data_); }
+
+ /// \brief The size of the raw data.
+ ///
+ /// This is the number of bytes the data takes. It is valid only
+ /// if type() == DATA.
+ size_t size() const { return (size_); }
+
+ /// \brief The domain label.
+ ///
+ /// This holds the domain label. It is only valid if type() == NAME.
+ const dns::LabelSequence& label() const { return (label_); }
+
+ /// \brief Is the name in label() compressible?
+ ///
+ /// This is valid only if type() == NAME.
+ bool compressible() const { return (compressible_); }
+
+ /// \brief Does the name expect additional processing?
+ ///
+ /// This is valid only if type() == NAME.
+ bool additional() const { return (additional_); }
+
+ /// \brief If there are data returned.
+ ///
+ /// This returns if there are any data at all returned. This is
+ /// equivalent to action != END, but it allows for more convenient
+ /// code of a loop through the data.
+ operator bool() const {
+ return (type() != END);
+ }
+ private:
+ dns::LabelSequence label_;
+ const uint8_t* data_;
+ size_t size_;
+ DataType type_;
+ bool compressible_;
+ bool additional_;
+ };
+
+ /// \brief Step to next piece of data.
+ ///
+ /// This returns the next available data. Also, the apropriate hook
+ /// (name_action or data_action, depending on the data type) as passed
+ /// to the constructor is called.
+ ///
+ /// If there are no more data, a Result with type END is returned and
+ /// no callback is called.
+ Result next();
+
+ /// \brief Call next() until the end.
+ ///
+ /// This is just convenience method to iterate through all the data.
+ /// It calls next until it reaches the end (it does not rewind before,
+ /// therefore if you already called next() yourself, it does not start
+ /// at the beginning).
+ ///
+ /// The method only makes sense if you set the callbacks in constructor.
+ void iterate();
+
+ /// \brief Step to next piece of RRSig data.
+ ///
+ /// This is almost the same as next(), but it iterates through the
+ /// associated RRSig data, not the data for the given RRType.
+ Result nextSig();
+
+ /// \brief Iterate through all RRSig data.
+ ///
+ /// This is almost the same as iterate(), but it iterates through the
+ /// RRSig data instead.
+ void iterateSig();
+
+ /// \brief Rewind the iterator to the beginnig of data.
+ ///
+ /// The following next() and nextSig() will start iterating from the
+ /// beginning again.
+ void rewind();
+
+ /// \brief Returns the size of associated data.
+ ///
+ /// This should be the same as the return value of
+ /// RdataEncoder::getStorageLength() for the same set of data.
+ /// The intended use of this method is to tell the caller the size of
+ /// data that were possibly dynamically allocated so that the caller can
+ /// use it for deallocation.
+ ///
+ /// This method only uses the parameters given at the construction of the
+ /// object, and does not rely on or modify other mutable states.
+ /// In practice, when the caller wants to call this method, that would be
+ /// the only purpose of that RdataReader object (although it doesn't have
+ /// to be so).
+ size_t getSize() const;
+private:
+ const NameAction name_action_;
+ const DataAction data_action_;
+ const RdataEncodeSpec& spec_;
+ // Total number of var-length fields, count of signatures
+ const size_t var_count_total_, sig_count_, spec_count_;
+ // Pointer to the beginning of length fields
+ const uint16_t* const lengths_;
+ // Pointer to the beginning of the data (after the lengths)
+ const uint8_t* const data_;
+ // Pointer to the first data signature
+ // Will be computed during the normal RR iteration
+ const uint8_t* sigs_;
+ // The positions in data.
+ size_t data_pos_, spec_pos_, length_pos_;
+ size_t sig_pos_, sig_data_pos_;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc b/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
new file mode 100644
index 0000000..24b4894
--- /dev/null
+++ b/src/lib/datasrc/memory/benchmarks/rdata_reader_bench.cc
@@ -0,0 +1,334 @@
+// Copyright (C) 2012 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 <bench/benchmark.h>
+
+#include <util/buffer.h>
+
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrset.h>
+#include <dns/rrclass.h>
+#include <dns/masterload.h>
+
+#include <datasrc/memory/rdata_field.h>
+#include <datasrc/memory/rdata_encoder.h>
+#include "rdata_reader.h"
+
+#include <boost/bind.hpp>
+
+#include <vector>
+#include <sstream>
+
+#include <unistd.h>
+
+using std::vector;
+using namespace isc::bench;
+using namespace isc::datasrc::memory;
+using namespace isc::dns;
+
+namespace {
+// Encapsulating parameters for a RdataReader. It extracts from the given
+// RRset and its RRSIGs parameters that are necessary construct an RdataReader.
+// RDATA data will be stored in the 'data' vector.
+// members are defined as non cost so we can use the object of this struct
+// in a vector.
+struct EncodeParam {
+ EncodeParam(RdataEncoder& encoder, ConstRRsetPtr rrset,
+ ConstRRsetPtr sig_rrset = ConstRRsetPtr()) :
+ rrclass(rrset->getClass()), rrtype(rrset->getType()),
+ rdata_count(rrset->getRdataCount()),
+ sig_count(sig_rrset ? sig_rrset->getRdataCount() : 0)
+ {
+ encoder.start(rrclass, rrtype);
+ for (RdataIteratorPtr it = rrset->getRdataIterator();
+ !it->isLast();
+ it->next()) {
+ encoder.addRdata(it->getCurrent());
+ }
+ if (sig_rrset) {
+ for (RdataIteratorPtr it = sig_rrset->getRdataIterator();
+ !it->isLast();
+ it->next())
+ {
+ encoder.addSIGRdata(it->getCurrent());
+ }
+ }
+ const size_t data_len = encoder.getStorageLength();
+ data.resize(data_len);
+ encoder.encode(&data[0], data.size());
+ }
+ RRClass rrclass;
+ RRType rrtype;
+ size_t rdata_count;
+ size_t sig_count;
+ vector<uint8_t> data;
+};
+
+// Benchmark for the "next" type of reader. In its run() it iterates over
+// the list of EncodeParams, and render the corresponding RDATA to the
+// given message renderer.
+class NextReaderBenchMark {
+public:
+ NextReaderBenchMark(const vector<EncodeParam>& encode_params,
+ MessageRenderer& renderer) :
+ encode_params_(encode_params), renderer_(renderer)
+ {}
+ unsigned int run() {
+ vector<EncodeParam>::const_iterator it;
+ const vector<EncodeParam>::const_iterator it_end =
+ encode_params_.end();
+ renderer_.clear();
+ for (it = encode_params_.begin(); it != it_end; ++it) {
+ RdataReader2 reader(it->rrclass, it->rrtype, &it->data[0],
+ it->rdata_count, it->sig_count);
+ RdataReader2::Result data;
+ while ((data = reader.next())) {
+ switch (data.type()) {
+ case RdataReader2::NAME:
+ renderer_.writeName(data.label(), data.compressible());
+ break;
+ case RdataReader2::DATA:
+ renderer_.writeData(data.data(), data.size());
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ while ((data = reader.nextSig())) {
+ switch (data.type()) {
+ case RdataReader2::DATA:
+ renderer_.writeData(data.data(), data.size());
+ break;
+ default:
+ assert(false);
+ }
+ }
+ }
+ return (1);
+ }
+private:
+ const vector<EncodeParam>& encode_params_;
+ MessageRenderer& renderer_;
+};
+
+// Similar to NextReaderBenchMark, but avoid unnecessary default construction
+// of the result object and assignment operation after that. It also avoids
+// relying on the type conversion operator.
+class NextReaderBenchMark2 {
+public:
+ NextReaderBenchMark2(const vector<EncodeParam>& encode_params,
+ MessageRenderer& renderer) :
+ encode_params_(encode_params), renderer_(renderer)
+ {}
+ unsigned int run() {
+ vector<EncodeParam>::const_iterator it;
+ const vector<EncodeParam>::const_iterator it_end =
+ encode_params_.end();
+ renderer_.clear();
+ for (it = encode_params_.begin(); it != it_end; ++it) {
+ RdataReader2 reader(it->rrclass, it->rrtype, &it->data[0],
+ it->rdata_count, it->sig_count);
+ bool reading = true;
+ while (reading) {
+ const RdataReader2::Result data = reader.next();
+ switch (data.type()) {
+ case RdataReader2::NAME:
+ renderer_.writeName(data.label(), data.compressible());
+ break;
+ case RdataReader2::DATA:
+ renderer_.writeData(data.data(), data.size());
+ break;
+ case RdataReader2::END:
+ reading = false;
+ break;
+ }
+ }
+
+ reading = true;
+ while (reading) {
+ const RdataReader2::Result data = reader.nextSig();
+ switch (data.type()) {
+ case RdataReader2::DATA:
+ renderer_.writeData(data.data(), data.size());
+ break;
+ case RdataReader2::END:
+ reading = false;
+ break;
+ default:
+ assert(false);
+ }
+ }
+ }
+ return (1);
+ }
+private:
+ const vector<EncodeParam>& encode_params_;
+ MessageRenderer& renderer_;
+};
+
+// Similar to NextReaderBenchMark, but using the "iterate" type reader.
+class IterateBenchMark {
+public:
+ IterateBenchMark(const vector<EncodeParam>& encode_params,
+ MessageRenderer& renderer) :
+ encode_params_(encode_params), renderer_(renderer)
+ {}
+ unsigned int run() {
+ vector<EncodeParam>::const_iterator it;
+ const vector<EncodeParam>::const_iterator it_end =
+ encode_params_.end();
+ renderer_.clear();
+ for (it = encode_params_.begin(); it != it_end; ++it) {
+ RdataReader2 reader(it->rrclass, it->rrtype, &it->data[0],
+ it->rdata_count, it->sig_count,
+ boost::bind(&IterateBenchMark::renderName,
+ this, _1, _2),
+ boost::bind(&IterateBenchMark::renderData,
+ this, _1, _2));
+ reader.iterate();
+ reader.iterateSig();
+ }
+ return (1);
+ }
+ void renderName(const LabelSequence& labels, unsigned attributes) {
+ const bool compress =
+ (attributes & NAMEATTR_COMPRESSIBLE) != 0;
+ renderer_.writeName(labels, compress);
+ }
+ void renderData(const uint8_t* data, size_t data_len) {
+ renderer_.writeData(data, data_len);
+ }
+private:
+ const vector<EncodeParam>& encode_params_;
+ MessageRenderer& renderer_;
+};
+
+// Builtin benchmark data. This is a list of RDATA (of RRs) in a response
+// from a root server for the query for "www.example.com" (as of this
+// implementation). We use a real world example to make the case practical.
+const char* const rrsets_txt =
+ // AUTHORITY SECTION (NS)
+ "com. 172800 IN NS a.gtld-servers.net.\n"
+ "com. 172800 IN NS b.gtld-servers.net.\n"
+ "com. 172800 IN NS c.gtld-servers.net.\n"
+ "com. 172800 IN NS d.gtld-servers.net.\n"
+ "com. 172800 IN NS e.gtld-servers.net.\n"
+ "com. 172800 IN NS f.gtld-servers.net.\n"
+ "com. 172800 IN NS g.gtld-servers.net.\n"
+ "com. 172800 IN NS h.gtld-servers.net.\n"
+ "com. 172800 IN NS i.gtld-servers.net.\n"
+ "com. 172800 IN NS j.gtld-servers.net.\n"
+ "com. 172800 IN NS k.gtld-servers.net.\n"
+ "com. 172800 IN NS l.gtld-servers.net.\n"
+ "com. 172800 IN NS m.gtld-servers.net.\n"
+ // AUTHORITY SECTION (DS)
+ "com. 86400 IN DS 30909 8 2 "
+ "E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CFC41A5766\n"
+ // AUTHORITY SECTION (RRSIG for DS)
+ "com. 86400 IN RRSIG DS 8 1 86400 20120822000000 20120814230000 50398 . "
+ "lcIpLRq4s91Fh1FihDXiDvVMMRqgy2jjlpiP4Y6sSjIrLue6Boi7xraj"
+ "Ouka34ubpl4KuIcopWe99LI/7Npvq0MYr9DaqfnX9dTW6Vc2C7/hKSsz"
+ "POYjraZZA3SCApgfNVzq+AscYlShi56f1vm7DQWw1eh1wHLdatidrQwNyDo=\n"
+ // ADDITIONAL SECTION
+ "a.gtld-servers.net. 172800 IN A 192.5.6.30\n"
+ "b.gtld-servers.net. 172800 IN A 192.33.14.30\n"
+ "c.gtld-servers.net. 172800 IN A 192.26.92.30\n"
+ "d.gtld-servers.net. 172800 IN A 192.31.80.30\n"
+ "e.gtld-servers.net. 172800 IN A 192.12.94.30\n"
+ "f.gtld-servers.net. 172800 IN A 192.35.51.30\n"
+ "g.gtld-servers.net. 172800 IN A 192.42.93.30\n"
+ "h.gtld-servers.net. 172800 IN A 192.54.112.30\n"
+ "i.gtld-servers.net. 172800 IN A 192.43.172.30\n"
+ "j.gtld-servers.net. 172800 IN A 192.48.79.30\n"
+ "k.gtld-servers.net. 172800 IN A 192.52.178.30\n"
+ "l.gtld-servers.net. 172800 IN A 192.41.162.30\n"
+ "m.gtld-servers.net. 172800 IN A 192.55.83.30\n"
+ "a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30\n"
+ "b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30";
+
+void
+usage() {
+ std::cerr << "Usage: rdata_reader_bench [-n iterations]" << std::endl;
+ exit (1);
+}
+
+// Helper callback for masterLoad() used in main() to build test data.
+void
+setRRset(vector<ConstRRsetPtr>* rrsets, ConstRRsetPtr rrset) {
+ rrsets->push_back(rrset);
+}
+}
+
+int
+main(int argc, char* argv[]) {
+ int ch;
+ int iteration = 100000;
+ while ((ch = getopt(argc, argv, "n:")) != -1) {
+ switch (ch) {
+ case 'n':
+ iteration = atoi(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc != 0) {
+ usage();
+ }
+
+ // Build test data. rrsets will consist of a list of RRsets corresponding
+ // to rrsets_txt defined above.
+ vector<ConstRRsetPtr> rrsets;
+ std::stringstream rrsets_stream(rrsets_txt);
+ masterLoad(rrsets_stream, Name::ROOT_NAME(), RRClass::IN(),
+ boost::bind(setRRset, &rrsets, _1));
+
+ // Create EncodeParam for each RRset (possibly with RRSIG) in rrsets,
+ // and store them in encode_param_list. It's the direct test input.
+ vector<EncodeParam> encode_param_list;
+ RdataEncoder encoder;
+ encode_param_list.push_back(EncodeParam(encoder, rrsets.at(0)));
+ encode_param_list.push_back(EncodeParam(encoder, rrsets.at(1),
+ rrsets.at(2)));
+ for (vector<ConstRRsetPtr>::const_iterator it = rrsets.begin() + 3;
+ it != rrsets.end();
+ ++it) {
+ encode_param_list.push_back(EncodeParam(encoder, *it));
+ }
+
+ // The benchmark test uses a message renderer. Create it now and keep
+ // using it throughout the test.
+ isc::util::OutputBuffer buffer(4096); // 4096 should be sufficiently large
+ MessageRenderer renderer;
+ renderer.setBuffer(&buffer);
+
+ std::cout << "Benchmark for next-based RdataReader" << std::endl;
+ BenchMark<NextReaderBenchMark>(iteration,
+ NextReaderBenchMark(encode_param_list,
+ renderer));
+ std::cout << "Benchmark for next-based RdataReader without type conversion"
+ << std::endl;
+ BenchMark<NextReaderBenchMark2>(iteration,
+ NextReaderBenchMark2(encode_param_list,
+ renderer));
+ std::cout << "Benchmark for iterator-based RdataReader" << std::endl;
+ BenchMark<IterateBenchMark>(iteration,
+ IterateBenchMark(encode_param_list, renderer));
+ return (0);
+}
diff --git a/src/lib/datasrc/memory/rdata_encoder.h b/src/lib/datasrc/memory/rdata_encoder.h
index 44803a6..585a500 100644
--- a/src/lib/datasrc/memory/rdata_encoder.h
+++ b/src/lib/datasrc/memory/rdata_encoder.h
@@ -15,7 +15,7 @@
#ifndef DATASRC_MEMORY_RDATA_ENCODER_H
#define DATASRC_MEMORY_RDATA_ENCODER_H 1
-#include "rdata_field.h"
+#include <datasrc/memory/rdata_field.h>
#include <exceptions/exceptions.h>
@@ -29,7 +29,6 @@
#include <vector>
-
namespace isc {
namespace datasrc {
namespace memory {
diff --git a/src/lib/datasrc/memory/rdata_reader.cc b/src/lib/datasrc/memory/rdata_reader.cc
index 653dc0d..664b9bb 100644
--- a/src/lib/datasrc/memory/rdata_reader.cc
+++ b/src/lib/datasrc/memory/rdata_reader.cc
@@ -56,7 +56,7 @@ RdataReader::nextInternal(const NameAction& name_action,
{
if (spec_pos_ < spec_count_) {
- const RdataFieldSpec& spec(spec_.fields[(spec_pos_ ++) %
+ const RdataFieldSpec& spec(spec_.fields[(spec_pos_++) %
spec_.field_count]);
if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
const LabelSequence sequence(data_ + data_pos_);
@@ -120,7 +120,7 @@ RdataReader::nextSig() {
const uint8_t* const pos = sigs_ + sig_data_pos_;
// Move the position of iterator.
sig_data_pos_ += lengths_[var_count_total_ + sig_pos_];
- sig_pos_ ++;
+ ++sig_pos_;
// Call the callback
data_action_(pos, length);
return (RDATA_BOUNDARY);
diff --git a/src/lib/datasrc/memory/rdata_reader.h b/src/lib/datasrc/memory/rdata_reader.h
index 8e888b7..b2aeb1f 100644
--- a/src/lib/datasrc/memory/rdata_reader.h
+++ b/src/lib/datasrc/memory/rdata_reader.h
@@ -34,7 +34,7 @@ namespace memory {
/// \brief Class to read serialized rdata
///
-/// This class allows you to read the data encoded by RDataEncoder.
+/// This class allows you to read the data encoded by RdataEncoder.
/// It is rather low-level -- it provides sequence of data fields.
/// Each field is either opaque data, passed as a pointer and length,
/// or a name, in the form of dns::LabelSequence (which is always
@@ -131,10 +131,11 @@ public:
/// field and returns RDATA_BOUNDARY and then it returns RRSET_BOUNDARY
/// on the next call.
Boundary next();
+
/// \brief Call next() until the end.
///
/// This is just convenience method to iterate through all the data.
- /// It calls next until it reaches the end (it does not revind before,
+ /// It calls next until it reaches the end (it does not rewind before,
/// therefore if you already called next() yourself, it does not start
/// at the beginning).
void iterate() {
@@ -156,11 +157,13 @@ public:
}
}
}
+
/// \brief Step to next field of RRSig data.
///
/// This is almost the same as next(), but it iterates through the
/// associated RRSig data, not the data for the given RRType.
Boundary nextSig();
+
/// \brief Iterate through all RRSig data.
///
/// This is almost the same as iterate(), but it iterates through the
@@ -168,6 +171,7 @@ public:
void iterateAllSigs() {
while (nextSig() != RRSET_BOUNDARY) { }
}
+
/// \brief Iterate through the current RRSig Rdata.
///
/// This is almote the same as iterateRdata, except it is for single
@@ -183,6 +187,7 @@ public:
}
}
}
+
/// \brief Rewind the iterator to the beginnig of data.
///
/// The following next() and nextSig() will start iterating from the
diff --git a/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc b/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
index ba76f4c..fbbd4ef 100644
--- a/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
+++ b/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
@@ -13,7 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
// Note: This file tests both the rdata_encoder and rdata_reader. They are
-// tested together because they form kind the oposite sides of the same
+// tested together because they form kind the opposite sides of the same
// functionality.
#include <exceptions/exceptions.h>
@@ -104,8 +104,7 @@ void
renderNameField(MessageRenderer* renderer, bool additional_required,
const LabelSequence& labels, unsigned attributes)
{
- EXPECT_EQ(additional_required,
- (attributes & NAMEATTR_ADDITIONAL) != 0);
+ EXPECT_EQ(additional_required, (attributes & NAMEATTR_ADDITIONAL) != 0);
renderer->writeName(labels, (attributes & NAMEATTR_COMPRESSIBLE) != 0);
}
@@ -151,7 +150,7 @@ protected:
template<class DecoderStyle>
class RdataEncodeDecodeTest : public RdataSerializationTest {
public:
- // This helper test method constructs encodes the given list of RDATAs
+ // This helper test method encodes the given list of RDATAs
// (in rdata_list), and then iterates over the data, rendering the fields
// in the wire format. It then compares the wire data with the one
// generated by the normal libdns++ interface to see the encoding/decoding
@@ -289,8 +288,8 @@ public:
encoded_data.end());
}
- // If RRSIGs are given, we need to extract the list of the RRSIG lengths
- // and adjust encoded_data_ further.
+ // If RRSIGs are given, we need to extract the list of the RRSIG
+ // lengths and adjust encoded_data_ further.
vector<uint16_t> rrsiglen_list;
if (rrsig_count > 0) {
const size_t rrsig_len_size = rrsig_count * sizeof(uint16_t);
@@ -308,11 +307,11 @@ public:
additionalRequired(rrtype), _1, _2),
boost::bind(renderDataField, &renderer, _1, _2));
- // 2nd dummy name
- renderer.writeName(dummyName2());
- // Finally, dump any RRSIGs in wire format.
- foreachRRSig(encoded_data, rrsiglen_list,
- boost::bind(renderDataField, &renderer, _1, _2));
+ // 2nd dummy name
+ renderer.writeName(dummyName2());
+ // Finally, dump any RRSIGs in wire format.
+ foreachRRSig(encoded_data, rrsiglen_list,
+ boost::bind(renderDataField, &renderer, _1, _2));
}
};
@@ -601,7 +600,7 @@ addRdataCommon(const vector<ConstRdataPtr>& rrsigs) {
TYPED_TEST(RdataEncodeDecodeTest, addRdata) {
vector<ConstRdataPtr> rrsigs;
- this->addRdataCommon(rrsigs); // basic tests without RRSIGs (empty vector)
+ this->addRdataCommon(rrsigs); // basic tests without RRSIGs (empty vector)
// Test with RRSIGs (covered type doesn't always match, but the encoder
// doesn't check that)
@@ -832,5 +831,4 @@ TEST_F(RdataSerializationTest, badAddSIGRdata) {
encoder_.start(RRClass::IN(), RRType::A());
EXPECT_THROW(encoder_.addSIGRdata(big_sigrdata), RdataEncodingError);
}
-
}
More information about the bind10-changes
mailing list