1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
17 #if defined(__linux__) || defined(__FreeBSD__)
23 # define _XOPEN_SOURCE 600
29 #if defined(__linux__) // For malloc(2).
38 # include <sys/mman.h>
46 #if __cplusplus >= 201703L
47 #include <string_view>
48 #endif // __cplusplus >= 201703L
51 #include <type_traits>
55 #include "buffer_fwd.h"
58 # include "include/ceph_assert.h"
63 #include "inline_memory.h"
65 #define CEPH_BUFFER_API
69 class XioDispatchHook
;
73 template <typename T
> class temporary_buffer
;
78 #endif // HAVE_SEASTAR
82 using sha1_digest_t
= sha_digest_t
<20>;
88 void operator()(T
*) {}
91 // This is not unique_ptr-like smart pointer! It just signalizes ownership
92 // but DOES NOT manage the resource. It WILL LEAK if not manually deleted.
93 // It's rather a replacement for raw pointer than any other smart one.
95 // Considered options:
96 // * unique_ptr with custom deleter implemented in .cc (would provide
97 // the non-zero-cost resource management),
98 // * GSL's owner<T*> (pretty neat but would impose an extra depedency),
99 // * unique_ptr with nop deleter,
100 // * raw pointer (doesn't embed ownership enforcement - std::move).
102 struct unique_leakable_ptr
: public std::unique_ptr
<T
, ceph::nop_delete
<T
>> {
103 using std::unique_ptr
<T
, ceph::nop_delete
<T
>>::unique_ptr
;
106 namespace buffer CEPH_BUFFER_API
{
107 inline namespace v14_2_0
{
113 struct error
: public std::exception
{
114 const char *what() const throw () override
;
116 struct bad_alloc
: public error
{
117 const char *what() const throw () override
;
119 struct end_of_buffer
: public error
{
120 const char *what() const throw () override
;
122 struct malformed_input
: public error
{
123 explicit malformed_input(const std::string
& w
) {
124 snprintf(buf
, sizeof(buf
), "buffer::malformed_input: %s", w
.c_str());
126 const char *what() const throw () override
;
130 struct error_code
: public malformed_input
{
131 explicit error_code(int error
);
136 /// count of cached crc hits (matching input)
137 int get_cached_crc();
138 /// count of cached crc hits (mismatching input, required adjustment)
139 int get_cached_crc_adjusted();
140 /// count of crc cache misses
141 int get_missed_crc();
142 /// enable/disable tracking of cached crcs
143 void track_cached_crc(bool b
);
146 * an abstract raw buffer. with a reference count.
151 class raw_posix_aligned
;
152 class raw_hack_aligned
;
154 class raw_claimed_char
;
155 class raw_unshareable
; // diagnostic, unshareable char buffer
157 class raw_claim_buffer
;
161 class xio_msg_buffer
;
166 ceph::unique_leakable_ptr
<raw
> copy(const char *c
, unsigned len
);
167 ceph::unique_leakable_ptr
<raw
> create(unsigned len
);
168 ceph::unique_leakable_ptr
<raw
> create_in_mempool(unsigned len
, int mempool
);
169 raw
* claim_char(unsigned len
, char *buf
);
170 raw
* create_malloc(unsigned len
);
171 raw
* claim_malloc(unsigned len
, char *buf
);
172 raw
* create_static(unsigned len
, char *buf
);
173 ceph::unique_leakable_ptr
<raw
> create_aligned(unsigned len
, unsigned align
);
174 ceph::unique_leakable_ptr
<raw
> create_aligned_in_mempool(unsigned len
, unsigned align
, int mempool
);
175 ceph::unique_leakable_ptr
<raw
> create_page_aligned(unsigned len
);
176 ceph::unique_leakable_ptr
<raw
> create_small_page_aligned(unsigned len
);
177 raw
* create_unshareable(unsigned len
);
178 raw
* create_static(unsigned len
, char *buf
);
179 raw
* claim_buffer(unsigned len
, char *buf
, deleter del
);
182 /// create a raw buffer to wrap seastar cpu-local memory, using foreign_ptr to
183 /// make it safe to share between cpus
184 raw
* create_foreign(seastar::temporary_buffer
<char>&& buf
);
185 /// create a raw buffer to wrap seastar cpu-local memory, without the safety
186 /// of foreign_ptr. the caller must otherwise guarantee that the buffer ptr is
187 /// destructed on this cpu
188 raw
* create(seastar::temporary_buffer
<char>&& buf
);
190 #if defined(HAVE_XIO)
191 raw
* create_msg(unsigned len
, char *buf
, XioDispatchHook
*m_hook
);
195 * a buffer pointer. references (a subsequence of) a raw buffer.
197 class CEPH_BUFFER_API ptr
{
199 public: // dirty hack for testing; if it works, this will be abstracted
205 template<bool is_const
>
206 class iterator_impl
{
207 const ptr
*bp
; ///< parent ptr
208 const char *start
; ///< starting pointer into bp->c_str()
209 const char *pos
; ///< pointer into bp->c_str()
210 const char *end_ptr
; ///< pointer to bp->end_c_str()
211 const bool deep
; ///< if true, do not allow shallow ptr copies
213 iterator_impl(typename
std::conditional
<is_const
, const ptr
*, ptr
*>::type p
,
214 size_t offset
, bool d
)
216 start(p
->c_str() + offset
),
218 end_ptr(p
->end_c_str()),
225 using pointer
= typename
std::conditional
<is_const
, const char*, char *>::type
;
226 pointer
get_pos_add(size_t n
) {
231 ptr
get_ptr(size_t len
) {
233 return buffer::copy(get_pos_add(len
), len
);
235 size_t off
= pos
- bp
->c_str();
237 return ptr(*bp
, off
, len
);
241 void advance(size_t len
) {
244 throw end_of_buffer();
247 const char *get_pos() {
250 const char *get_end() {
254 size_t get_offset() {
259 return pos
== end_ptr
;
264 using const_iterator
= iterator_impl
<true>;
265 using iterator
= iterator_impl
<false>;
267 ptr() : _raw(nullptr), _off(0), _len(0) {}
268 // cppcheck-suppress noExplicitConstructor
270 ptr(ceph::unique_leakable_ptr
<raw
> r
);
271 // cppcheck-suppress noExplicitConstructor
273 ptr(const char *d
, unsigned l
);
275 ptr(ptr
&& p
) noexcept
;
276 ptr(const ptr
& p
, unsigned o
, unsigned l
);
277 ptr(const ptr
& p
, ceph::unique_leakable_ptr
<raw
> r
);
278 ptr
& operator= (const ptr
& p
);
279 ptr
& operator= (ptr
&& p
) noexcept
;
281 // BE CAREFUL: this destructor is called also for hypercombined ptr_node.
282 // After freeing underlying raw, `*this` can become inaccessible as well!
286 bool have_raw() const { return _raw
? true:false; }
288 ceph::unique_leakable_ptr
<raw
> clone();
289 void swap(ptr
& other
) noexcept
;
291 iterator
begin(size_t offset
=0) {
292 return iterator(this, offset
, false);
294 const_iterator
begin(size_t offset
=0) const {
295 return const_iterator(this, offset
, false);
297 const_iterator
cbegin() const {
300 const_iterator
begin_deep(size_t offset
=0) const {
301 return const_iterator(this, offset
, true);
305 bool is_aligned(unsigned align
) const {
306 return ((long)c_str() & (align
-1)) == 0;
308 bool is_page_aligned() const { return is_aligned(CEPH_PAGE_SIZE
); }
309 bool is_n_align_sized(unsigned align
) const
311 return (length() % align
) == 0;
313 bool is_n_page_sized() const { return is_n_align_sized(CEPH_PAGE_SIZE
); }
314 bool is_partial() const {
315 return have_raw() && (start() > 0 || end() < raw_length());
318 int get_mempool() const;
319 void reassign_to_mempool(int pool
);
320 void try_assign_to_mempool(int pool
);
323 raw
*get_raw() const { return _raw
; }
324 const char *c_str() const;
326 const char *end_c_str() const;
328 unsigned length() const { return _len
; }
329 unsigned offset() const { return _off
; }
330 unsigned start() const { return _off
; }
331 unsigned end() const { return _off
+ _len
; }
332 unsigned unused_tail_length() const;
333 const char& operator[](unsigned n
) const;
334 char& operator[](unsigned n
);
336 const char *raw_c_str() const;
337 unsigned raw_length() const;
338 int raw_nref() const;
340 void copy_out(unsigned o
, unsigned l
, char *dest
) const;
342 unsigned wasted() const;
344 int cmp(const ptr
& o
) const;
345 bool is_zero() const;
348 void set_offset(unsigned o
) {
350 ceph_assert(raw_length() >= o
);
352 assert(raw_length() >= o
);
356 void set_length(unsigned l
) {
358 ceph_assert(raw_length() >= l
);
360 assert(raw_length() >= l
);
365 unsigned append(char c
);
366 unsigned append(const char *p
, unsigned l
);
367 #if __cplusplus >= 201703L
368 inline unsigned append(std::string_view s
) {
369 return append(s
.data(), s
.length());
371 #endif // __cplusplus >= 201703L
372 void copy_in(unsigned o
, unsigned l
, const char *src
, bool crc_reset
= true);
373 void zero(bool crc_reset
= true);
374 void zero(unsigned o
, unsigned l
, bool crc_reset
= true);
375 unsigned append_zeros(unsigned l
);
378 /// create a temporary_buffer, copying the ptr as its deleter
379 operator seastar::temporary_buffer
<char>() &;
380 /// convert to temporary_buffer, stealing the ptr as its deleter
381 operator seastar::temporary_buffer
<char>() &&;
382 #endif // HAVE_SEASTAR
388 mutable ptr_hook
* next
;
390 ptr_hook() = default;
391 ptr_hook(ptr_hook
* const next
)
396 class ptr_node
: public ptr_hook
, public ptr
{
399 ptr_node
* operator()(const ptr_node
& clone_this
);
402 void operator()(ptr_node
* const delete_this
) {
403 if (!dispose_if_hypercombined(delete_this
)) {
409 ~ptr_node() = default;
411 static std::unique_ptr
<ptr_node
, disposer
>
412 create(ceph::unique_leakable_ptr
<raw
> r
) {
413 return create_hypercombined(std::move(r
));
415 static std::unique_ptr
<ptr_node
, disposer
> create(raw
* const r
) {
416 return create_hypercombined(r
);
418 static std::unique_ptr
<ptr_node
, disposer
> create(const unsigned l
) {
419 return create_hypercombined(buffer::create(l
));
421 template <class... Args
>
422 static std::unique_ptr
<ptr_node
, disposer
> create(Args
&&... args
) {
423 return std::unique_ptr
<ptr_node
, disposer
>(
424 new ptr_node(std::forward
<Args
>(args
)...));
427 static ptr_node
* copy_hypercombined(const ptr_node
& copy_this
);
430 template <class... Args
>
431 ptr_node(Args
&&... args
) : ptr(std::forward
<Args
>(args
)...) {
433 ptr_node(const ptr_node
&) = default;
435 ptr
& operator= (const ptr
& p
) = delete;
436 ptr
& operator= (ptr
&& p
) noexcept
= delete;
437 ptr_node
& operator= (const ptr_node
& p
) = delete;
438 ptr_node
& operator= (ptr_node
&& p
) noexcept
= delete;
439 void swap(ptr
& other
) noexcept
= delete;
440 void swap(ptr_node
& other
) noexcept
= delete;
442 static bool dispose_if_hypercombined(ptr_node
* delete_this
);
443 static std::unique_ptr
<ptr_node
, disposer
> create_hypercombined(
445 static std::unique_ptr
<ptr_node
, disposer
> create_hypercombined(
446 ceph::unique_leakable_ptr
<raw
> r
);
449 * list - the useful bit!
452 class CEPH_BUFFER_API list
{
454 // this the very low-level implementation of singly linked list
455 // ceph::buffer::list is built on. We don't use intrusive slist
456 // of Boost (or any other 3rd party) to save extra dependencies
457 // in our public headers.
459 // _root.next can be thought as _head
466 class buffers_iterator
{
467 typename
std::conditional
<
468 std::is_const
<T
>::value
, const ptr_hook
*, ptr_hook
*>::type cur
;
469 template <class U
> friend class buffers_iterator
;
471 using value_type
= T
;
472 using reference
= typename
std::add_lvalue_reference
<T
>::type
;
473 using pointer
= typename
std::add_pointer
<T
>::type
;
474 using difference_type
= std::ptrdiff_t;
475 using iterator_category
= std::forward_iterator_tag
;
478 buffers_iterator(U
* const p
)
482 buffers_iterator(const buffers_iterator
<U
>& other
)
485 buffers_iterator() = default;
487 T
& operator*() const {
488 return *reinterpret_cast<T
*>(cur
);
490 T
* operator->() const {
491 return reinterpret_cast<T
*>(cur
);
494 buffers_iterator
& operator++() {
498 buffers_iterator
operator++(int) {
499 const auto temp(*this);
505 buffers_iterator
& operator=(buffers_iterator
<U
>& other
) {
510 bool operator==(const buffers_iterator
& rhs
) const {
511 return cur
== rhs
.cur
;
513 bool operator!=(const buffers_iterator
& rhs
) const {
514 return !(*this==rhs
);
517 using citer_t
= buffers_iterator
<typename
std::add_const
<T
>::type
>;
518 operator citer_t() const {
523 typedef buffers_iterator
<const ptr_node
> const_iterator
;
524 typedef buffers_iterator
<ptr_node
> iterator
;
526 typedef const ptr_node
& const_reference
;
527 typedef ptr_node
& reference
;
534 buffers_t(const buffers_t
&) = delete;
535 buffers_t(buffers_t
&& other
)
536 : _root(other
._root
.next
== &other
._root
? &_root
: other
._root
.next
),
537 _tail(other
._tail
== &other
._root
? &_root
: other
._tail
),
539 other
._root
.next
= &other
._root
;
540 other
._tail
= &other
._root
;
543 _tail
->next
= &_root
;
545 buffers_t
& operator=(buffers_t
&& other
) {
546 if (&other
!= this) {
553 void push_back(reference item
) {
555 // this updates _root.next when called on empty
561 void push_front(reference item
) {
562 item
.next
= _root
.next
;
564 _tail
= _tail
== &_root
? &item
: _tail
;
569 iterator
erase_after(const_iterator it
) {
570 const auto* to_erase
= it
->next
;
572 it
->next
= to_erase
->next
;
573 _root
.next
= _root
.next
== to_erase
? to_erase
->next
: _root
.next
;
574 _tail
= _tail
== to_erase
? (ptr_hook
*)&*it
: _tail
;
579 void insert_after(const_iterator it
, reference item
) {
580 item
.next
= it
->next
;
582 _root
.next
= it
== end() ? &item
: _root
.next
;
583 _tail
= const_iterator(_tail
) == it
? &item
: _tail
;
587 void splice_back(buffers_t
& other
) {
588 if (other
._size
== 0) {
592 other
._tail
->next
= &_root
;
593 // will update root.next if empty() == true
594 _tail
->next
= other
._root
.next
;
596 _size
+= other
._size
;
598 other
._root
.next
= &other
._root
;
599 other
._tail
= &other
._root
;
603 std::size_t size() const { return _size
; }
604 bool empty() const { return _tail
== &_root
; }
606 const_iterator
begin() const {
609 const_iterator
before_begin() const {
612 const_iterator
end() const {
618 iterator
before_begin() {
626 return reinterpret_cast<reference
>(*_root
.next
);
629 return reinterpret_cast<reference
>(*_tail
);
631 const_reference
front() const {
632 return reinterpret_cast<const_reference
>(*_root
.next
);
634 const_reference
back() const {
635 return reinterpret_cast<const_reference
>(*_tail
);
638 void clone_from(const buffers_t
& other
) {
640 for (auto& node
: other
) {
641 ptr_node
* clone
= ptr_node::cloner()(node
);
645 void clear_and_dispose() {
646 for (auto it
= begin(); it
!= end(); /* nop */) {
649 ptr_node::disposer()(&node
);
655 iterator
erase_after_and_dispose(iterator it
) {
656 auto* to_dispose
= &*std::next(it
);
657 auto ret
= erase_after(it
);
658 ptr_node::disposer()(to_dispose
);
662 void swap(buffers_t
& other
) {
663 const auto copy_root
= _root
;
665 other
._root
.next
== &other
._root
? &this->_root
: other
._root
.next
;
667 copy_root
.next
== &_root
? &other
._root
: copy_root
.next
;
669 const auto copy_tail
= _tail
;
670 _tail
= other
._tail
== &other
._root
? &this->_root
: other
._tail
;
671 other
._tail
= copy_tail
== &_root
? &other
._root
: copy_tail
;
673 _tail
->next
= &_root
;
674 other
._tail
->next
= &other
._root
;
675 std::swap(_size
, other
._size
);
685 // track bufferptr we can modify (especially ::append() to). Not all bptrs
686 // bufferlist holds have this trait -- if somebody ::push_back(const ptr&),
687 // he expects it won't change.
690 unsigned _memcopy_count
; //the total of memcopy using rebuild().
692 template <bool is_const
>
693 class CEPH_BUFFER_API iterator_impl
{
695 typedef typename
std::conditional
<is_const
,
698 typedef typename
std::conditional
<is_const
,
700 buffers_t
>::type list_t
;
701 typedef typename
std::conditional
<is_const
,
702 typename
buffers_t::const_iterator
,
703 typename
buffers_t::iterator
>::type list_iter_t
;
705 list_t
* ls
; // meh.. just here to avoid an extra pointer dereference..
707 unsigned off
; // in bl
708 unsigned p_off
; // in *p
709 friend class iterator_impl
<true>;
712 using iterator_category
= std::forward_iterator_tag
;
713 using value_type
= typename
std::conditional
<is_const
, const char, char>::type
;
714 using difference_type
= std::ptrdiff_t;
715 using pointer
= typename
std::add_pointer
<value_type
>::type
;
716 using reference
= typename
std::add_lvalue_reference
<value_type
>::type
;
718 // constructor. position.
720 : bl(0), ls(0), off(0), p_off(0) {}
721 iterator_impl(bl_t
*l
, unsigned o
=0);
722 iterator_impl(bl_t
*l
, unsigned o
, list_iter_t ip
, unsigned po
)
723 : bl(l
), ls(&bl
->_buffers
), p(ip
), off(o
), p_off(po
) {}
724 iterator_impl(const list::iterator
& i
);
726 /// get current iterator offset in buffer::list
727 unsigned get_off() const { return off
; }
729 /// get number of bytes remaining from iterator position to the end of the buffer::list
730 unsigned get_remaining() const { return bl
->length() - off
; }
732 /// true if iterator is at the end of the buffer::list
734 return p
== ls
->end();
735 //return off == bl->length();
738 void advance(int o
) = delete;
739 void advance(unsigned o
);
740 void advance(size_t o
) { advance(static_cast<unsigned>(o
)); }
741 void seek(unsigned o
);
742 char operator*() const;
743 iterator_impl
& operator++();
744 ptr
get_current_ptr() const;
745 bool is_pointing_same_raw(const ptr
& other
) const;
747 bl_t
& get_bl() const { return *bl
; }
750 // note that these all _append_ to dest!
751 void copy(unsigned len
, char *dest
);
752 // deprecated, use copy_deep()
753 void copy(unsigned len
, ptr
&dest
) __attribute__((deprecated
));
754 void copy_deep(unsigned len
, ptr
&dest
);
755 void copy_shallow(unsigned len
, ptr
&dest
);
756 void copy(unsigned len
, list
&dest
);
757 void copy(unsigned len
, std::string
&dest
);
758 void copy_all(list
&dest
);
760 // get a pointer to the currenet iterator position, return the
761 // number of bytes we can read from that position (up to want),
762 // and advance the iterator by that amount.
763 size_t get_ptr_and_advance(size_t want
, const char **p
);
765 /// calculate crc from iterator position
766 uint32_t crc32c(size_t length
, uint32_t crc
);
768 friend bool operator==(const iterator_impl
& lhs
,
769 const iterator_impl
& rhs
) {
770 return &lhs
.get_bl() == &rhs
.get_bl() && lhs
.get_off() == rhs
.get_off();
772 friend bool operator!=(const iterator_impl
& lhs
,
773 const iterator_impl
& rhs
) {
774 return &lhs
.get_bl() != &rhs
.get_bl() || lhs
.get_off() != rhs
.get_off();
779 typedef iterator_impl
<true> const_iterator
;
781 class CEPH_BUFFER_API iterator
: public iterator_impl
<false> {
783 iterator() = default;
784 iterator(bl_t
*l
, unsigned o
=0);
785 iterator(bl_t
*l
, unsigned o
, list_iter_t ip
, unsigned po
);
787 void copy_in(unsigned len
, const char *src
, bool crc_reset
= true);
788 void copy_in(unsigned len
, const list
& otherl
);
797 class contiguous_appender
{
798 ceph::bufferlist
& bl
;
799 ceph::bufferlist::reserve_t space
;
803 /// running count of bytes appended that are not reflected by @pos
804 size_t out_of_band_offset
= 0;
806 contiguous_appender(bufferlist
& bl
, size_t len
, bool d
)
808 space(bl
.obtain_contiguous_space(len
)),
813 void flush_and_continue() {
814 const size_t l
= pos
- space
.bp_data
;
823 ~contiguous_appender() {
824 flush_and_continue();
827 size_t get_out_of_band_offset() const {
828 return out_of_band_offset
;
830 void append(const char* __restrict__ p
, size_t l
) {
831 maybe_inline_memcpy(pos
, p
, l
, 16);
834 char *get_pos_add(size_t len
) {
843 void append(const bufferptr
& p
) {
844 const auto plen
= p
.length();
849 append(p
.c_str(), plen
);
851 flush_and_continue();
853 space
= bl
.obtain_contiguous_space(0);
854 out_of_band_offset
+= plen
;
857 void append(const bufferlist
& l
) {
859 for (const auto &p
: l
._buffers
) {
860 append(p
.c_str(), p
.length());
863 flush_and_continue();
865 space
= bl
.obtain_contiguous_space(0);
866 out_of_band_offset
+= l
.length();
870 size_t get_logical_offset() {
871 return out_of_band_offset
+ (pos
- space
.bp_data
);
875 contiguous_appender
get_contiguous_appender(size_t len
, bool deep
=false) {
876 return contiguous_appender(*this, len
, deep
);
879 class contiguous_filler
{
883 contiguous_filler(char* const pos
) : pos(pos
) {}
886 void advance(const unsigned len
) {
889 void copy_in(const unsigned len
, const char* const src
) {
890 memcpy(pos
, src
, len
);
897 // The contiguous_filler is supposed to be not costlier than a single
898 // pointer. Keep it dumb, please.
899 static_assert(sizeof(contiguous_filler
) == sizeof(char*),
900 "contiguous_filler should be no costlier than pointer");
902 class page_aligned_appender
{
908 page_aligned_appender(list
*l
, unsigned min_pages
)
910 min_alloc(min_pages
* CEPH_PAGE_SIZE
),
911 pos(nullptr), end(nullptr) {}
916 ~page_aligned_appender() {
921 if (pos
&& pos
!= buffer
.c_str()) {
922 size_t len
= pos
- buffer
.c_str();
923 pbl
->append(buffer
, 0, len
);
924 buffer
.set_length(buffer
.length() - len
);
925 buffer
.set_offset(buffer
.offset() + len
);
929 void append(const char *buf
, size_t len
) {
932 size_t alloc
= (len
+ CEPH_PAGE_SIZE
- 1) & CEPH_PAGE_MASK
;
933 if (alloc
< min_alloc
) {
936 buffer
= create_page_aligned(alloc
);
937 pos
= buffer
.c_str();
938 end
= buffer
.end_c_str();
941 if (l
> (size_t)(end
- pos
)) {
949 pbl
->append(buffer
, 0, buffer
.length());
956 page_aligned_appender
get_page_aligned_appender(unsigned min_pages
=1) {
957 return page_aligned_appender(this, min_pages
);
961 mutable iterator last_p
;
963 // always_empty_bptr has no underlying raw but its _len is always 0.
964 // This is useful for e.g. get_append_buffer_unused_tail_length() as
965 // it allows to avoid conditionals on hot paths.
966 static ptr always_empty_bptr
;
967 ptr_node
& refill_append_space(const unsigned len
);
972 : _carriage(&always_empty_bptr
),
977 // cppcheck-suppress noExplicitConstructor
978 // cppcheck-suppress noExplicitConstructor
979 list(unsigned prealloc
)
980 : _carriage(&always_empty_bptr
),
987 list(const list
& other
)
988 : _carriage(&always_empty_bptr
),
990 _memcopy_count(other
._memcopy_count
),
992 _buffers
.clone_from(other
._buffers
);
994 list(list
&& other
) noexcept
;
997 _buffers
.clear_and_dispose();
1000 list
& operator= (const list
& other
) {
1001 if (this != &other
) {
1002 _carriage
= &always_empty_bptr
;
1003 _buffers
.clone_from(other
._buffers
);
1008 list
& operator= (list
&& other
) noexcept
{
1009 _buffers
= std::move(other
._buffers
);
1010 _carriage
= other
._carriage
;
1012 _memcopy_count
= other
._memcopy_count
;
1018 uint64_t get_wasted_space() const;
1019 unsigned get_num_buffers() const { return _buffers
.size(); }
1020 const ptr_node
& front() const { return _buffers
.front(); }
1021 const ptr_node
& back() const { return _buffers
.back(); }
1023 int get_mempool() const;
1024 void reassign_to_mempool(int pool
);
1025 void try_assign_to_mempool(int pool
);
1027 size_t get_append_buffer_unused_tail_length() const {
1028 return _carriage
->unused_tail_length();
1031 unsigned get_memcopy_count() const {return _memcopy_count
; }
1032 const buffers_t
& buffers() const { return _buffers
; }
1033 void swap(list
& other
) noexcept
;
1034 unsigned length() const {
1036 // DEBUG: verify _len
1038 for (std::list
<ptr
>::const_iterator it
= _buffers
.begin();
1039 it
!= _buffers
.end();
1041 len
+= (*it
).length();
1044 ceph_assert(len
== _len
);
1046 assert(len
== _len
);
1052 bool contents_equal(const buffer::list
& other
) const;
1054 bool is_provided_buffer(const char *dst
) const;
1055 bool is_aligned(unsigned align
) const;
1056 bool is_page_aligned() const;
1057 bool is_n_align_sized(unsigned align
) const;
1058 bool is_n_page_sized() const;
1059 bool is_aligned_size_and_memory(unsigned align_size
,
1060 unsigned align_memory
) const;
1062 bool is_zero() const;
1065 void clear() noexcept
{
1066 _carriage
= &always_empty_bptr
;
1067 _buffers
.clear_and_dispose();
1072 void push_back(const ptr
& bp
) {
1073 if (bp
.length() == 0)
1075 _buffers
.push_back(*ptr_node::create(bp
).release());
1076 _len
+= bp
.length();
1078 void push_back(ptr
&& bp
) {
1079 if (bp
.length() == 0)
1081 _len
+= bp
.length();
1082 _buffers
.push_back(*ptr_node::create(std::move(bp
)).release());
1083 _carriage
= &always_empty_bptr
;
1085 void push_back(const ptr_node
&) = delete;
1086 void push_back(ptr_node
&) = delete;
1087 void push_back(ptr_node
&&) = delete;
1088 void push_back(std::unique_ptr
<ptr_node
, ptr_node::disposer
> bp
) {
1089 if (bp
->length() == 0)
1091 _carriage
= bp
.get();
1092 _len
+= bp
->length();
1093 _buffers
.push_back(*bp
.release());
1095 void push_back(raw
* const r
) {
1096 _buffers
.push_back(*ptr_node::create(r
).release());
1097 _carriage
= &_buffers
.back();
1098 _len
+= _buffers
.back().length();
1100 void push_back(ceph::unique_leakable_ptr
<raw
> r
) {
1101 push_back(r
.release());
1105 void zero(unsigned o
, unsigned l
);
1107 bool is_contiguous() const;
1109 void rebuild(std::unique_ptr
<ptr_node
, ptr_node::disposer
> nb
);
1110 bool rebuild_aligned(unsigned align
);
1111 // max_buffers = 0 mean don't care _buffers.size(), other
1112 // must make _buffers.size() <= max_buffers after rebuilding.
1113 bool rebuild_aligned_size_and_memory(unsigned align_size
,
1114 unsigned align_memory
,
1115 unsigned max_buffers
= 0);
1116 bool rebuild_page_aligned();
1118 void reserve(size_t prealloc
);
1120 // assignment-op with move semantics
1121 const static unsigned int CLAIM_DEFAULT
= 0;
1122 const static unsigned int CLAIM_ALLOW_NONSHAREABLE
= 1;
1124 void claim(list
& bl
, unsigned int flags
= CLAIM_DEFAULT
);
1125 void claim_append(list
& bl
, unsigned int flags
= CLAIM_DEFAULT
);
1126 // only for bl is bufferlist::page_aligned_appender
1127 void claim_append_piecewise(list
& bl
);
1129 // copy with explicit volatile-sharing semantics
1130 void share(const list
& bl
)
1134 for (const auto& bp
: bl
._buffers
) {
1135 _buffers
.push_back(*ptr_node::create(bp
).release());
1142 /// convert the bufferlist into a network packet
1143 operator seastar::net::packet() &&;
1147 return iterator(this, 0);
1150 return iterator(this, _len
, _buffers
.end(), 0);
1153 const_iterator
begin() const {
1154 return const_iterator(this, 0);
1156 const_iterator
cbegin() const {
1159 const_iterator
end() const {
1160 return const_iterator(this, _len
, _buffers
.end(), 0);
1163 // crope lookalikes.
1164 // **** WARNING: this are horribly inefficient for large bufferlists. ****
1165 void copy(unsigned off
, unsigned len
, char *dest
) const;
1166 void copy(unsigned off
, unsigned len
, list
&dest
) const;
1167 void copy(unsigned off
, unsigned len
, std::string
& dest
) const;
1168 void copy_in(unsigned off
, unsigned len
, const char *src
, bool crc_reset
= true);
1169 void copy_in(unsigned off
, unsigned len
, const list
& src
);
1171 void append(char c
);
1172 void append(const char *data
, unsigned len
);
1173 void append(std::string s
) {
1174 append(s
.data(), s
.length());
1176 #if __cplusplus >= 201703L
1177 // To forcibly disambiguate between string and string_view in the
1179 template<std::size_t N
>
1180 void append(const char (&s
)[N
]) {
1183 void append(const char* s
) {
1184 append(s
, strlen(s
));
1186 void append(std::string_view s
) {
1187 append(s
.data(), s
.length());
1189 #endif // __cplusplus >= 201703L
1190 void append(const ptr
& bp
);
1191 void append(ptr
&& bp
);
1192 void append(const ptr
& bp
, unsigned off
, unsigned len
);
1193 void append(const list
& bl
);
1194 void append(std::istream
& in
);
1195 contiguous_filler
append_hole(unsigned len
);
1196 void append_zero(unsigned len
);
1197 void prepend_zero(unsigned len
);
1199 reserve_t
obtain_contiguous_space(unsigned len
);
1204 const char& operator[](unsigned n
) const;
1206 std::string
to_str() const;
1208 void substr_of(const list
& other
, unsigned off
, unsigned len
);
1211 void splice(unsigned off
, unsigned len
, list
*claim_by
=0 /*, bufferlist& replace_with */);
1212 void write(int off
, int len
, std::ostream
& out
) const;
1214 void encode_base64(list
& o
);
1215 void decode_base64(list
& o
);
1217 void write_stream(std::ostream
&out
) const;
1218 void hexdump(std::ostream
&out
, bool trailing_newline
= true) const;
1219 int read_file(const char *fn
, std::string
*error
);
1220 ssize_t
read_fd(int fd
, size_t len
);
1221 int write_file(const char *fn
, int mode
=0644);
1222 int write_fd(int fd
) const;
1223 int write_fd(int fd
, uint64_t offset
) const;
1224 template<typename VectorT
>
1225 void prepare_iov(VectorT
*piov
) const {
1227 ceph_assert(_buffers
.size() <= IOV_MAX
);
1229 assert(_buffers
.size() <= IOV_MAX
);
1231 piov
->resize(_buffers
.size());
1233 for (auto& p
: _buffers
) {
1234 (*piov
)[n
].iov_base
= (void *)p
.c_str();
1235 (*piov
)[n
].iov_len
= p
.length();
1239 uint32_t crc32c(uint32_t crc
) const;
1240 void invalidate_crc();
1241 sha1_digest_t
sha1();
1243 // These functions return a bufferlist with a pointer to a single
1244 // static buffer. They /must/ not outlive the memory they
1246 static list
static_from_mem(char* c
, size_t l
);
1247 static list
static_from_cstring(char* c
);
1248 static list
static_from_string(std::string
& s
);
1251 } // inline namespace v14_2_0
1254 * efficient hash of one or more bufferlists
1262 // cppcheck-suppress noExplicitConstructor
1263 hash(uint32_t init
) : crc(init
) { }
1265 void update(const buffer::list
& bl
) {
1266 crc
= bl
.crc32c(crc
);
1274 inline bool operator>(bufferlist
& l
, bufferlist
& r
) {
1275 for (unsigned p
= 0; ; p
++) {
1276 if (l
.length() > p
&& r
.length() == p
) return true;
1277 if (l
.length() == p
) return false;
1278 if (l
[p
] > r
[p
]) return true;
1279 if (l
[p
] < r
[p
]) return false;
1282 inline bool operator>=(bufferlist
& l
, bufferlist
& r
) {
1283 for (unsigned p
= 0; ; p
++) {
1284 if (l
.length() > p
&& r
.length() == p
) return true;
1285 if (r
.length() == p
&& l
.length() == p
) return true;
1286 if (l
.length() == p
&& r
.length() > p
) return false;
1287 if (l
[p
] > r
[p
]) return true;
1288 if (l
[p
] < r
[p
]) return false;
1292 inline bool operator==(const bufferlist
&l
, const bufferlist
&r
) {
1293 if (l
.length() != r
.length())
1295 for (unsigned p
= 0; p
< l
.length(); p
++) {
1301 inline bool operator<(bufferlist
& l
, bufferlist
& r
) {
1304 inline bool operator<=(bufferlist
& l
, bufferlist
& r
) {
1309 std::ostream
& operator<<(std::ostream
& out
, const buffer::ptr
& bp
);
1311 std::ostream
& operator<<(std::ostream
& out
, const buffer::raw
&r
);
1313 std::ostream
& operator<<(std::ostream
& out
, const buffer::list
& bl
);
1315 std::ostream
& operator<<(std::ostream
& out
, const buffer::error
& e
);
1317 inline bufferhash
& operator<<(bufferhash
& l
, const bufferlist
&r
) {
1322 } // namespace buffer
1324 #if defined(HAVE_XIO)
1325 xio_reg_mem
* get_xio_mp(const buffer::ptr
& bp
);