Browse Source

[2871] The fake interface implemented

Michal 'vorner' Vaner 12 years ago
parent
commit
a16cb0089b

+ 2 - 0
src/bin/resolver/bench/Makefile.am

@@ -20,3 +20,5 @@ resolver_bench_SOURCES += dummy_work.h dummy_work.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
+

+ 83 - 0
src/bin/resolver/bench/fake_resolution.cc

@@ -15,6 +15,10 @@
 #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>
 
@@ -84,6 +88,85 @@ FakeQuery::performTask(const StepCallback& 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 schedule a timeout with
+    // 0 time. That'll place the event for it directly at the end of the queue.
+    // Then, we'll just call processEvents() until that event happens.
+    bool processed = false;
+    asiolink::IntervalTimer zero_timer(service_);
+    zero_timer.setup(boost::bind(&processDone, &processed), 0);
+    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 operator()() {
+        query_->outstanding_ = false;
+        callback_();
+    }
+private:
+    FakeQuery* const query_;
+    const FakeQuery::StepCallback callback_;
+    // Just to hold it alive before the callback is called (or discarded for
+    // some reason, like destroying the service).
+    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(query, callback, timer);
+    timer->setup(q, msec);
+}
+
 }
 }
 }

+ 24 - 14
src/bin/resolver/bench/fake_resolution.h

@@ -16,6 +16,7 @@
 #define FAKE_RESOLUTION_H
 
 #include <exceptions/exceptions.h>
+#include <asiolink/io_service.h>
 
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
@@ -80,15 +81,6 @@ private:
     friend class FakeInterface;
     /// \brief Constructor
     FakeQuery(FakeInterface& interface);
-    // 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_;
 public:
     /// \brief Is work on the query completely done?
     ///
@@ -150,6 +142,16 @@ public:
         }
         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;
@@ -174,12 +176,12 @@ typedef boost::shared_ptr<FakeQuery> FakeQueryPtr;
 /// 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 {
-private:
-    friend class FakeQuery;
-    void scheduleUpstreamAnswer(FakeQuery* query,
-                                const FakeQuery::StepCallback& callback,
-                                size_t msec);
 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
@@ -202,6 +204,14 @@ public:
     /// 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_;
 };
 
 }