|
| 1 | +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
| 2 | + |
| 3 | +#include <errno.h> |
| 4 | +#include "common/ceph_context.h" |
| 5 | +#include "global/global_context.h" |
| 6 | +#include "include/encoding.h" |
| 7 | +#include "ECUtil.h" |
| 8 | + |
| 9 | +using namespace std; |
| 10 | +using ceph::bufferlist; |
| 11 | +using ceph::ErasureCodeInterfaceRef; |
| 12 | +using ceph::Formatter; |
| 13 | + |
| 14 | +std::pair<uint64_t, uint64_t> ECUtil::stripe_info_t::chunk_aligned_offset_len_to_chunk( |
| 15 | + std::pair<uint64_t, uint64_t> in) const { |
| 16 | + pair<uint64_t, uint64_t> tmp = offset_len_to_stripe_bounds(in); |
| 17 | + return std::make_pair( |
| 18 | + chunk_aligned_logical_offset_to_chunk_offset(tmp.first), |
| 19 | + chunk_aligned_logical_size_to_chunk_size(tmp.second)); |
| 20 | +} |
| 21 | + |
| 22 | +int ECUtil::decode( |
| 23 | + const stripe_info_t &sinfo, |
| 24 | + ErasureCodeInterfaceRef &ec_impl, |
| 25 | + const set<int> want_to_read, |
| 26 | + map<int, bufferlist> &to_decode, |
| 27 | + bufferlist *out) |
| 28 | +{ |
| 29 | + ceph_assert(to_decode.size()); |
| 30 | + |
| 31 | + uint64_t total_data_size = to_decode.begin()->second.length(); |
| 32 | + ceph_assert(total_data_size % sinfo.get_chunk_size() == 0); |
| 33 | + |
| 34 | + ceph_assert(out); |
| 35 | + ceph_assert(out->length() == 0); |
| 36 | + |
| 37 | + for (map<int, bufferlist>::iterator i = to_decode.begin(); |
| 38 | + i != to_decode.end(); |
| 39 | + ++i) { |
| 40 | + ceph_assert(i->second.length() == total_data_size); |
| 41 | + } |
| 42 | + |
| 43 | + if (total_data_size == 0) |
| 44 | + return 0; |
| 45 | + |
| 46 | + for (uint64_t i = 0; i < total_data_size; i += sinfo.get_chunk_size()) { |
| 47 | + map<int, bufferlist> chunks; |
| 48 | + for (map<int, bufferlist>::iterator j = to_decode.begin(); |
| 49 | + j != to_decode.end(); |
| 50 | + ++j) { |
| 51 | + chunks[j->first].substr_of(j->second, i, sinfo.get_chunk_size()); |
| 52 | + } |
| 53 | + bufferlist bl; |
| 54 | + int r = ec_impl->decode_concat(want_to_read, chunks, &bl); |
| 55 | + ceph_assert(r == 0); |
| 56 | + ceph_assert(bl.length() % sinfo.get_chunk_size() == 0); |
| 57 | + out->claim_append(bl); |
| 58 | + } |
| 59 | + return 0; |
| 60 | +} |
| 61 | + |
| 62 | +int ECUtil::decode( |
| 63 | + const stripe_info_t &sinfo, |
| 64 | + ErasureCodeInterfaceRef &ec_impl, |
| 65 | + map<int, bufferlist> &to_decode, |
| 66 | + map<int, bufferlist*> &out) { |
| 67 | + |
| 68 | + ceph_assert(to_decode.size()); |
| 69 | + |
| 70 | + for (auto &&i : to_decode) { |
| 71 | + if(i.second.length() == 0) |
| 72 | + return 0; |
| 73 | + } |
| 74 | + |
| 75 | + set<int> need; |
| 76 | + for (map<int, bufferlist*>::iterator i = out.begin(); |
| 77 | + i != out.end(); |
| 78 | + ++i) { |
| 79 | + ceph_assert(i->second); |
| 80 | + ceph_assert(i->second->length() == 0); |
| 81 | + need.insert(i->first); |
| 82 | + } |
| 83 | + |
| 84 | + set<int> avail; |
| 85 | + for (auto &&i : to_decode) { |
| 86 | + ceph_assert(i.second.length() != 0); |
| 87 | + avail.insert(i.first); |
| 88 | + } |
| 89 | + |
| 90 | + map<int, vector<pair<int, int>>> min; |
| 91 | + int r = ec_impl->minimum_to_decode(need, avail, &min); |
| 92 | + ceph_assert(r == 0); |
| 93 | + |
| 94 | + int chunks_count = 0; |
| 95 | + int repair_data_per_chunk = 0; |
| 96 | + int subchunk_size = sinfo.get_chunk_size()/ec_impl->get_sub_chunk_count(); |
| 97 | + |
| 98 | + for (auto &&i : to_decode) { |
| 99 | + auto found = min.find(i.first); |
| 100 | + if (found != min.end()) { |
| 101 | + int repair_subchunk_count = 0; |
| 102 | + for (auto& subchunks : min[i.first]) { |
| 103 | + repair_subchunk_count += subchunks.second; |
| 104 | + } |
| 105 | + repair_data_per_chunk = repair_subchunk_count * subchunk_size; |
| 106 | + chunks_count = (int)i.second.length() / repair_data_per_chunk; |
| 107 | + break; |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + for (int i = 0; i < chunks_count; i++) { |
| 112 | + map<int, bufferlist> chunks; |
| 113 | + for (auto j = to_decode.begin(); |
| 114 | + j != to_decode.end(); |
| 115 | + ++j) { |
| 116 | + chunks[j->first].substr_of(j->second, |
| 117 | + i*repair_data_per_chunk, |
| 118 | + repair_data_per_chunk); |
| 119 | + } |
| 120 | + map<int, bufferlist> out_bls; |
| 121 | + r = ec_impl->decode(need, chunks, &out_bls, sinfo.get_chunk_size()); |
| 122 | + ceph_assert(r == 0); |
| 123 | + for (auto j = out.begin(); j != out.end(); ++j) { |
| 124 | + ceph_assert(out_bls.count(j->first)); |
| 125 | + ceph_assert(out_bls[j->first].length() == sinfo.get_chunk_size()); |
| 126 | + j->second->claim_append(out_bls[j->first]); |
| 127 | + } |
| 128 | + } |
| 129 | + for (auto &&i : out) { |
| 130 | + ceph_assert(i.second->length() == chunks_count * sinfo.get_chunk_size()); |
| 131 | + } |
| 132 | + return 0; |
| 133 | +} |
| 134 | + |
| 135 | +int ECUtil::encode( |
| 136 | + const stripe_info_t &sinfo, |
| 137 | + ErasureCodeInterfaceRef &ec_impl, |
| 138 | + bufferlist &in, |
| 139 | + const set<int> &want, |
| 140 | + map<int, bufferlist> *out) { |
| 141 | + |
| 142 | + uint64_t logical_size = in.length(); |
| 143 | + |
| 144 | + ceph_assert(logical_size % sinfo.get_stripe_width() == 0); |
| 145 | + ceph_assert(out); |
| 146 | + ceph_assert(out->empty()); |
| 147 | + |
| 148 | + if (logical_size == 0) |
| 149 | + return 0; |
| 150 | + |
| 151 | + for (uint64_t i = 0; i < logical_size; i += sinfo.get_stripe_width()) { |
| 152 | + map<int, bufferlist> encoded; |
| 153 | + bufferlist buf; |
| 154 | + buf.substr_of(in, i, sinfo.get_stripe_width()); |
| 155 | + int r = ec_impl->encode(want, buf, &encoded); |
| 156 | + ceph_assert(r == 0); |
| 157 | + for (map<int, bufferlist>::iterator i = encoded.begin(); |
| 158 | + i != encoded.end(); |
| 159 | + ++i) { |
| 160 | + ceph_assert(i->second.length() == sinfo.get_chunk_size()); |
| 161 | + (*out)[i->first].claim_append(i->second); |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + for (map<int, bufferlist>::iterator i = out->begin(); |
| 166 | + i != out->end(); |
| 167 | + ++i) { |
| 168 | + ceph_assert(i->second.length() % sinfo.get_chunk_size() == 0); |
| 169 | + ceph_assert( |
| 170 | + sinfo.aligned_chunk_offset_to_logical_offset(i->second.length()) == |
| 171 | + logical_size); |
| 172 | + } |
| 173 | + return 0; |
| 174 | +} |
| 175 | + |
| 176 | +void ECUtil::HashInfo::append(uint64_t old_size, |
| 177 | + map<int, bufferlist> &to_append) { |
| 178 | + ceph_assert(old_size == total_chunk_size); |
| 179 | + uint64_t size_to_append = to_append.begin()->second.length(); |
| 180 | + if (has_chunk_hash()) { |
| 181 | + ceph_assert(to_append.size() == cumulative_shard_hashes.size()); |
| 182 | + for (map<int, bufferlist>::iterator i = to_append.begin(); |
| 183 | + i != to_append.end(); |
| 184 | + ++i) { |
| 185 | + ceph_assert(size_to_append == i->second.length()); |
| 186 | + ceph_assert((unsigned)i->first < cumulative_shard_hashes.size()); |
| 187 | + uint32_t new_hash = i->second.crc32c(cumulative_shard_hashes[i->first]); |
| 188 | + cumulative_shard_hashes[i->first] = new_hash; |
| 189 | + } |
| 190 | + } |
| 191 | + total_chunk_size += size_to_append; |
| 192 | +} |
| 193 | + |
| 194 | +void ECUtil::HashInfo::encode(bufferlist &bl) const |
| 195 | +{ |
| 196 | + ENCODE_START(1, 1, bl); |
| 197 | + encode(total_chunk_size, bl); |
| 198 | + encode(cumulative_shard_hashes, bl); |
| 199 | + ENCODE_FINISH(bl); |
| 200 | +} |
| 201 | + |
| 202 | +void ECUtil::HashInfo::decode(bufferlist::const_iterator &bl) |
| 203 | +{ |
| 204 | + DECODE_START(1, bl); |
| 205 | + decode(total_chunk_size, bl); |
| 206 | + decode(cumulative_shard_hashes, bl); |
| 207 | + projected_total_chunk_size = total_chunk_size; |
| 208 | + DECODE_FINISH(bl); |
| 209 | +} |
| 210 | + |
| 211 | +void ECUtil::HashInfo::dump(Formatter *f) const |
| 212 | +{ |
| 213 | + f->dump_unsigned("total_chunk_size", total_chunk_size); |
| 214 | + f->open_array_section("cumulative_shard_hashes"); |
| 215 | + for (unsigned i = 0; i != cumulative_shard_hashes.size(); ++i) { |
| 216 | + f->open_object_section("hash"); |
| 217 | + f->dump_unsigned("shard", i); |
| 218 | + f->dump_unsigned("hash", cumulative_shard_hashes[i]); |
| 219 | + f->close_section(); |
| 220 | + } |
| 221 | + f->close_section(); |
| 222 | +} |
| 223 | + |
| 224 | +namespace ECUtil { |
| 225 | +std::ostream& operator<<(std::ostream& out, const HashInfo& hi) |
| 226 | +{ |
| 227 | + ostringstream hashes; |
| 228 | + for (auto hash: hi.cumulative_shard_hashes) |
| 229 | + hashes << " " << hex << hash; |
| 230 | + return out << "tcs=" << hi.total_chunk_size << hashes.str(); |
| 231 | +} |
| 232 | +} |
| 233 | + |
| 234 | +void ECUtil::HashInfo::generate_test_instances(list<HashInfo*>& o) |
| 235 | +{ |
| 236 | + o.push_back(new HashInfo(3)); |
| 237 | + { |
| 238 | + bufferlist bl; |
| 239 | + bl.append_zero(20); |
| 240 | + map<int, bufferlist> buffers; |
| 241 | + buffers[0] = bl; |
| 242 | + buffers[1] = bl; |
| 243 | + buffers[2] = bl; |
| 244 | + o.back()->append(0, buffers); |
| 245 | + o.back()->append(20, buffers); |
| 246 | + } |
| 247 | + o.push_back(new HashInfo(4)); |
| 248 | +} |
| 249 | + |
| 250 | +const string HINFO_KEY = "hinfo_key"; |
| 251 | + |
| 252 | +bool ECUtil::is_hinfo_key_string(const string &key) |
| 253 | +{ |
| 254 | + return key == HINFO_KEY; |
| 255 | +} |
| 256 | + |
| 257 | +const string &ECUtil::get_hinfo_key() |
| 258 | +{ |
| 259 | + return HINFO_KEY; |
| 260 | +} |
0 commit comments