rmw_pipeline(cct, ec_impl, this->sinfo, get_parent()->get_eclistener(), *this),
recovery_backend(cct, this->coll, ec_impl, this->sinfo, read_pipeline, unstable_hashinfo_registry, get_parent(), this),
ec_impl(ec_impl),
- sinfo(ec_impl->get_data_chunk_count(), stripe_width),
+ sinfo(ec_impl, stripe_width),
unstable_hashinfo_registry(cct, ec_impl) {
ceph_assert((ec_impl->get_data_chunk_count() *
ec_impl->get_chunk_size(stripe_width)) == stripe_width);
async);
if (!get_parent()->pg_is_undersized() &&
- (unsigned)get_parent()->whoami_shard().shard >=
- ec_impl->get_data_chunk_count())
+ (unsigned)get_parent()->whoami_shard().shard >= sinfo.get_k())
op.t.set_fadvise_flag(CEPH_OSD_OP_FLAG_FADVISE_DONTNEED);
localt.register_on_commit(
const uint64_t offset,
const uint64_t length,
const ECUtil::stripe_info_t& sinfo,
- const vector<int>& chunk_mapping,
set<int> *want_to_read)
{
const auto [left_chunk_index, right_chunk_index] =
sinfo.offset_length_to_data_chunk_indices(offset, length);
const auto distance =
- std::min(right_chunk_index - left_chunk_index,
- sinfo.get_data_chunk_count());
+ std::min(right_chunk_index - left_chunk_index, (uint64_t)sinfo.get_k());
for(uint64_t i = 0; i < distance; i++) {
- auto raw_chunk = (left_chunk_index + i) % sinfo.get_data_chunk_count();
- auto chunk = chunk_mapping.size() > raw_chunk ?
- chunk_mapping[raw_chunk] : static_cast<int>(raw_chunk);
- want_to_read->insert(chunk);
+ auto raw_shard = (left_chunk_index + i) % sinfo.get_k();
+ want_to_read->insert(sinfo.get_shard(raw_shard));
}
}
const uint64_t length,
set<int> *want_to_read)
{
- get_min_want_to_read_shards(
- offset, length, sinfo, ec_impl->get_chunk_mapping(), want_to_read);
+ get_min_want_to_read_shards(offset, length, sinfo, want_to_read);
dout(20) << __func__ << ": offset " << offset << " length " << length
<< " want_to_read " << *want_to_read << dendl;
}
void ECCommon::ReadPipeline::get_want_to_read_shards(
std::set<int> *want_to_read) const
{
- const std::vector<int> &chunk_mapping = ec_impl->get_chunk_mapping();
- for (int i = 0; i < (int)ec_impl->get_data_chunk_count(); ++i) {
- int chunk = (int)chunk_mapping.size() > i ? chunk_mapping[i] : i;
- want_to_read->insert(chunk);
+ for (int i = 0; i < (int)sinfo.get_k(); ++i) {
+ want_to_read->insert(sinfo.get_shard(i));
}
}
const uint64_t offset,
const uint64_t length,
const ECUtil::stripe_info_t& sinfo,
- const std::vector<int>& chunk_mapping,
std::set<int> *want_to_read);
int get_remaining_shards(
class stripe_info_t {
const uint64_t stripe_width;
const uint64_t chunk_size;
+ const unsigned int k; // Can be calculated with a division from above. Better to cache.
+ const unsigned int m;
+ const std::vector<int> chunk_mapping;
+ const std::vector<unsigned int> chunk_mapping_reverse;
+private:
+ static std::vector<int> complete_chunk_mapping(
+ std::vector<int> _chunk_mapping, unsigned int n)
+ {
+ unsigned int size = _chunk_mapping.size();
+ std::vector<int> chunk_mapping(n);
+ for (unsigned int i = 0; i < n; i++) {
+ if (size > i) {
+ chunk_mapping.at(i) = _chunk_mapping.at(i);
+ } else {
+ chunk_mapping.at(i) = static_cast<int>(i);
+ }
+ }
+ return chunk_mapping;
+ }
+ static std::vector<unsigned int> reverse_chunk_mapping(
+ std::vector<int> chunk_mapping)
+ {
+ unsigned int size = chunk_mapping.size();
+ std::vector<unsigned int> reverse(size);
+ std::vector<bool> used(size,false);
+ for (unsigned int i = 0; i < size; i++) {
+ int index = chunk_mapping.at(i);
+ // Mapping must be a bijection and a permutation
+ ceph_assert(!used.at(index));
+ used.at(index) = true;
+ reverse.at(index) = i;
+ }
+ return reverse;
+ }
public:
- stripe_info_t(uint64_t stripe_size, uint64_t stripe_width)
+ stripe_info_t(ErasureCodeInterfaceRef ec_impl, uint64_t stripe_width)
+ : stripe_width(stripe_width),
+ chunk_size(stripe_width / ec_impl->get_data_chunk_count()),
+ k(ec_impl->get_data_chunk_count()),
+ m(ec_impl->get_coding_chunk_count()),
+ chunk_mapping(complete_chunk_mapping(ec_impl->get_chunk_mapping(),
+ k + m)),
+ chunk_mapping_reverse(reverse_chunk_mapping(chunk_mapping)) {
+ ceph_assert(stripe_width % k == 0);
+ }
+ // Simpler constructors for unit tests
+ stripe_info_t(unsigned int k, unsigned int m, uint64_t stripe_width)
: stripe_width(stripe_width),
- chunk_size(stripe_width / stripe_size) {
- ceph_assert(stripe_width % stripe_size == 0);
+ chunk_size(stripe_width / k),
+ k(k),
+ m(m),
+ chunk_mapping(complete_chunk_mapping(std::vector<int>(), k + m)),
+ chunk_mapping_reverse(reverse_chunk_mapping(chunk_mapping)) {
+ ceph_assert(stripe_width % k == 0);
+ }
+ stripe_info_t(unsigned int k, unsigned int m, uint64_t stripe_width,
+ std::vector<int> _chunk_mapping)
+ : stripe_width(stripe_width),
+ chunk_size(stripe_width / k),
+ k(k),
+ m(m),
+ chunk_mapping(complete_chunk_mapping(_chunk_mapping, k + m)),
+ chunk_mapping_reverse(reverse_chunk_mapping(chunk_mapping)) {
+ ceph_assert(stripe_width % k == 0);
}
bool logical_offset_is_stripe_aligned(uint64_t logical) const {
return (logical % stripe_width) == 0;
uint64_t get_chunk_size() const {
return chunk_size;
}
- uint64_t get_data_chunk_count() const {
- return get_stripe_width() / get_chunk_size();
+ unsigned int get_m() const {
+ return m;
+ }
+ unsigned int get_k() const {
+ return k;
+ }
+ unsigned int get_k_plus_m() const {
+ return k + m;
+ }
+ int get_shard(unsigned int raw_shard) const {
+ return chunk_mapping[raw_shard];
+ }
+ unsigned int get_raw_shard(int shard) const {
+ return chunk_mapping_reverse[shard];
}
uint64_t logical_to_prev_chunk_offset(uint64_t offset) const {
return (offset / stripe_width) * chunk_size;
static test_obj_t make_ec_head(const std::string &desc, Args&&... args) {
return make(
desc,
- ECUtil::stripe_info_t{4, 1<<20},
+ ECUtil::stripe_info_t{4, 2, 1<<20},
so_builder_t::make_ec_head(std::forward<Args>(args)...));
}
static test_obj_t make_ec_clone(const std::string &desc, Args&&... args) {
return make(
desc,
- ECUtil::stripe_info_t{4, 1<<20},
+ ECUtil::stripe_info_t{4, 2, 1<<20},
so_builder_t::make_ec_clone(std::forward<Args>(args)...));
}
TEST(ECUtil, stripe_info_t)
{
const uint64_t swidth = 4096;
- const uint64_t ssize = 4;
+ const unsigned int k = 4;
+ const unsigned int m = 2;
- ECUtil::stripe_info_t s(ssize, swidth);
+ ECUtil::stripe_info_t s(k, m, swidth);
ASSERT_EQ(s.get_stripe_width(), swidth);
ASSERT_EQ(s.logical_to_next_chunk_offset(0), 0u);
{
const uint64_t swidth = 4096;
const uint64_t schunk = 1024;
- const uint64_t ssize = 4;
+ const unsigned int k = 4;
+ const unsigned int m = 2;
- ECUtil::stripe_info_t s(ssize, swidth);
+ ECUtil::stripe_info_t s(k, m, swidth);
ASSERT_EQ(s.get_stripe_width(), swidth);
ASSERT_EQ(s.get_chunk_size(), schunk);
TEST(ECCommon, get_min_want_to_read_shards)
{
const uint64_t swidth = 4096;
- const uint64_t ssize = 4;
+ const unsigned int k = 4;
+ const unsigned int m = 2;
- ECUtil::stripe_info_t s(ssize, swidth);
+ ECUtil::stripe_info_t s(k, m, swidth);
ASSERT_EQ(s.get_stripe_width(), swidth);
ASSERT_EQ(s.get_chunk_size(), 1024);
- const std::vector<int> chunk_mapping = {}; // no remapping
-
// read nothing at the very beginning
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 0, 0, s, chunk_mapping, &want_to_read);
+ 0, 0, s, &want_to_read);
ASSERT_TRUE(want_to_read == std::set<int>{});
}
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 2048, 0, s, chunk_mapping, &want_to_read);
+ 2048, 0, s, &want_to_read);
ASSERT_TRUE(want_to_read == std::set<int>{});
}
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 2048, 42, s, chunk_mapping, &want_to_read);
+ 2048, 42, s, &want_to_read);
ASSERT_TRUE(want_to_read == std::set<int>{2});
}
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 1024, 1024+42, s, chunk_mapping, &want_to_read);
+ 1024, 1024+42, s, &want_to_read);
// extra () due to a language / macro limitation
ASSERT_TRUE(want_to_read == (std::set<int>{1, 2}));
}
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 0, 3*1024, s, chunk_mapping, &want_to_read);
+ 0, 3*1024, s, &want_to_read);
// extra () due to a language / macro limitation
ASSERT_TRUE(want_to_read == (std::set<int>{0, 1, 2}));
}
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 1024, swidth-1024, s, chunk_mapping, &want_to_read);
+ 1024, swidth-1024, s, &want_to_read);
// extra () due to a language / macro limitation
ASSERT_TRUE(want_to_read == (std::set<int>{1, 2, 3}));
}
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 1024, swidth*42, s, chunk_mapping, &want_to_read);
+ 1024, swidth*42, s, &want_to_read);
// extra () due to a language / macro limitation
ASSERT_TRUE(want_to_read == (std::set<int>{0, 1, 2, 3}));
}
{
std::set<int> want_to_read;
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 0, swidth*42, s, chunk_mapping, &want_to_read);
+ 0, swidth*42, s, &want_to_read);
// extra () due to a language / macro limitation
ASSERT_TRUE(want_to_read == (std::set<int>{0, 1, 2, 3}));
}
TEST(ECCommon, get_min_want_to_read_shards_bug67087)
{
const uint64_t swidth = 4096;
- const uint64_t ssize = 4;
+ const unsigned int k = 4;
+ const unsigned int m = 2;
- ECUtil::stripe_info_t s(ssize, swidth);
+ ECUtil::stripe_info_t s(k, m, swidth);
ASSERT_EQ(s.get_stripe_width(), swidth);
ASSERT_EQ(s.get_chunk_size(), 1024);
- const std::vector<int> chunk_mapping = {}; // no remapping
-
std::set<int> want_to_read;
// multitple calls with the same want_to_read can happen during
// multi-region reads.
{
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 512, 512, s, chunk_mapping, &want_to_read);
+ 512, 512, s, &want_to_read);
ASSERT_EQ(want_to_read, std::set<int>{0});
ECCommon::ReadPipeline::get_min_want_to_read_shards(
- 512+16*1024, 512, s, chunk_mapping, &want_to_read);
+ 512+16*1024, 512, s, &want_to_read);
ASSERT_EQ(want_to_read, std::set<int>{0});
}
}
b.append_zero(2437120);
t->write(h, 669856, b.length(), b, 0);
- ECUtil::stripe_info_t sinfo(2, 8192);
+ ECUtil::stripe_info_t sinfo(2, 2, 8192);
auto plan = ECTransaction::get_write_plan(
sinfo,
*t,
t->create(h);
// two nearby writes, both partly touching the same 8192-byte stripe
- ECUtil::stripe_info_t sinfo(2, 8192);
+ ECUtil::stripe_info_t sinfo(2, 2, 8192);
a.append_zero(565760);
t->write(h, 0, a.length(), a, 0);
b.append_zero(2437120);
b.append_zero(4096);
t->create(h);
- ECUtil::stripe_info_t sinfo(2, 8192);
+ ECUtil::stripe_info_t sinfo(2, 2, 8192);
// write 2801664~512
// write 2802176~512
// write 2802688~512
uint64_t stripe_size = atoi(profile["k"].c_str());
ceph_assert(stripe_size > 0);
uint64_t stripe_width = stripe_size * stripe_unit;
- sinfo->reset(new ECUtil::stripe_info_t(stripe_size, stripe_width));
+ sinfo->reset(new ECUtil::stripe_info_t(*ec_impl, stripe_width));
return 0;
}