void TMemoryBuffer::ensureCanWrite(uint32_t len) { // Check available space uint32_t avail = available_write(); if (len <= avail) { return; } if (!owner_) { throw TTransportException("Insufficient space in external MemoryBuffer"); } // Grow the buffer as necessary. uint32_t new_size = bufferSize_; while (len > avail) { new_size = new_size > 0 ? new_size * 2 : 1; avail = available_write() + (new_size - bufferSize_); } // Allocate into a new pointer so we don't bork ours if it fails. void* new_buffer = std::realloc(buffer_, new_size); if (new_buffer == NULL) { throw std::bad_alloc(); } bufferSize_ = new_size; ptrdiff_t offset = (uint8_t*)new_buffer - buffer_; buffer_ += offset; rBase_ += offset; rBound_ += offset; wBase_ += offset; wBound_ = buffer_ + bufferSize_; }
void TMemoryBuffer::wroteBytes(uint32_t len) { uint32_t avail = available_write(); if (len > avail) { throw TTransportException("Client wrote more bytes than size of buffer."); } wBase_ += len; }
void TMemoryBuffer::ensureCanWrite(uint32_t len) { // Check available space uint32_t avail = available_write(); if (len <= avail) { return; } if (!owner_) { throw TTransportException("Insufficient space in external MemoryBuffer"); } bool copy = false; if (observerCount_ > 0) { transferOwnership(); // going to make a copy and shift out consumed data copy = true; } avail = bufferSize_ - available_read(); // Grow the buffer as necessary. uint32_t new_size = bufferSize_; while (len > avail) { new_size = new_size > 0 ? new_size * 2 : 1; if (new_size <= bufferSize_) { // overflow throw TTransportException("Buffer size exceeded maximum (2GB)"); } avail = available_write() + (new_size - bufferSize_); } // Allocate into a new pointer so we don't bork ours if it fails. void* new_buffer = nullptr; ptrdiff_t offset = 0; if (copy) { /* This is not a memory leak, because an observed buffer still owns the * previous buffer pointer. * * NOTE: If you are seeing a memory issue here, it's probable the * buffers are just growing very large and not being freed often. * Consider setting setResizeBufferEveryN, * setIdleWriteBufferLimit, and setIdleReadBufferLimit. * This will likely solve the issue. */ new_buffer = std::malloc(new_size); if (new_buffer == nullptr) { throw std::bad_alloc(); } // only copy the unconsumed data memcpy(new_buffer, rBase_, wBase_ - rBase_); } else { if (rBase_ != buffer_) { // shift data memmove(buffer_, rBase_, wBase_ - rBase_); } if (new_size > bufferSize_) { new_buffer = std::realloc(buffer_, new_size); if (new_buffer == nullptr) { throw std::bad_alloc(); } } else { // plenty of space new_buffer = buffer_; } } offset = (uint8_t *)new_buffer - rBase_; bufferSize_ = new_size; buffer_ = (uint8_t *)new_buffer; rBase_ += offset; rBound_ += offset; wBase_ += offset; wBound_ = buffer_ + bufferSize_; }