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