diff options
Diffstat (limited to 'src/osd/ECTransaction.h')
-rw-r--r-- | src/osd/ECTransaction.h | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/src/osd/ECTransaction.h b/src/osd/ECTransaction.h new file mode 100644 index 000000000..5cb16261a --- /dev/null +++ b/src/osd/ECTransaction.h @@ -0,0 +1,200 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2013 Inktank Storage, Inc. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef ECTRANSACTION_H +#define ECTRANSACTION_H + +#include "OSD.h" +#include "PGBackend.h" +#include "ECUtil.h" +#include "erasure-code/ErasureCodeInterface.h" +#include "PGTransaction.h" +#include "ExtentCache.h" + +namespace ECTransaction { + struct WritePlan { + PGTransactionUPtr t; + bool invalidates_cache = false; // Yes, both are possible + std::map<hobject_t,extent_set> to_read; + std::map<hobject_t,extent_set> will_write; // superset of to_read + + std::map<hobject_t,ECUtil::HashInfoRef> hash_infos; + }; + + bool requires_overwrite( + uint64_t prev_size, + const PGTransaction::ObjectOperation &op); + + template <typename F> + WritePlan get_write_plan( + const ECUtil::stripe_info_t &sinfo, + PGTransactionUPtr &&t, + F &&get_hinfo, + DoutPrefixProvider *dpp) { + WritePlan plan; + t->safe_create_traverse( + [&](std::pair<const hobject_t, PGTransaction::ObjectOperation> &i) { + ECUtil::HashInfoRef hinfo = get_hinfo(i.first); + plan.hash_infos[i.first] = hinfo; + + uint64_t projected_size = + hinfo->get_projected_total_logical_size(sinfo); + + if (i.second.deletes_first()) { + ldpp_dout(dpp, 20) << __func__ << ": delete, setting projected size" + << " to 0" << dendl; + projected_size = 0; + } + + hobject_t source; + if (i.second.has_source(&source)) { + plan.invalidates_cache = true; + + ECUtil::HashInfoRef shinfo = get_hinfo(source); + projected_size = shinfo->get_projected_total_logical_size(sinfo); + plan.hash_infos[source] = shinfo; + } + + auto &will_write = plan.will_write[i.first]; + if (i.second.truncate && + i.second.truncate->first < projected_size) { + if (!(sinfo.logical_offset_is_stripe_aligned( + i.second.truncate->first))) { + plan.to_read[i.first].union_insert( + sinfo.logical_to_prev_stripe_offset(i.second.truncate->first), + sinfo.get_stripe_width()); + + ldpp_dout(dpp, 20) << __func__ << ": unaligned truncate" << dendl; + + will_write.union_insert( + sinfo.logical_to_prev_stripe_offset(i.second.truncate->first), + sinfo.get_stripe_width()); + } + projected_size = sinfo.logical_to_next_stripe_offset( + i.second.truncate->first); + } + + extent_set raw_write_set; + for (auto &&extent: i.second.buffer_updates) { + using BufferUpdate = PGTransaction::ObjectOperation::BufferUpdate; + if (boost::get<BufferUpdate::CloneRange>(&(extent.get_val()))) { + ceph_assert( + 0 == + "CloneRange is not allowed, do_op should have returned ENOTSUPP"); + } + raw_write_set.insert(extent.get_off(), extent.get_len()); + } + + auto orig_size = projected_size; + for (auto extent = raw_write_set.begin(); + extent != raw_write_set.end(); + ++extent) { + uint64_t head_start = + sinfo.logical_to_prev_stripe_offset(extent.get_start()); + uint64_t head_finish = + sinfo.logical_to_next_stripe_offset(extent.get_start()); + if (head_start > projected_size) { + head_start = projected_size; + } + if (head_start != head_finish && + head_start < orig_size) { + ceph_assert(head_finish <= orig_size); + ceph_assert(head_finish - head_start == sinfo.get_stripe_width()); + ldpp_dout(dpp, 20) << __func__ << ": reading partial head stripe " + << head_start << "~" << sinfo.get_stripe_width() + << dendl; + plan.to_read[i.first].union_insert( + head_start, sinfo.get_stripe_width()); + } + + uint64_t tail_start = + sinfo.logical_to_prev_stripe_offset( + extent.get_start() + extent.get_len()); + uint64_t tail_finish = + sinfo.logical_to_next_stripe_offset( + extent.get_start() + extent.get_len()); + if (tail_start != tail_finish && + (head_start == head_finish || tail_start != head_start) && + tail_start < orig_size) { + ceph_assert(tail_finish <= orig_size); + ceph_assert(tail_finish - tail_start == sinfo.get_stripe_width()); + ldpp_dout(dpp, 20) << __func__ << ": reading partial tail stripe " + << tail_start << "~" << sinfo.get_stripe_width() + << dendl; + plan.to_read[i.first].union_insert( + tail_start, sinfo.get_stripe_width()); + } + + if (head_start != tail_finish) { + ceph_assert( + sinfo.logical_offset_is_stripe_aligned( + tail_finish - head_start) + ); + will_write.union_insert( + head_start, tail_finish - head_start); + if (tail_finish > projected_size) + projected_size = tail_finish; + } else { + ceph_assert(tail_finish <= projected_size); + } + } + + if (i.second.truncate && + i.second.truncate->second > projected_size) { + uint64_t truncating_to = + sinfo.logical_to_next_stripe_offset(i.second.truncate->second); + ldpp_dout(dpp, 20) << __func__ << ": truncating out to " + << truncating_to + << dendl; + will_write.union_insert(projected_size, + truncating_to - projected_size); + projected_size = truncating_to; + } + + ldpp_dout(dpp, 20) << __func__ << ": " << i.first + << " projected size " + << projected_size + << dendl; + hinfo->set_projected_total_logical_size( + sinfo, + projected_size); + + /* validate post conditions: + * to_read should have an entry for i.first iff it isn't empty + * and if we are reading from i.first, we can't be renaming or + * cloning it */ + ceph_assert(plan.to_read.count(i.first) == 0 || + (!plan.to_read.at(i.first).empty() && + !i.second.has_source())); + }); + plan.t = std::move(t); + return plan; + } + + void generate_transactions( + WritePlan &plan, + ceph::ErasureCodeInterfaceRef &ecimpl, + pg_t pgid, + const ECUtil::stripe_info_t &sinfo, + const std::map<hobject_t,extent_map> &partial_extents, + std::vector<pg_log_entry_t> &entries, + std::map<hobject_t,extent_map> *written, + std::map<shard_id_t, ObjectStore::Transaction> *transactions, + std::set<hobject_t> *temp_added, + std::set<hobject_t> *temp_removed, + DoutPrefixProvider *dpp, + const ceph_release_t require_osd_release = ceph_release_t::unknown); +}; + +#endif |