Lazily allocate input buffer for AsyncTCPSocket.

As a follow-up to https://codereview.webrtc.org/1737053006/ this CL further
improves memory usage by lazily allocating input buffers up to the passed
maximum size. This also changes the input buffer to a Buffer object.

BUG=

Review URL: https://codereview.webrtc.org/1744293002

Cr-Commit-Position: refs/heads/master@{#11859}
This commit is contained in:
jbauch 2016-03-03 03:41:05 -08:00 committed by Commit bot
parent 79a5cf9ed1
commit 313afba2eb
2 changed files with 43 additions and 17 deletions

View File

@ -12,6 +12,8 @@
#include <string.h>
#include <algorithm>
#include "webrtc/base/byteorder.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/common.h"
@ -30,6 +32,11 @@ static const size_t kPacketLenSize = sizeof(PacketLength);
static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
// The input buffer will be resized so that at least kMinimumRecvSize bytes can
// be received (but it will not grow above the maximum size passed to the
// constructor).
static const size_t kMinimumRecvSize = 128;
static const int kListenBacklog = 5;
// Binds and connects |socket|
@ -53,12 +60,11 @@ AsyncTCPSocketBase::AsyncTCPSocketBase(AsyncSocket* socket, bool listen,
size_t max_packet_size)
: socket_(socket),
listen_(listen),
insize_(max_packet_size),
inpos_(0),
max_insize_(max_packet_size),
max_outsize_(max_packet_size) {
if (!listen_) {
// Listening sockets don't send/receive data, so they don't need buffers.
inbuf_.reset(new char[insize_]);
inbuf_.EnsureCapacity(kMinimumRecvSize);
}
RTC_DCHECK(socket_.get() != NULL);
@ -182,7 +188,7 @@ void AsyncTCPSocketBase::OnReadEvent(AsyncSocket* socket) {
rtc::SocketAddress address;
rtc::AsyncSocket* new_socket = socket->Accept(&address);
if (!new_socket) {
// TODO: Do something better like forwarding the error
// TODO(stefan): Do something better like forwarding the error
// to the user.
LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
return;
@ -193,24 +199,44 @@ void AsyncTCPSocketBase::OnReadEvent(AsyncSocket* socket) {
// Prime a read event in case data is waiting.
new_socket->SignalReadEvent(new_socket);
} else {
RTC_DCHECK(inbuf_.get());
int len = socket_->Recv(inbuf_.get() + inpos_, insize_ - inpos_);
if (len < 0) {
// TODO: Do something better like forwarding the error to the user.
if (!socket_->IsBlocking()) {
LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
size_t total_recv = 0;
while (true) {
size_t free_size = inbuf_.capacity() - inbuf_.size();
if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) {
inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2));
free_size = inbuf_.capacity() - inbuf_.size();
}
int len = socket_->Recv(inbuf_.data() + inbuf_.size(), free_size);
if (len < 0) {
// TODO(stefan): Do something better like forwarding the error to the
// user.
if (!socket_->IsBlocking()) {
LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
}
break;
}
total_recv += len;
inbuf_.SetSize(inbuf_.size() + len);
if (!len || static_cast<size_t>(len) < free_size) {
break;
}
}
if (!total_recv) {
return;
}
inpos_ += len;
size_t size = inbuf_.size();
ProcessInput(inbuf_.data<char>(), &size);
ProcessInput(inbuf_.get(), &inpos_);
if (inpos_ >= insize_) {
if (size > inbuf_.size()) {
LOG(LS_ERROR) << "input buffer overflow";
RTC_NOTREACHED();
inpos_ = 0;
inbuf_.Clear();
} else {
inbuf_.SetSize(size);
}
}
}

View File

@ -72,9 +72,9 @@ class AsyncTCPSocketBase : public AsyncPacketSocket {
scoped_ptr<AsyncSocket> socket_;
bool listen_;
scoped_ptr<char[]> inbuf_;
Buffer inbuf_;
Buffer outbuf_;
size_t insize_, inpos_;
size_t max_insize_;
size_t max_outsize_;
RTC_DISALLOW_COPY_AND_ASSIGN(AsyncTCPSocketBase);