3
A brief file description
5
@section license License
7
Licensed to the Apache Software Foundation (ASF) under one
8
or more contributor license agreements. See the NOTICE file
9
distributed with this work for additional information
10
regarding copyright ownership. The ASF licenses this file
11
to you under the Apache License, Version 2.0 (the
12
"License"); you may not use this file except in compliance
13
with the License. You may obtain a copy of the License at
15
http://www.apache.org/licenses/LICENSE-2.0
17
Unless required by applicable law or agreed to in writing, software
18
distributed under the License is distributed on an "AS IS" BASIS,
19
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
See the License for the specific language governing permissions and
21
limitations under the License.
26
#if !defined (_P_IOBuffer_h)
30
// TODO: I think we're overly aggressive here on making MIOBuffer 64-bit
31
// but not sure it's worthwhile changing anything to 32-bit honestly.
33
//////////////////////////////////////////////////////////////
35
// returns 0 for DEFAULT_BUFFER_BASE_SIZE,
36
// +1 for each power of 2
38
//////////////////////////////////////////////////////////////
40
buffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size)
44
while (r && BUFFER_SIZE_FOR_INDEX(r - 1) >= size)
50
iobuffer_size_to_index(int64_t size, int64_t max)
52
if (size > BUFFER_SIZE_FOR_INDEX(max))
53
return BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size);
54
return buffer_size_to_index(size, max);
58
index_to_buffer_size(int64_t idx)
60
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(idx))
61
return BUFFER_SIZE_FOR_INDEX(idx);
62
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(idx))
63
return BUFFER_SIZE_FOR_XMALLOC(idx);
64
// coverity[dead_error_condition]
65
else if (BUFFER_SIZE_INDEX_IS_CONSTANT(idx))
66
return BUFFER_SIZE_FOR_CONSTANT(idx);
67
// coverity[dead_error_line]
71
TS_INLINE IOBufferBlock *
72
iobufferblock_clone(IOBufferBlock * b, int64_t offset, int64_t len)
75
IOBufferBlock *start_buf = NULL;
76
IOBufferBlock *current_buf = NULL;
78
while (b && len >= 0) {
79
char *start = b->_start;
81
int64_t max_bytes = end - start;
89
if (bytes >= max_bytes)
91
IOBufferBlock *new_buf = b->clone();
92
new_buf->_start += offset;
93
new_buf->_buf_end = new_buf->_end = new_buf->_start + bytes;
96
current_buf = start_buf;
98
current_buf->next = new_buf;
99
current_buf = new_buf;
108
TS_INLINE IOBufferBlock *
109
iobufferblock_skip(IOBufferBlock * b, int64_t *poffset, int64_t *plen, int64_t write)
111
int64_t offset = *poffset;
113
while (b && len >= 0) {
114
int64_t max_bytes = b->read_avail();
116
if (max_bytes <= 0) {
121
if (len >= max_bytes) {
126
offset = offset + len;
135
#ifdef TRACK_BUFFER_USER
137
extern Resource *res_lookup(const char *path);
140
iobuffer_mem_inc(const char *_loc, int64_t _size_index)
142
if (!res_track_memory)
145
if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
149
_loc = "memory/IOBuffer/UNKNOWN-LOCATION";
150
Resource *res = res_lookup(_loc);
151
ink_debug_assert(strcmp(_loc, res->path) == 0);
153
int64_t r = ink_atomic_increment64(&res->value, index_to_buffer_size(_size_index));
154
ink_debug_assert(r >= 0);
156
ink_atomic_increment64(&res->value, index_to_buffer_size(_size_index));
161
iobuffer_mem_dec(const char *_loc, int64_t _size_index)
163
if (!res_track_memory)
166
if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
169
_loc = "memory/IOBuffer/UNKNOWN-LOCATION";
170
Resource *res = res_lookup(_loc);
171
ink_debug_assert(strcmp(_loc, res->path) == 0);
173
int64_t r = ink_atomic_increment64(&res->value, -index_to_buffer_size(_size_index));
174
ink_debug_assert(r >= index_to_buffer_size(_size_index));
176
ink_atomic_increment64(&res->value, -index_to_buffer_size(_size_index));
181
//////////////////////////////////////////////////////////////////
183
// inline functions definitions
185
//////////////////////////////////////////////////////////////////
186
//////////////////////////////////////////////////////////////////
188
// class IOBufferData --
189
// inline functions definitions
191
//////////////////////////////////////////////////////////////////
193
IOBufferData::block_size()
195
return index_to_buffer_size(_size_index);
198
TS_INLINE IOBufferData *
199
new_IOBufferData_internal(
200
#ifdef TRACK_BUFFER_USER
201
const char *location,
203
void *b, int64_t size, int64_t asize_index)
206
IOBufferData *d = ioDataAllocator.alloc();
207
d->_size_index = asize_index;
208
ink_assert(BUFFER_SIZE_INDEX_IS_CONSTANT(asize_index)
209
|| size <= d->block_size());
210
#ifdef TRACK_BUFFER_USER
211
d->_location = location;
213
d->_data = (char *) b;
217
TS_INLINE IOBufferData *
218
new_constant_IOBufferData_internal(
219
#ifdef TRACK_BUFFER_USER
222
void *b, int64_t size)
224
return new_IOBufferData_internal(
225
#ifdef TRACK_BUFFER_USER
228
b, size, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(size));
231
TS_INLINE IOBufferData *
232
new_xmalloc_IOBufferData_internal(
233
#ifdef TRACK_BUFFER_USER
234
const char *location,
236
void *b, int64_t size)
238
return new_IOBufferData_internal(
239
#ifdef TRACK_BUFFER_USER
242
b, size, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size));
245
TS_INLINE IOBufferData *
246
new_IOBufferData_internal(
247
#ifdef TRACK_BUFFER_USER
248
const char *location,
250
void *b, int64_t size)
252
return new_IOBufferData_internal(
253
#ifdef TRACK_BUFFER_USER
256
b, size, iobuffer_size_to_index(size));
259
TS_INLINE IOBufferData *
260
new_IOBufferData_internal(
261
#ifdef TRACK_BUFFER_USER
264
int64_t size_index, AllocType type)
266
IOBufferData *d = ioDataAllocator.alloc();
267
#ifdef TRACK_BUFFER_USER
270
d->alloc(size_index, type);
274
// IRIX has a compiler bug which prevents this function
275
// from being compiled correctly at -O3
276
// so it is DUPLICATED in IOBuffer.cc
277
// ****** IF YOU CHANGE THIS FUNCTION change that one as well.
279
IOBufferData::alloc(int64_t size_index, AllocType type)
283
_size_index = size_index;
285
#ifdef TRACK_BUFFER_USER
286
iobuffer_mem_inc(_location, size_index);
290
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index))
291
_data = (char *) ioBufAllocator[size_index].alloc_void();
292
// coverity[dead_error_condition]
293
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index))
294
// coverity[dead_error_line]
295
_data = (char *) valloc(index_to_buffer_size(size_index));
299
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index))
300
_data = (char *) ioBufAllocator[size_index].alloc_void();
301
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index))
302
_data = (char *) xmalloc(BUFFER_SIZE_FOR_XMALLOC(size_index));
307
// ****** IF YOU CHANGE THIS FUNCTION change that one as well.
311
IOBufferData::dealloc()
313
#ifdef TRACK_BUFFER_USER
314
iobuffer_mem_dec(_location, _size_index);
318
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
319
ioBufAllocator[_size_index].free_void(_data);
320
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index))
321
::free((void *) _data);
325
if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
326
ioBufAllocator[_size_index].free_void(_data);
327
else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index))
332
_size_index = BUFFER_SIZE_NOT_ALLOCATED;
333
_mem_type = NO_ALLOC;
340
ioDataAllocator.free(this);
343
//////////////////////////////////////////////////////////////////
345
// class IOBufferBlock --
346
// inline functions definitions
348
//////////////////////////////////////////////////////////////////
349
TS_INLINE IOBufferBlock *
350
new_IOBufferBlock_internal(
351
#ifdef TRACK_BUFFER_USER
356
IOBufferBlock *b = ioBlockAllocator.alloc();
357
#ifdef TRACK_BUFFER_USER
358
b->_location = location;
363
TS_INLINE IOBufferBlock *
364
new_IOBufferBlock_internal(
365
#ifdef TRACK_BUFFER_USER
366
const char *location,
368
IOBufferData * d, int64_t len, int64_t offset)
370
IOBufferBlock *b = ioBlockAllocator.alloc();
371
#ifdef TRACK_BUFFER_USER
372
b->_location = location;
374
b->set(d, len, offset);
379
IOBufferBlock::IOBufferBlock():
383
#ifdef TRACK_BUFFER_USER
392
IOBufferBlock::consume(int64_t len)
395
ink_assert(_start <= _end);
399
IOBufferBlock::fill(int64_t len)
402
ink_assert(_end <= _buf_end);
406
IOBufferBlock::reset()
408
_end = _start = buf();
409
_buf_end = buf() + data->block_size();
413
IOBufferBlock::alloc(int64_t i)
415
ink_debug_assert(BUFFER_SIZE_ALLOCATED(i));
416
#ifdef TRACK_BUFFER_USER
417
data = new_IOBufferData_internal(_location, i);
419
data = new_IOBufferData_internal(i);
425
IOBufferBlock::clear()
428
IOBufferBlock *p = next;
430
int r = p->refcount_dec();
434
IOBufferBlock *n = p->next.m_ptr;
435
p->next.m_ptr = NULL;
441
_buf_end = _end = _start = NULL;
444
TS_INLINE IOBufferBlock *
445
IOBufferBlock::clone()
447
#ifdef TRACK_BUFFER_USER
448
IOBufferBlock *b = new_IOBufferBlock_internal(_location);
450
IOBufferBlock *b = new_IOBufferBlock_internal();
456
#ifdef TRACK_BUFFER_USER
457
b->_location = _location;
463
IOBufferBlock::dealloc()
469
IOBufferBlock::free()
472
ioBlockAllocator.free(this);
476
IOBufferBlock::set_internal(void *b, int64_t len, int64_t asize_index)
478
#ifdef TRACK_BUFFER_USER
479
data = new_IOBufferData_internal(_location, BUFFER_SIZE_NOT_ALLOCATED);
481
data = new_IOBufferData_internal(BUFFER_SIZE_NOT_ALLOCATED);
483
data->_data = (char *) b;
484
#ifdef TRACK_BUFFER_USER
485
iobuffer_mem_inc(_location, asize_index);
487
data->_size_index = asize_index;
493
IOBufferBlock::set(IOBufferData * d, int64_t len, int64_t offset)
496
_start = buf() + offset;
498
_buf_end = _start + d->block_size();
502
IOBufferBlock::realloc_set_internal(void *b, int64_t buf_size, int64_t asize_index)
504
int64_t data_size = size();
505
memcpy(b, _start, size());
507
set_internal(b, buf_size, asize_index);
508
_end = _start + data_size;
512
IOBufferBlock::realloc(void *b, int64_t buf_size)
514
realloc_set_internal(b, buf_size, BUFFER_SIZE_NOT_ALLOCATED);
518
IOBufferBlock::realloc_xmalloc(void *b, int64_t buf_size)
520
realloc_set_internal(b, buf_size, -buf_size);
524
IOBufferBlock::realloc_xmalloc(int64_t buf_size)
526
realloc_set_internal(xmalloc(buf_size), buf_size, -buf_size);
530
IOBufferBlock::realloc(int64_t i)
532
if (i == data->_size_index)
534
if (i >= (int64_t) sizeof(ioBufAllocator))
537
ink_release_assert(i > data->_size_index && i != BUFFER_SIZE_NOT_ALLOCATED);
538
void *b = ioBufAllocator[i].alloc_void();
539
realloc_set_internal(b, BUFFER_SIZE_FOR_INDEX(i), i);
542
//////////////////////////////////////////////////////////////////
544
// class IOBufferReader --
545
// inline functions definitions
547
//////////////////////////////////////////////////////////////////
549
IOBufferReader::skip_empty_blocks()
551
while (block->next && block->next->read_avail() && start_offset >= block->size()) {
552
start_offset -= block->size();
558
IOBufferReader::low_water()
560
return mbuf->low_water();
564
IOBufferReader::high_water()
566
return read_avail() >= mbuf->water_mark;
570
IOBufferReader::current_low_water()
572
return mbuf->current_low_water();
575
TS_INLINE IOBufferBlock *
576
IOBufferReader::get_current_block()
582
IOBufferReader::start()
587
return block->start() + start_offset;
591
IOBufferReader::end()
600
IOBufferReader::block_read_avail()
605
return (int64_t) (block->end() - (block->start() + start_offset));
609
IOBufferReader::block_count()
612
IOBufferBlock *b = block;
622
IOBufferReader::read_avail()
625
IOBufferBlock *b = block;
628
t += b->read_avail();
632
if (size_limit != INT64_MAX && t > size_limit)
638
IOBufferReader::consume(int64_t n)
641
if (size_limit != INT64_MAX)
643
ink_assert(size_limit >= 0);
646
int64_t r = block->read_avail();
647
int64_t s = start_offset;
648
while (r <= s && block->next && block->next->read_avail()) {
652
r = block->read_avail();
654
ink_debug_assert(read_avail() >= 0);
658
IOBufferReader::operator[] (int64_t i)
667
int64_t bytes = b->read_avail();
669
return b->start()[i];
674
ink_assert(!"out of range");
682
IOBufferReader::clear()
688
size_limit = INT64_MAX;
692
IOBufferReader::reset()
694
block = mbuf->_writer;
696
size_limit = INT64_MAX;
699
////////////////////////////////////////////////////////////////
701
// class MIOBuffer --
702
// inline functions definitions
704
////////////////////////////////////////////////////////////////
705
inkcoreapi extern ClassAllocator<MIOBuffer> ioAllocator;
706
////////////////////////////////////////////////////////////////
708
// MIOBuffer::MIOBuffer()
710
// This constructor accepts a pre-allocated memory buffer,
711
// wraps if in a IOBufferData and IOBufferBlock structures
712
// and sets it as the current block.
713
// NOTE that in this case the memory buffer will not be freed
714
// by the MIOBuffer class. It is the user responsibility to
715
// free the memory buffer. The wrappers (MIOBufferBlock and
716
// MIOBufferData) will be freed by this class.
718
////////////////////////////////////////////////////////////////
720
MIOBuffer::MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark)
723
water_mark = aWater_mark;
724
size_index = BUFFER_SIZE_NOT_ALLOCATED;
725
#ifdef TRACK_BUFFER_USER
732
MIOBuffer::MIOBuffer(int64_t default_size_index)
735
size_index = default_size_index;
736
#ifdef TRACK_BUFFER_USER
743
MIOBuffer::MIOBuffer()
746
#ifdef TRACK_BUFFER_USER
757
dealloc_all_readers();
760
TS_INLINE MIOBuffer * new_MIOBuffer_internal(
761
#ifdef TRACK_BUFFER_USER
762
const char *location,
766
MIOBuffer *b = ioAllocator.alloc();
767
#ifdef TRACK_BUFFER_USER
768
b->_location = location;
770
b->alloc(size_index);
775
free_MIOBuffer(MIOBuffer * mio)
778
mio->dealloc_all_readers();
779
ioAllocator.free(mio);
782
TS_INLINE MIOBuffer * new_empty_MIOBuffer_internal(
783
#ifdef TRACK_BUFFER_USER
784
const char *location,
788
MIOBuffer *b = ioAllocator.alloc();
789
b->size_index = size_index;
790
#ifdef TRACK_BUFFER_USER
791
b->_location = location;
797
free_empty_MIOBuffer(MIOBuffer * mio)
799
ioAllocator.free(mio);
802
TS_INLINE IOBufferReader *
803
MIOBuffer::alloc_accessor(MIOBufferAccessor * anAccessor)
806
for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
807
if (!readers[i].allocated())
810
// TODO refactor code to return NULL at some point
811
ink_release_assert(i < MAX_MIOBUFFER_READERS);
813
IOBufferReader *e = &readers[i];
816
e->accessor = anAccessor;
821
TS_INLINE IOBufferReader *
822
MIOBuffer::alloc_reader()
825
for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
826
if (!readers[i].allocated())
829
// TODO refactor code to return NULL at some point
830
ink_release_assert(i < MAX_MIOBUFFER_READERS);
832
IOBufferReader *e = &readers[i];
841
MIOBuffer::block_size()
843
return index_to_buffer_size(size_index);
845
TS_INLINE IOBufferReader *
846
MIOBuffer::clone_reader(IOBufferReader * r)
849
for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
850
if (!readers[i].allocated())
853
// TODO refactor code to return NULL at some point
854
ink_release_assert(i < MAX_MIOBUFFER_READERS);
856
IOBufferReader *e = &readers[i];
860
e->start_offset = r->start_offset;
861
e->size_limit = r->size_limit;
862
ink_assert(e->size_limit >= 0);
868
MIOBuffer::block_write_avail()
870
IOBufferBlock *b = first_write_block();
871
return b ? b->write_avail() : 0;
874
////////////////////////////////////////////////////////////////
876
// MIOBuffer::append_block()
878
// Appends a block to writer->next and make it the current
880
// Note that the block is not appended to the end of the list.
881
// That means that if writer->next was not null before this
882
// call then the block that writer->next was pointing to will
883
// have its reference count decremented and writer->next
884
// will have a new value which is the new block.
885
// In any case the new appended block becomes the current
888
////////////////////////////////////////////////////////////////
890
MIOBuffer::append_block_internal(IOBufferBlock * b)
892
// It would be nice to remove an empty buffer at the beginning,
893
// but this breaks HTTP.
894
// if (!_writer || !_writer->read_avail())
899
ink_assert(!_writer->next || !_writer->next->read_avail());
901
while (b->read_avail()) {
908
while (_writer->next && !_writer->write_avail() && _writer->next->read_avail())
909
_writer = _writer->next;
913
MIOBuffer::append_block(IOBufferBlock * b)
915
ink_assert(b->read_avail());
916
append_block_internal(b);
919
////////////////////////////////////////////////////////////////
921
// MIOBuffer::append_block()
923
// Allocate a block, appends it to current->next
924
// and make the new block the current block (writer).
926
////////////////////////////////////////////////////////////////
928
MIOBuffer::append_block(int64_t asize_index)
930
ink_debug_assert(BUFFER_SIZE_ALLOCATED(asize_index));
931
#ifdef TRACK_BUFFER_USER
932
IOBufferBlock *b = new_IOBufferBlock_internal(_location);
934
IOBufferBlock *b = new_IOBufferBlock_internal();
936
b->alloc(asize_index);
937
append_block_internal(b);
942
MIOBuffer::add_block()
944
append_block(size_index);
948
MIOBuffer::check_add_block()
950
if (!high_water() && current_low_water())
954
TS_INLINE IOBufferBlock *
955
MIOBuffer::get_current_block()
957
return first_write_block();
960
//////////////////////////////////////////////////////////////////
962
// MIOBuffer::current_write_avail()
964
// returns the total space available in all blocks.
965
// This function is different than write_avail() because
966
// it will not append a new block if there is no space
967
// or below the watermark space available.
969
//////////////////////////////////////////////////////////////////
971
MIOBuffer::current_write_avail()
974
IOBufferBlock *b = _writer;
976
t += b->write_avail();
982
//////////////////////////////////////////////////////////////////
984
// MIOBuffer::write_avail()
986
// returns the number of bytes available in the current block.
987
// If there is no current block or not enough free space in
988
// the current block then a new block is appended.
990
//////////////////////////////////////////////////////////////////
992
MIOBuffer::write_avail()
995
return current_write_avail();
999
MIOBuffer::fill(int64_t len)
1001
int64_t f = _writer->write_avail();
1006
_writer = _writer->next;
1007
f = _writer->write_avail();
1013
MIOBuffer::max_block_count()
1016
for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) {
1017
if (readers[i].allocated()) {
1018
int c = readers[i].block_count();
1028
MIOBuffer::max_read_avail()
1032
for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) {
1033
if (readers[i].allocated()) {
1034
int64_t ss = readers[i].read_avail();
1041
if (!found && _writer)
1042
return _writer->read_avail();
1047
MIOBuffer::set(void *b, int64_t len)
1049
#ifdef TRACK_BUFFER_USER
1050
_writer = new_IOBufferBlock_internal(_location);
1052
_writer = new_IOBufferBlock_internal();
1054
_writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(len));
1059
MIOBuffer::set_xmalloced(void *b, int64_t len)
1061
#ifdef TRACK_BUFFER_USER
1062
_writer = new_IOBufferBlock_internal(_location);
1064
_writer = new_IOBufferBlock_internal();
1066
_writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len));
1071
MIOBuffer::append_xmalloced(void *b, int64_t len)
1073
#ifdef TRACK_BUFFER_USER
1074
IOBufferBlock *x = new_IOBufferBlock_internal(_location);
1076
IOBufferBlock *x = new_IOBufferBlock_internal();
1078
x->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len));
1079
append_block_internal(x);
1083
MIOBuffer::append_fast_allocated(void *b, int64_t len, int64_t fast_size_index)
1085
#ifdef TRACK_BUFFER_USER
1086
IOBufferBlock *x = new_IOBufferBlock_internal(_location);
1088
IOBufferBlock *x = new_IOBufferBlock_internal();
1090
x->set_internal(b, len, fast_size_index);
1091
append_block_internal(x);
1095
MIOBuffer::alloc(int64_t i)
1097
#ifdef TRACK_BUFFER_USER
1098
_writer = new_IOBufferBlock_internal(_location);
1100
_writer = new_IOBufferBlock_internal();
1108
MIOBuffer::alloc_xmalloc(int64_t buf_size)
1110
char *b = (char *) xmalloc(buf_size);
1111
set_xmalloced(b, buf_size);
1115
MIOBuffer::dealloc_reader(IOBufferReader * e)
1118
ink_assert(e->accessor->mbuf == this);
1119
ink_assert(e->accessor->entry == e);
1120
e->accessor->reset();
1125
TS_INLINE IOBufferReader *
1126
IOBufferReader::clone()
1128
return mbuf->clone_reader(this);
1132
IOBufferReader::dealloc()
1134
mbuf->dealloc_reader(this);
1138
MIOBuffer::dealloc_all_readers()
1140
for (int i = 0; i < MAX_MIOBUFFER_READERS; i++)
1141
if (readers[i].allocated())
1142
dealloc_reader(&readers[i]);
1146
MIOBuffer::set_size_index(int64_t size)
1148
size_index = iobuffer_size_to_index(size);
1152
MIOBufferAccessor::reader_for(MIOBuffer * abuf)
1156
entry = mbuf->alloc_accessor(this);
1162
MIOBufferAccessor::reader_for(IOBufferReader * areader)
1164
if (entry == areader)
1166
mbuf = areader->mbuf;
1172
MIOBufferAccessor::writer_for(MIOBuffer * abuf)
1179
MIOBufferAccessor::clear()
1186
MIOBufferAccessor::~