1 /** @file
2
3 A brief file description
4
5 @section license License
6
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
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
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.
22 */
23
24 /**************************************************************************
25 UIOBuffer.cc
26
27 **************************************************************************/
28 #include "tscore/ink_defs.h"
29 #include "P_EventSystem.h"
30
31 //
32 // General Buffer Allocator
33 //
34 inkcoreapi Allocator ioBufAllocator[DEFAULT_BUFFER_SIZES];
35 inkcoreapi ClassAllocator<MIOBuffer> ioAllocator("ioAllocator", DEFAULT_BUFFER_NUMBER);
36 inkcoreapi ClassAllocator<IOBufferData> ioDataAllocator("ioDataAllocator", DEFAULT_BUFFER_NUMBER);
37 inkcoreapi ClassAllocator<IOBufferBlock> ioBlockAllocator("ioBlockAllocator", DEFAULT_BUFFER_NUMBER);
38 int64_t default_large_iobuffer_size = DEFAULT_LARGE_BUFFER_SIZE;
39 int64_t default_small_iobuffer_size = DEFAULT_SMALL_BUFFER_SIZE;
40 int64_t max_iobuffer_size = DEFAULT_BUFFER_SIZES - 1;
41
42 //
43 // Initialization
44 //
45 void
init_buffer_allocators(int iobuffer_advice)46 init_buffer_allocators(int iobuffer_advice)
47 {
48 for (int i = 0; i < DEFAULT_BUFFER_SIZES; i++) {
49 int64_t s = DEFAULT_BUFFER_BASE_SIZE * ((static_cast<int64_t>(1)) << i);
50 int64_t a = DEFAULT_BUFFER_ALIGNMENT;
51 int n = i <= default_large_iobuffer_size ? DEFAULT_BUFFER_NUMBER : DEFAULT_HUGE_BUFFER_NUMBER;
52 if (s < a) {
53 a = s;
54 }
55
56 auto name = new char[64];
57 snprintf(name, 64, "ioBufAllocator[%d]", i);
58 ioBufAllocator[i].re_init(name, s, n, a, iobuffer_advice);
59 }
60 }
61
62 //
63 // MIOBuffer
64 //
65 int64_t
write(const void * abuf,int64_t alen)66 MIOBuffer::write(const void *abuf, int64_t alen)
67 {
68 const char *buf = static_cast<const char *>(abuf);
69 int64_t len = alen;
70 while (len) {
71 if (!_writer) {
72 add_block();
73 }
74 int64_t f = _writer->write_avail();
75 f = f < len ? f : len;
76 if (f > 0) {
77 ::memcpy(_writer->end(), buf, f);
78 _writer->fill(f);
79 buf += f;
80 len -= f;
81 }
82 if (len) {
83 if (!_writer->next) {
84 add_block();
85 } else {
86 _writer = _writer->next;
87 }
88 }
89 }
90 return alen;
91 }
92
93 int64_t
write(IOBufferReader * r,int64_t len,int64_t offset)94 MIOBuffer::write(IOBufferReader *r, int64_t len, int64_t offset)
95 {
96 return this->write(r->block.get(), len, offset + r->start_offset);
97 }
98
99 int64_t
write(IOBufferChain const * chain,int64_t len,int64_t offset)100 MIOBuffer::write(IOBufferChain const *chain, int64_t len, int64_t offset)
101 {
102 return this->write(chain->head(), std::min(len, chain->length()), offset);
103 }
104
105 int64_t
write(IOBufferBlock const * b,int64_t alen,int64_t offset)106 MIOBuffer::write(IOBufferBlock const *b, int64_t alen, int64_t offset)
107 {
108 int64_t len = alen;
109
110 while (b && len > 0) {
111 int64_t max_bytes = b->read_avail();
112 max_bytes -= offset;
113 if (max_bytes <= 0) {
114 offset = -max_bytes;
115 b = b->next.get();
116 continue;
117 }
118 int64_t bytes;
119 if (len >= max_bytes) {
120 bytes = max_bytes;
121 } else {
122 bytes = len;
123 }
124 IOBufferBlock *bb = b->clone();
125 bb->_start += offset;
126 bb->_buf_end = bb->_end = bb->_start + bytes;
127 append_block(bb);
128 offset = 0;
129 len -= bytes;
130 b = b->next.get();
131 }
132
133 return alen - len;
134 }
135
136 bool
is_max_read_avail_more_than(int64_t size)137 MIOBuffer::is_max_read_avail_more_than(int64_t size)
138 {
139 bool no_reader = true;
140 for (auto &reader : this->readers) {
141 if (reader.allocated()) {
142 if (reader.is_read_avail_more_than(size)) {
143 return true;
144 }
145 no_reader = false;
146 }
147 }
148
149 if (no_reader && this->_writer) {
150 return (this->_writer->read_avail() > size);
151 }
152
153 return false;
154 }
155
156 //
157 // IOBufferReader
158 //
159 int64_t
read(void * ab,int64_t len)160 IOBufferReader::read(void *ab, int64_t len)
161 {
162 char *b = static_cast<char *>(ab);
163 int64_t n = len;
164 int64_t l = block_read_avail();
165 int64_t bytes = 0;
166
167 while (n && l) {
168 if (n < l) {
169 l = n;
170 }
171 ::memcpy(b, start(), l);
172 consume(l);
173 b += l;
174 n -= l;
175 bytes += l;
176 l = block_read_avail();
177 }
178 return bytes;
179 }
180
181 // TODO: I don't think this method is used anywhere, so perhaps get rid of it ?
182 int64_t
memchr(char c,int64_t len,int64_t offset)183 IOBufferReader::memchr(char c, int64_t len, int64_t offset)
184 {
185 IOBufferBlock *b = block.get();
186 offset += start_offset;
187 int64_t o = offset;
188
189 while (b && len) {
190 int64_t max_bytes = b->read_avail();
191 max_bytes -= offset;
192 if (max_bytes <= 0) {
193 offset = -max_bytes;
194 b = b->next.get();
195 continue;
196 }
197 int64_t bytes;
198 if (len < 0 || len >= max_bytes) {
199 bytes = max_bytes;
200 } else {
201 bytes = len;
202 }
203 char *s = b->start() + offset;
204 char *p = static_cast<char *>(::memchr(s, c, bytes));
205 if (p) {
206 return static_cast<int64_t>(o - start_offset + p - s);
207 }
208 o += bytes;
209 len -= bytes;
210 b = b->next.get();
211 offset = 0;
212 }
213
214 return -1;
215 }
216
217 char *
memcpy(void * ap,int64_t len,int64_t offset)218 IOBufferReader::memcpy(void *ap, int64_t len, int64_t offset)
219 {
220 char *p = static_cast<char *>(ap);
221 IOBufferBlock *b = block.get();
222 offset += start_offset;
223
224 while (b && len) {
225 int64_t max_bytes = b->read_avail();
226 max_bytes -= offset;
227 if (max_bytes <= 0) {
228 offset = -max_bytes;
229 b = b->next.get();
230 continue;
231 }
232 int64_t bytes;
233 if (len < 0 || len >= max_bytes) {
234 bytes = max_bytes;
235 } else {
236 bytes = len;
237 }
238 ::memcpy(p, b->start() + offset, bytes);
239 p += bytes;
240 len -= bytes;
241 b = b->next.get();
242 offset = 0;
243 }
244
245 return p;
246 }
247
248 //
249 // IOBufferChain
250 //
251 int64_t
write(IOBufferBlock * blocks,int64_t length,int64_t offset)252 IOBufferChain::write(IOBufferBlock *blocks, int64_t length, int64_t offset)
253 {
254 int64_t n = length;
255
256 while (blocks && n > 0) {
257 int64_t block_bytes = blocks->read_avail();
258 if (block_bytes <= offset) { // skip the entire block
259 offset -= block_bytes;
260 } else {
261 int64_t bytes = std::min(n, block_bytes - offset);
262 IOBufferBlock *bb = blocks->clone();
263 if (offset) {
264 bb->consume(offset);
265 block_bytes -= offset; // bytes really available to use.
266 offset = 0;
267 }
268 if (block_bytes > n) {
269 bb->_end -= (block_bytes - n);
270 }
271 // Attach the cloned block since its data will be kept.
272 this->append(bb);
273 n -= bytes;
274 }
275 blocks = blocks->next.get();
276 }
277
278 length -= n; // actual bytes written to chain.
279 _len += length;
280 return length;
281 }
282
283 int64_t
write(IOBufferData * data,int64_t length,int64_t offset)284 IOBufferChain::write(IOBufferData *data, int64_t length, int64_t offset)
285 {
286 int64_t zret = 0;
287 IOBufferBlock *b = new_IOBufferBlock();
288
289 if (length < 0) {
290 length = 0;
291 }
292
293 b->set(data, length, offset);
294 this->append(b);
295
296 zret = b->read_avail();
297 _len += zret;
298 return zret;
299 }
300
301 void
append(IOBufferBlock * block)302 IOBufferChain::append(IOBufferBlock *block)
303 {
304 if (nullptr == _tail) {
305 _head = block;
306 _tail = block;
307 } else {
308 _tail->next = block;
309 _tail = block;
310 }
311 }
312
313 int64_t
consume(int64_t size)314 IOBufferChain::consume(int64_t size)
315 {
316 int64_t zret = 0;
317 int64_t bytes;
318 size = std::min(size, _len);
319
320 while (_head != nullptr && size > 0 && (bytes = _head->read_avail()) > 0) {
321 if (size >= bytes) {
322 _head = _head->next;
323 zret += bytes;
324 size -= bytes;
325 } else {
326 _head->consume(size);
327 zret += size;
328 size = 0;
329 }
330 }
331 _len -= zret;
332 if (_head == nullptr || _len == 0) {
333 _head = nullptr, _tail = nullptr, _len = 0;
334 }
335 return zret;
336 }
337