#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>
}
}
+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);
+}
+
}
}
}
#define FAKE_RESOLUTION_H
#include <exceptions/exceptions.h>
+#include <asiolink/io_service.h>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
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?
///
}
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;
/// 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
/// 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_;
};
}