blob: c82cd3361f7f1b828193212d9cc56515dab6666f [file] [log] [blame]
/** @file
A brief file description
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#if !defined (_P_IOBuffer_h)
#define _P_IOBuffer_h
#include "libts.h"
#include "ink_resource.h"
// TODO: I think we're overly aggressive here on making MIOBuffer 64-bit
// but not sure it's worthwhile changing anything to 32-bit honestly.
//////////////////////////////////////////////////////////////
//
// returns 0 for DEFAULT_BUFFER_BASE_SIZE,
// +1 for each power of 2
//
//////////////////////////////////////////////////////////////
TS_INLINE int64_t
buffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size)
{
int64_t r = max;
while (r && BUFFER_SIZE_FOR_INDEX(r - 1) >= size)
r--;
return r;
}
TS_INLINE int64_t
iobuffer_size_to_index(int64_t size, int64_t max)
{
if (size > BUFFER_SIZE_FOR_INDEX(max))
return BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size);
return buffer_size_to_index(size, max);
}
TS_INLINE int64_t
index_to_buffer_size(int64_t idx)
{
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(idx))
return BUFFER_SIZE_FOR_INDEX(idx);
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(idx))
return BUFFER_SIZE_FOR_XMALLOC(idx);
// coverity[dead_error_condition]
else if (BUFFER_SIZE_INDEX_IS_CONSTANT(idx))
return BUFFER_SIZE_FOR_CONSTANT(idx);
// coverity[dead_error_line]
return 0;
}
TS_INLINE IOBufferBlock *
iobufferblock_clone(IOBufferBlock * b, int64_t offset, int64_t len)
{
IOBufferBlock *start_buf = NULL;
IOBufferBlock *current_buf = NULL;
while (b && len >= 0) {
char *start = b->_start;
char *end = b->_end;
int64_t max_bytes = end - start;
max_bytes -= offset;
if (max_bytes <= 0) {
offset = -max_bytes;
b = b->next;
continue;
}
int64_t bytes = len;
if (bytes >= max_bytes)
bytes = max_bytes;
IOBufferBlock *new_buf = b->clone();
new_buf->_start += offset;
new_buf->_buf_end = new_buf->_end = new_buf->_start + bytes;
if (!start_buf) {
start_buf = new_buf;
current_buf = start_buf;
} else {
current_buf->next = new_buf;
current_buf = new_buf;
}
len -= bytes;
b = b->next;
offset = 0;
}
return start_buf;
}
TS_INLINE IOBufferBlock *
iobufferblock_skip(IOBufferBlock * b, int64_t *poffset, int64_t *plen, int64_t write)
{
int64_t offset = *poffset;
int64_t len = write;
while (b && len >= 0) {
int64_t max_bytes = b->read_avail();
max_bytes -= offset;
if (max_bytes <= 0) {
offset = -max_bytes;
b = b->next;
continue;
}
if (len >= max_bytes) {
b = b->next;
len -= max_bytes;
offset = 0;
} else {
offset = offset + len;
break;
}
}
*poffset = offset;
*plen -= write;
return b;
}
#ifdef TRACK_BUFFER_USER
extern Resource *res_lookup(const char *path);
TS_INLINE void
iobuffer_mem_inc(const char *_loc, int64_t _size_index)
{
if (!res_track_memory)
return;
if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
return;
if (!_loc)
_loc = "memory/IOBuffer/UNKNOWN-LOCATION";
Resource *res = res_lookup(_loc);
ink_assert(strcmp(_loc, res->path) == 0);
#ifdef DEBUG
int64_t r = ink_atomic_increment(&res->value, index_to_buffer_size(_size_index));
ink_assert(r >= 0);
#else
ink_atomic_increment(&res->value, index_to_buffer_size(_size_index));
#endif
}
TS_INLINE void
iobuffer_mem_dec(const char *_loc, int64_t _size_index)
{
if (!res_track_memory)
return;
if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
return;
if (!_loc)
_loc = "memory/IOBuffer/UNKNOWN-LOCATION";
Resource *res = res_lookup(_loc);
ink_assert(strcmp(_loc, res->path) == 0);
#ifdef DEBUG
int64_t r = ink_atomic_increment(&res->value, -index_to_buffer_size(_size_index));
ink_assert(r >= index_to_buffer_size(_size_index));
#else
ink_atomic_increment(&res->value, -index_to_buffer_size(_size_index));
#endif
}
#endif
//////////////////////////////////////////////////////////////////
//
// inline functions definitions
//
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//
// class IOBufferData --
// inline functions definitions
//
//////////////////////////////////////////////////////////////////
TS_INLINE int64_t
IOBufferData::block_size()
{
return index_to_buffer_size(_size_index);
}
TS_INLINE IOBufferData *
new_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
const char *location,
#endif
void *b, int64_t size, int64_t asize_index)
{
(void) size;
IOBufferData *d = THREAD_ALLOC(ioDataAllocator, this_thread());
d->_size_index = asize_index;
ink_assert(BUFFER_SIZE_INDEX_IS_CONSTANT(asize_index)
|| size <= d->block_size());
#ifdef TRACK_BUFFER_USER
d->_location = location;
#endif
d->_data = (char *) b;
return d;
}
TS_INLINE IOBufferData *
new_constant_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
const char *loc,
#endif
void *b, int64_t size)
{
return new_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
loc,
#endif
b, size, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(size));
}
TS_INLINE IOBufferData *
new_xmalloc_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
const char *location,
#endif
void *b, int64_t size)
{
return new_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
location,
#endif
b, size, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size));
}
TS_INLINE IOBufferData *
new_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
const char *location,
#endif
void *b, int64_t size)
{
return new_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
location,
#endif
b, size, iobuffer_size_to_index(size));
}
TS_INLINE IOBufferData *
new_IOBufferData_internal(
#ifdef TRACK_BUFFER_USER
const char *loc,
#endif
int64_t size_index, AllocType type)
{
IOBufferData *d = THREAD_ALLOC(ioDataAllocator, this_thread());
#ifdef TRACK_BUFFER_USER
d->_location = loc;
#endif
d->alloc(size_index, type);
return d;
}
// IRIX has a compiler bug which prevents this function
// from being compiled correctly at -O3
// so it is DUPLICATED in IOBuffer.cc
// ****** IF YOU CHANGE THIS FUNCTION change that one as well.
TS_INLINE void
IOBufferData::alloc(int64_t size_index, AllocType type)
{
if (_data)
dealloc();
_size_index = size_index;
_mem_type = type;
#ifdef TRACK_BUFFER_USER
iobuffer_mem_inc(_location, size_index);
#endif
switch (type) {
case MEMALIGNED:
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index))
_data = (char *) THREAD_ALLOC(ioBufAllocator[size_index], this_thread());
// coverity[dead_error_condition]
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index))
_data = (char *)ats_memalign(ats_pagesize(), index_to_buffer_size(size_index));
break;
default:
case DEFAULT_ALLOC:
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index))
_data = (char *) THREAD_ALLOC(ioBufAllocator[size_index], this_thread());
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index))
_data = (char *)ats_malloc(BUFFER_SIZE_FOR_XMALLOC(size_index));
break;
}
}
// ****** IF YOU CHANGE THIS FUNCTION change that one as well.
TS_INLINE void
IOBufferData::dealloc()
{
#ifdef TRACK_BUFFER_USER
iobuffer_mem_dec(_location, _size_index);
#endif
switch (_mem_type) {
case MEMALIGNED:
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
THREAD_FREE(_data, ioBufAllocator[_size_index], this_thread());
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index))
::free((void *) _data);
break;
default:
case DEFAULT_ALLOC:
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
THREAD_FREE(_data, ioBufAllocator[_size_index], this_thread());
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index))
ats_free(_data);
break;
}
_data = 0;
_size_index = BUFFER_SIZE_NOT_ALLOCATED;
_mem_type = NO_ALLOC;
}
TS_INLINE void
IOBufferData::free()
{
dealloc();
THREAD_FREE(this, ioDataAllocator, this_thread());
}
//////////////////////////////////////////////////////////////////
//
// class IOBufferBlock --
// inline functions definitions
//
//////////////////////////////////////////////////////////////////
TS_INLINE IOBufferBlock *
new_IOBufferBlock_internal(
#ifdef TRACK_BUFFER_USER
const char *location
#endif
)
{
IOBufferBlock *b = THREAD_ALLOC(ioBlockAllocator, this_thread());
#ifdef TRACK_BUFFER_USER
b->_location = location;
#endif
return b;
}
TS_INLINE IOBufferBlock *
new_IOBufferBlock_internal(
#ifdef TRACK_BUFFER_USER
const char *location,
#endif
IOBufferData * d, int64_t len, int64_t offset)
{
IOBufferBlock *b = THREAD_ALLOC(ioBlockAllocator, this_thread());
#ifdef TRACK_BUFFER_USER
b->_location = location;
#endif
b->set(d, len, offset);
return b;
}
TS_INLINE
IOBufferBlock::IOBufferBlock():
_start(0),
_end(0),
_buf_end(0)
#ifdef TRACK_BUFFER_USER
,
_location(0)
#endif
{
return;
}
TS_INLINE void
IOBufferBlock::consume(int64_t len)
{
_start += len;
ink_assert(_start <= _end);
}
TS_INLINE void
IOBufferBlock::fill(int64_t len)
{
_end += len;
ink_assert(_end <= _buf_end);
}
TS_INLINE void
IOBufferBlock::reset()
{
_end = _start = buf();
_buf_end = buf() + data->block_size();
}
TS_INLINE void
IOBufferBlock::alloc(int64_t i)
{
ink_assert(BUFFER_SIZE_ALLOCATED(i));
#ifdef TRACK_BUFFER_USER
data = new_IOBufferData_internal(_location, i);
#else
data = new_IOBufferData_internal(i);
#endif
reset();
}
TS_INLINE void
IOBufferBlock::clear()
{
data = NULL;
IOBufferBlock *p = next;
while (p) {
int r = p->refcount_dec();
if (r)
break;
else {
IOBufferBlock *n = p->next.m_ptr;
p->next.m_ptr = NULL;
p->free();
p = n;
}
}
next.m_ptr = NULL;
_buf_end = _end = _start = NULL;
}
TS_INLINE IOBufferBlock *
IOBufferBlock::clone()
{
#ifdef TRACK_BUFFER_USER
IOBufferBlock *b = new_IOBufferBlock_internal(_location);
#else
IOBufferBlock *b = new_IOBufferBlock_internal();
#endif
b->data = data;
b->_start = _start;
b->_end = _end;
b->_buf_end = _end;
#ifdef TRACK_BUFFER_USER
b->_location = _location;
#endif
return b;
}
TS_INLINE void
IOBufferBlock::dealloc()
{
clear();
}
TS_INLINE void
IOBufferBlock::free()
{
dealloc();
THREAD_FREE(this, ioBlockAllocator, this_thread());
}
TS_INLINE void
IOBufferBlock::set_internal(void *b, int64_t len, int64_t asize_index)
{
#ifdef TRACK_BUFFER_USER
data = new_IOBufferData_internal(_location, BUFFER_SIZE_NOT_ALLOCATED);
#else
data = new_IOBufferData_internal(BUFFER_SIZE_NOT_ALLOCATED);
#endif
data->_data = (char *) b;
#ifdef TRACK_BUFFER_USER
iobuffer_mem_inc(_location, asize_index);
#endif
data->_size_index = asize_index;
reset();
_end = _start + len;
}
TS_INLINE void
IOBufferBlock::set(IOBufferData * d, int64_t len, int64_t offset)
{
data = d;
_start = buf() + offset;
_end = _start + len;
_buf_end = _start + d->block_size();
}
TS_INLINE void
IOBufferBlock::realloc_set_internal(void *b, int64_t buf_size, int64_t asize_index)
{
int64_t data_size = size();
memcpy(b, _start, size());
dealloc();
set_internal(b, buf_size, asize_index);
_end = _start + data_size;
}
TS_INLINE void
IOBufferBlock::realloc(void *b, int64_t buf_size)
{
realloc_set_internal(b, buf_size, BUFFER_SIZE_NOT_ALLOCATED);
}
TS_INLINE void
IOBufferBlock::realloc_xmalloc(void *b, int64_t buf_size)
{
realloc_set_internal(b, buf_size, -buf_size);
}
TS_INLINE void
IOBufferBlock::realloc_xmalloc(int64_t buf_size)
{
realloc_set_internal(ats_malloc(buf_size), buf_size, -buf_size);
}
TS_INLINE void
IOBufferBlock::realloc(int64_t i)
{
if (i == data->_size_index)
return;
if (i >= (int64_t) sizeof(ioBufAllocator))
return;
ink_release_assert(i > data->_size_index && i != BUFFER_SIZE_NOT_ALLOCATED);
void *b = THREAD_ALLOC(ioBufAllocator[i], this_thread());
realloc_set_internal(b, BUFFER_SIZE_FOR_INDEX(i), i);
}
//////////////////////////////////////////////////////////////////
//
// class IOBufferReader --
// inline functions definitions
//
//////////////////////////////////////////////////////////////////
TS_INLINE void
IOBufferReader::skip_empty_blocks()
{
while (block->next && block->next->read_avail() && start_offset >= block->size()) {
start_offset -= block->size();
block = block->next;
}
}
TS_INLINE bool
IOBufferReader::low_water()
{
return mbuf->low_water();
}
TS_INLINE bool
IOBufferReader::high_water()
{
return read_avail() >= mbuf->water_mark;
}
TS_INLINE bool
IOBufferReader::current_low_water()
{
return mbuf->current_low_water();
}
TS_INLINE IOBufferBlock *
IOBufferReader::get_current_block()
{
return block;
}
TS_INLINE char *
IOBufferReader::start()
{
if (block == 0)
return 0;
skip_empty_blocks();
return block->start() + start_offset;
}
TS_INLINE char *
IOBufferReader::end()
{
if (block == 0)
return 0;
skip_empty_blocks();
return block->end();
}
TS_INLINE int64_t
IOBufferReader::block_read_avail()
{
if (block == 0)
return 0;
skip_empty_blocks();
return (int64_t) (block->end() - (block->start() + start_offset));
}
TS_INLINE int
IOBufferReader::block_count()
{
int count = 0;
IOBufferBlock *b = block;
while (b) {
count++;
b = b->next;
}
return count;
}
TS_INLINE int64_t
IOBufferReader::read_avail()
{
int64_t t = 0;
IOBufferBlock *b = block;
while (b) {
t += b->read_avail();
b = b->next;
}
t -= start_offset;
if (size_limit != INT64_MAX && t > size_limit)
t = size_limit;
return t;
}
inline bool
IOBufferReader::is_read_avail_more_than(int64_t size)
{
int64_t t = -start_offset;
IOBufferBlock* b = block;
while (b) {
t += b->read_avail();
if (t > size) {
return true;
}
b = b->next;
}
return false;
}
TS_INLINE void
IOBufferReader::consume(int64_t n)
{
start_offset += n;
if (size_limit != INT64_MAX)
size_limit -= n;
ink_assert(size_limit >= 0);
if (block == 0)
return;
int64_t r = block->read_avail();
int64_t s = start_offset;
while (r <= s && block->next && block->next->read_avail()) {
s -= r;
start_offset = s;
block = block->next;
r = block->read_avail();
}
ink_assert(read_avail() >= 0);
}
TS_INLINE char &
IOBufferReader::operator[] (int64_t i)
{
static char
_error = '\0';
IOBufferBlock *
b = block;
i += start_offset;
while (b) {
int64_t bytes = b->read_avail();
if (bytes > i)
return b->start()[i];
i -= bytes;
b = b->next;
}
ink_assert(!"out of range");
if (unlikely(b))
return *b->start();
return _error;
}
TS_INLINE void
IOBufferReader::clear()
{
accessor = NULL;
block = NULL;
mbuf = NULL;
start_offset = 0;
size_limit = INT64_MAX;
}
TS_INLINE void
IOBufferReader::reset()
{
block = mbuf->_writer;
start_offset = 0;
size_limit = INT64_MAX;
}
////////////////////////////////////////////////////////////////
//
// class MIOBuffer --
// inline functions definitions
//
////////////////////////////////////////////////////////////////
inkcoreapi extern ClassAllocator<MIOBuffer> ioAllocator;
////////////////////////////////////////////////////////////////
//
// MIOBuffer::MIOBuffer()
//
// This constructor accepts a pre-allocated memory buffer,
// wraps if in a IOBufferData and IOBufferBlock structures
// and sets it as the current block.
// NOTE that in this case the memory buffer will not be freed
// by the MIOBuffer class. It is the user responsibility to
// free the memory buffer. The wrappers (MIOBufferBlock and
// MIOBufferData) will be freed by this class.
//
////////////////////////////////////////////////////////////////
TS_INLINE
MIOBuffer::MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark)
{
set(b, bufsize);
water_mark = aWater_mark;
size_index = BUFFER_SIZE_NOT_ALLOCATED;
#ifdef TRACK_BUFFER_USER
_location = NULL;
#endif
return;
}
TS_INLINE
MIOBuffer::MIOBuffer(int64_t default_size_index)
{
clear();
size_index = default_size_index;
#ifdef TRACK_BUFFER_USER
_location = NULL;
#endif
return;
}
TS_INLINE
MIOBuffer::MIOBuffer()
{
clear();
#ifdef TRACK_BUFFER_USER
_location = NULL;
#endif
return;
}
TS_INLINE
MIOBuffer::~
MIOBuffer()
{
_writer = NULL;
dealloc_all_readers();
}
TS_INLINE MIOBuffer * new_MIOBuffer_internal(
#ifdef TRACK_BUFFER_USER
const char *location,
#endif
int64_t size_index)
{
MIOBuffer *b = THREAD_ALLOC(ioAllocator, this_thread());
#ifdef TRACK_BUFFER_USER
b->_location = location;
#endif
b->alloc(size_index);
return b;
}
TS_INLINE void
free_MIOBuffer(MIOBuffer * mio)
{
mio->_writer = NULL;
mio->dealloc_all_readers();
THREAD_FREE(mio, ioAllocator, this_thread());
}
TS_INLINE MIOBuffer * new_empty_MIOBuffer_internal(
#ifdef TRACK_BUFFER_USER
const char *location,
#endif
int64_t size_index)
{
MIOBuffer *b = THREAD_ALLOC(ioAllocator, this_thread());
b->size_index = size_index;
#ifdef TRACK_BUFFER_USER
b->_location = location;
#endif
return b;
}
TS_INLINE void
free_empty_MIOBuffer(MIOBuffer * mio)
{
THREAD_FREE(mio, ioAllocator, this_thread());
}
TS_INLINE IOBufferReader *
MIOBuffer::alloc_accessor(MIOBufferAccessor * anAccessor)
{
int i;
for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
if (!readers[i].allocated())
break;
// TODO refactor code to return NULL at some point
ink_release_assert(i < MAX_MIOBUFFER_READERS);
IOBufferReader *e = &readers[i];
e->mbuf = this;
e->reset();
e->accessor = anAccessor;
return e;
}
TS_INLINE IOBufferReader *
MIOBuffer::alloc_reader()
{
int i;
for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
if (!readers[i].allocated())
break;
// TODO refactor code to return NULL at some point
ink_release_assert(i < MAX_MIOBUFFER_READERS);
IOBufferReader *e = &readers[i];
e->mbuf = this;
e->reset();
e->accessor = NULL;
return e;
}
TS_INLINE int64_t
MIOBuffer::block_size()
{
return index_to_buffer_size(size_index);
}
TS_INLINE IOBufferReader *
MIOBuffer::clone_reader(IOBufferReader * r)
{
int i;
for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
if (!readers[i].allocated())
break;
// TODO refactor code to return NULL at some point
ink_release_assert(i < MAX_MIOBUFFER_READERS);
IOBufferReader *e = &readers[i];
e->mbuf = this;
e->accessor = NULL;
e->block = r->block;
e->start_offset = r->start_offset;
e->size_limit = r->size_limit;
ink_assert(e->size_limit >= 0);
return e;
}
TS_INLINE int64_t
MIOBuffer::block_write_avail()
{
IOBufferBlock *b = first_write_block();
return b ? b->write_avail() : 0;
}
////////////////////////////////////////////////////////////////
//
// MIOBuffer::append_block()
//
// Appends a block to writer->next and make it the current
// block.
// Note that the block is not appended to the end of the list.
// That means that if writer->next was not null before this
// call then the block that writer->next was pointing to will
// have its reference count decremented and writer->next
// will have a new value which is the new block.
// In any case the new appended block becomes the current
// block.
//
////////////////////////////////////////////////////////////////
TS_INLINE void
MIOBuffer::append_block_internal(IOBufferBlock * b)
{
// It would be nice to remove an empty buffer at the beginning,
// but this breaks HTTP.
// if (!_writer || !_writer->read_avail())
if (!_writer) {
_writer = b;
init_readers();
} else {
ink_assert(!_writer->next || !_writer->next->read_avail());
_writer->next = b;
while (b->read_avail()) {
_writer = b;
b = b->next;
if (!b)
break;
}
}
while (_writer->next && !_writer->write_avail() && _writer->next->read_avail())
_writer = _writer->next;
}
TS_INLINE void
MIOBuffer::append_block(IOBufferBlock * b)
{
ink_assert(b->read_avail());
append_block_internal(b);
}
////////////////////////////////////////////////////////////////
//
// MIOBuffer::append_block()
//
// Allocate a block, appends it to current->next
// and make the new block the current block (writer).
//
////////////////////////////////////////////////////////////////
TS_INLINE void
MIOBuffer::append_block(int64_t asize_index)
{
ink_assert(BUFFER_SIZE_ALLOCATED(asize_index));
#ifdef TRACK_BUFFER_USER
IOBufferBlock *b = new_IOBufferBlock_internal(_location);
#else
IOBufferBlock *b = new_IOBufferBlock_internal();
#endif
b->alloc(asize_index);
append_block_internal(b);
return;
}
TS_INLINE void
MIOBuffer::add_block()
{
append_block(size_index);
}
TS_INLINE void
MIOBuffer::check_add_block()
{
if (!high_water() && current_low_water())
add_block();
}
TS_INLINE IOBufferBlock *
MIOBuffer::get_current_block()
{
return first_write_block();
}
//////////////////////////////////////////////////////////////////
//
// MIOBuffer::current_write_avail()
//
// returns the total space available in all blocks.
// This function is different than write_avail() because
// it will not append a new block if there is no space
// or below the watermark space available.
//
//////////////////////////////////////////////////////////////////
TS_INLINE int64_t
MIOBuffer::current_write_avail()
{
int64_t t = 0;
IOBufferBlock *b = _writer;
while (b) {
t += b->write_avail();
b = b->next;
}
return t;
}
//////////////////////////////////////////////////////////////////
//
// MIOBuffer::write_avail()
//
// returns the number of bytes available in the current block.
// If there is no current block or not enough free space in
// the current block then a new block is appended.
//
//////////////////////////////////////////////////////////////////
TS_INLINE int64_t
MIOBuffer::write_avail()
{
check_add_block();
return current_write_avail();
}
TS_INLINE void
MIOBuffer::fill(int64_t len)
{
int64_t f = _writer->write_avail();
while (f < len) {
_writer->fill(f);
len -= f;
if (len > 0)
_writer = _writer->next;
f = _writer->write_avail();
}
_writer->fill(len);
}
TS_INLINE int
MIOBuffer::max_block_count()
{
int maxb = 0;
for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) {
if (readers[i].allocated()) {
int c = readers[i].block_count();
if (c > maxb) {
maxb = c;
}
}
}
return maxb;
}
TS_INLINE int64_t
MIOBuffer::max_read_avail()
{
int64_t s = 0;
int found = 0;
for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) {
if (readers[i].allocated()) {
int64_t ss = readers[i].read_avail();
if (ss > s) {
s = ss;
}
found = 1;
}
}
if (!found && _writer)
return _writer->read_avail();
return s;
}
TS_INLINE void
MIOBuffer::set(void *b, int64_t len)
{
#ifdef TRACK_BUFFER_USER
_writer = new_IOBufferBlock_internal(_location);
#else
_writer = new_IOBufferBlock_internal();
#endif
_writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(len));
init_readers();
}
TS_INLINE void
MIOBuffer::set_xmalloced(void *b, int64_t len)
{
#ifdef TRACK_BUFFER_USER
_writer = new_IOBufferBlock_internal(_location);
#else
_writer = new_IOBufferBlock_internal();
#endif
_writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len));
init_readers();
}
TS_INLINE void
MIOBuffer::append_xmalloced(void *b, int64_t len)
{
#ifdef TRACK_BUFFER_USER
IOBufferBlock *x = new_IOBufferBlock_internal(_location);
#else
IOBufferBlock *x = new_IOBufferBlock_internal();
#endif
x->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len));
append_block_internal(x);
}
TS_INLINE void
MIOBuffer::append_fast_allocated(void *b, int64_t len, int64_t fast_size_index)
{
#ifdef TRACK_BUFFER_USER
IOBufferBlock *x = new_IOBufferBlock_internal(_location);
#else
IOBufferBlock *x = new_IOBufferBlock_internal();
#endif
x->set_internal(b, len, fast_size_index);
append_block_internal(x);
}
TS_INLINE void
MIOBuffer::alloc(int64_t i)
{
#ifdef TRACK_BUFFER_USER
_writer = new_IOBufferBlock_internal(_location);
#else
_writer = new_IOBufferBlock_internal();
#endif
_writer->alloc(i);
size_index = i;
init_readers();
}
TS_INLINE void
MIOBuffer::alloc_xmalloc(int64_t buf_size)
{
char *b = (char *)ats_malloc(buf_size);
set_xmalloced(b, buf_size);
}
TS_INLINE void
MIOBuffer::dealloc_reader(IOBufferReader * e)
{
if (e->accessor) {
ink_assert(e->accessor->writer() == this);
ink_assert(e->accessor->reader() == e);
e->accessor->clear();
}
e->clear();
}
TS_INLINE IOBufferReader *
IOBufferReader::clone()
{
return mbuf->clone_reader(this);
}
TS_INLINE void
IOBufferReader::dealloc()
{
mbuf->dealloc_reader(this);
}
TS_INLINE void
MIOBuffer::dealloc_all_readers()
{
for (int i = 0; i < MAX_MIOBUFFER_READERS; i++)
if (readers[i].allocated())
dealloc_reader(&readers[i]);
}
TS_INLINE void
MIOBuffer::set_size_index(int64_t size)
{
size_index = iobuffer_size_to_index(size);
}
TS_INLINE void
MIOBufferAccessor::reader_for(MIOBuffer * abuf)
{
mbuf = abuf;
if (abuf)
entry = mbuf->alloc_accessor(this);
else
entry = NULL;
}
TS_INLINE void
MIOBufferAccessor::reader_for(IOBufferReader * areader)
{
if (entry == areader)
return;
mbuf = areader->mbuf;
entry = areader;
ink_assert(mbuf);
}
TS_INLINE void
MIOBufferAccessor::writer_for(MIOBuffer * abuf)
{
mbuf = abuf;
entry = NULL;
}
TS_INLINE
MIOBufferAccessor::~
MIOBufferAccessor()
{
}
#endif