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