]> git.proxmox.com Git - ceph.git/blob - ceph/src/include/buffer.h
update sources to v12.1.0
[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 #include <exception>
47 #include <type_traits>
48
49 #include "page.h"
50 #include "crc32c.h"
51 #include "buffer_fwd.h"
52
53 #ifdef __CEPH__
54 # include "include/assert.h"
55 #else
56 # include <assert.h>
57 #endif
58
59 #include "inline_memory.h"
60
61 #if __GNUC__ >= 4
62 #define CEPH_BUFFER_API __attribute__ ((visibility ("default")))
63 #else
64 #define CEPH_BUFFER_API
65 #endif
66
67 #if defined(HAVE_XIO)
68 struct xio_reg_mem;
69 class XioDispatchHook;
70 #endif
71 class deleter;
72
73 namespace ceph {
74
75 namespace buffer CEPH_BUFFER_API {
76 /*
77 * exceptions
78 */
79
80 struct error : public std::exception{
81 const char *what() const throw () override;
82 };
83 struct bad_alloc : public error {
84 const char *what() const throw () override;
85 };
86 struct end_of_buffer : public error {
87 const char *what() const throw () override;
88 };
89 struct malformed_input : public error {
90 explicit malformed_input(const std::string& w) {
91 snprintf(buf, sizeof(buf), "buffer::malformed_input: %s", w.c_str());
92 }
93 const char *what() const throw () override;
94 private:
95 char buf[256];
96 };
97 struct error_code : public malformed_input {
98 explicit error_code(int error);
99 int code;
100 };
101
102
103 /// total bytes allocated
104 int get_total_alloc();
105
106 /// history total bytes allocated
107 uint64_t get_history_alloc_bytes();
108
109 /// total num allocated
110 uint64_t get_history_alloc_num();
111
112 /// enable/disable alloc tracking
113 void track_alloc(bool b);
114
115 /// count of cached crc hits (matching input)
116 int get_cached_crc();
117 /// count of cached crc hits (mismatching input, required adjustment)
118 int get_cached_crc_adjusted();
119 /// count of crc cache misses
120 int get_missed_crc();
121 /// enable/disable tracking of cached crcs
122 void track_cached_crc(bool b);
123
124 /// count of calls to buffer::ptr::c_str()
125 int get_c_str_accesses();
126 /// enable/disable tracking of buffer::ptr::c_str() calls
127 void track_c_str(bool b);
128
129 /*
130 * an abstract raw buffer. with a reference count.
131 */
132 class raw;
133 class raw_malloc;
134 class raw_static;
135 class raw_mmap_pages;
136 class raw_posix_aligned;
137 class raw_hack_aligned;
138 class raw_char;
139 class raw_claimed_char;
140 class raw_pipe;
141 class raw_unshareable; // diagnostic, unshareable char buffer
142 class raw_combined;
143 class raw_claim_buffer;
144
145
146 class xio_mempool;
147 class xio_msg_buffer;
148
149 /*
150 * named constructors
151 */
152 raw* copy(const char *c, unsigned len);
153 raw* create(unsigned len);
154 raw* claim_char(unsigned len, char *buf);
155 raw* create_malloc(unsigned len);
156 raw* claim_malloc(unsigned len, char *buf);
157 raw* create_static(unsigned len, char *buf);
158 raw* create_aligned(unsigned len, unsigned align);
159 raw* create_page_aligned(unsigned len);
160 raw* create_zero_copy(unsigned len, int fd, int64_t *offset);
161 raw* create_unshareable(unsigned len);
162 raw* create_static(unsigned len, char *buf);
163 raw* claim_buffer(unsigned len, char *buf, deleter del);
164
165 #if defined(HAVE_XIO)
166 raw* create_msg(unsigned len, char *buf, XioDispatchHook *m_hook);
167 #endif
168
169 /*
170 * a buffer pointer. references (a subsequence of) a raw buffer.
171 */
172 class CEPH_BUFFER_API ptr {
173 raw *_raw;
174 unsigned _off, _len;
175
176 void release();
177
178 public:
179 class iterator {
180 const ptr *bp; ///< parent ptr
181 const char *start; ///< starting pointer into bp->c_str()
182 const char *pos; ///< pointer into bp->c_str()
183 const char *end_ptr; ///< pointer to bp->end_c_str()
184 bool deep; ///< if true, no not allow shallow ptr copies
185
186 iterator(const ptr *p, size_t offset, bool d)
187 : bp(p),
188 start(p->c_str() + offset),
189 pos(start),
190 end_ptr(p->end_c_str()),
191 deep(d) {}
192
193 friend class ptr;
194
195 public:
196 const char *get_pos_add(size_t n) {
197 const char *r = pos;
198 pos += n;
199 if (pos > end_ptr)
200 throw end_of_buffer();
201 return r;
202 }
203
204 ptr get_ptr(size_t len) {
205 if (deep) {
206 return buffer::copy(get_pos_add(len), len);
207 } else {
208 size_t off = pos - bp->c_str();
209 pos += len;
210 if (pos > end_ptr)
211 throw end_of_buffer();
212 return ptr(*bp, off, len);
213 }
214 }
215 ptr get_preceding_ptr(size_t len) {
216 if (deep) {
217 return buffer::copy(get_pos() - len, len);
218 } else {
219 size_t off = pos - bp->c_str();
220 return ptr(*bp, off - len, len);
221 }
222 }
223
224 void advance(size_t len) {
225 pos += len;
226 if (pos > end_ptr)
227 throw end_of_buffer();
228 }
229
230 const char *get_pos() {
231 return pos;
232 }
233 const char *get_end() {
234 return end_ptr;
235 }
236
237 size_t get_offset() {
238 return pos - start;
239 }
240
241 bool end() const {
242 return pos == end_ptr;
243 }
244 };
245
246 ptr() : _raw(0), _off(0), _len(0) {}
247 // cppcheck-suppress noExplicitConstructor
248 ptr(raw *r);
249 // cppcheck-suppress noExplicitConstructor
250 ptr(unsigned l);
251 ptr(const char *d, unsigned l);
252 ptr(const ptr& p);
253 ptr(ptr&& p) noexcept;
254 ptr(const ptr& p, unsigned o, unsigned l);
255 ptr& operator= (const ptr& p);
256 ptr& operator= (ptr&& p) noexcept;
257 ~ptr() {
258 release();
259 }
260
261 bool have_raw() const { return _raw ? true:false; }
262
263 raw *clone();
264 void swap(ptr& other);
265 ptr& make_shareable();
266
267 iterator begin(size_t offset=0) const {
268 return iterator(this, offset, false);
269 }
270 iterator begin_deep(size_t offset=0) const {
271 return iterator(this, offset, true);
272 }
273
274 // misc
275 bool at_buffer_head() const { return _off == 0; }
276 bool at_buffer_tail() const;
277
278 bool is_aligned(unsigned align) const {
279 return ((long)c_str() & (align-1)) == 0;
280 }
281 bool is_page_aligned() const { return is_aligned(CEPH_PAGE_SIZE); }
282 bool is_n_align_sized(unsigned align) const
283 {
284 return (length() % align) == 0;
285 }
286 bool is_n_page_sized() const { return is_n_align_sized(CEPH_PAGE_SIZE); }
287 bool is_partial() const {
288 return have_raw() && (start() > 0 || end() < raw_length());
289 }
290
291 // accessors
292 raw *get_raw() const { return _raw; }
293 const char *c_str() const;
294 char *c_str();
295 const char *end_c_str() const;
296 char *end_c_str();
297 unsigned length() const { return _len; }
298 unsigned offset() const { return _off; }
299 unsigned start() const { return _off; }
300 unsigned end() const { return _off + _len; }
301 unsigned unused_tail_length() const;
302 const char& operator[](unsigned n) const;
303 char& operator[](unsigned n);
304
305 const char *raw_c_str() const;
306 unsigned raw_length() const;
307 int raw_nref() const;
308
309 void copy_out(unsigned o, unsigned l, char *dest) const;
310
311 bool can_zero_copy() const;
312 int zero_copy_to_fd(int fd, int64_t *offset) const;
313
314 unsigned wasted() const;
315
316 int cmp(const ptr& o) const;
317 bool is_zero() const;
318
319 // modifiers
320 void set_offset(unsigned o) {
321 assert(raw_length() >= o);
322 _off = o;
323 }
324 void set_length(unsigned l) {
325 assert(raw_length() >= l);
326 _len = l;
327 }
328
329 unsigned append(char c);
330 unsigned append(const char *p, unsigned l);
331 void copy_in(unsigned o, unsigned l, const char *src);
332 void copy_in(unsigned o, unsigned l, const char *src, bool crc_reset);
333 void zero();
334 void zero(bool crc_reset);
335 void zero(unsigned o, unsigned l);
336 void zero(unsigned o, unsigned l, bool crc_reset);
337
338 };
339
340
341 /*
342 * list - the useful bit!
343 */
344
345 class CEPH_BUFFER_API list {
346 // my private bits
347 std::list<ptr> _buffers;
348 unsigned _len;
349 unsigned _memcopy_count; //the total of memcopy using rebuild().
350 ptr append_buffer; // where i put small appends.
351 int _mempool = -1;
352
353 public:
354 class iterator;
355
356 private:
357 template <bool is_const>
358 class CEPH_BUFFER_API iterator_impl
359 : public std::iterator<std::forward_iterator_tag, char> {
360 protected:
361 typedef typename std::conditional<is_const,
362 const list,
363 list>::type bl_t;
364 typedef typename std::conditional<is_const,
365 const std::list<ptr>,
366 std::list<ptr> >::type list_t;
367 typedef typename std::conditional<is_const,
368 typename std::list<ptr>::const_iterator,
369 typename std::list<ptr>::iterator>::type list_iter_t;
370 bl_t* bl;
371 list_t* ls; // meh.. just here to avoid an extra pointer dereference..
372 unsigned off; // in bl
373 list_iter_t p;
374 unsigned p_off; // in *p
375 friend class iterator_impl<true>;
376
377 public:
378 // constructor. position.
379 iterator_impl()
380 : bl(0), ls(0), off(0), p_off(0) {}
381 iterator_impl(bl_t *l, unsigned o=0);
382 iterator_impl(bl_t *l, unsigned o, list_iter_t ip, unsigned po)
383 : bl(l), ls(&bl->_buffers), off(o), p(ip), p_off(po) {}
384 iterator_impl(const list::iterator& i);
385
386 /// get current iterator offset in buffer::list
387 unsigned get_off() const { return off; }
388
389 /// get number of bytes remaining from iterator position to the end of the buffer::list
390 unsigned get_remaining() const { return bl->length() - off; }
391
392 /// true if iterator is at the end of the buffer::list
393 bool end() const {
394 return p == ls->end();
395 //return off == bl->length();
396 }
397
398 void advance(int o);
399 void seek(unsigned o);
400 char operator*() const;
401 iterator_impl& operator++();
402 ptr get_current_ptr() const;
403
404 bl_t& get_bl() const { return *bl; }
405
406 // copy data out.
407 // note that these all _append_ to dest!
408 void copy(unsigned len, char *dest);
409 // deprecated, use copy_deep()
410 void copy(unsigned len, ptr &dest) __attribute__((deprecated));
411 void copy_deep(unsigned len, ptr &dest);
412 void copy_shallow(unsigned len, ptr &dest);
413 void copy(unsigned len, list &dest);
414 void copy(unsigned len, std::string &dest);
415 void copy_all(list &dest);
416
417 // get a pointer to the currenet iterator position, return the
418 // number of bytes we can read from that position (up to want),
419 // and advance the iterator by that amount.
420 size_t get_ptr_and_advance(size_t want, const char **p);
421
422 /// calculate crc from iterator position
423 uint32_t crc32c(size_t length, uint32_t crc);
424
425 friend bool operator==(const iterator_impl& lhs,
426 const iterator_impl& rhs) {
427 return &lhs.get_bl() == &rhs.get_bl() && lhs.get_off() == rhs.get_off();
428 }
429 friend bool operator!=(const iterator_impl& lhs,
430 const iterator_impl& rhs) {
431 return &lhs.get_bl() != &rhs.get_bl() || lhs.get_off() != rhs.get_off();
432 }
433 };
434
435 public:
436 typedef iterator_impl<true> const_iterator;
437
438 class CEPH_BUFFER_API iterator : public iterator_impl<false> {
439 public:
440 iterator() = default;
441 iterator(bl_t *l, unsigned o=0);
442 iterator(bl_t *l, unsigned o, list_iter_t ip, unsigned po);
443
444 void advance(int o);
445 void seek(unsigned o);
446 char operator*();
447 iterator& operator++();
448 ptr get_current_ptr();
449
450 // copy data out
451 void copy(unsigned len, char *dest);
452 // deprecated, use copy_deep()
453 void copy(unsigned len, ptr &dest) __attribute__((deprecated));
454 void copy_deep(unsigned len, ptr &dest);
455 void copy_shallow(unsigned len, ptr &dest);
456 void copy(unsigned len, list &dest);
457 void copy(unsigned len, std::string &dest);
458 void copy_all(list &dest);
459
460 // copy data in
461 void copy_in(unsigned len, const char *src);
462 void copy_in(unsigned len, const char *src, bool crc_reset);
463 void copy_in(unsigned len, const list& otherl);
464
465 bool operator==(const iterator& rhs) const {
466 return bl == rhs.bl && off == rhs.off;
467 }
468 bool operator!=(const iterator& rhs) const {
469 return bl != rhs.bl || off != rhs.off;
470 }
471 };
472
473 class contiguous_appender {
474 bufferlist *pbl;
475 char *pos;
476 ptr bp;
477 bool deep;
478
479 /// running count of bytes appended that are not reflected by @pos
480 size_t out_of_band_offset = 0;
481
482 contiguous_appender(bufferlist *l, size_t len, bool d)
483 : pbl(l),
484 deep(d) {
485 size_t unused = pbl->append_buffer.unused_tail_length();
486 if (len > unused) {
487 // note: if len < the normal append_buffer size it *might*
488 // be better to allocate a normal-sized append_buffer and
489 // use part of it. however, that optimizes for the case of
490 // old-style types including new-style types. and in most
491 // such cases, this won't be the very first thing encoded to
492 // the list, so append_buffer will already be allocated.
493 // OTOH if everything is new-style, we *should* allocate
494 // only what we need and conserve memory.
495 bp = buffer::create(len);
496 pos = bp.c_str();
497 } else {
498 pos = pbl->append_buffer.end_c_str();
499 }
500 }
501
502 void flush_and_continue() {
503 if (bp.have_raw()) {
504 // we allocated a new buffer
505 size_t l = pos - bp.c_str();
506 pbl->append(bufferptr(bp, 0, l));
507 bp.set_length(bp.length() - l);
508 bp.set_offset(bp.offset() + l);
509 } else {
510 // we are using pbl's append_buffer
511 size_t l = pos - pbl->append_buffer.end_c_str();
512 if (l) {
513 pbl->append_buffer.set_length(pbl->append_buffer.length() + l);
514 pbl->append(pbl->append_buffer, pbl->append_buffer.end() - l, l);
515 pos = pbl->append_buffer.end_c_str();
516 }
517 }
518 }
519
520 friend class list;
521
522 public:
523 ~contiguous_appender() {
524 if (bp.have_raw()) {
525 // we allocated a new buffer
526 bp.set_length(pos - bp.c_str());
527 pbl->append(std::move(bp));
528 } else {
529 // we are using pbl's append_buffer
530 size_t l = pos - pbl->append_buffer.end_c_str();
531 if (l) {
532 pbl->append_buffer.set_length(pbl->append_buffer.length() + l);
533 pbl->append(pbl->append_buffer, pbl->append_buffer.end() - l, l);
534 }
535 }
536 }
537
538 size_t get_out_of_band_offset() const {
539 return out_of_band_offset;
540 }
541 void append(const char *p, size_t l) {
542 maybe_inline_memcpy(pos, p, l, 16);
543 pos += l;
544 }
545 char *get_pos_add(size_t len) {
546 char *r = pos;
547 pos += len;
548 return r;
549 }
550 char *get_pos() {
551 return pos;
552 }
553
554 void append(const bufferptr& p) {
555 if (!p.length()) {
556 return;
557 }
558 if (deep) {
559 append(p.c_str(), p.length());
560 } else {
561 flush_and_continue();
562 pbl->append(p);
563 out_of_band_offset += p.length();
564 }
565 }
566 void append(const bufferlist& l) {
567 if (!l.length()) {
568 return;
569 }
570 if (deep) {
571 for (const auto &p : l._buffers) {
572 append(p.c_str(), p.length());
573 }
574 } else {
575 flush_and_continue();
576 pbl->append(l);
577 out_of_band_offset += l.length();
578 }
579 }
580
581 size_t get_logical_offset() {
582 if (bp.have_raw()) {
583 return out_of_band_offset + (pos - bp.c_str());
584 } else {
585 return out_of_band_offset + (pos - pbl->append_buffer.end_c_str());
586 }
587 }
588 };
589
590 contiguous_appender get_contiguous_appender(size_t len, bool deep=false) {
591 return contiguous_appender(this, len, deep);
592 }
593
594 class page_aligned_appender {
595 bufferlist *pbl;
596 size_t offset;
597 unsigned min_alloc;
598 ptr buffer;
599 char *pos, *end;
600
601 page_aligned_appender(list *l, unsigned min_pages)
602 : pbl(l),
603 min_alloc(min_pages * CEPH_PAGE_SIZE),
604 pos(nullptr), end(nullptr) {}
605
606 friend class list;
607
608 public:
609 ~page_aligned_appender() {
610 flush();
611 }
612
613 void flush() {
614 if (pos && pos != buffer.c_str()) {
615 size_t len = pos - buffer.c_str();
616 pbl->append(buffer, 0, len);
617 buffer.set_length(buffer.length() - len);
618 buffer.set_offset(buffer.offset() + len);
619 }
620 }
621
622 void append(const char *buf, size_t len) {
623 while (len > 0) {
624 if (!pos) {
625 size_t alloc = (len + CEPH_PAGE_SIZE - 1) & CEPH_PAGE_MASK;
626 if (alloc < min_alloc) {
627 alloc = min_alloc;
628 }
629 buffer = create_page_aligned(alloc);
630 pos = buffer.c_str();
631 end = buffer.end_c_str();
632 }
633 size_t l = len;
634 if (l > (size_t)(end - pos)) {
635 l = end - pos;
636 }
637 memcpy(pos, buf, l);
638 pos += l;
639 buf += l;
640 len -= l;
641 if (pos == end) {
642 pbl->append(buffer, 0, buffer.length());
643 pos = end = nullptr;
644 }
645 }
646 }
647 };
648
649 page_aligned_appender get_page_aligned_appender(unsigned min_pages=1) {
650 return page_aligned_appender(this, min_pages);
651 }
652
653 private:
654 mutable iterator last_p;
655 int zero_copy_to_fd(int fd) const;
656
657 public:
658 // cons/des
659 list() : _len(0), _memcopy_count(0), last_p(this) {}
660 // cppcheck-suppress noExplicitConstructor
661 list(unsigned prealloc) : _len(0), _memcopy_count(0), last_p(this) {
662 reserve(prealloc);
663 }
664
665 list(const list& other) : _buffers(other._buffers), _len(other._len),
666 _memcopy_count(other._memcopy_count), last_p(this) {
667 make_shareable();
668 }
669 list(list&& other);
670 list& operator= (const list& other) {
671 if (this != &other) {
672 _buffers = other._buffers;
673 _len = other._len;
674 make_shareable();
675 }
676 return *this;
677 }
678
679 list& operator= (list&& other) {
680 _buffers = std::move(other._buffers);
681 _len = other._len;
682 _memcopy_count = other._memcopy_count;
683 last_p = begin();
684 append_buffer.swap(other.append_buffer);
685 _mempool = other._mempool;
686 other.clear();
687 return *this;
688 }
689
690 unsigned get_num_buffers() const { return _buffers.size(); }
691 const ptr& front() const { return _buffers.front(); }
692 const ptr& back() const { return _buffers.back(); }
693
694 void reassign_to_mempool(int pool);
695 void try_assign_to_mempool(int pool);
696
697 size_t get_append_buffer_unused_tail_length() const {
698 return append_buffer.unused_tail_length();
699 }
700
701 unsigned get_memcopy_count() const {return _memcopy_count; }
702 const std::list<ptr>& buffers() const { return _buffers; }
703 void swap(list& other);
704 unsigned length() const {
705 #if 0
706 // DEBUG: verify _len
707 unsigned len = 0;
708 for (std::list<ptr>::const_iterator it = _buffers.begin();
709 it != _buffers.end();
710 it++) {
711 len += (*it).length();
712 }
713 assert(len == _len);
714 #endif
715 return _len;
716 }
717
718 bool contents_equal(buffer::list& other);
719 bool contents_equal(const buffer::list& other) const;
720
721 bool can_zero_copy() const;
722 bool is_provided_buffer(const char *dst) const;
723 bool is_aligned(unsigned align) const;
724 bool is_page_aligned() const;
725 bool is_n_align_sized(unsigned align) const;
726 bool is_n_page_sized() const;
727 bool is_aligned_size_and_memory(unsigned align_size,
728 unsigned align_memory) const;
729
730 bool is_zero() const;
731
732 // modifiers
733 void clear() {
734 _buffers.clear();
735 _len = 0;
736 _memcopy_count = 0;
737 last_p = begin();
738 append_buffer = ptr();
739 }
740 void push_front(ptr& bp) {
741 if (bp.length() == 0)
742 return;
743 _buffers.push_front(bp);
744 _len += bp.length();
745 }
746 void push_front(ptr&& bp) {
747 if (bp.length() == 0)
748 return;
749 _len += bp.length();
750 _buffers.push_front(std::move(bp));
751 }
752 void push_front(raw *r) {
753 push_front(ptr(r));
754 }
755 void push_back(const ptr& bp) {
756 if (bp.length() == 0)
757 return;
758 _buffers.push_back(bp);
759 _len += bp.length();
760 }
761 void push_back(ptr&& bp) {
762 if (bp.length() == 0)
763 return;
764 _len += bp.length();
765 _buffers.push_back(std::move(bp));
766 }
767 void push_back(raw *r) {
768 push_back(ptr(r));
769 }
770
771 void zero();
772 void zero(unsigned o, unsigned l);
773
774 bool is_contiguous() const;
775 void rebuild();
776 void rebuild(ptr& nb);
777 bool rebuild_aligned(unsigned align);
778 bool rebuild_aligned_size_and_memory(unsigned align_size,
779 unsigned align_memory);
780 bool rebuild_page_aligned();
781
782 void reserve(size_t prealloc);
783
784 // assignment-op with move semantics
785 const static unsigned int CLAIM_DEFAULT = 0;
786 const static unsigned int CLAIM_ALLOW_NONSHAREABLE = 1;
787
788 void claim(list& bl, unsigned int flags = CLAIM_DEFAULT);
789 void claim_append(list& bl, unsigned int flags = CLAIM_DEFAULT);
790 void claim_prepend(list& bl, unsigned int flags = CLAIM_DEFAULT);
791 // only for bl is bufferlist::page_aligned_appender
792 void claim_append_piecewise(list& bl);
793
794 // clone non-shareable buffers (make shareable)
795 void make_shareable() {
796 std::list<buffer::ptr>::iterator pb;
797 for (pb = _buffers.begin(); pb != _buffers.end(); ++pb) {
798 (void) pb->make_shareable();
799 }
800 }
801
802 // copy with explicit volatile-sharing semantics
803 void share(const list& bl)
804 {
805 if (this != &bl) {
806 clear();
807 std::list<buffer::ptr>::const_iterator pb;
808 for (pb = bl._buffers.begin(); pb != bl._buffers.end(); ++pb) {
809 push_back(*pb);
810 }
811 }
812 }
813
814 iterator begin() {
815 return iterator(this, 0);
816 }
817 iterator end() {
818 return iterator(this, _len, _buffers.end(), 0);
819 }
820
821 const_iterator begin() const {
822 return const_iterator(this, 0);
823 }
824 const_iterator end() const {
825 return const_iterator(this, _len, _buffers.end(), 0);
826 }
827
828 // crope lookalikes.
829 // **** WARNING: this are horribly inefficient for large bufferlists. ****
830 void copy(unsigned off, unsigned len, char *dest) const;
831 void copy(unsigned off, unsigned len, list &dest) const;
832 void copy(unsigned off, unsigned len, std::string& dest) const;
833 void copy_in(unsigned off, unsigned len, const char *src);
834 void copy_in(unsigned off, unsigned len, const char *src, bool crc_reset);
835 void copy_in(unsigned off, unsigned len, const list& src);
836
837 void append(char c);
838 void append(const char *data, unsigned len);
839 void append(const std::string& s) {
840 append(s.data(), s.length());
841 }
842 void append(const ptr& bp);
843 void append(ptr&& bp);
844 void append(const ptr& bp, unsigned off, unsigned len);
845 void append(const list& bl);
846 void append(std::istream& in);
847 void append_zero(unsigned len);
848 void prepend_zero(unsigned len);
849
850 /*
851 * get a char
852 */
853 const char& operator[](unsigned n) const;
854 char *c_str();
855 std::string to_str() const;
856
857 void substr_of(const list& other, unsigned off, unsigned len);
858
859 /// return a pointer to a contiguous extent of the buffer,
860 /// reallocating as needed
861 char *get_contiguous(unsigned off, ///< offset
862 unsigned len); ///< length
863
864 // funky modifer
865 void splice(unsigned off, unsigned len, list *claim_by=0 /*, bufferlist& replace_with */);
866 void write(int off, int len, std::ostream& out) const;
867
868 void encode_base64(list& o);
869 void decode_base64(list& o);
870
871 void write_stream(std::ostream &out) const;
872 void hexdump(std::ostream &out, bool trailing_newline = true) const;
873 int read_file(const char *fn, std::string *error);
874 ssize_t read_fd(int fd, size_t len);
875 int read_fd_zero_copy(int fd, size_t len);
876 int write_file(const char *fn, int mode=0644);
877 int write_fd(int fd) const;
878 int write_fd(int fd, uint64_t offset) const;
879 int write_fd_zero_copy(int fd) const;
880 template<typename VectorT>
881 void prepare_iov(VectorT *piov) const {
882 assert(_buffers.size() <= IOV_MAX);
883 piov->resize(_buffers.size());
884 unsigned n = 0;
885 for (auto& p : _buffers) {
886 (*piov)[n].iov_base = (void *)p.c_str();
887 (*piov)[n].iov_len = p.length();
888 ++n;
889 }
890 }
891 uint32_t crc32c(uint32_t crc) const;
892 void invalidate_crc();
893
894 // These functions return a bufferlist with a pointer to a single
895 // static buffer. They /must/ not outlive the memory they
896 // reference.
897 static list static_from_mem(char* c, size_t l);
898 static list static_from_cstring(char* c);
899 static list static_from_string(std::string& s);
900 };
901
902 /*
903 * efficient hash of one or more bufferlists
904 */
905
906 class hash {
907 uint32_t crc;
908
909 public:
910 hash() : crc(0) { }
911 // cppcheck-suppress noExplicitConstructor
912 hash(uint32_t init) : crc(init) { }
913
914 void update(const buffer::list& bl) {
915 crc = bl.crc32c(crc);
916 }
917
918 uint32_t digest() {
919 return crc;
920 }
921 };
922
923 inline bool operator>(bufferlist& l, bufferlist& r) {
924 for (unsigned p = 0; ; p++) {
925 if (l.length() > p && r.length() == p) return true;
926 if (l.length() == p) return false;
927 if (l[p] > r[p]) return true;
928 if (l[p] < r[p]) return false;
929 }
930 }
931 inline bool operator>=(bufferlist& l, bufferlist& r) {
932 for (unsigned p = 0; ; p++) {
933 if (l.length() > p && r.length() == p) return true;
934 if (r.length() == p && l.length() == p) return true;
935 if (l.length() == p && r.length() > p) return false;
936 if (l[p] > r[p]) return true;
937 if (l[p] < r[p]) return false;
938 }
939 }
940
941 inline bool operator==(const bufferlist &l, const bufferlist &r) {
942 if (l.length() != r.length())
943 return false;
944 for (unsigned p = 0; p < l.length(); p++) {
945 if (l[p] != r[p])
946 return false;
947 }
948 return true;
949 }
950 inline bool operator<(bufferlist& l, bufferlist& r) {
951 return r > l;
952 }
953 inline bool operator<=(bufferlist& l, bufferlist& r) {
954 return r >= l;
955 }
956
957
958 std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp);
959
960 std::ostream& operator<<(std::ostream& out, const raw &r);
961
962 std::ostream& operator<<(std::ostream& out, const buffer::list& bl);
963
964 std::ostream& operator<<(std::ostream& out, const buffer::error& e);
965
966 inline bufferhash& operator<<(bufferhash& l, const bufferlist &r) {
967 l.update(r);
968 return l;
969 }
970
971 }
972
973 #if defined(HAVE_XIO)
974 xio_reg_mem* get_xio_mp(const buffer::ptr& bp);
975 #endif
976
977 }
978
979 #endif