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 ostream
& operator<<(ostream
& out
, const bluestore_cnode_t
& l
)
121 return out
<< "cnode(bits " << l
.bits
<< ")";
124 // bluestore_extent_ref_map_t
126 void bluestore_extent_ref_map_t::_check() const
130 for (const auto &p
: ref_map
) {
132 assert(0 == "overlap");
133 if (p
.first
== pos
&& p
.second
.refs
== refs
)
134 assert(0 == "unmerged");
135 pos
= p
.first
+ p
.second
.length
;
136 refs
= p
.second
.refs
;
140 void bluestore_extent_ref_map_t::_maybe_merge_left(
141 map
<uint64_t,record_t
>::iterator
& p
)
143 if (p
== ref_map
.begin())
147 if (q
->second
.refs
== p
->second
.refs
&&
148 q
->first
+ q
->second
.length
== p
->first
) {
149 q
->second
.length
+= p
->second
.length
;
155 void bluestore_extent_ref_map_t::get(uint64_t offset
, uint32_t length
)
157 auto p
= ref_map
.lower_bound(offset
);
158 if (p
!= ref_map
.begin()) {
160 if (p
->first
+ p
->second
.length
<= offset
) {
165 if (p
== ref_map
.end()) {
166 // nothing after offset; add the whole thing.
168 map
<uint64_t,record_t
>::value_type(offset
, record_t(length
, 1))).first
;
171 if (p
->first
> offset
) {
173 uint64_t newlen
= MIN(p
->first
- offset
, length
);
175 map
<uint64_t,record_t
>::value_type(offset
,
176 record_t(newlen
, 1))).first
;
179 _maybe_merge_left(p
);
183 if (p
->first
< offset
) {
184 // split off the portion before offset
185 assert(p
->first
+ p
->second
.length
> offset
);
186 uint64_t left
= p
->first
+ p
->second
.length
- offset
;
187 p
->second
.length
= offset
- p
->first
;
188 p
= ref_map
.insert(map
<uint64_t,record_t
>::value_type(
189 offset
, record_t(left
, p
->second
.refs
))).first
;
192 assert(p
->first
== offset
);
193 if (length
< p
->second
.length
) {
194 ref_map
.insert(make_pair(offset
+ length
,
195 record_t(p
->second
.length
- length
,
197 p
->second
.length
= length
;
202 offset
+= p
->second
.length
;
203 length
-= p
->second
.length
;
204 _maybe_merge_left(p
);
207 if (p
!= ref_map
.end())
208 _maybe_merge_left(p
);
212 void bluestore_extent_ref_map_t::put(
213 uint64_t offset
, uint32_t length
,
214 PExtentVector
*release
,
215 bool *maybe_unshared
)
217 //NB: existing entries in 'release' container must be preserved!
218 bool unshared
= true;
219 auto p
= ref_map
.lower_bound(offset
);
220 if (p
== ref_map
.end() || p
->first
> offset
) {
221 if (p
== ref_map
.begin()) {
222 assert(0 == "put on missing extent (nothing before)");
225 if (p
->first
+ p
->second
.length
<= offset
) {
226 assert(0 == "put on missing extent (gap)");
229 if (p
->first
< offset
) {
230 uint64_t left
= p
->first
+ p
->second
.length
- offset
;
231 p
->second
.length
= offset
- p
->first
;
232 if (p
->second
.refs
!= 1) {
235 p
= ref_map
.insert(map
<uint64_t,record_t
>::value_type(
236 offset
, record_t(left
, p
->second
.refs
))).first
;
239 assert(p
->first
== offset
);
240 if (length
< p
->second
.length
) {
241 if (p
->second
.refs
!= 1) {
244 ref_map
.insert(make_pair(offset
+ length
,
245 record_t(p
->second
.length
- length
,
247 if (p
->second
.refs
> 1) {
248 p
->second
.length
= length
;
250 if (p
->second
.refs
!= 1) {
253 _maybe_merge_left(p
);
256 release
->push_back(bluestore_pextent_t(p
->first
, length
));
261 offset
+= p
->second
.length
;
262 length
-= p
->second
.length
;
263 if (p
->second
.refs
> 1) {
265 if (p
->second
.refs
!= 1) {
268 _maybe_merge_left(p
);
272 release
->push_back(bluestore_pextent_t(p
->first
, p
->second
.length
));
276 if (p
!= ref_map
.end())
277 _maybe_merge_left(p
);
280 if (maybe_unshared
) {
282 // we haven't seen a ref != 1 yet; check the whole map.
283 for (auto& p
: ref_map
) {
284 if (p
.second
.refs
!= 1) {
290 *maybe_unshared
= unshared
;
294 bool bluestore_extent_ref_map_t::contains(uint64_t offset
, uint32_t length
) const
296 auto p
= ref_map
.lower_bound(offset
);
297 if (p
== ref_map
.end() || p
->first
> offset
) {
298 if (p
== ref_map
.begin()) {
299 return false; // nothing before
302 if (p
->first
+ p
->second
.length
<= offset
) {
307 if (p
== ref_map
.end())
309 if (p
->first
> offset
)
311 if (p
->first
+ p
->second
.length
>= offset
+ length
)
313 uint64_t overlap
= p
->first
+ p
->second
.length
- offset
;
321 bool bluestore_extent_ref_map_t::intersects(
323 uint32_t length
) const
325 auto p
= ref_map
.lower_bound(offset
);
326 if (p
!= ref_map
.begin()) {
328 if (p
->first
+ p
->second
.length
<= offset
) {
332 if (p
== ref_map
.end())
334 if (p
->first
>= offset
+ length
)
336 return true; // intersects p!
339 void bluestore_extent_ref_map_t::dump(Formatter
*f
) const
341 f
->open_array_section("ref_map");
342 for (auto& p
: ref_map
) {
343 f
->open_object_section("ref");
344 f
->dump_unsigned("offset", p
.first
);
345 f
->dump_unsigned("length", p
.second
.length
);
346 f
->dump_unsigned("refs", p
.second
.refs
);
352 void bluestore_extent_ref_map_t::generate_test_instances(
353 list
<bluestore_extent_ref_map_t
*>& o
)
355 o
.push_back(new bluestore_extent_ref_map_t
);
356 o
.push_back(new bluestore_extent_ref_map_t
);
357 o
.back()->get(10, 10);
358 o
.back()->get(18, 22);
359 o
.back()->get(20, 20);
360 o
.back()->get(10, 25);
361 o
.back()->get(15, 20);
364 ostream
& operator<<(ostream
& out
, const bluestore_extent_ref_map_t
& m
)
367 for (auto p
= m
.ref_map
.begin(); p
!= m
.ref_map
.end(); ++p
) {
368 if (p
!= m
.ref_map
.begin())
370 out
<< std::hex
<< "0x" << p
->first
<< "~" << p
->second
.length
<< std::dec
371 << "=" << p
->second
.refs
;
377 // bluestore_blob_use_tracker_t
379 void bluestore_blob_use_tracker_t::allocate()
382 bytes_per_au
= new uint32_t[num_au
];
383 for (uint32_t i
= 0; i
< num_au
; ++i
) {
388 void bluestore_blob_use_tracker_t::init(
389 uint32_t full_length
, uint32_t _au_size
) {
390 assert(!au_size
|| is_empty());
391 assert(_au_size
> 0);
392 assert(full_length
> 0);
394 uint32_t _num_au
= ROUND_UP_TO(full_length
, _au_size
) / _au_size
;
402 void bluestore_blob_use_tracker_t::get(
403 uint32_t offset
, uint32_t length
)
407 total_bytes
+= length
;
409 auto end
= offset
+ length
;
411 while (offset
< end
) {
412 auto phase
= offset
% au_size
;
413 bytes_per_au
[offset
/ au_size
] +=
414 MIN(au_size
- phase
, end
- offset
);
415 offset
+= (phase
? au_size
- phase
: au_size
);
420 bool bluestore_blob_use_tracker_t::put(
421 uint32_t offset
, uint32_t length
,
422 PExtentVector
*release_units
)
426 release_units
->clear();
428 bool maybe_empty
= true;
430 assert(total_bytes
>= length
);
431 total_bytes
-= length
;
433 auto end
= offset
+ length
;
434 uint64_t next_offs
= 0;
435 while (offset
< end
) {
436 auto phase
= offset
% au_size
;
437 size_t pos
= offset
/ au_size
;
438 auto diff
= MIN(au_size
- phase
, end
- offset
);
439 assert(diff
<= bytes_per_au
[pos
]);
440 bytes_per_au
[pos
] -= diff
;
441 offset
+= (phase
? au_size
- phase
: au_size
);
442 if (bytes_per_au
[pos
] == 0) {
444 if (release_units
->empty() || next_offs
!= pos
* au_size
) {
445 release_units
->emplace_back(pos
* au_size
, au_size
);
447 release_units
->back().length
+= au_size
;
449 next_offs
+= au_size
;
452 maybe_empty
= false; // micro optimization detecting we aren't empty
453 // even in the affected extent
457 bool empty
= maybe_empty
? !is_not_empty() : false;
458 if (empty
&& release_units
) {
459 release_units
->clear();
464 bool bluestore_blob_use_tracker_t::can_split() const
469 bool bluestore_blob_use_tracker_t::can_split_at(uint32_t blob_offset
) const
472 return (blob_offset
% au_size
) == 0 &&
473 blob_offset
< num_au
* au_size
;
476 void bluestore_blob_use_tracker_t::split(
477 uint32_t blob_offset
,
478 bluestore_blob_use_tracker_t
* r
)
482 assert(can_split_at(blob_offset
));
483 assert(r
->is_empty());
485 uint32_t new_num_au
= blob_offset
/ au_size
;
486 r
->init( (num_au
- new_num_au
) * au_size
, au_size
);
488 for (auto i
= new_num_au
; i
< num_au
; i
++) {
489 r
->get((i
- new_num_au
) * au_size
, bytes_per_au
[i
]);
492 if (new_num_au
== 0) {
494 } else if (new_num_au
== 1) {
495 uint32_t tmp
= bytes_per_au
[0];
496 uint32_t _au_size
= au_size
;
505 bool bluestore_blob_use_tracker_t::equal(
506 const bluestore_blob_use_tracker_t
& other
) const
508 if (!num_au
&& !other
.num_au
) {
509 return total_bytes
== other
.total_bytes
&& au_size
== other
.au_size
;
510 } else if (num_au
&& other
.num_au
) {
511 if (num_au
!= other
.num_au
|| au_size
!= other
.au_size
) {
514 for (size_t i
= 0; i
< num_au
; i
++) {
515 if (bytes_per_au
[i
] != other
.bytes_per_au
[i
]) {
522 uint32_t n
= num_au
? num_au
: other
.num_au
;
523 uint32_t referenced
=
524 num_au
? other
.get_referenced_bytes() : get_referenced_bytes();
525 auto bytes_per_au_tmp
= num_au
? bytes_per_au
: other
.bytes_per_au
;
526 uint32_t my_referenced
= 0;
527 for (size_t i
= 0; i
< n
; i
++) {
528 my_referenced
+= bytes_per_au_tmp
[i
];
529 if (my_referenced
> referenced
) {
533 return my_referenced
== referenced
;
536 void bluestore_blob_use_tracker_t::dump(Formatter
*f
) const
538 f
->dump_unsigned("num_au", num_au
);
539 f
->dump_unsigned("au_size", au_size
);
541 f
->dump_unsigned("total_bytes", total_bytes
);
543 f
->open_array_section("bytes_per_au");
544 for (size_t i
= 0; i
< num_au
; ++i
) {
545 f
->dump_unsigned("", bytes_per_au
[i
]);
551 void bluestore_blob_use_tracker_t::generate_test_instances(
552 list
<bluestore_blob_use_tracker_t
*>& o
)
554 o
.push_back(new bluestore_blob_use_tracker_t());
555 o
.back()->init(16, 16);
556 o
.back()->get(10, 10);
557 o
.back()->get(10, 5);
558 o
.push_back(new bluestore_blob_use_tracker_t());
559 o
.back()->init(60, 16);
560 o
.back()->get(18, 22);
561 o
.back()->get(20, 20);
562 o
.back()->get(15, 20);
565 ostream
& operator<<(ostream
& out
, const bluestore_blob_use_tracker_t
& m
)
567 out
<< "use_tracker(" << std::hex
;
569 out
<< "0x" << m
.au_size
571 << "0x" << m
.total_bytes
;
573 out
<< "0x" << m
.num_au
574 << "*0x" << m
.au_size
576 for (size_t i
= 0; i
< m
.num_au
; ++i
) {
579 out
<< m
.bytes_per_au
[i
];
583 out
<< std::dec
<< ")";
587 // bluestore_pextent_t
589 void bluestore_pextent_t::dump(Formatter
*f
) const
591 f
->dump_unsigned("offset", offset
);
592 f
->dump_unsigned("length", length
);
595 ostream
& operator<<(ostream
& out
, const bluestore_pextent_t
& o
) {
597 return out
<< "0x" << std::hex
<< o
.offset
<< "~" << o
.length
<< std::dec
;
599 return out
<< "!~" << std::hex
<< o
.length
<< std::dec
;
602 void bluestore_pextent_t::generate_test_instances(list
<bluestore_pextent_t
*>& ls
)
604 ls
.push_back(new bluestore_pextent_t
);
605 ls
.push_back(new bluestore_pextent_t(1, 2));
610 string
bluestore_blob_t::get_flags_string(unsigned flags
)
613 if (flags
& FLAG_COMPRESSED
) {
618 if (flags
& FLAG_CSUM
) {
623 if (flags
& FLAG_HAS_UNUSED
) {
628 if (flags
& FLAG_SHARED
) {
637 size_t bluestore_blob_t::get_csum_value_size() const
639 return Checksummer::get_csum_value_size(csum_type
);
642 void bluestore_blob_t::dump(Formatter
*f
) const
644 f
->open_array_section("extents");
645 for (auto& p
: extents
) {
646 f
->dump_object("extent", p
);
649 f
->dump_unsigned("logical_length", logical_length
);
650 f
->dump_unsigned("compressed_length", compressed_length
);
651 f
->dump_unsigned("flags", flags
);
652 f
->dump_unsigned("csum_type", csum_type
);
653 f
->dump_unsigned("csum_chunk_order", csum_chunk_order
);
654 f
->open_array_section("csum_data");
655 size_t n
= get_csum_count();
656 for (unsigned i
= 0; i
< n
; ++i
)
657 f
->dump_unsigned("csum", get_csum_item(i
));
659 f
->dump_unsigned("unused", unused
);
662 void bluestore_blob_t::generate_test_instances(list
<bluestore_blob_t
*>& ls
)
664 ls
.push_back(new bluestore_blob_t
);
665 ls
.push_back(new bluestore_blob_t(0));
666 ls
.push_back(new bluestore_blob_t
);
667 ls
.back()->allocated_test(bluestore_pextent_t(111, 222));
668 ls
.push_back(new bluestore_blob_t
);
669 ls
.back()->init_csum(Checksummer::CSUM_XXHASH32
, 16, 65536);
670 ls
.back()->csum_data
= buffer::claim_malloc(4, strdup("abcd"));
671 ls
.back()->add_unused(0, 3);
672 ls
.back()->add_unused(8, 8);
673 ls
.back()->allocated_test(bluestore_pextent_t(0x40100000, 0x10000));
674 ls
.back()->allocated_test(
675 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
, 0x1000));
676 ls
.back()->allocated_test(bluestore_pextent_t(0x40120000, 0x10000));
679 ostream
& operator<<(ostream
& out
, const bluestore_blob_t
& o
)
681 out
<< "blob(" << o
.get_extents();
682 if (o
.is_compressed()) {
683 out
<< " clen 0x" << std::hex
684 << o
.get_logical_length()
686 << o
.get_compressed_payload_length()
690 out
<< " " << o
.get_flags_string();
693 out
<< " " << Checksummer::get_csum_type_string(o
.csum_type
)
694 << "/0x" << std::hex
<< (1ull << o
.csum_chunk_order
) << std::dec
;
697 out
<< " unused=0x" << std::hex
<< o
.unused
<< std::dec
;
702 void bluestore_blob_t::calc_csum(uint64_t b_off
, const bufferlist
& bl
)
705 case Checksummer::CSUM_XXHASH32
:
706 Checksummer::calculate
<Checksummer::xxhash32
>(
707 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
709 case Checksummer::CSUM_XXHASH64
:
710 Checksummer::calculate
<Checksummer::xxhash64
>(
711 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
713 case Checksummer::CSUM_CRC32C
:
714 Checksummer::calculate
<Checksummer::crc32c
>(
715 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
717 case Checksummer::CSUM_CRC32C_16
:
718 Checksummer::calculate
<Checksummer::crc32c_16
>(
719 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
721 case Checksummer::CSUM_CRC32C_8
:
722 Checksummer::calculate
<Checksummer::crc32c_8
>(
723 get_csum_chunk_size(), b_off
, bl
.length(), bl
, &csum_data
);
728 int bluestore_blob_t::verify_csum(uint64_t b_off
, const bufferlist
& bl
,
729 int* b_bad_off
, uint64_t *bad_csum
) const
735 case Checksummer::CSUM_NONE
:
737 case Checksummer::CSUM_XXHASH32
:
738 *b_bad_off
= Checksummer::verify
<Checksummer::xxhash32
>(
739 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
741 case Checksummer::CSUM_XXHASH64
:
742 *b_bad_off
= Checksummer::verify
<Checksummer::xxhash64
>(
743 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
745 case Checksummer::CSUM_CRC32C
:
746 *b_bad_off
= Checksummer::verify
<Checksummer::crc32c
>(
747 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
749 case Checksummer::CSUM_CRC32C_16
:
750 *b_bad_off
= Checksummer::verify
<Checksummer::crc32c_16
>(
751 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
753 case Checksummer::CSUM_CRC32C_8
:
754 *b_bad_off
= Checksummer::verify
<Checksummer::crc32c_8
>(
755 get_csum_chunk_size(), b_off
, bl
.length(), bl
, csum_data
, bad_csum
);
764 else if (*b_bad_off
>= 0)
765 return -1; // bad checksum
770 void bluestore_blob_t::allocated(uint32_t b_off
, uint32_t length
, const AllocExtentVector
& allocs
)
772 if (extents
.size() == 0) {
773 // if blob is compressed then logical length to be already configured
774 // otherwise - to be unset.
775 assert((is_compressed() && logical_length
!= 0) ||
776 (!is_compressed() && logical_length
== 0));
778 extents
.reserve(allocs
.size() + (b_off
? 1 : 0));
780 extents
.emplace_back(
781 bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
, b_off
));
783 uint32_t new_len
= b_off
;
784 for (auto& a
: allocs
) {
785 extents
.emplace_back(a
.offset
, a
.length
);
788 if (!is_compressed()) {
789 logical_length
= new_len
;
792 assert(!is_compressed()); // partial allocations are forbidden when
794 assert(b_off
< logical_length
);
795 uint32_t cur_offs
= 0;
796 auto start_it
= extents
.begin();
799 assert(start_it
!= extents
.end());
800 if (cur_offs
+ start_it
->length
> b_off
) {
803 cur_offs
+= start_it
->length
;
807 uint32_t head
= b_off
- cur_offs
;
808 uint32_t end_off
= b_off
+ length
;
809 auto end_it
= start_it
;
812 assert(end_it
!= extents
.end());
813 assert(!end_it
->is_valid());
814 if (cur_offs
+ end_it
->length
>= end_off
) {
817 cur_offs
+= end_it
->length
;
820 assert(cur_offs
+ end_it
->length
>= end_off
);
821 uint32_t tail
= cur_offs
+ end_it
->length
- end_off
;
823 start_it
= extents
.erase(start_it
, end_it
+ 1);
824 size_t count
= allocs
.size();
825 count
+= head
? 1 : 0;
826 count
+= tail
? 1 : 0;
827 extents
.insert(start_it
,
830 bluestore_pextent_t::INVALID_OFFSET
, 0));
832 // Workaround to resolve lack of proper iterator return in vector::insert
833 // Looks like some gcc/stl implementations still lack it despite c++11
835 start_it
= extents
.begin() + pos
;
838 start_it
->length
= head
;
841 for(auto& e
: allocs
) {
846 start_it
->length
= tail
;
851 // cut it out of extents
854 uint64_t invalid
= 0;
856 void add_invalid(uint64_t length
) {
861 v
.emplace_back(bluestore_pextent_t(bluestore_pextent_t::INVALID_OFFSET
,
866 void add(uint64_t offset
, uint64_t length
) {
867 if (offset
== bluestore_pextent_t::INVALID_OFFSET
) {
872 v
.emplace_back(bluestore_pextent_t(offset
, length
));
877 void bluestore_blob_t::allocated_test(const bluestore_pextent_t
& alloc
)
879 extents
.emplace_back(alloc
);
880 if (!is_compressed()) {
881 logical_length
+= alloc
.length
;
885 bool bluestore_blob_t::release_extents(bool all
,
886 const PExtentVector
& logical
,
889 // common case: all of it?
892 for (auto& e
: extents
) {
898 assert(is_compressed() || get_logical_length() == pos
);
900 extents
[0].offset
= bluestore_pextent_t::INVALID_OFFSET
;
901 extents
[0].length
= pos
;
904 // remove from pextents according to logical release list
906 auto loffs_it
= logical
.begin();
907 auto lend
= logical
.end();
908 uint32_t pext_loffs_start
= 0; //starting loffset of the current pextent
909 uint32_t pext_loffs
= 0; //current loffset
910 auto pext_it
= extents
.begin();
911 auto pext_end
= extents
.end();
912 while (pext_it
!= pext_end
) {
913 if (loffs_it
== lend
||
914 pext_loffs_start
+ pext_it
->length
<= loffs_it
->offset
) {
915 int delta0
= pext_loffs
- pext_loffs_start
;
917 if ((uint32_t)delta0
< pext_it
->length
) {
918 vb
.add(pext_it
->offset
+ delta0
, pext_it
->length
- delta0
);
920 pext_loffs_start
+= pext_it
->length
;
921 pext_loffs
= pext_loffs_start
;
925 //assert(pext_loffs == pext_loffs_start);
926 int delta0
= pext_loffs
- pext_loffs_start
;
929 int delta
= loffs_it
->offset
- pext_loffs
;
932 vb
.add(pext_it
->offset
+ delta0
, delta
);
936 PExtentVector::iterator last_r
= r
->end();
937 if (r
->begin() != last_r
) {
940 uint32_t to_release
= loffs_it
->length
;
942 uint32_t to_release_part
=
943 MIN(pext_it
->length
- delta0
- delta
, to_release
);
944 auto o
= pext_it
->offset
+ delta0
+ delta
;
945 if (last_r
!= r
->end() && last_r
->offset
+ last_r
->length
== o
) {
946 last_r
->length
+= to_release_part
;
949 last_r
= r
->emplace(r
->end(), o
, to_release_part
);
951 to_release
-= to_release_part
;
952 pext_loffs
+= to_release_part
;
953 if (pext_loffs
== pext_loffs_start
+ pext_it
->length
) {
954 pext_loffs_start
+= pext_it
->length
;
955 pext_loffs
= pext_loffs_start
;
959 } while (to_release
> 0 && pext_it
!= pext_end
);
960 vb
.add_invalid(loffs_it
->length
- to_release
);
969 void bluestore_blob_t::split(uint32_t blob_offset
, bluestore_blob_t
& rb
)
971 size_t left
= blob_offset
;
972 uint32_t llen_lb
= 0;
973 uint32_t llen_rb
= 0;
975 for (auto p
= extents
.begin(); p
!= extents
.end(); ++p
, ++i
) {
976 if (p
->length
<= left
) {
978 llen_lb
+= p
->length
;
983 rb
.extents
.emplace_back(bluestore_pextent_t(p
->offset
+ left
,
987 rb
.extents
.emplace_back(bluestore_pextent_t(
988 bluestore_pextent_t::INVALID_OFFSET
,
991 llen_rb
+= p
->length
- left
;
997 while (p
!= extents
.end()) {
998 llen_rb
+= p
->length
;
999 rb
.extents
.push_back(*p
++);
1002 logical_length
= llen_lb
;
1003 rb
.logical_length
= llen_rb
;
1009 rb
.csum_type
= csum_type
;
1010 rb
.csum_chunk_order
= csum_chunk_order
;
1011 size_t csum_order
= get_csum_chunk_size();
1012 assert(blob_offset
% csum_order
== 0);
1013 size_t pos
= (blob_offset
/ csum_order
) * get_csum_value_size();
1014 // deep copy csum data
1016 old
.swap(csum_data
);
1017 rb
.csum_data
= bufferptr(old
.c_str() + pos
, old
.length() - pos
);
1018 csum_data
= bufferptr(old
.c_str(), pos
);
1022 // bluestore_shared_blob_t
1024 void bluestore_shared_blob_t::dump(Formatter
*f
) const
1026 f
->dump_int("sbid", sbid
);
1027 f
->dump_object("ref_map", ref_map
);
1030 void bluestore_shared_blob_t::generate_test_instances(
1031 list
<bluestore_shared_blob_t
*>& ls
)
1033 ls
.push_back(new bluestore_shared_blob_t(1));
1036 ostream
& operator<<(ostream
& out
, const bluestore_shared_blob_t
& sb
)
1038 out
<< "(sbid 0x" << std::hex
<< sb
.sbid
<< std::dec
;
1039 out
<< " " << sb
.ref_map
<< ")";
1043 // bluestore_onode_t
1045 void bluestore_onode_t::shard_info::dump(Formatter
*f
) const
1047 f
->dump_unsigned("offset", offset
);
1048 f
->dump_unsigned("bytes", bytes
);
1051 ostream
& operator<<(ostream
& out
, const bluestore_onode_t::shard_info
& si
)
1053 return out
<< std::hex
<< "0x" << si
.offset
<< "(0x" << si
.bytes
<< " bytes"
1057 void bluestore_onode_t::dump(Formatter
*f
) const
1059 f
->dump_unsigned("nid", nid
);
1060 f
->dump_unsigned("size", size
);
1061 f
->open_object_section("attrs");
1062 for (auto p
= attrs
.begin(); p
!= attrs
.end(); ++p
) {
1063 f
->open_object_section("attr");
1064 f
->dump_string("name", p
->first
.c_str()); // it's not quite std::string
1065 f
->dump_unsigned("len", p
->second
.length());
1069 f
->dump_string("flags", get_flags_string());
1070 f
->open_array_section("extent_map_shards");
1071 for (auto si
: extent_map_shards
) {
1072 f
->dump_object("shard", si
);
1075 f
->dump_unsigned("expected_object_size", expected_object_size
);
1076 f
->dump_unsigned("expected_write_size", expected_write_size
);
1077 f
->dump_unsigned("alloc_hint_flags", alloc_hint_flags
);
1080 void bluestore_onode_t::generate_test_instances(list
<bluestore_onode_t
*>& o
)
1082 o
.push_back(new bluestore_onode_t());
1086 // bluestore_deferred_op_t
1088 void bluestore_deferred_op_t::dump(Formatter
*f
) const
1090 f
->dump_unsigned("op", (int)op
);
1091 f
->dump_unsigned("data_len", data
.length());
1092 f
->open_array_section("extents");
1093 for (auto& e
: extents
) {
1094 f
->dump_object("extent", e
);
1099 void bluestore_deferred_op_t::generate_test_instances(list
<bluestore_deferred_op_t
*>& o
)
1101 o
.push_back(new bluestore_deferred_op_t
);
1102 o
.push_back(new bluestore_deferred_op_t
);
1103 o
.back()->op
= OP_WRITE
;
1104 o
.back()->extents
.push_back(bluestore_pextent_t(1, 2));
1105 o
.back()->extents
.push_back(bluestore_pextent_t(100, 5));
1106 o
.back()->data
.append("my data");
1109 void bluestore_deferred_transaction_t::dump(Formatter
*f
) const
1111 f
->dump_unsigned("seq", seq
);
1112 f
->open_array_section("ops");
1113 for (list
<bluestore_deferred_op_t
>::const_iterator p
= ops
.begin(); p
!= ops
.end(); ++p
) {
1114 f
->dump_object("op", *p
);
1118 f
->open_array_section("released extents");
1119 for (interval_set
<uint64_t>::const_iterator p
= released
.begin(); p
!= released
.end(); ++p
) {
1120 f
->open_object_section("extent");
1121 f
->dump_unsigned("offset", p
.get_start());
1122 f
->dump_unsigned("length", p
.get_len());
1128 void bluestore_deferred_transaction_t::generate_test_instances(list
<bluestore_deferred_transaction_t
*>& o
)
1130 o
.push_back(new bluestore_deferred_transaction_t());
1131 o
.push_back(new bluestore_deferred_transaction_t());
1132 o
.back()->seq
= 123;
1133 o
.back()->ops
.push_back(bluestore_deferred_op_t());
1134 o
.back()->ops
.push_back(bluestore_deferred_op_t());
1135 o
.back()->ops
.back().op
= bluestore_deferred_op_t::OP_WRITE
;
1136 o
.back()->ops
.back().extents
.push_back(bluestore_pextent_t(1,7));
1137 o
.back()->ops
.back().data
.append("foodata");
1140 void bluestore_compression_header_t::dump(Formatter
*f
) const
1142 f
->dump_unsigned("type", type
);
1143 f
->dump_unsigned("length", length
);
1146 void bluestore_compression_header_t::generate_test_instances(
1147 list
<bluestore_compression_header_t
*>& o
)
1149 o
.push_back(new bluestore_compression_header_t
);
1150 o
.push_back(new bluestore_compression_header_t(1));
1151 o
.back()->length
= 1234;