1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2014 Red Hat
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.
15 #include "bluestore_types.h"
16 #include "common/Formatter.h"
17 #include "common/Checksummer.h"
18 #include "include/stringify.h"
20 void ExtentList::add_extents(int64_t start
, int64_t count
) {
21 AllocExtent
*last_extent
= NULL
;
22 bool can_merge
= false;
24 if (!m_extents
->empty()) {
25 last_extent
= &(m_extents
->back());
26 uint64_t last_offset
= last_extent
->end() / m_block_size
;
27 uint32_t last_length
= last_extent
->length
/ m_block_size
;
28 if ((last_offset
== (uint64_t) start
) &&
29 (!m_max_blocks
|| (last_length
+ count
) <= m_max_blocks
)) {
35 last_extent
->length
+= (count
* m_block_size
);
37 m_extents
->emplace_back(AllocExtent(start
* m_block_size
,
38 count
* m_block_size
));
42 // bluestore_bdev_label_t
44 void bluestore_bdev_label_t::encode(bufferlist
& bl
) const
46 // be slightly friendly to someone who looks at the device
47 bl
.append("bluestore block device\n");
48 bl
.append(stringify(osd_uuid
));
50 ENCODE_START(2, 1, bl
);
51 ::encode(osd_uuid
, bl
);
54 ::encode(description
, bl
);
59 void bluestore_bdev_label_t::decode(bufferlist::iterator
& p
)
61 p
.advance(60); // see above
63 ::decode(osd_uuid
, p
);
66 ::decode(description
, p
);
73 void bluestore_bdev_label_t::dump(Formatter
*f
) const
75 f
->dump_stream("osd_uuid") << osd_uuid
;
76 f
->dump_unsigned("size", size
);
77 f
->dump_stream("btime") << btime
;
78 f
->dump_string("description", description
);
79 for (auto& i
: meta
) {
80 f
->dump_string(i
.first
.c_str(), i
.second
);
84 void bluestore_bdev_label_t::generate_test_instances(
85 list
<bluestore_bdev_label_t
*>& o
)
87 o
.push_back(new bluestore_bdev_label_t
);
88 o
.push_back(new bluestore_bdev_label_t
);
90 o
.back()->btime
= utime_t(4, 5);
91 o
.back()->description
= "fakey";
92 o
.back()->meta
["foo"] = "bar";
95 ostream
& operator<<(ostream
& out
, const bluestore_bdev_label_t
& l
)
97 return out
<< "bdev(osd_uuid " << l
.osd_uuid
98 << ", size 0x" << std::hex
<< l
.size
<< std::dec
99 << ", btime " << l
.btime
100 << ", desc " << l
.description
101 << ", " << l
.meta
.size() << " meta"
107 void bluestore_cnode_t::dump(Formatter
*f
) const
109 f
->dump_unsigned("bits", bits
);
112 void bluestore_cnode_t::generate_test_instances(list
<bluestore_cnode_t
*>& o
)
114 o
.push_back(new bluestore_cnode_t());
115 o
.push_back(new bluestore_cnode_t(0));
116 o
.push_back(new bluestore_cnode_t(123));
119 // bluestore_extent_ref_map_t
121 void bluestore_extent_ref_map_t::_check() const
125 for (const auto &p
: ref_map
) {
127 assert(0 == "overlap");
128 if (p
.first
== pos
&& p
.second
.refs
== refs
)
129 assert(0 == "unmerged");
130 pos
= p
.first
+ p
.second
.length
;
131 refs
= p
.second
.refs
;
135 void bluestore_extent_ref_map_t::_maybe_merge_left(
136 map
<uint64_t,record_t
>::iterator
& p
)
138 if (p
== ref_map
.begin())
142 if (q
->second
.refs
== p
->second
.refs
&&
143 q
->first
+ q
->second
.length
== p
->first
) {
144 q
->second
.length
+= p
->second
.length
;
150 void bluestore_extent_ref_map_t::get(uint64_t offset
, uint32_t length
)
152 auto p
= ref_map
.lower_bound(offset
);
153 if (p
!= ref_map
.begin()) {
155 if (p
->first
+ p
->second
.length
<= offset
) {
160 if (p
== ref_map
.end()) {
161 // nothing after offset; add the whole thing.
163 map
<uint64_t,record_t
>::value_type(offset
, record_t(length
, 1))).first
;
166 if (p
->first
> offset
) {
168 uint64_t newlen
= MIN(p
->first
- offset
, length
);
170 map
<uint64_t,record_t
>::value_type(offset
,
171 record_t(newlen
, 1))).first
;
174 _maybe_merge_left(p
);
178 if (p
->first
< offset
) {
179 // split off the portion before offset
180 assert(p
->first
+ p
->second
.length
> offset
);
181 uint64_t left
= p
->first
+ p
->second
.length
- offset
;
182 p
->second
.length
= offset
- p
->first
;
183 p
= ref_map
.insert(map
<uint64_t,record_t
>::value_type(
184 offset
, record_t(left
, p
->second
.refs
))).first
;
187 assert(p
->first
== offset
);
188 if (length
< p
->second
.length
) {
189 ref_map
.insert(make_pair(offset
+ length
,
190 record_t(p
->second
.length
- length
,
192 p
->second
.length
= length
;
197 offset
+= p
->second
.length
;
198 length
-= p
->second
.length
;
199 _maybe_merge_left(p
);
202 if (p
!= ref_map
.end())
203 _maybe_merge_left(p
);
207 void bluestore_extent_ref_map_t::put(
208 uint64_t offset
, uint32_t length
,
209 PExtentVector
*release
,
210 bool *maybe_unshared
)
212 //NB: existing entries in 'release' container must be preserved!
213 bool unshared
= true;
214 auto p
= ref_map
.lower_bound(offset
);
215 if (p
== ref_map
.end() || p
->first
> offset
) {
216 if (p
== ref_map
.begin()) {
217 assert(0 == "put on missing extent (nothing before)");
220 if (p
->first
+ p
->second
.length
<= offset
) {
221 assert(0 == "put on missing extent (gap)");
224 if (p
->first
< offset
) {
225 uint64_t left
= p
->first
+ p
->second
.length
- offset
;
226 p
->second
.length
= offset
- p
->first
;
227 if (p
->second
.refs
!= 1) {
230 p
= ref_map
.insert(map
<uint64_t,record_t
>::value_type(
231 offset
, record_t(left
, p
->second
.refs
))).first
;
234 assert(p
->first
== offset
);
235 if (length
< p
->second
.length
) {
236 if (p
->second
.refs
!= 1) {
239 ref_map
.insert(make_pair(offset
+ length
,
240 record_t(p
->second
.length
- length
,
242 if (p
->second
.refs
> 1) {
243 p
->second
.length
= length
;
245 if (p
->second
.refs
!= 1) {
248 _maybe_merge_left(p
);
251 release
->push_back(bluestore_pextent_t(p
->first
, length
));
256 offset
+= p
->second
.length
;
257 length
-= p
->second
.length
;
258 if (p
->second
.refs
> 1) {
260 if (p
->second
.refs
!= 1) {
263 _maybe_merge_left(p
);
267 release
->push_back(bluestore_pextent_t(p
->first
, p
->second
.length
));
271 if (p
!= ref_map
.end())
272 _maybe_merge_left(p
);
275 if (maybe_unshared
) {
277 // we haven't seen a ref != 1 yet; check the whole map.
278 for (auto& p
: ref_map
) {
279 if (p
.second
.refs
!= 1) {
285 *maybe_unshared
= unshared
;
289 bool bluestore_extent_ref_map_t::contains(uint64_t offset
, uint32_t length
) const
291 auto p
= ref_map
.lower_bound(offset
);
292 if (p
== ref_map
.end() || p
->first
> offset
) {
293 if (p
== ref_map
.begin()) {
294 return false; // nothing before
297 if (p
->first
+ p
->second
.length
<= offset
) {
302 if (p
== ref_map
.end())
304 if (p
->first
> offset
)
306 if (p
->first
+ p
->second
.length
>= offset
+ length
)
308 uint64_t overlap
= p
->first
+ p
->second
.length
- offset
;
316 bool bluestore_extent_ref_map_t::intersects(
318 uint32_t length
) const
320 auto p
= ref_map
.lower_bound(offset
);
321 if (p
!= ref_map
.begin()) {
323 if (p
->first
+ p
->second
.length
<= offset
) {
327 if (p
== ref_map
.end())
329 if (p
->first
>= offset
+ length
)
331 return true; // intersects p!
334 void bluestore_extent_ref_map_t::dump(Formatter
*f
) const
336 f
->open_array_section("ref_map");
337 for (auto& p
: ref_map
) {
338 f
->open_object_section("ref");
339 f
->dump_unsigned("offset", p
.first
);
340 f
->dump_unsigned("length", p
.second
.length
);
341 f
->dump_unsigned("refs", p
.second
.refs
);
347 void bluestore_extent_ref_map_t::generate_test_instances(
348 list
<bluestore_extent_ref_map_t
*>& o
)
350 o
.push_back(new bluestore_extent_ref_map_t
);
351 o
.push_back(new bluestore_extent_ref_map_t
);
352 o
.back()->get(10, 10);
353 o
.back()->get(18, 22);
354 o
.back()->get(20, 20);
355 o
.back()->get(10, 25);
356 o
.back()->get(15, 20);
359 ostream
& operator<<(ostream
& out
, const bluestore_extent_ref_map_t
& m
)
362 for (auto p
= m
.ref_map
.begin(); p
!= m
.ref_map
.end(); ++p
) {
363 if (p
!= m
.ref_map
.begin())
365 out
<< std::hex
<< "0x" << p
->first
<< "~" << p
->second
.length
<< std::dec
366 << "=" << p
->second
.refs
;
372 // bluestore_blob_use_tracker_t
374 void bluestore_blob_use_tracker_t::allocate()
377 bytes_per_au
= new uint32_t[num_au
];
378 for (uint32_t i
= 0; i
< num_au
; ++i
) {
383 void bluestore_blob_use_tracker_t::init(
384 uint32_t full_length
, uint32_t _au_size
) {
385 assert(!au_size
|| is_empty());
386 assert(_au_size
> 0);
387 assert(full_length
> 0);
389 uint32_t _num_au
= ROUND_UP_TO(full_length
, _au_size
) / _au_size
;
397 void bluestore_blob_use_tracker_t::get(
398 uint32_t offset
, uint32_t length
)
402 total_bytes
+= length
;
404 auto end
= offset
+ length
;
406 while (offset
< end
) {
407 auto phase
= offset
% au_size
;
408 bytes_per_au
[offset
/ au_size
] +=
409 MIN(au_size
- phase
, end
- offset
);
410 offset
+= (phase
? au_size
- phase
: au_size
);
415 bool bluestore_blob_use_tracker_t::put(
416 uint32_t offset
, uint32_t length
,
417 PExtentVector
*release_units
)
421 release_units
->clear();
423 bool maybe_empty
= true;
425 assert(total_bytes
>= length
);
426 total_bytes
-= length
;
428 auto end
= offset
+ length
;
429 uint64_t next_offs
= 0;
430 while (offset
< end
) {
431 auto phase
= offset
% au_size
;
432 size_t pos
= offset
/ au_size
;
433 auto diff
= MIN(au_size
- phase
, end
- offset
);
434 assert(diff
<= bytes_per_au
[pos
]);
435 bytes_per_au
[pos
] -= diff
;
436 offset
+= (phase
? au_size
- phase
: au_size
);
437 if (bytes_per_au
[pos
] == 0) {
439 if (release_units
->empty() || next_offs
!= pos
* au_size
) {
440 release_units
->emplace_back(pos
* au_size
, au_size
);
442 release_units
->back().length
+= au_size
;
444 next_offs
+= au_size
;
447 maybe_empty
= false; // micro optimization detecting we aren't empty
448 // even in the affected extent
452 bool empty
= maybe_empty
? !is_not_empty() : false;
453 if (empty
&& release_units
) {
454 release_units
->clear();
459 bool bluestore_blob_use_tracker_t::can_split() const
464 bool bluestore_blob_use_tracker_t::can_split_at(uint32_t blob_offset
) const
467 return (blob_offset
% au_size
) == 0 &&
468 blob_offset
< num_au
* au_size
;
471 void bluestore_blob_use_tracker_t::split(
472 uint32_t blob_offset
,
473 bluestore_blob_use_tracker_t
* r
)
477 assert(can_split_at(blob_offset
));
478 assert(r
->is_empty());
480 uint32_t new_num_au
= blob_offset
/ au_size
;
481 r
->init( (num_au
- new_num_au
) * au_size
, au_size
);
483 for (auto i
= new_num_au
; i
< num_au
; i
++) {
484 r
->get((i
- new_num_au
) * au_size
, bytes_per_au
[i
]);
487 if (new_num_au
== 0) {
489 } else if (new_num_au
== 1) {
490 uint32_t tmp
= bytes_per_au
[0];
491 uint32_t _au_size
= au_size
;
500 bool bluestore_blob_use_tracker_t::equal(
501 const bluestore_blob_use_tracker_t
& other
) const
503 if (!num_au
&& !other
.num_au
) {
504 return total_bytes
== other
.total_bytes
&& au_size
== other
.au_size
;
505 } else if (num_au
&& other
.num_au
) {
506 if (num_au
!= other
.num_au
|| au_size
!= other
.au_size
) {
509 for (size_t i
= 0; i
< num_au
; i
++) {
510 if (bytes_per_au
[i
] != other
.bytes_per_au
[i
]) {
517 uint32_t n
= num_au
? num_au
: other
.num_au
;
518 uint32_t referenced
=
519 num_au
? other
.get_referenced_bytes() : get_referenced_bytes();
520 auto bytes_per_au_tmp
= num_au
? bytes_per_au
: other
.bytes_per_au
;
521 uint32_t my_referenced
= 0;
522 for (size_t i
= 0; i
< n
; i
++) {
523 my_referenced
+= bytes_per_au_tmp
[i
];
524 if (my_referenced
> referenced
) {
528 return my_referenced
== referenced
;
531 void bluestore_blob_use_tracker_t::dump(Formatter
*f
) const
533 f
->dump_unsigned("num_au", num_au
);
534 f
->dump_unsigned("au_size", au_size
);
536 f
->dump_unsigned("total_bytes", total_bytes
);
538 f
->open_array_section("bytes_per_au");
539 for (size_t i
= 0; i
< num_au
; ++i
) {
540 f
->dump_unsigned("", bytes_per_au
[i
]);
546 void bluestore_blob_use_tracker_t::generate_test_instances(
547 list
<bluestore_blob_use_tracker_t
*>& o
)
549 o
.push_back(new bluestore_blob_use_tracker_t());
550 o
.back()->init(16, 16);
551 o
.back()->get(10, 10);
552 o
.back()->get(10, 5);
553 o
.push_back(new bluestore_blob_use_tracker_t());
554 o
.back()->init(60, 16);
555 o
.back()->get(18, 22);
556 o
.back()->get(20, 20);
557 o
.back()->get(15, 20);
560 ostream
& operator<<(ostream
& out
, const bluestore_blob_use_tracker_t
& m
)
562 out
<< "use_tracker(" << std::hex
;
564 out
<< "0x" << m
.au_size
566 << "0x" << m
.total_bytes
;
568 out
<< "0x" << m
.num_au
569 << "*0x" << m
.au_size
571 for (size_t i
= 0; i
< m
.num_au
; ++i
) {
574 out
<< m
.bytes_per_au
[i
];
578 out
<< std::dec
<< ")";
582 // bluestore_pextent_t
584 void bluestore_pextent_t::dump(Formatter
*f
) const
586 f
->dump_unsigned("offset", offset
);
587 f
->dump_unsigned("length", length
);
590 ostream
& operator<<(ostream
& out
, const bluestore_pextent_t
& o
) {
592 return out
<< "0x" << std::hex
<< o
.offset
<< "~" << o
.length
<< std::dec
;
594 return out
<< "!~" << std::hex
<< o
.length
<< std::dec
;
597 void bluestore_pextent_t::generate_test_instances(list
<bluestore_pextent_t
*>& ls
)
599 ls
.push_back(new bluestore_pextent_t
);
600 ls
.push_back(new bluestore_pextent_t(1, 2));
605 string
bluestore_blob_t::get_flags_string(unsigned flags
)
608 if (flags
& FLAG_COMPRESSED
) {
613 if (flags
& FLAG_CSUM
) {
618 if (flags
& FLAG_HAS_UNUSED
) {
623 if (flags
& FLAG_SHARED
) {
632 size_t bluestore_blob_t::get_csum_value_size() const
634 return Checksummer::get_csum_value_size(csum_type
);
637 void bluestore_blob_t::dump(Formatter
*f
) const
639 f
->open_array_section("extents");
640 for (auto& p
: extents
) {
641 f
->dump_object("extent", p
);
644 f
->dump_unsigned("logical_length", logical_length
);
645 f
->dump_unsigned("compressed_length", compressed_length
);
646 f
->dump_unsigned("flags", flags
);
647 f
->dump_unsigned("csum_type", csum_type
);
648 f
->dump_unsigned("csum_chunk_order", csum_chunk_order
);
649 f
->open_array_section("csum_data");
650 size_t n
= get_csum_count();
651 for (unsigned i
= 0; i
< n
; ++i
)
652 f
->dump_unsigned("csum", get_csum_item(i
));
654 f
->dump_unsigned("unused", unused
);
657 void bluestore_blob_t::generate_test_instances(list
<bluestore_blob_t
*>& ls
)
659 ls
.push_back(new bluestore_blob_t
);
660 ls
.push_back(new bluestore_blob_t(0));
661 ls
.push_back(new bluestore_blob_t
);
662 ls
.back()->allocated_test(bluestore_pextent_t(111, 222));
663 ls
.push_back(new bluestore_blob_t
);
664 ls
.back()->init_csum(Checksummer::CSUM_XXHASH32
, 16, 65536);
665 ls
.back()->csum_data
= buffer::claim_malloc(4, strdup("abcd"));
666 ls
.back()->add_unused(0, 3);
667 ls
.back()->add_unused(8, 8);
668 ls
.back()->allocated_test(bluestore_pextent_t(0x40100000, 0x10000));
669 ls
.back()->allocated_test(
670 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
, 0x1000));
671 ls
.back()->allocated_test(bluestore_pextent_t(0x40120000, 0x10000));
674 ostream
& operator<<(ostream
& out
, const bluestore_blob_t
& o
)
676 out
<< "blob(" << o
.get_extents();
677 if (o
.is_compressed()) {
678 out
<< " clen 0x" << std::hex
679 << o
.get_logical_length()
681 << o
.get_compressed_payload_length()
685 out
<< " " << o
.get_flags_string();
688 out
<< " " << Checksummer::get_csum_type_string(o
.csum_type
)
689 << "/0x" << std::hex
<< (1ull << o
.csum_chunk_order
) << std::dec
;
692 out
<< " unused=0x" << std::hex
<< o
.unused
<< std::dec
;
697 void bluestore_blob_t::calc_csum(uint64_t b_off
, const bufferlist
& bl
)
700 case Checksummer::CSUM_XXHASH32
:
701 Checksummer::calculate
<Checksummer::xxhash32
>(
702 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
704 case Checksummer::CSUM_XXHASH64
:
705 Checksummer::calculate
<Checksummer::xxhash64
>(
706 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
708 case Checksummer::CSUM_CRC32C
:
709 Checksummer::calculate
<Checksummer::crc32c
>(
710 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
712 case Checksummer::CSUM_CRC32C_16
:
713 Checksummer::calculate
<Checksummer::crc32c_16
>(
714 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
716 case Checksummer::CSUM_CRC32C_8
:
717 Checksummer::calculate
<Checksummer::crc32c_8
>(
718 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
723 int bluestore_blob_t::verify_csum(uint64_t b_off
, const bufferlist
& bl
,
724 int* b_bad_off
, uint64_t *bad_csum
) const
730 case Checksummer::CSUM_NONE
:
732 case Checksummer::CSUM_XXHASH32
:
733 *b_bad_off
= Checksummer::verify
<Checksummer::xxhash32
>(
734 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
736 case Checksummer::CSUM_XXHASH64
:
737 *b_bad_off
= Checksummer::verify
<Checksummer::xxhash64
>(
738 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
740 case Checksummer::CSUM_CRC32C
:
741 *b_bad_off
= Checksummer::verify
<Checksummer::crc32c
>(
742 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
744 case Checksummer::CSUM_CRC32C_16
:
745 *b_bad_off
= Checksummer::verify
<Checksummer::crc32c_16
>(
746 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
748 case Checksummer::CSUM_CRC32C_8
:
749 *b_bad_off
= Checksummer::verify
<Checksummer::crc32c_8
>(
750 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
759 else if (*b_bad_off
>= 0)
760 return -1; // bad checksum
765 void bluestore_blob_t::allocated(uint32_t b_off
, uint32_t length
, const AllocExtentVector
& allocs
)
767 if (extents
.size() == 0) {
768 // if blob is compressed then logical length to be already configured
769 // otherwise - to be unset.
770 assert((is_compressed() && logical_length
!= 0) ||
771 (!is_compressed() && logical_length
== 0));
773 extents
.reserve(allocs
.size() + (b_off
? 1 : 0));
775 extents
.emplace_back(
776 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
, b_off
));
778 uint32_t new_len
= b_off
;
779 for (auto& a
: allocs
) {
780 extents
.emplace_back(a
.offset
, a
.length
);
783 if (!is_compressed()) {
784 logical_length
= new_len
;
787 assert(!is_compressed()); // partial allocations are forbidden when
789 assert(b_off
< logical_length
);
790 uint32_t cur_offs
= 0;
791 auto start_it
= extents
.begin();
794 assert(start_it
!= extents
.end());
795 if (cur_offs
+ start_it
->length
> b_off
) {
798 cur_offs
+= start_it
->length
;
802 uint32_t head
= b_off
- cur_offs
;
803 uint32_t end_off
= b_off
+ length
;
804 auto end_it
= start_it
;
807 assert(end_it
!= extents
.end());
808 assert(!end_it
->is_valid());
809 if (cur_offs
+ end_it
->length
>= end_off
) {
812 cur_offs
+= end_it
->length
;
815 assert(cur_offs
+ end_it
->length
>= end_off
);
816 uint32_t tail
= cur_offs
+ end_it
->length
- end_off
;
818 start_it
= extents
.erase(start_it
, end_it
+ 1);
819 size_t count
= allocs
.size();
820 count
+= head
? 1 : 0;
821 count
+= tail
? 1 : 0;
822 extents
.insert(start_it
,
825 bluestore_pextent_t::INVALID_OFFSET
, 0));
827 // Workaround to resolve lack of proper iterator return in vector::insert
828 // Looks like some gcc/stl implementations still lack it despite c++11
830 start_it
= extents
.begin() + pos
;
833 start_it
->length
= head
;
836 for(auto& e
: allocs
) {
841 start_it
->length
= tail
;
846 // cut it out of extents
849 uint64_t invalid
= 0;
851 void add_invalid(uint64_t length
) {
856 v
.emplace_back(bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
,
861 void add(uint64_t offset
, uint64_t length
) {
862 if (offset
== bluestore_pextent_t::INVALID_OFFSET
) {
867 v
.emplace_back(bluestore_pextent_t(offset
, length
));
872 void bluestore_blob_t::allocated_test(const bluestore_pextent_t
& alloc
)
874 extents
.emplace_back(alloc
);
875 if (!is_compressed()) {
876 logical_length
+= alloc
.length
;
880 bool bluestore_blob_t::release_extents(bool all
,
881 const PExtentVector
& logical
,
884 // common case: all of it?
887 for (auto& e
: extents
) {
893 assert(is_compressed() || get_logical_length() == pos
);
895 extents
[0].offset
= bluestore_pextent_t::INVALID_OFFSET
;
896 extents
[0].length
= pos
;
899 // remove from pextents according to logical release list
901 auto loffs_it
= logical
.begin();
902 auto lend
= logical
.end();
903 uint32_t pext_loffs_start
= 0; //starting loffset of the current pextent
904 uint32_t pext_loffs
= 0; //current loffset
905 auto pext_it
= extents
.begin();
906 auto pext_end
= extents
.end();
907 while (pext_it
!= pext_end
) {
908 if (loffs_it
== lend
||
909 pext_loffs_start
+ pext_it
->length
<= loffs_it
->offset
) {
910 int delta0
= pext_loffs
- pext_loffs_start
;
912 if ((uint32_t)delta0
< pext_it
->length
) {
913 vb
.add(pext_it
->offset
+ delta0
, pext_it
->length
- delta0
);
915 pext_loffs_start
+= pext_it
->length
;
916 pext_loffs
= pext_loffs_start
;
920 //assert(pext_loffs == pext_loffs_start);
921 int delta0
= pext_loffs
- pext_loffs_start
;
924 int delta
= loffs_it
->offset
- pext_loffs
;
927 vb
.add(pext_it
->offset
+ delta0
, delta
);
931 PExtentVector::iterator last_r
= r
->end();
932 if (r
->begin() != last_r
) {
935 uint32_t to_release
= loffs_it
->length
;
937 uint32_t to_release_part
=
938 MIN(pext_it
->length
- delta0
- delta
, to_release
);
939 auto o
= pext_it
->offset
+ delta0
+ delta
;
940 if (last_r
!= r
->end() && last_r
->offset
+ last_r
->length
== o
) {
941 last_r
->length
+= to_release_part
;
944 last_r
= r
->emplace(r
->end(), o
, to_release_part
);
946 to_release
-= to_release_part
;
947 pext_loffs
+= to_release_part
;
948 if (pext_loffs
== pext_loffs_start
+ pext_it
->length
) {
949 pext_loffs_start
+= pext_it
->length
;
950 pext_loffs
= pext_loffs_start
;
954 } while (to_release
> 0 && pext_it
!= pext_end
);
955 vb
.add_invalid(loffs_it
->length
- to_release
);
964 void bluestore_blob_t::split(uint32_t blob_offset
, bluestore_blob_t
& rb
)
966 size_t left
= blob_offset
;
967 uint32_t llen_lb
= 0;
968 uint32_t llen_rb
= 0;
970 for (auto p
= extents
.begin(); p
!= extents
.end(); ++p
, ++i
) {
971 if (p
->length
<= left
) {
973 llen_lb
+= p
->length
;
978 rb
.extents
.emplace_back(bluestore_pextent_t(p
->offset
+ left
,
982 rb
.extents
.emplace_back(bluestore_pextent_t(
983 bluestore_pextent_t::INVALID_OFFSET
,
986 llen_rb
+= p
->length
- left
;
992 while (p
!= extents
.end()) {
993 llen_rb
+= p
->length
;
994 rb
.extents
.push_back(*p
++);
997 logical_length
= llen_lb
;
998 rb
.logical_length
= llen_rb
;
1004 rb
.csum_type
= csum_type
;
1005 rb
.csum_chunk_order
= csum_chunk_order
;
1006 size_t csum_order
= get_csum_chunk_size();
1007 assert(blob_offset
% csum_order
== 0);
1008 size_t pos
= (blob_offset
/ csum_order
) * get_csum_value_size();
1009 // deep copy csum data
1011 old
.swap(csum_data
);
1012 rb
.csum_data
= bufferptr(old
.c_str() + pos
, old
.length() - pos
);
1013 csum_data
= bufferptr(old
.c_str(), pos
);
1017 // bluestore_shared_blob_t
1019 void bluestore_shared_blob_t::dump(Formatter
*f
) const
1021 f
->dump_int("sbid", sbid
);
1022 f
->dump_object("ref_map", ref_map
);
1025 void bluestore_shared_blob_t::generate_test_instances(
1026 list
<bluestore_shared_blob_t
*>& ls
)
1028 ls
.push_back(new bluestore_shared_blob_t(1));
1031 ostream
& operator<<(ostream
& out
, const bluestore_shared_blob_t
& sb
)
1033 out
<< "(sbid 0x" << std::hex
<< sb
.sbid
<< std::dec
;
1034 out
<< " " << sb
.ref_map
<< ")";
1038 // bluestore_onode_t
1040 void bluestore_onode_t::shard_info::dump(Formatter
*f
) const
1042 f
->dump_unsigned("offset", offset
);
1043 f
->dump_unsigned("bytes", bytes
);
1046 ostream
& operator<<(ostream
& out
, const bluestore_onode_t::shard_info
& si
)
1048 return out
<< std::hex
<< "0x" << si
.offset
<< "(0x" << si
.bytes
<< " bytes"
1052 void bluestore_onode_t::dump(Formatter
*f
) const
1054 f
->dump_unsigned("nid", nid
);
1055 f
->dump_unsigned("size", size
);
1056 f
->open_object_section("attrs");
1057 for (auto p
= attrs
.begin(); p
!= attrs
.end(); ++p
) {
1058 f
->open_object_section("attr");
1059 f
->dump_string("name", p
->first
.c_str()); // it's not quite std::string
1060 f
->dump_unsigned("len", p
->second
.length());
1064 f
->dump_string("flags", get_flags_string());
1065 f
->open_array_section("extent_map_shards");
1066 for (auto si
: extent_map_shards
) {
1067 f
->dump_object("shard", si
);
1070 f
->dump_unsigned("expected_object_size", expected_object_size
);
1071 f
->dump_unsigned("expected_write_size", expected_write_size
);
1072 f
->dump_unsigned("alloc_hint_flags", alloc_hint_flags
);
1075 void bluestore_onode_t::generate_test_instances(list
<bluestore_onode_t
*>& o
)
1077 o
.push_back(new bluestore_onode_t());
1081 // bluestore_deferred_op_t
1083 void bluestore_deferred_op_t::dump(Formatter
*f
) const
1085 f
->dump_unsigned("op", (int)op
);
1086 f
->dump_unsigned("data_len", data
.length());
1087 f
->open_array_section("extents");
1088 for (auto& e
: extents
) {
1089 f
->dump_object("extent", e
);
1094 void bluestore_deferred_op_t::generate_test_instances(list
<bluestore_deferred_op_t
*>& o
)
1096 o
.push_back(new bluestore_deferred_op_t
);
1097 o
.push_back(new bluestore_deferred_op_t
);
1098 o
.back()->op
= OP_WRITE
;
1099 o
.back()->extents
.push_back(bluestore_pextent_t(1, 2));
1100 o
.back()->extents
.push_back(bluestore_pextent_t(100, 5));
1101 o
.back()->data
.append("my data");
1104 void bluestore_deferred_transaction_t::dump(Formatter
*f
) const
1106 f
->dump_unsigned("seq", seq
);
1107 f
->open_array_section("ops");
1108 for (list
<bluestore_deferred_op_t
>::const_iterator p
= ops
.begin(); p
!= ops
.end(); ++p
) {
1109 f
->dump_object("op", *p
);
1113 f
->open_array_section("released extents");
1114 for (interval_set
<uint64_t>::const_iterator p
= released
.begin(); p
!= released
.end(); ++p
) {
1115 f
->open_object_section("extent");
1116 f
->dump_unsigned("offset", p
.get_start());
1117 f
->dump_unsigned("length", p
.get_len());
1123 void bluestore_deferred_transaction_t::generate_test_instances(list
<bluestore_deferred_transaction_t
*>& o
)
1125 o
.push_back(new bluestore_deferred_transaction_t());
1126 o
.push_back(new bluestore_deferred_transaction_t());
1127 o
.back()->seq
= 123;
1128 o
.back()->ops
.push_back(bluestore_deferred_op_t());
1129 o
.back()->ops
.push_back(bluestore_deferred_op_t());
1130 o
.back()->ops
.back().op
= bluestore_deferred_op_t::OP_WRITE
;
1131 o
.back()->ops
.back().extents
.push_back(bluestore_pextent_t(1,7));
1132 o
.back()->ops
.back().data
.append("foodata");
1135 void bluestore_compression_header_t::dump(Formatter
*f
) const
1137 f
->dump_unsigned("type", type
);
1138 f
->dump_unsigned("length", length
);
1141 void bluestore_compression_header_t::generate_test_instances(
1142 list
<bluestore_compression_header_t
*>& o
)
1144 o
.push_back(new bluestore_compression_header_t
);
1145 o
.push_back(new bluestore_compression_header_t(1));
1146 o
.back()->length
= 1234;