]> git.proxmox.com Git - ceph.git/blame - ceph/src/include/buffer.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / include / buffer.h
CommitLineData
11fdf7f2 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
7c673cae
FG
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
11fdf7f2 10 * License version 2.1, as published by the Free Software
7c673cae 11 * Foundation. See file COPYING.
11fdf7f2 12 *
7c673cae
FG
13 */
14#ifndef CEPH_BUFFER_H
15#define CEPH_BUFFER_H
16
17#if defined(__linux__) || defined(__FreeBSD__)
18#include <stdlib.h>
19#endif
20#include <limits.h>
21
22#ifndef _XOPEN_SOURCE
23# define _XOPEN_SOURCE 600
24#endif
25
26#include <stdio.h>
27#include <sys/uio.h>
28
29#if defined(__linux__) // For malloc(2).
30#include <malloc.h>
31#endif
32
33#include <inttypes.h>
34#include <stdint.h>
35#include <string.h>
36
f67539c2 37#if !defined(__CYGWIN__) && !defined(_WIN32)
7c673cae
FG
38# include <sys/mman.h>
39#endif
40
41#include <iosfwd>
42#include <iomanip>
43#include <list>
2a845540 44#include <memory>
7c673cae
FG
45#include <vector>
46#include <string>
11fdf7f2
TL
47#if __cplusplus >= 201703L
48#include <string_view>
49#endif // __cplusplus >= 201703L
50
7c673cae
FG
51#include <exception>
52#include <type_traits>
53
54#include "page.h"
55#include "crc32c.h"
56#include "buffer_fwd.h"
57
f67539c2 58
7c673cae 59#ifdef __CEPH__
11fdf7f2 60# include "include/ceph_assert.h"
7c673cae
FG
61#else
62# include <assert.h>
63#endif
64
65#include "inline_memory.h"
66
11fdf7f2 67#define CEPH_BUFFER_API
7c673cae 68
11fdf7f2
TL
69#ifdef HAVE_SEASTAR
70namespace seastar {
71template <typename T> class temporary_buffer;
72namespace net {
73class packet;
74}
75}
76#endif // HAVE_SEASTAR
7c673cae 77class deleter;
9f95a23c
TL
78
79template<typename T> class DencDumper;
7c673cae
FG
80
81namespace ceph {
82
11fdf7f2
TL
83template <class T>
84struct nop_delete {
85 void operator()(T*) {}
86};
87
88// This is not unique_ptr-like smart pointer! It just signalizes ownership
89// but DOES NOT manage the resource. It WILL LEAK if not manually deleted.
90// It's rather a replacement for raw pointer than any other smart one.
91//
92// Considered options:
93// * unique_ptr with custom deleter implemented in .cc (would provide
94// the non-zero-cost resource management),
95// * GSL's owner<T*> (pretty neat but would impose an extra depedency),
96// * unique_ptr with nop deleter,
97// * raw pointer (doesn't embed ownership enforcement - std::move).
98template <class T>
99struct unique_leakable_ptr : public std::unique_ptr<T, ceph::nop_delete<T>> {
100 using std::unique_ptr<T, ceph::nop_delete<T>>::unique_ptr;
101};
102
7c673cae 103namespace buffer CEPH_BUFFER_API {
9f95a23c 104inline namespace v15_2_0 {
494da23a 105
f67539c2
TL
106/// Actual definitions in common/error_code.h
107struct error;
108struct bad_alloc;
109struct end_of_buffer;
110struct malformed_input;
111struct error_code;
7c673cae 112
7c673cae
FG
113 /// count of cached crc hits (matching input)
114 int get_cached_crc();
115 /// count of cached crc hits (mismatching input, required adjustment)
116 int get_cached_crc_adjusted();
117 /// count of crc cache misses
118 int get_missed_crc();
119 /// enable/disable tracking of cached crcs
120 void track_cached_crc(bool b);
121
7c673cae
FG
122 /*
123 * an abstract raw buffer. with a reference count.
124 */
125 class raw;
126 class raw_malloc;
127 class raw_static;
7c673cae
FG
128 class raw_posix_aligned;
129 class raw_hack_aligned;
31f18b77 130 class raw_claimed_char;
7c673cae
FG
131 class raw_unshareable; // diagnostic, unshareable char buffer
132 class raw_combined;
133 class raw_claim_buffer;
134
135
7c673cae 136 /*
11fdf7f2 137 * named constructors
7c673cae 138 */
11fdf7f2
TL
139 ceph::unique_leakable_ptr<raw> copy(const char *c, unsigned len);
140 ceph::unique_leakable_ptr<raw> create(unsigned len);
f67539c2 141 ceph::unique_leakable_ptr<raw> create(unsigned len, char c);
11fdf7f2 142 ceph::unique_leakable_ptr<raw> create_in_mempool(unsigned len, int mempool);
9f95a23c
TL
143 ceph::unique_leakable_ptr<raw> claim_char(unsigned len, char *buf);
144 ceph::unique_leakable_ptr<raw> create_malloc(unsigned len);
145 ceph::unique_leakable_ptr<raw> claim_malloc(unsigned len, char *buf);
146 ceph::unique_leakable_ptr<raw> create_static(unsigned len, char *buf);
11fdf7f2
TL
147 ceph::unique_leakable_ptr<raw> create_aligned(unsigned len, unsigned align);
148 ceph::unique_leakable_ptr<raw> create_aligned_in_mempool(unsigned len, unsigned align, int mempool);
149 ceph::unique_leakable_ptr<raw> create_page_aligned(unsigned len);
150 ceph::unique_leakable_ptr<raw> create_small_page_aligned(unsigned len);
9f95a23c 151 ceph::unique_leakable_ptr<raw> claim_buffer(unsigned len, char *buf, deleter del);
7c673cae 152
11fdf7f2
TL
153#ifdef HAVE_SEASTAR
154 /// create a raw buffer to wrap seastar cpu-local memory, using foreign_ptr to
155 /// make it safe to share between cpus
1e59de90 156 ceph::unique_leakable_ptr<buffer::raw> create(seastar::temporary_buffer<char>&& buf);
11fdf7f2
TL
157 /// create a raw buffer to wrap seastar cpu-local memory, without the safety
158 /// of foreign_ptr. the caller must otherwise guarantee that the buffer ptr is
159 /// destructed on this cpu
1e59de90 160 ceph::unique_leakable_ptr<buffer::raw> create_local(seastar::temporary_buffer<char>&& buf);
7c673cae
FG
161#endif
162
163 /*
164 * a buffer pointer. references (a subsequence of) a raw buffer.
165 */
166 class CEPH_BUFFER_API ptr {
9f95a23c
TL
167 friend class list;
168 protected:
7c673cae
FG
169 raw *_raw;
170 unsigned _off, _len;
11fdf7f2 171 private:
7c673cae
FG
172
173 void release();
174
11fdf7f2
TL
175 template<bool is_const>
176 class iterator_impl {
7c673cae
FG
177 const ptr *bp; ///< parent ptr
178 const char *start; ///< starting pointer into bp->c_str()
179 const char *pos; ///< pointer into bp->c_str()
180 const char *end_ptr; ///< pointer to bp->end_c_str()
11fdf7f2 181 const bool deep; ///< if true, do not allow shallow ptr copies
7c673cae 182
11fdf7f2
TL
183 iterator_impl(typename std::conditional<is_const, const ptr*, ptr*>::type p,
184 size_t offset, bool d)
7c673cae
FG
185 : bp(p),
186 start(p->c_str() + offset),
187 pos(start),
188 end_ptr(p->end_c_str()),
11fdf7f2
TL
189 deep(d)
190 {}
7c673cae
FG
191
192 friend class ptr;
193
194 public:
11fdf7f2
TL
195 using pointer = typename std::conditional<is_const, const char*, char *>::type;
196 pointer get_pos_add(size_t n) {
197 auto r = pos;
9f95a23c 198 *this += n;
7c673cae
FG
199 return r;
200 }
7c673cae
FG
201 ptr get_ptr(size_t len) {
202 if (deep) {
203 return buffer::copy(get_pos_add(len), len);
204 } else {
205 size_t off = pos - bp->c_str();
9f95a23c 206 *this += len;
7c673cae
FG
207 return ptr(*bp, off, len);
208 }
209 }
7c673cae 210
f67539c2 211 iterator_impl& operator+=(size_t len);
7c673cae
FG
212
213 const char *get_pos() {
214 return pos;
215 }
216 const char *get_end() {
217 return end_ptr;
218 }
219
220 size_t get_offset() {
221 return pos - start;
222 }
223
224 bool end() const {
225 return pos == end_ptr;
226 }
227 };
228
11fdf7f2
TL
229 public:
230 using const_iterator = iterator_impl<true>;
231 using iterator = iterator_impl<false>;
232
233 ptr() : _raw(nullptr), _off(0), _len(0) {}
11fdf7f2 234 ptr(ceph::unique_leakable_ptr<raw> r);
7c673cae
FG
235 // cppcheck-suppress noExplicitConstructor
236 ptr(unsigned l);
237 ptr(const char *d, unsigned l);
238 ptr(const ptr& p);
239 ptr(ptr&& p) noexcept;
240 ptr(const ptr& p, unsigned o, unsigned l);
11fdf7f2 241 ptr(const ptr& p, ceph::unique_leakable_ptr<raw> r);
7c673cae
FG
242 ptr& operator= (const ptr& p);
243 ptr& operator= (ptr&& p) noexcept;
244 ~ptr() {
11fdf7f2
TL
245 // BE CAREFUL: this destructor is called also for hypercombined ptr_node.
246 // After freeing underlying raw, `*this` can become inaccessible as well!
7c673cae
FG
247 release();
248 }
249
250 bool have_raw() const { return _raw ? true:false; }
251
11fdf7f2 252 void swap(ptr& other) noexcept;
7c673cae 253
11fdf7f2 254 iterator begin(size_t offset=0) {
7c673cae
FG
255 return iterator(this, offset, false);
256 }
11fdf7f2
TL
257 const_iterator begin(size_t offset=0) const {
258 return const_iterator(this, offset, false);
259 }
260 const_iterator cbegin() const {
261 return begin();
262 }
263 const_iterator begin_deep(size_t offset=0) const {
264 return const_iterator(this, offset, true);
7c673cae
FG
265 }
266
267 // misc
7c673cae 268 bool is_aligned(unsigned align) const {
f67539c2 269 return ((uintptr_t)c_str() & (align-1)) == 0;
7c673cae
FG
270 }
271 bool is_page_aligned() const { return is_aligned(CEPH_PAGE_SIZE); }
272 bool is_n_align_sized(unsigned align) const
273 {
274 return (length() % align) == 0;
275 }
276 bool is_n_page_sized() const { return is_n_align_sized(CEPH_PAGE_SIZE); }
277 bool is_partial() const {
278 return have_raw() && (start() > 0 || end() < raw_length());
279 }
280
3efd9988
FG
281 int get_mempool() const;
282 void reassign_to_mempool(int pool);
283 void try_assign_to_mempool(int pool);
284
7c673cae 285 // accessors
7c673cae
FG
286 const char *c_str() const;
287 char *c_str();
288 const char *end_c_str() const;
289 char *end_c_str();
290 unsigned length() const { return _len; }
291 unsigned offset() const { return _off; }
292 unsigned start() const { return _off; }
293 unsigned end() const { return _off + _len; }
294 unsigned unused_tail_length() const;
295 const char& operator[](unsigned n) const;
296 char& operator[](unsigned n);
297
298 const char *raw_c_str() const;
299 unsigned raw_length() const;
300 int raw_nref() const;
301
302 void copy_out(unsigned o, unsigned l, char *dest) const;
303
31f18b77 304 unsigned wasted() const;
7c673cae
FG
305
306 int cmp(const ptr& o) const;
307 bool is_zero() const;
308
309 // modifiers
310 void set_offset(unsigned o) {
11fdf7f2
TL
311#ifdef __CEPH__
312 ceph_assert(raw_length() >= o);
313#else
7c673cae 314 assert(raw_length() >= o);
11fdf7f2 315#endif
7c673cae
FG
316 _off = o;
317 }
318 void set_length(unsigned l) {
11fdf7f2
TL
319#ifdef __CEPH__
320 ceph_assert(raw_length() >= l);
321#else
7c673cae 322 assert(raw_length() >= l);
11fdf7f2 323#endif
7c673cae
FG
324 _len = l;
325 }
326
327 unsigned append(char c);
328 unsigned append(const char *p, unsigned l);
11fdf7f2
TL
329#if __cplusplus >= 201703L
330 inline unsigned append(std::string_view s) {
331 return append(s.data(), s.length());
332 }
333#endif // __cplusplus >= 201703L
334 void copy_in(unsigned o, unsigned l, const char *src, bool crc_reset = true);
335 void zero(bool crc_reset = true);
336 void zero(unsigned o, unsigned l, bool crc_reset = true);
337 unsigned append_zeros(unsigned l);
338
339#ifdef HAVE_SEASTAR
340 /// create a temporary_buffer, copying the ptr as its deleter
341 operator seastar::temporary_buffer<char>() &;
342 /// convert to temporary_buffer, stealing the ptr as its deleter
343 operator seastar::temporary_buffer<char>() &&;
344#endif // HAVE_SEASTAR
345
346 };
347
7c673cae 348
11fdf7f2
TL
349 struct ptr_hook {
350 mutable ptr_hook* next;
351
352 ptr_hook() = default;
353 ptr_hook(ptr_hook* const next)
354 : next(next) {
355 }
7c673cae
FG
356 };
357
11fdf7f2
TL
358 class ptr_node : public ptr_hook, public ptr {
359 public:
360 struct cloner {
361 ptr_node* operator()(const ptr_node& clone_this);
362 };
363 struct disposer {
364 void operator()(ptr_node* const delete_this) {
f67539c2 365 if (!__builtin_expect(dispose_if_hypercombined(delete_this), 0)) {
11fdf7f2
TL
366 delete delete_this;
367 }
368 }
369 };
370
371 ~ptr_node() = default;
372
373 static std::unique_ptr<ptr_node, disposer>
374 create(ceph::unique_leakable_ptr<raw> r) {
375 return create_hypercombined(std::move(r));
376 }
9f95a23c
TL
377 static std::unique_ptr<ptr_node, disposer>
378 create(const unsigned l) {
11fdf7f2
TL
379 return create_hypercombined(buffer::create(l));
380 }
381 template <class... Args>
9f95a23c
TL
382 static std::unique_ptr<ptr_node, disposer>
383 create(Args&&... args) {
11fdf7f2
TL
384 return std::unique_ptr<ptr_node, disposer>(
385 new ptr_node(std::forward<Args>(args)...));
386 }
387
388 static ptr_node* copy_hypercombined(const ptr_node& copy_this);
7c673cae 389
11fdf7f2 390 private:
f67539c2
TL
391 friend list;
392
11fdf7f2
TL
393 template <class... Args>
394 ptr_node(Args&&... args) : ptr(std::forward<Args>(args)...) {
395 }
396 ptr_node(const ptr_node&) = default;
397
398 ptr& operator= (const ptr& p) = delete;
399 ptr& operator= (ptr&& p) noexcept = delete;
400 ptr_node& operator= (const ptr_node& p) = delete;
401 ptr_node& operator= (ptr_node&& p) noexcept = delete;
402 void swap(ptr& other) noexcept = delete;
403 void swap(ptr_node& other) noexcept = delete;
404
405 static bool dispose_if_hypercombined(ptr_node* delete_this);
11fdf7f2
TL
406 static std::unique_ptr<ptr_node, disposer> create_hypercombined(
407 ceph::unique_leakable_ptr<raw> r);
408 };
7c673cae
FG
409 /*
410 * list - the useful bit!
411 */
412
413 class CEPH_BUFFER_API list {
7c673cae 414 public:
11fdf7f2
TL
415 // this the very low-level implementation of singly linked list
416 // ceph::buffer::list is built on. We don't use intrusive slist
417 // of Boost (or any other 3rd party) to save extra dependencies
418 // in our public headers.
419 class buffers_t {
420 // _root.next can be thought as _head
421 ptr_hook _root;
422 ptr_hook* _tail;
11fdf7f2
TL
423
424 public:
425 template <class T>
426 class buffers_iterator {
427 typename std::conditional<
428 std::is_const<T>::value, const ptr_hook*, ptr_hook*>::type cur;
429 template <class U> friend class buffers_iterator;
430 public:
431 using value_type = T;
432 using reference = typename std::add_lvalue_reference<T>::type;
433 using pointer = typename std::add_pointer<T>::type;
434 using difference_type = std::ptrdiff_t;
435 using iterator_category = std::forward_iterator_tag;
436
437 template <class U>
438 buffers_iterator(U* const p)
439 : cur(p) {
440 }
1e59de90
TL
441 // copy constructor
442 buffers_iterator(const buffers_iterator<T>& other)
443 : cur(other.cur) {
444 }
445 // converting constructor, from iterator -> const_iterator only
446 template <class U, typename std::enable_if<
447 std::is_const<T>::value && !std::is_const<U>::value, int>::type = 0>
11fdf7f2
TL
448 buffers_iterator(const buffers_iterator<U>& other)
449 : cur(other.cur) {
450 }
451 buffers_iterator() = default;
452
453 T& operator*() const {
454 return *reinterpret_cast<T*>(cur);
455 }
456 T* operator->() const {
457 return reinterpret_cast<T*>(cur);
458 }
459
460 buffers_iterator& operator++() {
461 cur = cur->next;
462 return *this;
463 }
464 buffers_iterator operator++(int) {
465 const auto temp(*this);
466 ++*this;
467 return temp;
468 }
469
470 template <class U>
471 buffers_iterator& operator=(buffers_iterator<U>& other) {
472 cur = other.cur;
473 return *this;
474 }
475
476 bool operator==(const buffers_iterator& rhs) const {
477 return cur == rhs.cur;
478 }
479 bool operator!=(const buffers_iterator& rhs) const {
480 return !(*this==rhs);
481 }
11fdf7f2
TL
482 };
483
484 typedef buffers_iterator<const ptr_node> const_iterator;
485 typedef buffers_iterator<ptr_node> iterator;
486
487 typedef const ptr_node& const_reference;
488 typedef ptr_node& reference;
489
490 buffers_t()
491 : _root(&_root),
9f95a23c 492 _tail(&_root) {
11fdf7f2
TL
493 }
494 buffers_t(const buffers_t&) = delete;
495 buffers_t(buffers_t&& other)
496 : _root(other._root.next == &other._root ? &_root : other._root.next),
9f95a23c 497 _tail(other._tail == &other._root ? &_root : other._tail) {
11fdf7f2
TL
498 other._root.next = &other._root;
499 other._tail = &other._root;
11fdf7f2
TL
500
501 _tail->next = &_root;
502 }
503 buffers_t& operator=(buffers_t&& other) {
504 if (&other != this) {
505 clear_and_dispose();
506 swap(other);
507 }
508 return *this;
509 }
510
511 void push_back(reference item) {
512 item.next = &_root;
513 // this updates _root.next when called on empty
514 _tail->next = &item;
515 _tail = &item;
11fdf7f2
TL
516 }
517
518 void push_front(reference item) {
519 item.next = _root.next;
520 _root.next = &item;
521 _tail = _tail == &_root ? &item : _tail;
11fdf7f2
TL
522 }
523
524 // *_after
525 iterator erase_after(const_iterator it) {
526 const auto* to_erase = it->next;
527
528 it->next = to_erase->next;
529 _root.next = _root.next == to_erase ? to_erase->next : _root.next;
530 _tail = _tail == to_erase ? (ptr_hook*)&*it : _tail;
11fdf7f2
TL
531 return it->next;
532 }
533
534 void insert_after(const_iterator it, reference item) {
535 item.next = it->next;
536 it->next = &item;
537 _root.next = it == end() ? &item : _root.next;
538 _tail = const_iterator(_tail) == it ? &item : _tail;
11fdf7f2
TL
539 }
540
541 void splice_back(buffers_t& other) {
9f95a23c 542 if (other.empty()) {
11fdf7f2
TL
543 return;
544 }
545
546 other._tail->next = &_root;
547 // will update root.next if empty() == true
548 _tail->next = other._root.next;
549 _tail = other._tail;
11fdf7f2
TL
550
551 other._root.next = &other._root;
552 other._tail = &other._root;
11fdf7f2
TL
553 }
554
11fdf7f2
TL
555 bool empty() const { return _tail == &_root; }
556
557 const_iterator begin() const {
558 return _root.next;
559 }
560 const_iterator before_begin() const {
561 return &_root;
562 }
563 const_iterator end() const {
564 return &_root;
565 }
566 iterator begin() {
567 return _root.next;
568 }
569 iterator before_begin() {
570 return &_root;
571 }
572 iterator end() {
573 return &_root;
574 }
575
576 reference front() {
577 return reinterpret_cast<reference>(*_root.next);
578 }
579 reference back() {
580 return reinterpret_cast<reference>(*_tail);
581 }
582 const_reference front() const {
583 return reinterpret_cast<const_reference>(*_root.next);
584 }
585 const_reference back() const {
586 return reinterpret_cast<const_reference>(*_tail);
587 }
588
589 void clone_from(const buffers_t& other) {
590 clear_and_dispose();
591 for (auto& node : other) {
592 ptr_node* clone = ptr_node::cloner()(node);
593 push_back(*clone);
594 }
595 }
596 void clear_and_dispose() {
1e59de90
TL
597 ptr_node::disposer dispose;
598 for (auto it = begin(), e = end(); it != e; /* nop */) {
599 auto& node = *it++;
600 dispose(&node);
601 }
602 _tail = &_root;
603 _root.next = _tail;
11fdf7f2
TL
604 }
605 iterator erase_after_and_dispose(iterator it) {
606 auto* to_dispose = &*std::next(it);
607 auto ret = erase_after(it);
608 ptr_node::disposer()(to_dispose);
609 return ret;
610 }
611
612 void swap(buffers_t& other) {
613 const auto copy_root = _root;
614 _root.next = \
615 other._root.next == &other._root ? &this->_root : other._root.next;
616 other._root.next = \
617 copy_root.next == &_root ? &other._root : copy_root.next;
618
619 const auto copy_tail = _tail;
620 _tail = other._tail == &other._root ? &this->_root : other._tail;
621 other._tail = copy_tail == &_root ? &other._root : copy_tail;
622
623 _tail->next = &_root;
624 other._tail->next = &other._root;
11fdf7f2
TL
625 }
626 };
627
7c673cae
FG
628 class iterator;
629
630 private:
11fdf7f2
TL
631 // my private bits
632 buffers_t _buffers;
633
634 // track bufferptr we can modify (especially ::append() to). Not all bptrs
635 // bufferlist holds have this trait -- if somebody ::push_back(const ptr&),
636 // he expects it won't change.
f67539c2 637 ptr_node* _carriage;
9f95a23c 638 unsigned _len, _num;
11fdf7f2 639
7c673cae 640 template <bool is_const>
11fdf7f2 641 class CEPH_BUFFER_API iterator_impl {
7c673cae
FG
642 protected:
643 typedef typename std::conditional<is_const,
644 const list,
645 list>::type bl_t;
646 typedef typename std::conditional<is_const,
11fdf7f2
TL
647 const buffers_t,
648 buffers_t >::type list_t;
7c673cae 649 typedef typename std::conditional<is_const,
11fdf7f2
TL
650 typename buffers_t::const_iterator,
651 typename buffers_t::iterator>::type list_iter_t;
7c673cae
FG
652 bl_t* bl;
653 list_t* ls; // meh.. just here to avoid an extra pointer dereference..
7c673cae 654 list_iter_t p;
11fdf7f2 655 unsigned off; // in bl
7c673cae
FG
656 unsigned p_off; // in *p
657 friend class iterator_impl<true>;
658
659 public:
11fdf7f2
TL
660 using iterator_category = std::forward_iterator_tag;
661 using value_type = typename std::conditional<is_const, const char, char>::type;
662 using difference_type = std::ptrdiff_t;
663 using pointer = typename std::add_pointer<value_type>::type;
664 using reference = typename std::add_lvalue_reference<value_type>::type;
665
7c673cae
FG
666 // constructor. position.
667 iterator_impl()
668 : bl(0), ls(0), off(0), p_off(0) {}
669 iterator_impl(bl_t *l, unsigned o=0);
670 iterator_impl(bl_t *l, unsigned o, list_iter_t ip, unsigned po)
11fdf7f2 671 : bl(l), ls(&bl->_buffers), p(ip), off(o), p_off(po) {}
7c673cae
FG
672 iterator_impl(const list::iterator& i);
673
674 /// get current iterator offset in buffer::list
675 unsigned get_off() const { return off; }
11fdf7f2 676
7c673cae
FG
677 /// get number of bytes remaining from iterator position to the end of the buffer::list
678 unsigned get_remaining() const { return bl->length() - off; }
679
680 /// true if iterator is at the end of the buffer::list
681 bool end() const {
682 return p == ls->end();
683 //return off == bl->length();
684 }
7c673cae
FG
685 void seek(unsigned o);
686 char operator*() const;
9f95a23c 687 iterator_impl& operator+=(unsigned o);
7c673cae
FG
688 iterator_impl& operator++();
689 ptr get_current_ptr() const;
11fdf7f2 690 bool is_pointing_same_raw(const ptr& other) const;
7c673cae
FG
691
692 bl_t& get_bl() const { return *bl; }
693
694 // copy data out.
695 // note that these all _append_ to dest!
696 void copy(unsigned len, char *dest);
697 // deprecated, use copy_deep()
698 void copy(unsigned len, ptr &dest) __attribute__((deprecated));
699 void copy_deep(unsigned len, ptr &dest);
700 void copy_shallow(unsigned len, ptr &dest);
701 void copy(unsigned len, list &dest);
702 void copy(unsigned len, std::string &dest);
703 void copy_all(list &dest);
704
705 // get a pointer to the currenet iterator position, return the
706 // number of bytes we can read from that position (up to want),
707 // and advance the iterator by that amount.
708 size_t get_ptr_and_advance(size_t want, const char **p);
709
710 /// calculate crc from iterator position
711 uint32_t crc32c(size_t length, uint32_t crc);
712
713 friend bool operator==(const iterator_impl& lhs,
714 const iterator_impl& rhs) {
715 return &lhs.get_bl() == &rhs.get_bl() && lhs.get_off() == rhs.get_off();
716 }
717 friend bool operator!=(const iterator_impl& lhs,
718 const iterator_impl& rhs) {
719 return &lhs.get_bl() != &rhs.get_bl() || lhs.get_off() != rhs.get_off();
720 }
721 };
722
723 public:
724 typedef iterator_impl<true> const_iterator;
725
726 class CEPH_BUFFER_API iterator : public iterator_impl<false> {
727 public:
728 iterator() = default;
729 iterator(bl_t *l, unsigned o=0);
730 iterator(bl_t *l, unsigned o, list_iter_t ip, unsigned po);
7c673cae 731 // copy data in
11fdf7f2 732 void copy_in(unsigned len, const char *src, bool crc_reset = true);
7c673cae 733 void copy_in(unsigned len, const list& otherl);
11fdf7f2 734 };
7c673cae 735
11fdf7f2
TL
736 struct reserve_t {
737 char* bp_data;
738 unsigned* bp_len;
739 unsigned* bl_len;
7c673cae
FG
740 };
741
742 class contiguous_appender {
11fdf7f2
TL
743 ceph::bufferlist& bl;
744 ceph::bufferlist::reserve_t space;
745 char* pos;
7c673cae
FG
746 bool deep;
747
748 /// running count of bytes appended that are not reflected by @pos
749 size_t out_of_band_offset = 0;
750
11fdf7f2
TL
751 contiguous_appender(bufferlist& bl, size_t len, bool d)
752 : bl(bl),
753 space(bl.obtain_contiguous_space(len)),
754 pos(space.bp_data),
7c673cae 755 deep(d) {
7c673cae
FG
756 }
757
758 void flush_and_continue() {
11fdf7f2
TL
759 const size_t l = pos - space.bp_data;
760 *space.bp_len += l;
761 *space.bl_len += l;
762 space.bp_data = pos;
7c673cae
FG
763 }
764
765 friend class list;
9f95a23c 766 template<typename Type> friend class ::DencDumper;
7c673cae
FG
767
768 public:
769 ~contiguous_appender() {
11fdf7f2 770 flush_and_continue();
7c673cae
FG
771 }
772
773 size_t get_out_of_band_offset() const {
774 return out_of_band_offset;
775 }
11fdf7f2 776 void append(const char* __restrict__ p, size_t l) {
7c673cae
FG
777 maybe_inline_memcpy(pos, p, l, 16);
778 pos += l;
779 }
780 char *get_pos_add(size_t len) {
781 char *r = pos;
782 pos += len;
783 return r;
784 }
9f95a23c 785 char *get_pos() const {
7c673cae
FG
786 return pos;
787 }
788
789 void append(const bufferptr& p) {
11fdf7f2
TL
790 const auto plen = p.length();
791 if (!plen) {
7c673cae
FG
792 return;
793 }
794 if (deep) {
11fdf7f2 795 append(p.c_str(), plen);
7c673cae
FG
796 } else {
797 flush_and_continue();
11fdf7f2
TL
798 bl.append(p);
799 space = bl.obtain_contiguous_space(0);
800 out_of_band_offset += plen;
7c673cae
FG
801 }
802 }
803 void append(const bufferlist& l) {
7c673cae
FG
804 if (deep) {
805 for (const auto &p : l._buffers) {
806 append(p.c_str(), p.length());
807 }
808 } else {
809 flush_and_continue();
11fdf7f2
TL
810 bl.append(l);
811 space = bl.obtain_contiguous_space(0);
7c673cae
FG
812 out_of_band_offset += l.length();
813 }
814 }
815
9f95a23c 816 size_t get_logical_offset() const {
11fdf7f2 817 return out_of_band_offset + (pos - space.bp_data);
7c673cae
FG
818 }
819 };
820
821 contiguous_appender get_contiguous_appender(size_t len, bool deep=false) {
11fdf7f2 822 return contiguous_appender(*this, len, deep);
7c673cae
FG
823 }
824
11fdf7f2
TL
825 class contiguous_filler {
826 friend buffer::list;
827 char* pos;
828
829 contiguous_filler(char* const pos) : pos(pos) {}
830
831 public:
832 void advance(const unsigned len) {
833 pos += len;
834 }
835 void copy_in(const unsigned len, const char* const src) {
836 memcpy(pos, src, len);
837 advance(len);
838 }
839 char* c_str() {
840 return pos;
841 }
842 };
843 // The contiguous_filler is supposed to be not costlier than a single
844 // pointer. Keep it dumb, please.
845 static_assert(sizeof(contiguous_filler) == sizeof(char*),
846 "contiguous_filler should be no costlier than pointer");
847
7c673cae 848 class page_aligned_appender {
f67539c2 849 bufferlist& bl;
7c673cae 850 unsigned min_alloc;
7c673cae
FG
851
852 page_aligned_appender(list *l, unsigned min_pages)
f67539c2
TL
853 : bl(*l),
854 min_alloc(min_pages * CEPH_PAGE_SIZE) {
855 }
856
857 void _refill(size_t len);
858
859 template <class Func>
860 void _append_common(size_t len, Func&& impl_f) {
861 const auto free_in_last = bl.get_append_buffer_unused_tail_length();
862 const auto first_round = std::min(len, free_in_last);
863 if (first_round) {
864 impl_f(first_round);
865 }
2a845540
TL
866 // no C++17 for the sake of the C++11 guarantees of librados, sorry.
867 const auto second_round = len - first_round;
868 if (second_round) {
f67539c2
TL
869 _refill(second_round);
870 impl_f(second_round);
871 }
872 }
7c673cae
FG
873
874 friend class list;
875
876 public:
f67539c2
TL
877 void append(const bufferlist& l) {
878 bl.append(l);
879 bl.obtain_contiguous_space(0);
7c673cae
FG
880 }
881
f67539c2
TL
882 void append(const char* buf, size_t entire_len) {
883 _append_common(entire_len,
884 [buf, this] (const size_t chunk_len) mutable {
885 bl.append(buf, chunk_len);
886 buf += chunk_len;
887 });
7c673cae
FG
888 }
889
f67539c2
TL
890 void append_zero(size_t entire_len) {
891 _append_common(entire_len, [this] (const size_t chunk_len) {
892 bl.append_zero(chunk_len);
893 });
894 }
895
896 void substr_of(const list& bl, unsigned off, unsigned len) {
897 for (const auto& bptr : bl.buffers()) {
898 if (off >= bptr.length()) {
899 off -= bptr.length();
900 continue;
7c673cae 901 }
f67539c2
TL
902 const auto round_size = std::min(bptr.length() - off, len);
903 append(bptr.c_str() + off, round_size);
904 len -= round_size;
905 off = 0;
7c673cae
FG
906 }
907 }
908 };
909
910 page_aligned_appender get_page_aligned_appender(unsigned min_pages=1) {
911 return page_aligned_appender(this, min_pages);
912 }
913
914 private:
11fdf7f2
TL
915 // always_empty_bptr has no underlying raw but its _len is always 0.
916 // This is useful for e.g. get_append_buffer_unused_tail_length() as
917 // it allows to avoid conditionals on hot paths.
f67539c2 918 static ptr_node always_empty_bptr;
11fdf7f2 919 ptr_node& refill_append_space(const unsigned len);
7c673cae 920
f67539c2
TL
921 // for page_aligned_appender; never ever expose this publicly!
922 // carriage / append_buffer is just an implementation's detail.
923 ptr& get_append_buffer() {
924 return *_carriage;
925 }
926
7c673cae
FG
927 public:
928 // cons/des
11fdf7f2
TL
929 list()
930 : _carriage(&always_empty_bptr),
931 _len(0),
9f95a23c 932 _num(0) {
11fdf7f2
TL
933 }
934 // cppcheck-suppress noExplicitConstructor
7c673cae 935 // cppcheck-suppress noExplicitConstructor
11fdf7f2
TL
936 list(unsigned prealloc)
937 : _carriage(&always_empty_bptr),
938 _len(0),
9f95a23c 939 _num(0) {
7c673cae
FG
940 reserve(prealloc);
941 }
942
11fdf7f2
TL
943 list(const list& other)
944 : _carriage(&always_empty_bptr),
945 _len(other._len),
9f95a23c 946 _num(other._num) {
11fdf7f2 947 _buffers.clone_from(other._buffers);
7c673cae 948 }
9f95a23c
TL
949
950 list(list&& other) noexcept
951 : _buffers(std::move(other._buffers)),
952 _carriage(other._carriage),
953 _len(other._len),
954 _num(other._num) {
955 other.clear();
956 }
11fdf7f2
TL
957
958 ~list() {
959 _buffers.clear_and_dispose();
960 }
961
7c673cae
FG
962 list& operator= (const list& other) {
963 if (this != &other) {
11fdf7f2
TL
964 _carriage = &always_empty_bptr;
965 _buffers.clone_from(other._buffers);
7c673cae 966 _len = other._len;
9f95a23c 967 _num = other._num;
7c673cae
FG
968 }
969 return *this;
970 }
11fdf7f2 971 list& operator= (list&& other) noexcept {
7c673cae 972 _buffers = std::move(other._buffers);
11fdf7f2 973 _carriage = other._carriage;
7c673cae 974 _len = other._len;
9f95a23c 975 _num = other._num;
7c673cae
FG
976 other.clear();
977 return *this;
978 }
979
f64942e4 980 uint64_t get_wasted_space() const;
9f95a23c 981 unsigned get_num_buffers() const { return _num; }
11fdf7f2
TL
982 const ptr_node& front() const { return _buffers.front(); }
983 const ptr_node& back() const { return _buffers.back(); }
7c673cae 984
3efd9988 985 int get_mempool() const;
31f18b77
FG
986 void reassign_to_mempool(int pool);
987 void try_assign_to_mempool(int pool);
988
989 size_t get_append_buffer_unused_tail_length() const {
11fdf7f2 990 return _carriage->unused_tail_length();
31f18b77
FG
991 }
992
11fdf7f2 993 const buffers_t& buffers() const { return _buffers; }
f67539c2 994 buffers_t& mut_buffers() { return _buffers; }
11fdf7f2 995 void swap(list& other) noexcept;
7c673cae
FG
996 unsigned length() const {
997#if 0
998 // DEBUG: verify _len
999 unsigned len = 0;
1000 for (std::list<ptr>::const_iterator it = _buffers.begin();
1001 it != _buffers.end();
1002 it++) {
1003 len += (*it).length();
1004 }
11fdf7f2
TL
1005#ifdef __CEPH__
1006 ceph_assert(len == _len);
1007#else
7c673cae 1008 assert(len == _len);
11fdf7f2 1009#endif // __CEPH__
7c673cae
FG
1010#endif
1011 return _len;
1012 }
1013
7c673cae 1014 bool contents_equal(const buffer::list& other) const;
9f95a23c 1015 bool contents_equal(const void* other, size_t length) const;
7c673cae 1016
7c673cae
FG
1017 bool is_provided_buffer(const char *dst) const;
1018 bool is_aligned(unsigned align) const;
1019 bool is_page_aligned() const;
1020 bool is_n_align_sized(unsigned align) const;
1021 bool is_n_page_sized() const;
1022 bool is_aligned_size_and_memory(unsigned align_size,
1023 unsigned align_memory) const;
1024
1025 bool is_zero() const;
1026
1027 // modifiers
11fdf7f2
TL
1028 void clear() noexcept {
1029 _carriage = &always_empty_bptr;
1030 _buffers.clear_and_dispose();
7c673cae 1031 _len = 0;
9f95a23c 1032 _num = 0;
7c673cae 1033 }
11fdf7f2 1034 void push_back(const ptr& bp) {
7c673cae
FG
1035 if (bp.length() == 0)
1036 return;
11fdf7f2 1037 _buffers.push_back(*ptr_node::create(bp).release());
7c673cae 1038 _len += bp.length();
9f95a23c 1039 _num += 1;
7c673cae 1040 }
11fdf7f2 1041 void push_back(ptr&& bp) {
7c673cae
FG
1042 if (bp.length() == 0)
1043 return;
1044 _len += bp.length();
9f95a23c 1045 _num += 1;
11fdf7f2
TL
1046 _buffers.push_back(*ptr_node::create(std::move(bp)).release());
1047 _carriage = &always_empty_bptr;
7c673cae 1048 }
11fdf7f2
TL
1049 void push_back(const ptr_node&) = delete;
1050 void push_back(ptr_node&) = delete;
1051 void push_back(ptr_node&&) = delete;
1052 void push_back(std::unique_ptr<ptr_node, ptr_node::disposer> bp) {
11fdf7f2
TL
1053 _carriage = bp.get();
1054 _len += bp->length();
9f95a23c 1055 _num += 1;
11fdf7f2 1056 _buffers.push_back(*bp.release());
7c673cae 1057 }
9f95a23c
TL
1058 void push_back(raw* const r) = delete;
1059 void push_back(ceph::unique_leakable_ptr<raw> r) {
1060 _buffers.push_back(*ptr_node::create(std::move(r)).release());
11fdf7f2
TL
1061 _carriage = &_buffers.back();
1062 _len += _buffers.back().length();
9f95a23c 1063 _num += 1;
7c673cae
FG
1064 }
1065
1066 void zero();
1067 void zero(unsigned o, unsigned l);
1068
1069 bool is_contiguous() const;
1070 void rebuild();
11fdf7f2 1071 void rebuild(std::unique_ptr<ptr_node, ptr_node::disposer> nb);
7c673cae 1072 bool rebuild_aligned(unsigned align);
b32b8144
FG
1073 // max_buffers = 0 mean don't care _buffers.size(), other
1074 // must make _buffers.size() <= max_buffers after rebuilding.
7c673cae 1075 bool rebuild_aligned_size_and_memory(unsigned align_size,
b32b8144
FG
1076 unsigned align_memory,
1077 unsigned max_buffers = 0);
7c673cae
FG
1078 bool rebuild_page_aligned();
1079
31f18b77 1080 void reserve(size_t prealloc);
7c673cae 1081
f67539c2
TL
1082 [[deprecated("in favor of operator=(list&&)")]] void claim(list& bl) {
1083 *this = std::move(bl);
1084 }
9f95a23c 1085 void claim_append(list& bl);
f67539c2
TL
1086 void claim_append(list&& bl) {
1087 claim_append(bl);
1088 }
7c673cae 1089
7c673cae
FG
1090 // copy with explicit volatile-sharing semantics
1091 void share(const list& bl)
1092 {
1093 if (this != &bl) {
1094 clear();
11fdf7f2
TL
1095 for (const auto& bp : bl._buffers) {
1096 _buffers.push_back(*ptr_node::create(bp).release());
7c673cae 1097 }
11fdf7f2 1098 _len = bl._len;
9f95a23c 1099 _num = bl._num;
7c673cae
FG
1100 }
1101 }
1102
11fdf7f2
TL
1103#ifdef HAVE_SEASTAR
1104 /// convert the bufferlist into a network packet
1105 operator seastar::net::packet() &&;
1106#endif
1107
9f95a23c
TL
1108 iterator begin(size_t offset=0) {
1109 return iterator(this, offset);
7c673cae
FG
1110 }
1111 iterator end() {
1112 return iterator(this, _len, _buffers.end(), 0);
1113 }
1114
9f95a23c
TL
1115 const_iterator begin(size_t offset=0) const {
1116 return const_iterator(this, offset);
7c673cae 1117 }
9f95a23c
TL
1118 const_iterator cbegin(size_t offset=0) const {
1119 return begin(offset);
11fdf7f2 1120 }
7c673cae
FG
1121 const_iterator end() const {
1122 return const_iterator(this, _len, _buffers.end(), 0);
1123 }
1124
7c673cae
FG
1125 void append(char c);
1126 void append(const char *data, unsigned len);
11fdf7f2 1127 void append(std::string s) {
7c673cae
FG
1128 append(s.data(), s.length());
1129 }
11fdf7f2
TL
1130#if __cplusplus >= 201703L
1131 // To forcibly disambiguate between string and string_view in the
1132 // case of arrays
1133 template<std::size_t N>
1134 void append(const char (&s)[N]) {
1135 append(s, N);
1136 }
1137 void append(const char* s) {
1138 append(s, strlen(s));
1139 }
1140 void append(std::string_view s) {
1141 append(s.data(), s.length());
1142 }
1143#endif // __cplusplus >= 201703L
7c673cae
FG
1144 void append(const ptr& bp);
1145 void append(ptr&& bp);
1146 void append(const ptr& bp, unsigned off, unsigned len);
1147 void append(const list& bl);
f67539c2
TL
1148 /// append each non-empty line from the stream and add '\n',
1149 /// so a '\n' will be added even the stream does not end with EOL.
1150 ///
1151 /// For example, if the stream contains "ABC\n\nDEF", "ABC\nDEF\n" is
1152 /// actually appended.
7c673cae 1153 void append(std::istream& in);
11fdf7f2 1154 contiguous_filler append_hole(unsigned len);
7c673cae
FG
1155 void append_zero(unsigned len);
1156 void prepend_zero(unsigned len);
11fdf7f2 1157
f67539c2 1158 reserve_t obtain_contiguous_space(const unsigned len);
11fdf7f2 1159
7c673cae
FG
1160 /*
1161 * get a char
1162 */
1163 const char& operator[](unsigned n) const;
1164 char *c_str();
1165 std::string to_str() const;
1166
1167 void substr_of(const list& other, unsigned off, unsigned len);
1168
7c673cae
FG
1169 // funky modifer
1170 void splice(unsigned off, unsigned len, list *claim_by=0 /*, bufferlist& replace_with */);
1171 void write(int off, int len, std::ostream& out) const;
1172
1173 void encode_base64(list& o);
1174 void decode_base64(list& o);
1175
1176 void write_stream(std::ostream &out) const;
1177 void hexdump(std::ostream &out, bool trailing_newline = true) const;
9f95a23c 1178 ssize_t pread_file(const char *fn, uint64_t off, uint64_t len, std::string *error);
7c673cae
FG
1179 int read_file(const char *fn, std::string *error);
1180 ssize_t read_fd(int fd, size_t len);
f67539c2 1181 ssize_t recv_fd(int fd, size_t len);
7c673cae
FG
1182 int write_file(const char *fn, int mode=0644);
1183 int write_fd(int fd) const;
1184 int write_fd(int fd, uint64_t offset) const;
f67539c2 1185 int send_fd(int fd) const;
7c673cae
FG
1186 template<typename VectorT>
1187 void prepare_iov(VectorT *piov) const {
11fdf7f2 1188#ifdef __CEPH__
9f95a23c 1189 ceph_assert(_num <= IOV_MAX);
11fdf7f2 1190#else
9f95a23c 1191 assert(_num <= IOV_MAX);
11fdf7f2 1192#endif
9f95a23c 1193 piov->resize(_num);
7c673cae
FG
1194 unsigned n = 0;
1195 for (auto& p : _buffers) {
1196 (*piov)[n].iov_base = (void *)p.c_str();
1197 (*piov)[n].iov_len = p.length();
1198 ++n;
1199 }
1200 }
20effc67
TL
1201
1202 struct iovec_t {
1203 uint64_t offset;
1204 uint64_t length;
1205 std::vector<iovec> iov;
1206 };
1207 using iov_vec_t = std::vector<iovec_t>;
1208 iov_vec_t prepare_iovs() const;
1209
7c673cae
FG
1210 uint32_t crc32c(uint32_t crc) const;
1211 void invalidate_crc();
31f18b77
FG
1212
1213 // These functions return a bufferlist with a pointer to a single
1214 // static buffer. They /must/ not outlive the memory they
1215 // reference.
1216 static list static_from_mem(char* c, size_t l);
1217 static list static_from_cstring(char* c);
1218 static list static_from_string(std::string& s);
7c673cae
FG
1219 };
1220
9f95a23c 1221} // inline namespace v15_2_0
11fdf7f2 1222
7c673cae
FG
1223 /*
1224 * efficient hash of one or more bufferlists
1225 */
1226
1227 class hash {
1228 uint32_t crc;
1229
1230 public:
1231 hash() : crc(0) { }
1232 // cppcheck-suppress noExplicitConstructor
1233 hash(uint32_t init) : crc(init) { }
1234
31f18b77 1235 void update(const buffer::list& bl) {
7c673cae
FG
1236 crc = bl.crc32c(crc);
1237 }
1238
1239 uint32_t digest() {
1240 return crc;
1241 }
1242 };
1243
f67539c2
TL
1244inline bool operator==(const bufferlist &lhs, const bufferlist &rhs) {
1245 if (lhs.length() != rhs.length())
1246 return false;
1247 return std::equal(lhs.begin(), lhs.end(), rhs.begin());
7c673cae 1248}
f67539c2
TL
1249
1250inline bool operator<(const bufferlist& lhs, const bufferlist& rhs) {
1251 auto l = lhs.begin(), r = rhs.begin();
1252 for (; l != lhs.end() && r != rhs.end(); ++l, ++r) {
1253 if (*l < *r) return true;
1254 if (*l > *r) return false;
7c673cae 1255 }
f67539c2 1256 return (l == lhs.end()) && (r != rhs.end()); // lhs.length() < rhs.length()
7c673cae
FG
1257}
1258
f67539c2
TL
1259inline bool operator<=(const bufferlist& lhs, const bufferlist& rhs) {
1260 auto l = lhs.begin(), r = rhs.begin();
1261 for (; l != lhs.end() && r != rhs.end(); ++l, ++r) {
1262 if (*l < *r) return true;
1263 if (*l > *r) return false;
7c673cae 1264 }
f67539c2 1265 return l == lhs.end(); // lhs.length() <= rhs.length()
7c673cae 1266}
f67539c2
TL
1267
1268inline bool operator!=(const bufferlist &l, const bufferlist &r) {
1269 return !(l == r);
7c673cae 1270}
f67539c2
TL
1271inline bool operator>(const bufferlist& lhs, const bufferlist& rhs) {
1272 return rhs < lhs;
1273}
1274inline bool operator>=(const bufferlist& lhs, const bufferlist& rhs) {
1275 return rhs <= lhs;
7c673cae 1276}
7c673cae
FG
1277
1278std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp);
1279
494da23a 1280std::ostream& operator<<(std::ostream& out, const buffer::raw &r);
7c673cae
FG
1281
1282std::ostream& operator<<(std::ostream& out, const buffer::list& bl);
1283
31f18b77 1284inline bufferhash& operator<<(bufferhash& l, const bufferlist &r) {
7c673cae
FG
1285 l.update(r);
1286 return l;
1287}
1288
11fdf7f2 1289} // namespace buffer
7c673cae 1290
11fdf7f2 1291} // namespace ceph
7c673cae 1292
f67539c2 1293
7c673cae 1294#endif