/src/brpc/src/butil/iobuf_inl.h
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | // iobuf - A non-continuous zero-copied buffer |
19 | | |
20 | | // Date: Thu Nov 22 13:57:56 CST 2012 |
21 | | |
22 | | // Inlined implementations of some methods defined in iobuf.h |
23 | | |
24 | | #ifndef BUTIL_IOBUF_INL_H |
25 | | #define BUTIL_IOBUF_INL_H |
26 | | |
27 | | #include "butil/atomicops.h" // butil::atomic |
28 | | #include "butil/thread_local.h" // thread_atexit |
29 | | #include "butil/logging.h" // CHECK, LOG |
30 | | |
31 | | void* fast_memcpy(void *__restrict dest, const void *__restrict src, size_t n); |
32 | | |
33 | | namespace butil { |
34 | | |
35 | | using UserDataDeleter = std::function<void(void*)>; |
36 | | |
37 | | struct UserDataExtension { |
38 | | UserDataDeleter deleter; |
39 | | }; |
40 | | |
41 | | bool IsIOBufProfilerSamplable(); |
42 | | void SubmitIOBufSample(IOBuf::Block* block, int64_t ref); |
43 | | |
44 | | const uint16_t IOBUF_BLOCK_FLAGS_USER_DATA = 1 << 0; |
45 | | const uint16_t IOBUF_BLOCK_FLAGS_SAMPLED = 1 << 1; |
46 | | |
47 | 0 | inline ssize_t IOBuf::cut_into_file_descriptor(int fd, size_t size_hint) { |
48 | 0 | return pcut_into_file_descriptor(fd, -1, size_hint); |
49 | 0 | } |
50 | | |
51 | | inline ssize_t IOBuf::cut_multiple_into_file_descriptor( |
52 | 0 | int fd, IOBuf* const* pieces, size_t count) { |
53 | 0 | return pcut_multiple_into_file_descriptor(fd, -1, pieces, count); |
54 | 0 | } |
55 | | |
56 | 0 | inline int IOBuf::append_user_data(void* data, size_t size, std::function<void(void*)> deleter) { |
57 | 0 | return append_user_data_with_meta(data, size, std::move(deleter), 0); |
58 | 0 | } |
59 | | |
60 | 0 | inline ssize_t IOPortal::append_from_file_descriptor(int fd, size_t max_count) { |
61 | 0 | return pappend_from_file_descriptor(fd, -1, max_count); |
62 | 0 | } |
63 | | |
64 | 0 | inline void IOPortal::return_cached_blocks() { |
65 | 0 | if (_block) { |
66 | 0 | return_cached_blocks_impl(_block); |
67 | 0 | _block = NULL; |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | 2.06k | inline void reset_block_ref(IOBuf::BlockRef& ref) { |
72 | 2.06k | ref.offset = 0; |
73 | 2.06k | ref.length = 0; |
74 | 2.06k | ref.block = NULL; |
75 | 2.06k | } |
76 | | |
77 | 685 | inline IOBuf::IOBuf() { |
78 | 685 | reset_block_ref(_sv.refs[0]); |
79 | 685 | reset_block_ref(_sv.refs[1]); |
80 | 685 | } |
81 | | |
82 | | inline IOBuf::IOBuf(const Movable& rhs) { |
83 | | _sv = rhs.value()._sv; |
84 | | new (&rhs.value()) IOBuf; |
85 | | } |
86 | | |
87 | 0 | inline void IOBuf::operator=(const Movable& rhs) { |
88 | 0 | clear(); |
89 | 0 | _sv = rhs.value()._sv; |
90 | 0 | new (&rhs.value()) IOBuf; |
91 | 0 | } |
92 | | |
93 | 0 | inline void IOBuf::operator=(const char* s) { |
94 | 0 | clear(); |
95 | 0 | append(s); |
96 | 0 | } |
97 | | |
98 | 0 | inline void IOBuf::operator=(const std::string& s) { |
99 | 0 | clear(); |
100 | 0 | append(s); |
101 | 0 | } |
102 | | |
103 | 0 | inline void IOBuf::swap(IOBuf& other) { |
104 | 0 | const SmallView tmp = other._sv; |
105 | 0 | other._sv = _sv; |
106 | 0 | _sv = tmp; |
107 | 0 | } |
108 | | |
109 | 0 | inline int IOBuf::cut_until(IOBuf* out, char const* delim) { |
110 | 0 | if (*delim) { |
111 | 0 | if (!*(delim+1)) { |
112 | 0 | return _cut_by_char(out, *delim); |
113 | 0 | } else { |
114 | 0 | return _cut_by_delim(out, delim, strlen(delim)); |
115 | 0 | } |
116 | 0 | } |
117 | 0 | return -1; |
118 | 0 | } |
119 | | |
120 | 0 | inline int IOBuf::cut_until(IOBuf* out, const std::string& delim) { |
121 | 0 | if (delim.length() == 1UL) { |
122 | 0 | return _cut_by_char(out, delim[0]); |
123 | 0 | } else if (delim.length() > 1UL) { |
124 | 0 | return _cut_by_delim(out, delim.data(), delim.length()); |
125 | 0 | } else { |
126 | 0 | return -1; |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | 685 | inline int IOBuf::append(const std::string& s) { |
131 | 685 | return append(s.data(), s.length()); |
132 | 685 | } |
133 | | |
134 | 0 | inline std::string IOBuf::to_string() const { |
135 | 0 | std::string s; |
136 | 0 | copy_to(&s); |
137 | 0 | return s; |
138 | 0 | } |
139 | | |
140 | 0 | inline bool IOBuf::empty() const { |
141 | 0 | return _small() ? !_sv.refs[0].block : !_bv.nbytes; |
142 | 0 | } |
143 | | |
144 | 972 | inline size_t IOBuf::length() const { |
145 | 972 | return _small() ? |
146 | 972 | (_sv.refs[0].length + _sv.refs[1].length) : _bv.nbytes; |
147 | 972 | } |
148 | | |
149 | 4.23k | inline bool IOBuf::_small() const { |
150 | 4.23k | return _bv.magic >= 0; |
151 | 4.23k | } |
152 | | |
153 | 692 | inline size_t IOBuf::_ref_num() const { |
154 | 692 | return _small() |
155 | 692 | ? (!!_sv.refs[0].block + !!_sv.refs[1].block) : _bv.nref; |
156 | 692 | } |
157 | | |
158 | 208 | inline IOBuf::BlockRef& IOBuf::_front_ref() { |
159 | 208 | return _small() ? _sv.refs[0] : _bv.refs[_bv.start]; |
160 | 208 | } |
161 | | |
162 | 0 | inline const IOBuf::BlockRef& IOBuf::_front_ref() const { |
163 | 0 | return _small() ? _sv.refs[0] : _bv.refs[_bv.start]; |
164 | 0 | } |
165 | | |
166 | 0 | inline IOBuf::BlockRef& IOBuf::_back_ref() { |
167 | 0 | return _small() ? _sv.refs[!!_sv.refs[1].block] : _bv.ref_at(_bv.nref - 1); |
168 | 0 | } |
169 | | |
170 | 0 | inline const IOBuf::BlockRef& IOBuf::_back_ref() const { |
171 | 0 | return _small() ? _sv.refs[!!_sv.refs[1].block] : _bv.ref_at(_bv.nref - 1); |
172 | 0 | } |
173 | | |
174 | 0 | inline IOBuf::BlockRef& IOBuf::_ref_at(size_t i) { |
175 | 0 | return _small() ? _sv.refs[i] : _bv.ref_at(i); |
176 | 0 | } |
177 | | |
178 | 692 | inline const IOBuf::BlockRef& IOBuf::_ref_at(size_t i) const { |
179 | 692 | return _small() ? _sv.refs[i] : _bv.ref_at(i); |
180 | 692 | } |
181 | | |
182 | 0 | inline const IOBuf::BlockRef* IOBuf::_pref_at(size_t i) const { |
183 | 0 | if (_small()) { |
184 | 0 | return i < (size_t)(!!_sv.refs[0].block + !!_sv.refs[1].block) ? &_sv.refs[i] : NULL; |
185 | 0 | } else { |
186 | 0 | return i < _bv.nref ? &_bv.ref_at(i) : NULL; |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | 0 | inline bool operator==(const IOBuf::BlockRef& r1, const IOBuf::BlockRef& r2) { |
191 | 0 | return r1.offset == r2.offset && r1.length == r2.length && |
192 | 0 | r1.block == r2.block; |
193 | 0 | } |
194 | | |
195 | 0 | inline bool operator!=(const IOBuf::BlockRef& r1, const IOBuf::BlockRef& r2) { |
196 | 0 | return !(r1 == r2); |
197 | 0 | } |
198 | | |
199 | 693 | inline void IOBuf::_push_back_ref(const BlockRef& r) { |
200 | 693 | if (_small()) { |
201 | 693 | return _push_or_move_back_ref_to_smallview<false>(r); |
202 | 693 | } else { |
203 | 0 | return _push_or_move_back_ref_to_bigview<false>(r); |
204 | 0 | } |
205 | 693 | } |
206 | | |
207 | 0 | inline void IOBuf::_move_back_ref(const BlockRef& r) { |
208 | 0 | if (_small()) { |
209 | 0 | return _push_or_move_back_ref_to_smallview<true>(r); |
210 | 0 | } else { |
211 | 0 | return _push_or_move_back_ref_to_bigview<true>(r); |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | | //////////////// IOBufCutter //////////////// |
216 | 0 | inline size_t IOBufCutter::remaining_bytes() const { |
217 | 0 | if (_block) { |
218 | 0 | return (char*)_data_end - (char*)_data + _buf->size() - _buf->_front_ref().length; |
219 | 0 | } else { |
220 | 0 | return _buf->size(); |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | 0 | inline bool IOBufCutter::cut1(void* c) { |
225 | 0 | if (_data == _data_end) { |
226 | 0 | if (!load_next_ref()) { |
227 | 0 | return false; |
228 | 0 | } |
229 | 0 | } |
230 | 0 | *(char*)c = *(const char*)_data; |
231 | 0 | _data = (char*)_data + 1; |
232 | 0 | return true; |
233 | 0 | } |
234 | | |
235 | 0 | inline const void* IOBufCutter::fetch1() { |
236 | 0 | if (_data == _data_end) { |
237 | 0 | if (!load_next_ref()) { |
238 | 0 | return NULL; |
239 | 0 | } |
240 | 0 | } |
241 | 0 | return _data; |
242 | 0 | } |
243 | | |
244 | 0 | inline size_t IOBufCutter::copy_to(void* out, size_t n) { |
245 | 0 | size_t size = (char*)_data_end - (char*)_data; |
246 | 0 | if (n <= size) { |
247 | 0 | memcpy(out, _data, n); |
248 | 0 | return n; |
249 | 0 | } |
250 | 0 | return slower_copy_to(out, n); |
251 | 0 | } |
252 | | |
253 | 0 | inline size_t IOBufCutter::pop_front(size_t n) { |
254 | 0 | const size_t saved_n = n; |
255 | 0 | do { |
256 | 0 | const size_t size = (char*)_data_end - (char*)_data; |
257 | 0 | if (n <= size) { |
258 | 0 | _data = (char*)_data + n; |
259 | 0 | return saved_n; |
260 | 0 | } |
261 | 0 | n -= size; |
262 | 0 | if (!load_next_ref()) { |
263 | 0 | return saved_n - n; |
264 | 0 | } |
265 | 0 | } while (true); |
266 | 0 | } |
267 | | |
268 | 0 | inline size_t IOBufCutter::cutn(std::string* out, size_t n) { |
269 | 0 | if (n == 0) { |
270 | 0 | return 0; |
271 | 0 | } |
272 | 0 | const size_t len = remaining_bytes(); |
273 | 0 | if (n > len) { |
274 | 0 | n = len; |
275 | 0 | } |
276 | 0 | const size_t old_size = out->size(); |
277 | 0 | out->resize(out->size() + n); |
278 | 0 | return cutn(&(*out)[old_size], n); |
279 | 0 | } |
280 | | |
281 | | /////////////// IOBufAppender ///////////////// |
282 | 0 | inline int IOBufAppender::append(const void* src, size_t n) { |
283 | 0 | do { |
284 | 0 | const size_t size = (char*)_data_end - (char*)_data; |
285 | 0 | if (n <= size) { |
286 | 0 | memcpy(_data, src, n); |
287 | 0 | _data = (char*)_data + n; |
288 | 0 | return 0; |
289 | 0 | } |
290 | 0 | if (size != 0) { |
291 | 0 | memcpy(_data, src, size); |
292 | 0 | src = (const char*)src + size; |
293 | 0 | n -= size; |
294 | 0 | } |
295 | 0 | if (add_block() != 0) { |
296 | 0 | return -1; |
297 | 0 | } |
298 | 0 | } while (true); |
299 | 0 | } |
300 | | |
301 | 0 | inline int IOBufAppender::append(const StringPiece& str) { |
302 | 0 | return append(str.data(), str.size()); |
303 | 0 | } |
304 | | |
305 | 0 | inline int IOBufAppender::append_decimal(long d) { |
306 | 0 | char buf[24]; // enough for decimal 64-bit integers |
307 | 0 | size_t n = sizeof(buf); |
308 | 0 | bool negative = false; |
309 | 0 | if (d < 0) { |
310 | 0 | negative = true; |
311 | 0 | d = -d; |
312 | 0 | } |
313 | 0 | do { |
314 | 0 | const long q = d / 10; |
315 | 0 | buf[--n] = d - q * 10 + '0'; |
316 | 0 | d = q; |
317 | 0 | } while (d); |
318 | 0 | if (negative) { |
319 | 0 | buf[--n] = '-'; |
320 | 0 | } |
321 | 0 | return append(buf + n, sizeof(buf) - n); |
322 | 0 | } |
323 | | |
324 | 0 | inline int IOBufAppender::push_back(char c) { |
325 | 0 | if (_data == _data_end) { |
326 | 0 | if (add_block() != 0) { |
327 | 0 | return -1; |
328 | 0 | } |
329 | 0 | } |
330 | 0 | char* const p = (char*)_data; |
331 | 0 | *p = c; |
332 | 0 | _data = p + 1; |
333 | 0 | return 0; |
334 | 0 | } |
335 | | |
336 | 0 | inline int IOBufAppender::add_block() { |
337 | 0 | int size = 0; |
338 | 0 | if (_zc_stream.Next(&_data, &size)) { |
339 | 0 | _data_end = (char*)_data + size; |
340 | 0 | return 0; |
341 | 0 | } |
342 | 0 | _data = NULL; |
343 | 0 | _data_end = NULL; |
344 | 0 | return -1; |
345 | 0 | } |
346 | | |
347 | 0 | inline void IOBufAppender::shrink() { |
348 | 0 | const size_t size = (char*)_data_end - (char*)_data; |
349 | 0 | if (size != 0) { |
350 | 0 | _zc_stream.BackUp(size); |
351 | 0 | _data = NULL; |
352 | 0 | _data_end = NULL; |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | | inline IOBufBytesIterator::IOBufBytesIterator(const butil::IOBuf& buf) |
357 | 685 | : _block_begin(NULL), _block_end(NULL), _block_count(0), |
358 | 685 | _bytes_left(buf.length()), _buf(&buf) { |
359 | 685 | try_next_block(); |
360 | 685 | } |
361 | | |
362 | | inline IOBufBytesIterator::IOBufBytesIterator(const IOBufBytesIterator& it) |
363 | | : _block_begin(it._block_begin) |
364 | | , _block_end(it._block_end) |
365 | | , _block_count(it._block_count) |
366 | | , _bytes_left(it._bytes_left) |
367 | | , _buf(it._buf) { |
368 | | } |
369 | | |
370 | | inline IOBufBytesIterator::IOBufBytesIterator( |
371 | | const IOBufBytesIterator& it, size_t bytes_left) |
372 | | : _block_begin(it._block_begin) |
373 | | , _block_end(it._block_end) |
374 | | , _block_count(it._block_count) |
375 | | , _bytes_left(bytes_left) |
376 | | , _buf(it._buf) { |
377 | | //CHECK_LE(_bytes_left, it._bytes_left); |
378 | | if (_block_end > _block_begin + _bytes_left) { |
379 | | _block_end = _block_begin + _bytes_left; |
380 | | } |
381 | | } |
382 | | |
383 | 1.17k | inline void IOBufBytesIterator::try_next_block() { |
384 | 1.17k | if (_bytes_left == 0) { |
385 | 487 | return; |
386 | 487 | } |
387 | 692 | butil::StringPiece s = _buf->backing_block(_block_count++); |
388 | 692 | _block_begin = s.data(); |
389 | 692 | _block_end = s.data() + std::min(s.size(), (size_t)_bytes_left); |
390 | 692 | } |
391 | | |
392 | 48.7k | inline void IOBufBytesIterator::operator++() { |
393 | 48.7k | ++_block_begin; |
394 | 48.7k | --_bytes_left; |
395 | 48.7k | if (_block_begin == _block_end) { |
396 | 464 | try_next_block(); |
397 | 464 | } |
398 | 48.7k | } |
399 | | |
400 | 271 | inline size_t IOBufBytesIterator::copy_and_forward(void* buf, size_t n) { |
401 | 271 | size_t nc = 0; |
402 | 343 | while (nc < n && _bytes_left != 0) { |
403 | 72 | const size_t block_size = _block_end - _block_begin; |
404 | 72 | const size_t to_copy = std::min(block_size, n - nc); |
405 | 72 | memcpy((char*)buf + nc, _block_begin, to_copy); |
406 | 72 | _block_begin += to_copy; |
407 | 72 | _bytes_left -= to_copy; |
408 | 72 | nc += to_copy; |
409 | 72 | if (_block_begin == _block_end) { |
410 | 30 | try_next_block(); |
411 | 30 | } |
412 | 72 | } |
413 | 271 | return nc; |
414 | 271 | } |
415 | | |
416 | 271 | inline size_t IOBufBytesIterator::copy_and_forward(std::string* s, size_t n) { |
417 | 271 | bool resized = false; |
418 | 271 | if (s->size() < n) { |
419 | 71 | resized = true; |
420 | 71 | s->resize(n); |
421 | 71 | } |
422 | 271 | const size_t nc = copy_and_forward(const_cast<char*>(s->data()), n); |
423 | 271 | if (nc < n && resized) { |
424 | 0 | s->resize(nc); |
425 | 0 | } |
426 | 271 | return nc; |
427 | 271 | } |
428 | | |
429 | 0 | inline size_t IOBufBytesIterator::forward(size_t n) { |
430 | 0 | size_t nc = 0; |
431 | 0 | while (nc < n && _bytes_left != 0) { |
432 | 0 | const size_t block_size = _block_end - _block_begin; |
433 | 0 | const size_t to_copy = std::min(block_size, n - nc); |
434 | 0 | _block_begin += to_copy; |
435 | 0 | _bytes_left -= to_copy; |
436 | 0 | nc += to_copy; |
437 | 0 | if (_block_begin == _block_end) { |
438 | 0 | try_next_block(); |
439 | 0 | } |
440 | 0 | } |
441 | 0 | return nc; |
442 | 0 | } |
443 | | |
444 | | // Used by max_blocks_per_thread() |
445 | | bool IsIOBufProfilerEnabled(); |
446 | | |
447 | | namespace iobuf { |
448 | | void inc_g_nblock(); |
449 | | void dec_g_nblock(); |
450 | | |
451 | | void inc_g_blockmem(); |
452 | | void dec_g_blockmem(); |
453 | | |
454 | | void inc_g_num_hit_tls_threshold(); |
455 | | void dec_g_num_hit_tls_threshold(); |
456 | | |
457 | | // Function pointers to allocate or deallocate memory for a IOBuf::Block |
458 | | extern void* (*blockmem_allocate)(size_t); |
459 | | extern void (*blockmem_deallocate)(void*); |
460 | | |
461 | | } // namespace iobuf |
462 | | |
463 | | struct IOBuf::Block { |
464 | | butil::atomic<int> nshared; |
465 | | uint16_t flags; |
466 | | uint16_t abi_check; // original cap, never be zero. |
467 | | uint32_t size; |
468 | | uint32_t cap; |
469 | | // When flag is 0, portal_next is valid. |
470 | | // When flag & IOBUF_BLOCK_FLAGS_USER_DATA is non-0, data_meta is valid. |
471 | | union { |
472 | | Block* portal_next; |
473 | | uint64_t data_meta; |
474 | | } u; |
475 | | // When flag is 0, data points to `size` bytes starting at `(char*)this+sizeof(Block)' |
476 | | // When flag & IOBUF_BLOCK_FLAGS_USER_DATA is non-0, data points to the user data and |
477 | | // the deleter is put in UserDataExtension at `(char*)this+sizeof(Block)' |
478 | | char* data; |
479 | | |
480 | | Block(char* data_in, uint32_t data_size) |
481 | 9 | : nshared(1) |
482 | 9 | , flags(0) |
483 | 9 | , abi_check(0) |
484 | 9 | , size(0) |
485 | 9 | , cap(data_size) |
486 | 9 | , u({NULL}) |
487 | 9 | , data(data_in) { |
488 | 9 | iobuf::inc_g_nblock(); |
489 | 9 | iobuf::inc_g_blockmem(); |
490 | 9 | if (is_samplable()) { |
491 | 9 | SubmitIOBufSample(this, 1); |
492 | 9 | } |
493 | 9 | } |
494 | | |
495 | | Block(char* data_in, uint32_t data_size, UserDataDeleter deleter) |
496 | 0 | : nshared(1) |
497 | 0 | , flags(IOBUF_BLOCK_FLAGS_USER_DATA) |
498 | 0 | , abi_check(0) |
499 | 0 | , size(data_size) |
500 | 0 | , cap(data_size) |
501 | 0 | , u({0}) |
502 | 0 | , data(data_in) { |
503 | 0 | auto ext = new (get_user_data_extension()) UserDataExtension(); |
504 | 0 | ext->deleter = std::move(deleter); |
505 | 0 | if (is_samplable()) { |
506 | 0 | SubmitIOBufSample(this, 1); |
507 | 0 | } |
508 | 0 | } |
509 | | |
510 | | // Undefined behavior when (flags & IOBUF_BLOCK_FLAGS_USER_DATA) is 0. |
511 | 0 | UserDataExtension* get_user_data_extension() { |
512 | 0 | char* p = (char*)this; |
513 | 0 | return (UserDataExtension*)(p + sizeof(Block)); |
514 | 0 | } |
515 | | |
516 | 1.39k | inline void check_abi() { |
517 | 1.39k | #ifndef NDEBUG |
518 | 1.39k | if (abi_check != 0) { |
519 | 0 | LOG(FATAL) << "Your program seems to wrongly contain two " |
520 | 0 | "ABI-incompatible implementations of IOBuf"; |
521 | 0 | } |
522 | 1.39k | #endif |
523 | 1.39k | } |
524 | | |
525 | 693 | void inc_ref() { |
526 | 693 | check_abi(); |
527 | 693 | nshared.fetch_add(1, butil::memory_order_relaxed); |
528 | 693 | if (sampled()) { |
529 | 693 | SubmitIOBufSample(this, 1); |
530 | 693 | } |
531 | 693 | } |
532 | | |
533 | 701 | void dec_ref() { |
534 | 701 | check_abi(); |
535 | 701 | if (sampled()) { |
536 | 701 | SubmitIOBufSample(this, -1); |
537 | 701 | } |
538 | 701 | if (nshared.fetch_sub(1, butil::memory_order_release) == 1) { |
539 | 8 | butil::atomic_thread_fence(butil::memory_order_acquire); |
540 | 8 | if (!is_user_data()) { |
541 | 8 | iobuf::dec_g_nblock(); |
542 | 8 | iobuf::dec_g_blockmem(); |
543 | 8 | this->~Block(); |
544 | 8 | iobuf::blockmem_deallocate(this); |
545 | 8 | } else if (flags & IOBUF_BLOCK_FLAGS_USER_DATA) { |
546 | 0 | auto ext = get_user_data_extension(); |
547 | 0 | ext->deleter(data); |
548 | 0 | ext->~UserDataExtension(); |
549 | 0 | this->~Block(); |
550 | 0 | free(this); |
551 | 0 | } |
552 | 8 | } |
553 | 701 | } |
554 | | |
555 | 0 | int ref_count() const { |
556 | 0 | return nshared.load(butil::memory_order_relaxed); |
557 | 0 | } |
558 | | |
559 | 700 | bool full() const { return size >= cap; } |
560 | 693 | size_t left_space() const { return cap - size; } |
561 | | |
562 | | private: |
563 | 9 | bool is_samplable() { |
564 | 9 | if (IsIOBufProfilerSamplable()) { |
565 | 9 | flags |= IOBUF_BLOCK_FLAGS_SAMPLED; |
566 | 9 | return true; |
567 | 9 | } |
568 | 0 | return false; |
569 | 9 | } |
570 | | |
571 | 1.39k | bool sampled() const { |
572 | 1.39k | return flags & IOBUF_BLOCK_FLAGS_SAMPLED; |
573 | 1.39k | } |
574 | | |
575 | 8 | bool is_user_data() const { |
576 | 8 | return flags & IOBUF_BLOCK_FLAGS_USER_DATA; |
577 | 8 | } |
578 | | }; |
579 | | |
580 | | namespace iobuf { |
581 | | struct TLSData { |
582 | | // Head of the TLS block chain. |
583 | | IOBuf::Block* block_head; |
584 | | |
585 | | // Number of TLS blocks |
586 | | int num_blocks; |
587 | | |
588 | | // True if the remote_tls_block_chain is registered to the thread. |
589 | | bool registered; |
590 | | }; |
591 | | |
592 | | // Max number of blocks in each TLS. This is a soft limit namely |
593 | | // release_tls_block_chain() may exceed this limit sometimes. |
594 | | const int MAX_BLOCKS_PER_THREAD = 8; |
595 | | |
596 | 0 | inline int max_blocks_per_thread() { |
597 | | // If IOBufProfiler is enabled, do not cache blocks in TLS. |
598 | 0 | return IsIOBufProfilerEnabled() ? 0 : MAX_BLOCKS_PER_THREAD; |
599 | 0 | } |
600 | | |
601 | | TLSData* get_g_tls_data(); |
602 | | void remove_tls_block_chain(); |
603 | | |
604 | | IOBuf::Block* acquire_tls_block(); |
605 | | |
606 | | // Return one block to TLS. |
607 | 0 | inline void release_tls_block(IOBuf::Block* b) { |
608 | 0 | if (!b) { |
609 | 0 | return; |
610 | 0 | } |
611 | 0 | TLSData *tls_data = get_g_tls_data(); |
612 | 0 | if (b->full()) { |
613 | 0 | b->dec_ref(); |
614 | 0 | } else if (tls_data->num_blocks >= max_blocks_per_thread()) { |
615 | 0 | b->dec_ref(); |
616 | | // g_num_hit_tls_threshold.fetch_add(1, butil::memory_order_relaxed); |
617 | 0 | inc_g_num_hit_tls_threshold(); |
618 | 0 | } else { |
619 | 0 | b->u.portal_next = tls_data->block_head; |
620 | 0 | tls_data->block_head = b; |
621 | 0 | ++tls_data->num_blocks; |
622 | 0 | if (!tls_data->registered) { |
623 | 0 | tls_data->registered = true; |
624 | 0 | butil::thread_atexit(remove_tls_block_chain); |
625 | 0 | } |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | 9 | inline IOBuf::Block* create_block(const size_t block_size) { |
630 | 9 | if (block_size > 0xFFFFFFFFULL) { |
631 | 0 | LOG(FATAL) << "block_size=" << block_size << " is too large"; |
632 | 0 | return NULL; |
633 | 0 | } |
634 | 9 | char* mem = (char*)iobuf::blockmem_allocate(block_size); |
635 | 9 | if (mem == NULL) { |
636 | 0 | return NULL; |
637 | 0 | } |
638 | 9 | return new (mem) IOBuf::Block(mem + sizeof(IOBuf::Block), |
639 | 9 | block_size - sizeof(IOBuf::Block)); |
640 | 9 | } |
641 | | |
642 | 9 | inline IOBuf::Block* create_block() { |
643 | 9 | return create_block(IOBuf::DEFAULT_BLOCK_SIZE); |
644 | 9 | } |
645 | | |
646 | | void* cp(void *__restrict dest, const void *__restrict src, size_t n); |
647 | | |
648 | | }; // namespace iobuf; |
649 | | |
650 | | } // namespace butil |
651 | | |
652 | | #endif // BUTIL_IOBUF_INL_H |