const uint8_t* TMemoryBuffer::borrowSlow(uint8_t* buf, uint32_t* len) { rBound_ = wBase_; if (available_read() >= *len) { *len = available_read(); return rBase_; } return NULL; }
void TMemoryBuffer::computeRead(uint32_t len, uint8_t** out_start, uint32_t* out_give) { // Correct rBound_ so we can use the fast path in the future. rBound_ = wBase_; // Decide how much to give. uint32_t give = std::min(len, available_read()); *out_start = rBase_; *out_give = give; // Preincrement rBase_ so the caller doesn't have to. rBase_ += give; }
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_; }