BIND 10 master, updated. 33e10c84c8b6ab274c157816ba81e6d2fc8ba628 Merge #2871

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Apr 30 07:00:22 UTC 2013


The branch, master has been updated
       via  33e10c84c8b6ab274c157816ba81e6d2fc8ba628 (commit)
       via  e4870b2ea373a314214f1ff575aa675496557b00 (commit)
       via  135070d34df3a8c70cfaec68fcdd43704e017fb7 (commit)
       via  e893a8d8b65af8f4b4d01ddf0388fb2bceb52ea0 (commit)
       via  ef8e4e281a59bd4e3f5396533f96e54b7ffd1434 (commit)
       via  bcabe81c90f6e6294b714b4aef589f60f6b6cca1 (commit)
       via  8c2655df05e51decb5cb0ff7ec48d484341b5f6e (commit)
       via  493b6d66358602da6281641df2c80833f2b10b94 (commit)
       via  1b437a9f90cf46154bd7cc3c0c63315293d8860c (commit)
       via  2ca8aec80f6a9dcb4da01a9057e9abb9717ab93e (commit)
       via  dd0c9ba580d2b87324e3063de6f69d2bc8be5687 (commit)
      from  3a382331f1308099930d6b653dd6d11b70da8e22 (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 33e10c84c8b6ab274c157816ba81e6d2fc8ba628
Merge: 3a38233 e4870b2
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Apr 30 08:56:22 2013 +0200

    Merge #2871
    
    Fake work for resolution models testing.

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

Summary of changes:
 configure.ac                                       |    1 +
 src/bin/resolver/Makefile.am                       |    2 +-
 src/bin/resolver/bench/Makefile.am                 |   25 +++
 .../{spec_config.h.pre.in => bench/dummy_work.cc}  |   43 ++--
 .../resolver/bench/dummy_work.h}                   |   29 ++-
 src/bin/resolver/bench/fake_resolution.cc          |  172 +++++++++++++++
 src/bin/resolver/bench/fake_resolution.h           |  221 ++++++++++++++++++++
 .../resolver/bench/main.cc}                        |   28 +--
 src/bin/resolver/bench/naive_resolver.cc           |   66 ++++++
 .../resolver/bench/naive_resolver.h}               |   44 ++--
 src/lib/asiolink/io_service.cc                     |    8 +
 src/lib/asiolink/io_service.h                      |   13 ++
 src/lib/asiolink/tests/Makefile.am                 |    1 +
 .../tests/io_service_unittest.cc}                  |   52 ++---
 src/lib/bench/benchmark.h                          |    2 +-
 15 files changed, 615 insertions(+), 92 deletions(-)
 create mode 100644 src/bin/resolver/bench/Makefile.am
 copy src/bin/resolver/{spec_config.h.pre.in => bench/dummy_work.cc} (82%)
 copy src/{lib/datasrc/tests/run_unittests.cc => bin/resolver/bench/dummy_work.h} (62%)
 create mode 100644 src/bin/resolver/bench/fake_resolution.cc
 create mode 100644 src/bin/resolver/bench/fake_resolution.h
 copy src/{lib/dns/python/zone_checker_python.h => bin/resolver/bench/main.cc} (67%)
 create mode 100644 src/bin/resolver/bench/naive_resolver.cc
 copy src/{lib/exceptions/exceptions.cc => bin/resolver/bench/naive_resolver.h} (57%)
 copy src/lib/{util/tests/interprocess_util.cc => asiolink/tests/io_service_unittest.cc} (51%)

-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 2f8171d..e35e498 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1201,6 +1201,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/dhcp4/tests/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
+                 src/bin/resolver/bench/Makefile
                  src/bin/sysinfo/Makefile
                  src/bin/sockcreator/Makefile
                  src/bin/sockcreator/tests/Makefile
diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am
index 47e242c..a549e6a 100644
--- a/src/bin/resolver/Makefile.am
+++ b/src/bin/resolver/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . tests bench
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
diff --git a/src/bin/resolver/bench/Makefile.am b/src/bin/resolver/bench/Makefile.am
new file mode 100644
index 0000000..e4689fb
--- /dev/null
+++ b/src/bin/resolver/bench/Makefile.am
@@ -0,0 +1,25 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_builddir)/src/bin/resolver
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+noinst_PROGRAMS = resolver-bench
+
+resolver_bench_SOURCES = main.cc
+resolver_bench_SOURCES += fake_resolution.h fake_resolution.cc
+resolver_bench_SOURCES += dummy_work.h dummy_work.cc
+resolver_bench_SOURCES += naive_resolver.h naive_resolver.cc
+
+resolver_bench_LDADD  = $(GTEST_LDADD)
+resolver_bench_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+resolver_bench_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+
diff --git a/src/bin/resolver/bench/dummy_work.cc b/src/bin/resolver/bench/dummy_work.cc
new file mode 100644
index 0000000..a0669b3
--- /dev/null
+++ b/src/bin/resolver/bench/dummy_work.cc
@@ -0,0 +1,28 @@
+// 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 <resolver/bench/dummy_work.h>
+
+namespace isc {
+namespace resolver {
+namespace bench {
+
+void
+dummy_work() {
+    // Function left intentonally blank.
+};
+
+}
+}
+}
diff --git a/src/bin/resolver/bench/dummy_work.h b/src/bin/resolver/bench/dummy_work.h
new file mode 100644
index 0000000..aacb222
--- /dev/null
+++ b/src/bin/resolver/bench/dummy_work.h
@@ -0,0 +1,36 @@
+// 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 DUMMY_WORK_H
+#define DUMMY_WORK_H
+
+namespace isc {
+namespace resolver {
+namespace bench {
+
+/// \brief An empty function.
+///
+/// An empty function, to fill the CPU with something during the benchmark.
+/// It is expected to be called many times by whatever simulates doing some
+/// real CPU-bound work.
+///
+/// It is defined in separate translation unit, so the compiler does not
+/// know it is empty and can't optimise the call out.
+void dummy_work();
+
+}
+}
+}
+
+#endif
diff --git a/src/bin/resolver/bench/fake_resolution.cc b/src/bin/resolver/bench/fake_resolution.cc
new file mode 100644
index 0000000..a538302
--- /dev/null
+++ b/src/bin/resolver/bench/fake_resolution.cc
@@ -0,0 +1,172 @@
+// 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 <resolver/bench/fake_resolution.h>
+#include <resolver/bench/dummy_work.h>
+
+#include <asiolink/interval_timer.h>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <algorithm>
+#include <cstdlib>
+
+namespace isc {
+namespace resolver {
+namespace bench {
+
+// Parameters of the generated queries.
+// How much work is each operation?
+const size_t parse_size = 100000;
+const size_t render_size = 100000;
+const size_t send_size = 1000;
+const size_t cache_read_size = 10000;
+const size_t cache_write_size = 10000;
+// How large a change is to terminate in this iteration (either by getting
+// the complete answer, or by finding it in the cache). With 0.5, half the
+// queries are found in the cache directly. Half of the rest needs just one
+// upstream query. Etc.
+const float chance_complete = 0.5;
+// Number of milliseconds an upstream query can take. It picks a random number
+// in between.
+const size_t upstream_time_min = 2;
+const size_t upstream_time_max = 50;
+
+FakeQuery::FakeQuery(FakeInterface& interface) :
+    interface_(&interface),
+    outstanding_(false)
+{
+    // Schedule what tasks are needed.
+    // First, parse the query
+    steps_.push_back(Step(Compute, parse_size));
+    // Look into the cache if it is there
+    steps_.push_back(Step(CacheRead, cache_read_size));
+    while ((1.0 * random()) / RAND_MAX > chance_complete) {
+        // Needs another step of recursion. Render the upstream query.
+        steps_.push_back(Step(Compute, render_size));
+        // Send it and wait for the answer.
+        steps_.push_back(Step(Upstream, upstream_time_min +
+                              (random() *
+                               (upstream_time_max - upstream_time_min) /
+                               RAND_MAX)));
+        // After it comes, parse the answer and store it in the cache.
+        steps_.push_back(Step(Compute, parse_size));
+        steps_.push_back(Step(CacheWrite, cache_write_size));
+    }
+    // Last, render the answer and send it.
+    steps_.push_back(Step(Compute, render_size));
+    steps_.push_back(Step(Send, send_size));
+    // Reverse it, so we can pop_back the tasks as we work on them.
+    std::reverse(steps_.begin(), steps_.end());
+}
+
+void
+FakeQuery::performTask(const StepCallback& callback) {
+    // nextTask also does all the sanity checking we need.
+    if (nextTask() == Upstream) {
+        outstanding_ = true;
+        interface_->scheduleUpstreamAnswer(this, callback,
+                                           steps_.back().second);
+        steps_.pop_back();
+    } else {
+        for (size_t i = 0; i < steps_.back().second; ++i) {
+            dummy_work();
+        }
+        steps_.pop_back();
+        callback();
+    }
+}
+
+FakeInterface::FakeInterface(size_t query_count) :
+    queries_(query_count)
+{
+    BOOST_FOREACH(FakeQueryPtr& query, queries_) {
+        query = FakeQueryPtr(new FakeQuery(*this));
+    }
+}
+
+void
+FakeInterface::processEvents() {
+    service_.run_one();
+}
+
+namespace {
+
+void
+processDone(bool* flag) {
+    *flag = true;
+}
+
+}
+
+FakeQueryPtr
+FakeInterface::receiveQuery() {
+    // Handle all the events that are already scheduled.
+    // As processEvents blocks until an event happens and we want to terminate
+    // if there are no events, we do a small trick. We post an event to the end
+    // of the queue and work until it is found. This should process all the
+    // events that were there already.
+    bool processed = false;
+    service_.post(boost::bind(&processDone, &processed));
+    while (!processed) {
+        processEvents();
+    }
+
+    // Now, look if there are more queries to return.
+    if (queries_.empty()) {
+        return (FakeQueryPtr());
+    } else {
+        // Take from the back. The order doesn't matter and it's faster from
+        // there.
+        FakeQueryPtr result(queries_.back());
+        queries_.pop_back();
+        return (result);
+    }
+}
+
+class FakeInterface::UpstreamQuery {
+public:
+    UpstreamQuery(FakeQuery* query, const FakeQuery::StepCallback& callback,
+                  const boost::shared_ptr<asiolink::IntervalTimer> timer) :
+        query_(query),
+        callback_(callback),
+        timer_(timer)
+    {}
+    void trigger() {
+        query_->outstanding_ = false;
+        callback_();
+        // We are not needed any more.
+        delete this;
+    }
+private:
+    FakeQuery* const query_;
+    const FakeQuery::StepCallback callback_;
+    // Just to hold it alive before the callback is called.
+    const boost::shared_ptr<asiolink::IntervalTimer> timer_;
+};
+
+void
+FakeInterface::scheduleUpstreamAnswer(FakeQuery* query,
+                                      const FakeQuery::StepCallback& callback,
+                                      size_t msec)
+{
+    const boost::shared_ptr<asiolink::IntervalTimer>
+        timer(new asiolink::IntervalTimer(service_));
+    UpstreamQuery* q(new UpstreamQuery(query, callback, timer));
+    timer->setup(boost::bind(&UpstreamQuery::trigger, q), msec);
+}
+
+}
+}
+}
diff --git a/src/bin/resolver/bench/fake_resolution.h b/src/bin/resolver/bench/fake_resolution.h
new file mode 100644
index 0000000..0fc0b40
--- /dev/null
+++ b/src/bin/resolver/bench/fake_resolution.h
@@ -0,0 +1,221 @@
+// 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 FAKE_RESOLUTION_H
+#define FAKE_RESOLUTION_H
+
+#include <exceptions/exceptions.h>
+#include <asiolink/io_service.h>
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <utility>
+#include <vector>
+
+namespace isc {
+namespace resolver {
+namespace bench {
+
+/// \brief The kind of task a FakeQuery might want to perform.
+///
+/// The benchmark should examine which kind of task the query needs to perform
+/// to progress forward. According to the task, some resources might need to be
+/// locked, something re-scheduled, or such.
+enum Task {
+    /// \brief Some CPU-bound computation.
+    ///
+    /// The query needs to do some computation without any shared resources.
+    /// This might be parsing or rendering of the query, verification of
+    /// signatures, etc.
+    Compute,
+    /// \brief The query needs to read data from cache.
+    CacheRead,
+    /// \brief The query needs to modify the cache.
+    CacheWrite,
+    /// \brief A response is to be sent.
+    ///
+    /// This needs to access the interface/socket. If the socket is shared
+    /// between threads, it might need to lock it.
+    Send,
+    /// \brief An answer from upstream server is needed.
+    ///
+    /// The query needs to send a query to some authoritative server and wait
+    /// for the answer. Something might need to be locked (or not, depending
+    /// on the architecture of the thing that sends and receives). Also, the
+    /// task will not complete immediately, the callback of performTask
+    /// will be called at later time.
+    Upstream
+};
+
+class FakeInterface;
+
+/// \brief Imitation of the work done to resolve a query.
+///
+/// An object of this class represents some fake work that should look like
+/// the work needed to perform resolution of one query. No real work is done,
+/// but several steps are scheduled, with characteristics hopefully
+/// corresponding to steps of the real query.
+///
+/// The idea is that benchmark will repeatedly check if the query is done.
+/// If not, it examines the next task by calling nextTask(). Depending on
+/// the result, it'd lock or prepare any shared resources. After that, it'd
+/// call performTask() to do the task. Once the query calls the callback
+/// passed, it can proceed to the next step.
+///
+/// See naive_resolver.cc for example code how this could be done.
+class FakeQuery {
+private:
+    // The queries come only through an interface. Don't let others create.
+    friend class FakeInterface;
+    /// \brief Constructor
+    FakeQuery(FakeInterface& interface);
+public:
+    /// \brief Is work on the query completely done?
+    ///
+    /// If this returns true, do not call performTask or nextTask any more.
+    /// The resolution is done.
+    ///
+    /// \throw isc::InvalidOperation if upstream query is still in progress.
+    bool done() const {
+        if (outstanding_) {
+            isc_throw(isc::InvalidOperation, "Upstream query outstanding");
+        }
+        return (steps_.empty());
+    }
+    /// \brief Callback to signify a task has been performed.
+    typedef boost::function<void()> StepCallback;
+    /// \brief Perform next step in the resolution.
+    ///
+    /// Do whatever is needed to be done for the next step of resolution.
+    /// Once the step is done, the callback is called.
+    ///
+    /// The callback is usually called from within this call. However, in
+    /// the case when the nextTask() returned `Upstream`, the call to the
+    /// callback is delayed for some period of time after the method
+    /// returns.
+    ///
+    /// \throw isc::InvalidOperation if it is called when done() is true, or
+    ///     if an upstream query is still in progress (performTask was called
+    ///     before and the callback was not called by the query yet).
+    void performTask(const StepCallback& callback);
+    /// \brief Examine the kind of the next resolution process.
+    ///
+    /// Call this to know what kind of task will performTask do next.
+    ///
+    /// \throw isc::InvalidOperation if it is called when done() is true, or
+    ///     if an upstream query is still in progress (performTask was called
+    ///     before and the callback was not called by the query yet).
+    Task nextTask() const {
+        // Will check for outstanding_ internally too
+        if (done()) {
+            isc_throw(isc::InvalidOperation, "We are done, no more tasks");
+        }
+        return (steps_.back().first);
+    }
+    /// \brief Move network communication to different interface.
+    ///
+    /// By default, a query does all the "communication" on the interface
+    /// it was born on. This may be used to move a query from one interface
+    /// to another.
+    ///
+    /// You don't have to lock either of the interfaces to do so, this
+    /// only switches the data in the query.
+    ///
+    /// \throw isc::InvalidOperation if it is called while an upstream query
+    ///     is in progress.
+    void migrateTo(FakeInterface& dst_interface) {
+        if (outstanding_) {
+            isc_throw(isc::InvalidOperation,
+                      "Can't migrate in the middle of query");
+        }
+        interface_ = &dst_interface;
+    }
+private:
+    // The scheduled steps for this task.
+    typedef std::pair<Task, size_t> Step;
+    // The scheduled steps. Reversed (first to be done at the end), so we can
+    // pop_back() the completed steps.
+    std::vector<Step> steps_;
+    // The interface to schedule timeouts on.
+    FakeInterface* interface_;
+    // Is an upstream query outstanding?
+    bool outstanding_;
+};
+
+typedef boost::shared_ptr<FakeQuery> FakeQueryPtr;
+
+/// \brief An imitation of interface for receiving queries.
+///
+/// This is effectively a little bit smarter factory for queries. You can
+/// request a new query from it, or let process events (incoming answers).
+///
+/// It contains its own event loop. If the benchmark has more threads, have
+/// one in each of the threads (if the threads ever handles network
+/// communication -- if it accepts queries, sends answers or does upstream
+/// queries).
+///
+/// If the model simulated would share the same interface between multiple
+/// threads, it is better to have one in each thread as well, but lock
+/// access to receiveQuery() so only one is used at once (no idea what happens
+/// if ASIO loop is accessed from multiple threads).
+///
+/// Note that the creation of the queries is not thread safe (due to
+/// the random() function inside). The interface generates all its queries
+/// in advance, on creation time. But you need to create all the needed
+/// interfaces from single thread and then distribute them to your threads.
+class FakeInterface {
+public:
+    /// \brief Constructor
+    ///
+    /// Initiarile the interface and create query_count queries for the
+    /// benchmark. They will be handed out one by one with receiveQuery().
+    FakeInterface(size_t query_count);
+    /// \brief Wait for answers from upstream servers.
+    ///
+    /// Wait until at least one "answer" comes from the remote server. This
+    /// will effectively block the calling thread until it is time to call
+    /// a callback of performTask.
+    ///
+    /// It is not legal to call it without any outstanding upstream queries
+    /// on this interface. However, the situation is not explicitly checked.
+    ///
+    /// \note Due to internal implementation, it is not impossible no or more
+    ///    than one callbacks to be called from within this method.
+    void processEvents();
+    /// \brief Accept another query.
+    ///
+    /// Generate a new fake query to resolve.
+    ///
+    /// This method might call callbacks of other queries waiting for upstream
+    /// answer.
+    ///
+    /// This returns a NULL pointer when there are no more queries to answer
+    /// (the number designated for the benchmark was reached).
+    FakeQueryPtr receiveQuery();
+private:
+    class UpstreamQuery;
+    friend class FakeQuery;
+    void scheduleUpstreamAnswer(FakeQuery* query,
+                                const FakeQuery::StepCallback& callback,
+                                size_t msec);
+    asiolink::IOService service_;
+    std::vector<FakeQueryPtr> queries_;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/bin/resolver/bench/main.cc b/src/bin/resolver/bench/main.cc
new file mode 100644
index 0000000..3007c40
--- /dev/null
+++ b/src/bin/resolver/bench/main.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2013  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 <resolver/bench/naive_resolver.h>
+
+#include <bench/benchmark.h>
+
+const size_t count = 1000; // TODO: We may want to read this from argv.
+
+int main(int, const char**) {
+    // Run the naive implementation
+    isc::resolver::bench::NaiveResolver naive_resolver(count);
+    isc::bench::BenchMark<isc::resolver::bench::NaiveResolver>
+        (1, naive_resolver, true);
+    return 0;
+}
diff --git a/src/bin/resolver/bench/naive_resolver.cc b/src/bin/resolver/bench/naive_resolver.cc
new file mode 100644
index 0000000..3c50271
--- /dev/null
+++ b/src/bin/resolver/bench/naive_resolver.cc
@@ -0,0 +1,66 @@
+// 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 <resolver/bench/naive_resolver.h>
+
+#include <cassert>
+#include <boost/bind.hpp>
+
+namespace isc {
+namespace resolver {
+namespace bench {
+
+NaiveResolver::NaiveResolver(size_t query_count) :
+    interface_(query_count),
+    processed_(false)
+{}
+
+namespace {
+
+void
+stepDone(bool* flag) {
+    *flag = true;
+}
+
+}
+
+size_t
+NaiveResolver::run() {
+    assert(!processed_);
+    size_t count = 0;
+    FakeQueryPtr query;
+    // Process a query at a time. As the previous is already handled, the
+    // receiveQuery may never trigger other events.
+    while ((query = interface_.receiveQuery())) {
+        // Handle each step
+        while (!query->done()) {
+            bool done = false; // This step is not yet done.
+            // If there were more queries/threads/whatever, we would examine
+            // the query->nextTask() and lock or prepare resources accordingly.
+            // But as there's just one, we simply do the task, without caring.
+            query->performTask(boost::bind(&stepDone, &done));
+            // We may need to wait for the upstream query.
+            while (!done) {
+                interface_.processEvents();
+            }
+        }
+        count ++;
+    }
+    processed_ = true;
+    return (count);
+}
+
+}
+}
+}
diff --git a/src/bin/resolver/bench/naive_resolver.h b/src/bin/resolver/bench/naive_resolver.h
new file mode 100644
index 0000000..fdf3c56
--- /dev/null
+++ b/src/bin/resolver/bench/naive_resolver.h
@@ -0,0 +1,44 @@
+// 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 RESOLVER_BENCH_NAIVE_H
+#define RESOLVER_BENCH_NAIVE_H
+
+#include <resolver/bench/fake_resolution.h>
+
+namespace isc {
+namespace resolver {
+namespace bench {
+
+/// \brief Naive implementation of resolver for the benchmark
+///
+/// This is here mostly to show how to implement the other benchmark
+/// implementations. Look at the code inside how to use the fake
+/// resolution.
+class NaiveResolver {
+public:
+    /// \brief Constructor. Initializes the data.
+    NaiveResolver(size_t query_count);
+    /// \brief Run the resolution.
+    size_t run();
+private:
+    FakeInterface interface_;
+    bool processed_;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/asiolink/io_service.cc b/src/lib/asiolink/io_service.cc
index 15fad0c..ad4ae94 100644
--- a/src/lib/asiolink/io_service.cc
+++ b/src/lib/asiolink/io_service.cc
@@ -63,6 +63,9 @@ public:
     /// It will eventually be removed once the wrapper interface is
     /// generalized.
     asio::io_service& get_io_service() { return io_service_; };
+    void post(const boost::function<void ()>& callback) {
+        io_service_.post(callback);
+    }
 private:
     asio::io_service io_service_;
     asio::io_service::work work_;
@@ -96,5 +99,10 @@ IOService::get_io_service() {
     return (io_impl_->get_io_service());
 }
 
+void
+IOService::post(const boost::function<void ()>& callback) {
+    return (io_impl_->post(callback));
+}
+
 } // namespace asiolink
 } // namespace isc
diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h
index e0198dd..7e0da8f 100644
--- a/src/lib/asiolink/io_service.h
+++ b/src/lib/asiolink/io_service.h
@@ -15,6 +15,8 @@
 #ifndef ASIOLINK_IO_SERVICE_H
 #define ASIOLINK_IO_SERVICE_H 1
 
+#include <boost/function.hpp>
+
 namespace asio {
     class io_service;
 }
@@ -70,6 +72,17 @@ public:
     /// generalized.
     asio::io_service& get_io_service();
 
+    /// \brief Post a callback to the end of the queue.
+    ///
+    /// Requests the callback be called sometime later. It is not guaranteed
+    /// by the underlying asio, but it can reasonably be expected the callback
+    /// is put to the end of the callback queue. It is not called from within
+    /// this function.
+    ///
+    /// It may be used to implement "background" work, for example (doing stuff
+    /// by small bits that are called from time to time).
+    void post(const boost::function<void ()>& callback);
+
 private:
     IOServiceImpl* io_impl_;
 };
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index b401834..70b94dc 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -33,6 +33,7 @@ run_unittests_SOURCES += tcp_endpoint_unittest.cc
 run_unittests_SOURCES += tcp_socket_unittest.cc
 run_unittests_SOURCES += udp_endpoint_unittest.cc
 run_unittests_SOURCES += udp_socket_unittest.cc
+run_unittests_SOURCES += io_service_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 
diff --git a/src/lib/asiolink/tests/io_service_unittest.cc b/src/lib/asiolink/tests/io_service_unittest.cc
new file mode 100644
index 0000000..2fe4f12
--- /dev/null
+++ b/src/lib/asiolink/tests/io_service_unittest.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2013  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 <asiolink/io_service.h>
+
+#include <gtest/gtest.h>
+#include <boost/bind.hpp>
+#include <vector>
+
+using namespace isc::asiolink;
+
+namespace {
+
+void
+postedEvent(std::vector<int>* destination, int value) {
+    destination->push_back(value);
+}
+
+// Check the posted events are called, in the same order they are posted.
+TEST(IOService, post) {
+    std::vector<int> called;
+    IOService service;
+    // Post two events
+    service.post(boost::bind(&postedEvent, &called, 1));
+    service.post(boost::bind(&postedEvent, &called, 2));
+    // They have not yet been called
+    EXPECT_TRUE(called.empty());
+    // Process two events
+    service.run_one();
+    service.run_one();
+    // Both events were called in the right order
+    ASSERT_EQ(2, called.size());
+    EXPECT_EQ(1, called[0]);
+    EXPECT_EQ(2, called[1]);
+}
+
+}
diff --git a/src/lib/bench/benchmark.h b/src/lib/bench/benchmark.h
index 3e380dc..029f95a 100644
--- a/src/lib/bench/benchmark.h
+++ b/src/lib/bench/benchmark.h
@@ -93,7 +93,7 @@ namespace bench {
 ///        vector<int>::const_iterator end_key = keys_.end();
 ///        for (iter = keys_.begin(); iter != end_key; ++iter) {
 ///            data_.find(*iter);
-///        }        
+///        }
 ///        return (keys_.size());
 ///    }
 ///    const set<int>& data_;



More information about the bind10-changes mailing list