]> git.proxmox.com Git - ceph.git/blob - ceph/src/include/buffer.h
b8c78210eae0e81057f0396f91c1678ae4716b8a
[ceph.git] / ceph / src / include / buffer.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
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
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
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
37 #ifndef __CYGWIN__
38 # include <sys/mman.h>
39 #endif
40
41 #include <iosfwd>
42 #include <iomanip>
43 #include <list>
44 #include <vector>
45 #include <string>
46 #if __cplusplus >= 201703L
47 #include <string_view>
48 #endif // __cplusplus >= 201703L
49
50 #include <exception>
51 #include <type_traits>
52
53 #include "page.h"
54 #include "crc32c.h"
55 #include "buffer_fwd.h"
56
57 #ifdef __CEPH__
58 # include "include/ceph_assert.h"
59 #else
60 # include <assert.h>
61 #endif
62
63 #include "inline_memory.h"
64
65 #define CEPH_BUFFER_API
66
67 #if defined(HAVE_XIO)
68 struct xio_reg_mem;
69 class XioDispatchHook;
70 #endif
71 #ifdef HAVE_SEASTAR
72 namespace seastar {
73 template <typename T> class temporary_buffer;
74 namespace net {
75 class packet;
76 }
77 }
78 #endif // HAVE_SEASTAR
79 class deleter;
80 template<uint8_t S>
81 struct sha_digest_t;
82 using sha1_digest_t = sha_digest_t<20>;
83
84 namespace ceph {
85
86 template <class T>
87 struct nop_delete {
88 void operator()(T*) {}
89 };
90
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.
94 //
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).
101 template <class T>
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;
104 };
105
106 namespace buffer CEPH_BUFFER_API {
107 inline namespace v14_2_0 {
108
109 /*
110 * exceptions
111 */
112
113 struct error : public std::exception{
114 const char *what() const throw () override;
115 };
116 struct bad_alloc : public error {
117 const char *what() const throw () override;
118 };
119 struct end_of_buffer : public error {
120 const char *what() const throw () override;
121 };
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());
125 }
126 const char *what() const throw () override;
127 private:
128 char buf[256];
129 };
130 struct error_code : public malformed_input {
131 explicit error_code(int error);
132 int code;
133 };
134
135
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);
144
145 /*
146 * an abstract raw buffer. with a reference count.
147 */
148 class raw;
149 class raw_malloc;
150 class raw_static;
151 class raw_posix_aligned;
152 class raw_hack_aligned;
153 class raw_char;
154 class raw_claimed_char;
155 class raw_unshareable; // diagnostic, unshareable char buffer
156 class raw_combined;
157 class raw_claim_buffer;
158
159
160 class xio_mempool;
161 class xio_msg_buffer;
162
163 /*
164 * named constructors
165 */
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);
180
181 #ifdef HAVE_SEASTAR
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);
189 #endif
190 #if defined(HAVE_XIO)
191 raw* create_msg(unsigned len, char *buf, XioDispatchHook *m_hook);
192 #endif
193
194 /*
195 * a buffer pointer. references (a subsequence of) a raw buffer.
196 */
197 class CEPH_BUFFER_API ptr {
198 raw *_raw;
199 public: // dirty hack for testing; if it works, this will be abstracted
200 unsigned _off, _len;
201 private:
202
203 void release();
204
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
212
213 iterator_impl(typename std::conditional<is_const, const ptr*, ptr*>::type p,
214 size_t offset, bool d)
215 : bp(p),
216 start(p->c_str() + offset),
217 pos(start),
218 end_ptr(p->end_c_str()),
219 deep(d)
220 {}
221
222 friend class ptr;
223
224 public:
225 using pointer = typename std::conditional<is_const, const char*, char *>::type;
226 pointer get_pos_add(size_t n) {
227 auto r = pos;
228 advance(n);
229 return r;
230 }
231 ptr get_ptr(size_t len) {
232 if (deep) {
233 return buffer::copy(get_pos_add(len), len);
234 } else {
235 size_t off = pos - bp->c_str();
236 advance(len);
237 return ptr(*bp, off, len);
238 }
239 }
240
241 void advance(size_t len) {
242 pos += len;
243 if (pos > end_ptr)
244 throw end_of_buffer();
245 }
246
247 const char *get_pos() {
248 return pos;
249 }
250 const char *get_end() {
251 return end_ptr;
252 }
253
254 size_t get_offset() {
255 return pos - start;
256 }
257
258 bool end() const {
259 return pos == end_ptr;
260 }
261 };
262
263 public:
264 using const_iterator = iterator_impl<true>;
265 using iterator = iterator_impl<false>;
266
267 ptr() : _raw(nullptr), _off(0), _len(0) {}
268 // cppcheck-suppress noExplicitConstructor
269 ptr(raw* r);
270 ptr(ceph::unique_leakable_ptr<raw> r);
271 // cppcheck-suppress noExplicitConstructor
272 ptr(unsigned l);
273 ptr(const char *d, unsigned l);
274 ptr(const ptr& p);
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;
280 ~ptr() {
281 // BE CAREFUL: this destructor is called also for hypercombined ptr_node.
282 // After freeing underlying raw, `*this` can become inaccessible as well!
283 release();
284 }
285
286 bool have_raw() const { return _raw ? true:false; }
287
288 ceph::unique_leakable_ptr<raw> clone();
289 void swap(ptr& other) noexcept;
290
291 iterator begin(size_t offset=0) {
292 return iterator(this, offset, false);
293 }
294 const_iterator begin(size_t offset=0) const {
295 return const_iterator(this, offset, false);
296 }
297 const_iterator cbegin() const {
298 return begin();
299 }
300 const_iterator begin_deep(size_t offset=0) const {
301 return const_iterator(this, offset, true);
302 }
303
304 // misc
305 bool is_aligned(unsigned align) const {
306 return ((long)c_str() & (align-1)) == 0;
307 }
308 bool is_page_aligned() const { return is_aligned(CEPH_PAGE_SIZE); }
309 bool is_n_align_sized(unsigned align) const
310 {
311 return (length() % align) == 0;
312 }
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());
316 }
317
318 int get_mempool() const;
319 void reassign_to_mempool(int pool);
320 void try_assign_to_mempool(int pool);
321
322 // accessors
323 raw *get_raw() const { return _raw; }
324 const char *c_str() const;
325 char *c_str();
326 const char *end_c_str() const;
327 char *end_c_str();
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);
335
336 const char *raw_c_str() const;
337 unsigned raw_length() const;
338 int raw_nref() const;
339
340 void copy_out(unsigned o, unsigned l, char *dest) const;
341
342 unsigned wasted() const;
343
344 int cmp(const ptr& o) const;
345 bool is_zero() const;
346
347 // modifiers
348 void set_offset(unsigned o) {
349 #ifdef __CEPH__
350 ceph_assert(raw_length() >= o);
351 #else
352 assert(raw_length() >= o);
353 #endif
354 _off = o;
355 }
356 void set_length(unsigned l) {
357 #ifdef __CEPH__
358 ceph_assert(raw_length() >= l);
359 #else
360 assert(raw_length() >= l);
361 #endif
362 _len = l;
363 }
364
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());
370 }
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);
376
377 #ifdef HAVE_SEASTAR
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
383
384 };
385
386
387 struct ptr_hook {
388 mutable ptr_hook* next;
389
390 ptr_hook() = default;
391 ptr_hook(ptr_hook* const next)
392 : next(next) {
393 }
394 };
395
396 class ptr_node : public ptr_hook, public ptr {
397 public:
398 struct cloner {
399 ptr_node* operator()(const ptr_node& clone_this);
400 };
401 struct disposer {
402 void operator()(ptr_node* const delete_this) {
403 if (!dispose_if_hypercombined(delete_this)) {
404 delete delete_this;
405 }
406 }
407 };
408
409 ~ptr_node() = default;
410
411 static std::unique_ptr<ptr_node, disposer>
412 create(ceph::unique_leakable_ptr<raw> r) {
413 return create_hypercombined(std::move(r));
414 }
415 static std::unique_ptr<ptr_node, disposer> create(raw* const r) {
416 return create_hypercombined(r);
417 }
418 static std::unique_ptr<ptr_node, disposer> create(const unsigned l) {
419 return create_hypercombined(buffer::create(l));
420 }
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)...));
425 }
426
427 static ptr_node* copy_hypercombined(const ptr_node& copy_this);
428
429 private:
430 template <class... Args>
431 ptr_node(Args&&... args) : ptr(std::forward<Args>(args)...) {
432 }
433 ptr_node(const ptr_node&) = default;
434
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;
441
442 static bool dispose_if_hypercombined(ptr_node* delete_this);
443 static std::unique_ptr<ptr_node, disposer> create_hypercombined(
444 buffer::raw* r);
445 static std::unique_ptr<ptr_node, disposer> create_hypercombined(
446 ceph::unique_leakable_ptr<raw> r);
447 };
448 /*
449 * list - the useful bit!
450 */
451
452 class CEPH_BUFFER_API list {
453 public:
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.
458 class buffers_t {
459 // _root.next can be thought as _head
460 ptr_hook _root;
461 ptr_hook* _tail;
462 std::size_t _size;
463
464 public:
465 template <class T>
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;
470 public:
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;
476
477 template <class U>
478 buffers_iterator(U* const p)
479 : cur(p) {
480 }
481 template <class U>
482 buffers_iterator(const buffers_iterator<U>& other)
483 : cur(other.cur) {
484 }
485 buffers_iterator() = default;
486
487 T& operator*() const {
488 return *reinterpret_cast<T*>(cur);
489 }
490 T* operator->() const {
491 return reinterpret_cast<T*>(cur);
492 }
493
494 buffers_iterator& operator++() {
495 cur = cur->next;
496 return *this;
497 }
498 buffers_iterator operator++(int) {
499 const auto temp(*this);
500 ++*this;
501 return temp;
502 }
503
504 template <class U>
505 buffers_iterator& operator=(buffers_iterator<U>& other) {
506 cur = other.cur;
507 return *this;
508 }
509
510 bool operator==(const buffers_iterator& rhs) const {
511 return cur == rhs.cur;
512 }
513 bool operator!=(const buffers_iterator& rhs) const {
514 return !(*this==rhs);
515 }
516
517 using citer_t = buffers_iterator<typename std::add_const<T>::type>;
518 operator citer_t() const {
519 return citer_t(cur);
520 }
521 };
522
523 typedef buffers_iterator<const ptr_node> const_iterator;
524 typedef buffers_iterator<ptr_node> iterator;
525
526 typedef const ptr_node& const_reference;
527 typedef ptr_node& reference;
528
529 buffers_t()
530 : _root(&_root),
531 _tail(&_root),
532 _size(0) {
533 }
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),
538 _size(other._size) {
539 other._root.next = &other._root;
540 other._tail = &other._root;
541 other._size = 0;
542
543 _tail->next = &_root;
544 }
545 buffers_t& operator=(buffers_t&& other) {
546 if (&other != this) {
547 clear_and_dispose();
548 swap(other);
549 }
550 return *this;
551 }
552
553 void push_back(reference item) {
554 item.next = &_root;
555 // this updates _root.next when called on empty
556 _tail->next = &item;
557 _tail = &item;
558 _size++;
559 }
560
561 void push_front(reference item) {
562 item.next = _root.next;
563 _root.next = &item;
564 _tail = _tail == &_root ? &item : _tail;
565 _size++;
566 }
567
568 // *_after
569 iterator erase_after(const_iterator it) {
570 const auto* to_erase = it->next;
571
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;
575 _size--;
576 return it->next;
577 }
578
579 void insert_after(const_iterator it, reference item) {
580 item.next = it->next;
581 it->next = &item;
582 _root.next = it == end() ? &item : _root.next;
583 _tail = const_iterator(_tail) == it ? &item : _tail;
584 _size++;
585 }
586
587 void splice_back(buffers_t& other) {
588 if (other._size == 0) {
589 return;
590 }
591
592 other._tail->next = &_root;
593 // will update root.next if empty() == true
594 _tail->next = other._root.next;
595 _tail = other._tail;
596 _size += other._size;
597
598 other._root.next = &other._root;
599 other._tail = &other._root;
600 other._size = 0;
601 }
602
603 std::size_t size() const { return _size; }
604 bool empty() const { return _tail == &_root; }
605
606 const_iterator begin() const {
607 return _root.next;
608 }
609 const_iterator before_begin() const {
610 return &_root;
611 }
612 const_iterator end() const {
613 return &_root;
614 }
615 iterator begin() {
616 return _root.next;
617 }
618 iterator before_begin() {
619 return &_root;
620 }
621 iterator end() {
622 return &_root;
623 }
624
625 reference front() {
626 return reinterpret_cast<reference>(*_root.next);
627 }
628 reference back() {
629 return reinterpret_cast<reference>(*_tail);
630 }
631 const_reference front() const {
632 return reinterpret_cast<const_reference>(*_root.next);
633 }
634 const_reference back() const {
635 return reinterpret_cast<const_reference>(*_tail);
636 }
637
638 void clone_from(const buffers_t& other) {
639 clear_and_dispose();
640 for (auto& node : other) {
641 ptr_node* clone = ptr_node::cloner()(node);
642 push_back(*clone);
643 }
644 }
645 void clear_and_dispose() {
646 for (auto it = begin(); it != end(); /* nop */) {
647 auto& node = *it;
648 it = it->next;
649 ptr_node::disposer()(&node);
650 }
651 _root.next = &_root;
652 _tail = &_root;
653 _size = 0;
654 }
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);
659 return ret;
660 }
661
662 void swap(buffers_t& other) {
663 const auto copy_root = _root;
664 _root.next = \
665 other._root.next == &other._root ? &this->_root : other._root.next;
666 other._root.next = \
667 copy_root.next == &_root ? &other._root : copy_root.next;
668
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;
672
673 _tail->next = &_root;
674 other._tail->next = &other._root;
675 std::swap(_size, other._size);
676 }
677 };
678
679 class iterator;
680
681 private:
682 // my private bits
683 buffers_t _buffers;
684
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.
688 ptr* _carriage;
689 unsigned _len;
690 unsigned _memcopy_count; //the total of memcopy using rebuild().
691
692 template <bool is_const>
693 class CEPH_BUFFER_API iterator_impl {
694 protected:
695 typedef typename std::conditional<is_const,
696 const list,
697 list>::type bl_t;
698 typedef typename std::conditional<is_const,
699 const buffers_t,
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;
704 bl_t* bl;
705 list_t* ls; // meh.. just here to avoid an extra pointer dereference..
706 list_iter_t p;
707 unsigned off; // in bl
708 unsigned p_off; // in *p
709 friend class iterator_impl<true>;
710
711 public:
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;
717
718 // constructor. position.
719 iterator_impl()
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);
725
726 /// get current iterator offset in buffer::list
727 unsigned get_off() const { return off; }
728
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; }
731
732 /// true if iterator is at the end of the buffer::list
733 bool end() const {
734 return p == ls->end();
735 //return off == bl->length();
736 }
737
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;
746
747 bl_t& get_bl() const { return *bl; }
748
749 // copy data out.
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);
759
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);
764
765 /// calculate crc from iterator position
766 uint32_t crc32c(size_t length, uint32_t crc);
767
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();
771 }
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();
775 }
776 };
777
778 public:
779 typedef iterator_impl<true> const_iterator;
780
781 class CEPH_BUFFER_API iterator : public iterator_impl<false> {
782 public:
783 iterator() = default;
784 iterator(bl_t *l, unsigned o=0);
785 iterator(bl_t *l, unsigned o, list_iter_t ip, unsigned po);
786 // copy data in
787 void copy_in(unsigned len, const char *src, bool crc_reset = true);
788 void copy_in(unsigned len, const list& otherl);
789 };
790
791 struct reserve_t {
792 char* bp_data;
793 unsigned* bp_len;
794 unsigned* bl_len;
795 };
796
797 class contiguous_appender {
798 ceph::bufferlist& bl;
799 ceph::bufferlist::reserve_t space;
800 char* pos;
801 bool deep;
802
803 /// running count of bytes appended that are not reflected by @pos
804 size_t out_of_band_offset = 0;
805
806 contiguous_appender(bufferlist& bl, size_t len, bool d)
807 : bl(bl),
808 space(bl.obtain_contiguous_space(len)),
809 pos(space.bp_data),
810 deep(d) {
811 }
812
813 void flush_and_continue() {
814 const size_t l = pos - space.bp_data;
815 *space.bp_len += l;
816 *space.bl_len += l;
817 space.bp_data = pos;
818 }
819
820 friend class list;
821
822 public:
823 ~contiguous_appender() {
824 flush_and_continue();
825 }
826
827 size_t get_out_of_band_offset() const {
828 return out_of_band_offset;
829 }
830 void append(const char* __restrict__ p, size_t l) {
831 maybe_inline_memcpy(pos, p, l, 16);
832 pos += l;
833 }
834 char *get_pos_add(size_t len) {
835 char *r = pos;
836 pos += len;
837 return r;
838 }
839 char *get_pos() {
840 return pos;
841 }
842
843 void append(const bufferptr& p) {
844 const auto plen = p.length();
845 if (!plen) {
846 return;
847 }
848 if (deep) {
849 append(p.c_str(), plen);
850 } else {
851 flush_and_continue();
852 bl.append(p);
853 space = bl.obtain_contiguous_space(0);
854 out_of_band_offset += plen;
855 }
856 }
857 void append(const bufferlist& l) {
858 if (deep) {
859 for (const auto &p : l._buffers) {
860 append(p.c_str(), p.length());
861 }
862 } else {
863 flush_and_continue();
864 bl.append(l);
865 space = bl.obtain_contiguous_space(0);
866 out_of_band_offset += l.length();
867 }
868 }
869
870 size_t get_logical_offset() {
871 return out_of_band_offset + (pos - space.bp_data);
872 }
873 };
874
875 contiguous_appender get_contiguous_appender(size_t len, bool deep=false) {
876 return contiguous_appender(*this, len, deep);
877 }
878
879 class contiguous_filler {
880 friend buffer::list;
881 char* pos;
882
883 contiguous_filler(char* const pos) : pos(pos) {}
884
885 public:
886 void advance(const unsigned len) {
887 pos += len;
888 }
889 void copy_in(const unsigned len, const char* const src) {
890 memcpy(pos, src, len);
891 advance(len);
892 }
893 char* c_str() {
894 return pos;
895 }
896 };
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");
901
902 class page_aligned_appender {
903 bufferlist *pbl;
904 unsigned min_alloc;
905 ptr buffer;
906 char *pos, *end;
907
908 page_aligned_appender(list *l, unsigned min_pages)
909 : pbl(l),
910 min_alloc(min_pages * CEPH_PAGE_SIZE),
911 pos(nullptr), end(nullptr) {}
912
913 friend class list;
914
915 public:
916 ~page_aligned_appender() {
917 flush();
918 }
919
920 void flush() {
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);
926 }
927 }
928
929 void append(const char *buf, size_t len) {
930 while (len > 0) {
931 if (!pos) {
932 size_t alloc = (len + CEPH_PAGE_SIZE - 1) & CEPH_PAGE_MASK;
933 if (alloc < min_alloc) {
934 alloc = min_alloc;
935 }
936 buffer = create_page_aligned(alloc);
937 pos = buffer.c_str();
938 end = buffer.end_c_str();
939 }
940 size_t l = len;
941 if (l > (size_t)(end - pos)) {
942 l = end - pos;
943 }
944 memcpy(pos, buf, l);
945 pos += l;
946 buf += l;
947 len -= l;
948 if (pos == end) {
949 pbl->append(buffer, 0, buffer.length());
950 pos = end = nullptr;
951 }
952 }
953 }
954 };
955
956 page_aligned_appender get_page_aligned_appender(unsigned min_pages=1) {
957 return page_aligned_appender(this, min_pages);
958 }
959
960 private:
961 mutable iterator last_p;
962
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);
968
969 public:
970 // cons/des
971 list()
972 : _carriage(&always_empty_bptr),
973 _len(0),
974 _memcopy_count(0),
975 last_p(this) {
976 }
977 // cppcheck-suppress noExplicitConstructor
978 // cppcheck-suppress noExplicitConstructor
979 list(unsigned prealloc)
980 : _carriage(&always_empty_bptr),
981 _len(0),
982 _memcopy_count(0),
983 last_p(this) {
984 reserve(prealloc);
985 }
986
987 list(const list& other)
988 : _carriage(&always_empty_bptr),
989 _len(other._len),
990 _memcopy_count(other._memcopy_count),
991 last_p(this) {
992 _buffers.clone_from(other._buffers);
993 }
994 list(list&& other) noexcept;
995
996 ~list() {
997 _buffers.clear_and_dispose();
998 }
999
1000 list& operator= (const list& other) {
1001 if (this != &other) {
1002 _carriage = &always_empty_bptr;
1003 _buffers.clone_from(other._buffers);
1004 _len = other._len;
1005 }
1006 return *this;
1007 }
1008 list& operator= (list&& other) noexcept {
1009 _buffers = std::move(other._buffers);
1010 _carriage = other._carriage;
1011 _len = other._len;
1012 _memcopy_count = other._memcopy_count;
1013 last_p = begin();
1014 other.clear();
1015 return *this;
1016 }
1017
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(); }
1022
1023 int get_mempool() const;
1024 void reassign_to_mempool(int pool);
1025 void try_assign_to_mempool(int pool);
1026
1027 size_t get_append_buffer_unused_tail_length() const {
1028 return _carriage->unused_tail_length();
1029 }
1030
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 {
1035 #if 0
1036 // DEBUG: verify _len
1037 unsigned len = 0;
1038 for (std::list<ptr>::const_iterator it = _buffers.begin();
1039 it != _buffers.end();
1040 it++) {
1041 len += (*it).length();
1042 }
1043 #ifdef __CEPH__
1044 ceph_assert(len == _len);
1045 #else
1046 assert(len == _len);
1047 #endif // __CEPH__
1048 #endif
1049 return _len;
1050 }
1051
1052 bool contents_equal(const buffer::list& other) const;
1053
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;
1061
1062 bool is_zero() const;
1063
1064 // modifiers
1065 void clear() noexcept {
1066 _carriage = &always_empty_bptr;
1067 _buffers.clear_and_dispose();
1068 _len = 0;
1069 _memcopy_count = 0;
1070 last_p = begin();
1071 }
1072 void push_back(const ptr& bp) {
1073 if (bp.length() == 0)
1074 return;
1075 _buffers.push_back(*ptr_node::create(bp).release());
1076 _len += bp.length();
1077 }
1078 void push_back(ptr&& bp) {
1079 if (bp.length() == 0)
1080 return;
1081 _len += bp.length();
1082 _buffers.push_back(*ptr_node::create(std::move(bp)).release());
1083 _carriage = &always_empty_bptr;
1084 }
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)
1090 return;
1091 _carriage = bp.get();
1092 _len += bp->length();
1093 _buffers.push_back(*bp.release());
1094 }
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();
1099 }
1100 void push_back(ceph::unique_leakable_ptr<raw> r) {
1101 push_back(r.release());
1102 }
1103
1104 void zero();
1105 void zero(unsigned o, unsigned l);
1106
1107 bool is_contiguous() const;
1108 void rebuild();
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();
1117
1118 void reserve(size_t prealloc);
1119
1120 // assignment-op with move semantics
1121 const static unsigned int CLAIM_DEFAULT = 0;
1122 const static unsigned int CLAIM_ALLOW_NONSHAREABLE = 1;
1123
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);
1128
1129 // copy with explicit volatile-sharing semantics
1130 void share(const list& bl)
1131 {
1132 if (this != &bl) {
1133 clear();
1134 for (const auto& bp : bl._buffers) {
1135 _buffers.push_back(*ptr_node::create(bp).release());
1136 }
1137 _len = bl._len;
1138 }
1139 }
1140
1141 #ifdef HAVE_SEASTAR
1142 /// convert the bufferlist into a network packet
1143 operator seastar::net::packet() &&;
1144 #endif
1145
1146 iterator begin() {
1147 return iterator(this, 0);
1148 }
1149 iterator end() {
1150 return iterator(this, _len, _buffers.end(), 0);
1151 }
1152
1153 const_iterator begin() const {
1154 return const_iterator(this, 0);
1155 }
1156 const_iterator cbegin() const {
1157 return begin();
1158 }
1159 const_iterator end() const {
1160 return const_iterator(this, _len, _buffers.end(), 0);
1161 }
1162
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);
1170
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());
1175 }
1176 #if __cplusplus >= 201703L
1177 // To forcibly disambiguate between string and string_view in the
1178 // case of arrays
1179 template<std::size_t N>
1180 void append(const char (&s)[N]) {
1181 append(s, N);
1182 }
1183 void append(const char* s) {
1184 append(s, strlen(s));
1185 }
1186 void append(std::string_view s) {
1187 append(s.data(), s.length());
1188 }
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);
1198
1199 reserve_t obtain_contiguous_space(unsigned len);
1200
1201 /*
1202 * get a char
1203 */
1204 const char& operator[](unsigned n) const;
1205 char *c_str();
1206 std::string to_str() const;
1207
1208 void substr_of(const list& other, unsigned off, unsigned len);
1209
1210 // funky modifer
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;
1213
1214 void encode_base64(list& o);
1215 void decode_base64(list& o);
1216
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 {
1226 #ifdef __CEPH__
1227 ceph_assert(_buffers.size() <= IOV_MAX);
1228 #else
1229 assert(_buffers.size() <= IOV_MAX);
1230 #endif
1231 piov->resize(_buffers.size());
1232 unsigned n = 0;
1233 for (auto& p : _buffers) {
1234 (*piov)[n].iov_base = (void *)p.c_str();
1235 (*piov)[n].iov_len = p.length();
1236 ++n;
1237 }
1238 }
1239 uint32_t crc32c(uint32_t crc) const;
1240 void invalidate_crc();
1241 sha1_digest_t sha1();
1242
1243 // These functions return a bufferlist with a pointer to a single
1244 // static buffer. They /must/ not outlive the memory they
1245 // reference.
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);
1249 };
1250
1251 } // inline namespace v14_2_0
1252
1253 /*
1254 * efficient hash of one or more bufferlists
1255 */
1256
1257 class hash {
1258 uint32_t crc;
1259
1260 public:
1261 hash() : crc(0) { }
1262 // cppcheck-suppress noExplicitConstructor
1263 hash(uint32_t init) : crc(init) { }
1264
1265 void update(const buffer::list& bl) {
1266 crc = bl.crc32c(crc);
1267 }
1268
1269 uint32_t digest() {
1270 return crc;
1271 }
1272 };
1273
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;
1280 }
1281 }
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;
1289 }
1290 }
1291
1292 inline bool operator==(const bufferlist &l, const bufferlist &r) {
1293 if (l.length() != r.length())
1294 return false;
1295 for (unsigned p = 0; p < l.length(); p++) {
1296 if (l[p] != r[p])
1297 return false;
1298 }
1299 return true;
1300 }
1301 inline bool operator<(bufferlist& l, bufferlist& r) {
1302 return r > l;
1303 }
1304 inline bool operator<=(bufferlist& l, bufferlist& r) {
1305 return r >= l;
1306 }
1307
1308
1309 std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp);
1310
1311 std::ostream& operator<<(std::ostream& out, const buffer::raw &r);
1312
1313 std::ostream& operator<<(std::ostream& out, const buffer::list& bl);
1314
1315 std::ostream& operator<<(std::ostream& out, const buffer::error& e);
1316
1317 inline bufferhash& operator<<(bufferhash& l, const bufferlist &r) {
1318 l.update(r);
1319 return l;
1320 }
1321
1322 } // namespace buffer
1323
1324 #if defined(HAVE_XIO)
1325 xio_reg_mem* get_xio_mp(const buffer::ptr& bp);
1326 #endif
1327
1328 } // namespace ceph
1329
1330 #endif