Commit a73eb2ba authored by Michal Vaner's avatar Michal Vaner
Browse files

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
parent f467ed39
......@@ -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;
};
}
......
......@@ -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);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment