Browse Source

Move members of asiolink::UDPQuery inside Priv

This is not because of stable ABI, but because the class is copyed a lot
and it would need many shared pointers.

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/vorner-recursor-timeouts@3404 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner 14 years ago
parent
commit
a73eb2ba4d
2 changed files with 40 additions and 45 deletions
  1. 8 30
      src/lib/asiolink/internal/udpdns.h
  2. 32 15
      src/lib/asiolink/udpdns.cc

+ 8 - 30
src/lib/asiolink/internal/udpdns.h

@@ -218,36 +218,14 @@ public:
 private:
     enum { MAX_LENGTH = 4096 };
 
-    // The \c UDPQuery coroutine never forks, but it is copied whenever
-    // it calls an async_*() function, so it's best to keep copy overhead
-    // small by using pointers or references when possible.  However, this
-    // is not always possible.
-    //
-    // Socket used to for upstream queries. Created in the
-    // constructor and stored in a shared_ptr because socket objects
-    // are not copyable.
-    boost::shared_ptr<asio::ip::udp::socket> socket_;
-
-    // The remote endpoint.  Instantiated in the constructor.  Not
-    // stored as a shared_ptr because copy overhead of an endpoint
-    // object is no larger than that of a shared_ptr.
-    asio::ip::udp::endpoint remote_;
-
-    // The question being answered.  Copied rather than referenced
-    // because the object that created it is not guaranteed to persist.
-    isc::dns::Question question_;
-
-    // The output buffer supplied by the caller.  The resposne frmo
-    // the upstream server will be copied here.
-    isc::dns::OutputBufferPtr buffer_;
-
-    // These are allocated for each new query and are stored as
-    // shared pointers to minimize copy overhead.
-    isc::dns::OutputBufferPtr msgbuf_;
-    boost::shared_array<char> data_;
-
-    // This will be called when we are done.
-    Callback* callback_;
+    /**
+     * Private data. They are not private because of stability of the
+     * interface (this is private class anyway), but because this class
+     * will be copyed often and we want to keep the same data between
+     * the coroutines.
+     */
+    struct Priv;
+    boost::shared_ptr<Priv> priv;
 };
 }
 

+ 32 - 15
src/lib/asiolink/udpdns.cc

@@ -171,18 +171,36 @@ UDPServer::resume(const bool done) {
     io_.post(*this);
 }
 
+struct UDPQuery::Priv {
+    udp::socket socket;
+    udp::endpoint remote;
+    Question question;
+    OutputBufferPtr buffer;
+    OutputBufferPtr msgbuf;
+    boost::shared_array<char> data;
+    Callback* callback;
+
+    Priv(io_service& service, const udp::socket::protocol_type& protocol,
+        const Question &q, OutputBufferPtr b, Callback *c) :
+        socket(service, protocol),
+        question(q),
+        buffer(b),
+        msgbuf(new OutputBuffer(512)),
+        callback(c)
+    { }
+};
+
 /// The following functions implement the \c UDPQuery class.
 ///
 /// The constructor
 UDPQuery::UDPQuery(io_service& io_service,
                    const Question& q, const IOAddress& addr, uint16_t port,
                    OutputBufferPtr buffer, Callback *callback, int timeout) :
-    question_(q), buffer_(buffer), callback_(callback)
+    priv(new Priv(io_service,
+        addr.getFamily() == AF_INET ? udp::v4() : udp::v6(), q, buffer,
+        callback))
 {
-    udp proto = (addr.getFamily() == AF_INET) ? udp::v4() : udp::v6();
-    socket_.reset(new udp::socket(io_service, proto));
-    msgbuf_.reset(new OutputBuffer(512));
-    remote_ = UDPEndpoint(addr, port).getASIOEndpoint();
+    priv->remote = UDPEndpoint(addr, port).getASIOEndpoint();
 }
 
 /// The function operator is implemented with the "stackless coroutine"
@@ -205,35 +223,34 @@ UDPQuery::operator()(error_code ec, size_t length) {
             msg.setOpcode(Opcode::QUERY());
             msg.setRcode(Rcode::NOERROR());
             msg.setHeaderFlag(MessageFlag::RD());
-            msg.addQuestion(question_);
-            MessageRenderer renderer(*msgbuf_);
+            msg.addQuestion(priv->question);
+            MessageRenderer renderer(*priv->msgbuf);
             msg.toWire(renderer);
         }
 
         // Begin an asynchronous send, and then yield.  When the
         // send completes, we will resume immediately after this point.
-        CORO_YIELD socket_->async_send_to(buffer(msgbuf_->getData(),
-                                                 msgbuf_->getLength()),
-                                           remote_, *this);
+        CORO_YIELD priv->socket.async_send_to(buffer(priv->msgbuf->getData(),
+            priv->msgbuf->getLength()), priv->remote, *this);
 
         /// Allocate space for the response.  (XXX: This should be
         /// optimized by maintaining a free list of pre-allocated blocks)
-        data_.reset(new char[MAX_LENGTH]);
+        priv->data.reset(new char[MAX_LENGTH]);
 
         /// Begin an asynchronous receive, and yield.  When the receive
         /// completes, we will resume immediately after this point.
-        CORO_YIELD socket_->async_receive_from(buffer(data_.get(), MAX_LENGTH),
-                                               remote_, *this);
+        CORO_YIELD priv->socket.async_receive_from(buffer(priv->data.get(),
+            MAX_LENGTH), priv->remote, *this);
 
         /// Copy the answer into the response buffer.  (XXX: If the
         /// OutputBuffer object were made to meet the requirements of
         /// a MutableBufferSequence, then it could be written to directly
         /// by async_recieve_from() and this additional copy step would
         /// be unnecessary.)
-        buffer_->writeData(data_.get(), length);
+        priv->buffer->writeData(priv->data.get(), length);
 
         /// We are done
-        (*callback_)(SUCCESS);
+        (*priv->callback)(SUCCESS);
     }
 }