|
@@ -15,9 +15,14 @@
|
|
|
#ifndef FAKE_RESOLUTION_H
|
|
|
#define FAKE_RESOLUTION_H
|
|
|
|
|
|
+#include <exceptions/exceptions.h>
|
|
|
+
|
|
|
#include <boost/function.hpp>
|
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
|
|
+#include <utility>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
namespace isc {
|
|
|
namespace resolver {
|
|
|
namespace bench {
|
|
@@ -70,16 +75,35 @@ class FakeInterface;
|
|
|
///
|
|
|
/// 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);
|
|
|
+ // 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 Callback to signify a task has been performed.
|
|
|
- typedef boost::function<void()> StepCallback;
|
|
|
/// \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;
|
|
|
+ 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.
|
|
@@ -101,7 +125,13 @@ public:
|
|
|
/// \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;
|
|
|
+ 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
|
|
@@ -113,7 +143,13 @@ public:
|
|
|
///
|
|
|
/// \throw isc::InvalidOperation if it is called while an upstream query
|
|
|
/// is in progress.
|
|
|
- void migrateTo(FakeInterface& dst_interface);
|
|
|
+ void migrateTo(FakeInterface& dst_interface) {
|
|
|
+ if (outstanding_) {
|
|
|
+ isc_throw(isc::InvalidOperation,
|
|
|
+ "Can't migrate in the middle of query");
|
|
|
+ }
|
|
|
+ interface_ = &dst_interface;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
typedef boost::shared_ptr<FakeQuery> FakeQueryPtr;
|
|
@@ -130,9 +166,19 @@ typedef boost::shared_ptr<FakeQuery> FakeQueryPtr;
|
|
|
///
|
|
|
/// 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 so only one is used at once (no idea what happens if ASIO loop is
|
|
|
-/// accessed from multiple threads).
|
|
|
+/// 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 {
|
|
|
+private:
|
|
|
+ friend class FakeQuery;
|
|
|
+ void scheduleUpstreamAnswer(FakeQuery* query,
|
|
|
+ const FakeQuery::StepCallback& callback,
|
|
|
+ size_t msec);
|
|
|
public:
|
|
|
/// \brief Wait for answers from upstream servers.
|
|
|
///
|