struct RollbackVisitor : public ObjectModDesc::Visitor {
const hobject_t &hoid;
PGBackend *pg;
+ const pg_log_entry_t &entry;
ObjectStore::Transaction t;
RollbackVisitor(
const hobject_t &hoid,
- PGBackend *pg) : hoid(hoid), pg(pg) {}
+ PGBackend *pg,
+ const pg_log_entry_t &entry) : hoid(hoid), pg(pg), entry(entry) {}
void append(uint64_t old_size) override {
ObjectStore::Transaction temp;
- int s = static_cast<int>(pg->get_parent()->whoami_shard().shard);
- const uint64_t shard_size = pg->object_size_to_shard_size(old_size, s);
+ auto dpp = pg->get_parent()->get_dpp();
+ const uint64_t shard_size = pg->object_size_to_shard_size(old_size,
+ pg->get_parent()->whoami_shard().shard);
+ ldpp_dout(dpp, 20) << " entry " << entry.version
+ << " rollback append object_size " << old_size
+ << " shard_size " << shard_size << dendl;
pg->rollback_append(hoid, shard_size, &temp);
temp.append(t);
temp.swap(t);
}
void setattrs(map<string, std::optional<bufferlist> > &attrs) override {
- ObjectStore::Transaction temp;
- pg->rollback_setattrs(hoid, attrs, &temp);
- temp.append(t);
- temp.swap(t);
+ auto dpp = pg->get_parent()->get_dpp();
+ const pg_pool_t &pool = pg->get_parent()->get_pool();
+ if (pool.is_nonprimary_shard(pg->get_parent()->whoami_shard().shard)) {
+ if (entry.is_written_shard(pg->get_parent()->whoami_shard().shard)) {
+ // Written shard - only rollback OI attr
+ ldpp_dout(dpp, 20) << " entry " << entry.version
+ << " written shard OI attr rollback "
+ << pg->get_parent()->whoami_shard().shard
+ << dendl;
+ ObjectStore::Transaction temp;
+ pg->rollback_setattrs(hoid, attrs, &temp, true);
+ temp.append(t);
+ temp.swap(t);
+ } else {
+ // Unwritten shard - nothing to rollback
+ ldpp_dout(dpp, 20) << " entry " << entry.version
+ << " unwritten shard skipping attr rollback "
+ << pg->get_parent()->whoami_shard().shard
+ << dendl;
+ }
+ } else {
+ // Primary shard - rollback all attrs
+ ldpp_dout(dpp, 20) << " entry " << entry.version
+ << " primary_shard attr rollback "
+ << pg->get_parent()->whoami_shard().shard
+ << dendl;
+ ObjectStore::Transaction temp;
+ pg->rollback_setattrs(hoid, attrs, &temp, false);
+ temp.append(t);
+ temp.swap(t);
+ }
}
void rmobject(version_t old_version) override {
ObjectStore::Transaction temp;
temp.swap(t);
}
void rollback_extents(
- version_t gen,
- const vector<pair<uint64_t, uint64_t> > &extents) override {
+ const version_t gen,
+ const std::vector<std::pair<uint64_t, uint64_t>> &extents,
+ const uint64_t object_size,
+ const std::vector<shard_id_set> &shards) override {
ObjectStore::Transaction temp;
- pg->rollback_extents(gen, extents, hoid, &temp);
- temp.append(t);
- temp.swap(t);
+ const pg_pool_t& pool = pg->get_parent()->get_pool();
+ ceph_assert(entry.written_shards.empty() ||
+ pool.allows_ecoptimizations());
+ auto dpp = pg->get_parent()->get_dpp();
+ bool donework = false;
+ ceph_assert(shards.empty() || shards.size() == extents.size());
+ for (unsigned int i = 0; i < extents.size(); i++) {
+ if (shards.empty() ||
+ shards[i].empty() ||
+ shards[i].contains(pg->get_parent()->whoami_shard().shard)) {
+ // Written shard - rollback extents
+ const uint64_t shard_size = pg->object_size_to_shard_size(
+ object_size,
+ pg->get_parent()->whoami_shard().shard);
+ ldpp_dout(dpp, 20) << " entry " << entry.version
+ << " written shard rollback_extents "
+ << entry.written_shards
+ << " shards "
+ << (shards.empty() ? shard_id_set() : shards[i])
+ << " " << pg->get_parent()->whoami_shard().shard
+ << " " << object_size
+ << " " << shard_size
+ << dendl;
+ pg->rollback_extents(gen, extents[i].first, extents[i].second,
+ hoid, shard_size, &temp);
+ donework = true;
+ } else {
+ // Unwritten shard - nothing to rollback
+ ldpp_dout(dpp, 20) << " entry " << entry.version
+ << " unwritten shard skipping rollback_extents "
+ << entry.written_shards
+ << " " << pg->get_parent()->whoami_shard().shard
+ << dendl;
+ }
+ }
+ if (donework) {
+ t.remove(
+ pg->coll,
+ ghobject_t(hoid, gen, pg->get_parent()->whoami_shard().shard));
+ temp.append(t);
+ temp.swap(t);
+ }
}
};
ceph_assert(entry.mod_desc.can_rollback());
- RollbackVisitor vis(entry.soid, this);
+ RollbackVisitor vis(entry.soid, this, entry);
entry.mod_desc.visit(&vis);
t->append(vis.t);
}
}
// try_rmobject defaults to rmobject
void rollback_extents(
- version_t gen,
- const vector<pair<uint64_t, uint64_t> > &extents) override {
- pg->trim_rollback_object(
- soid,
- gen,
- t);
+ const version_t gen,
+ const std::vector<std::pair<uint64_t, uint64_t>> &extents,
+ const uint64_t object_size,
+ const std::vector<shard_id_set> &shards) override {
+ auto dpp = pg->get_parent()->get_dpp();
+ ceph_assert(shards.empty() || shards.size() == extents.size());
+ for (unsigned int i = 0; i < extents.size(); i++) {
+ if (shards.empty() ||
+ shards[i].empty() ||
+ shards[i].contains(pg->get_parent()->whoami_shard().shard)) {
+ ldpp_dout(dpp, 30) << __func__ << " trim " << shards << " "
+ << pg->get_parent()->whoami_shard().shard << dendl;
+ pg->trim_rollback_object(
+ soid,
+ gen,
+ t);
+ break;
+ } else {
+ ldpp_dout(dpp, 20) << __func__ << " skipping trim " << shards << " "
+ << pg->get_parent()->whoami_shard().shard << dendl;
+ }
+ }
}
};
void PGBackend::rollback_setattrs(
const hobject_t &hoid,
map<string, std::optional<bufferlist> > &old_attrs,
- ObjectStore::Transaction *t) {
+ ObjectStore::Transaction *t,
+ bool only_oi) {
map<string, bufferlist, less<>> to_set;
ceph_assert(!hoid.is_temp());
for (map<string, std::optional<bufferlist> >::iterator i = old_attrs.begin();
++i) {
if (i->second) {
to_set[i->first] = *(i->second);
- } else {
+ } else if (!only_oi) {
t->rmattr(
coll,
ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard),
i->first);
}
}
- t->setattrs(
- coll,
- ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard),
- to_set);
+ if (only_oi) {
+ t->setattr(
+ coll,
+ ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard),
+ OI_ATTR,
+ to_set[OI_ATTR]);
+ } else {
+ t->setattrs(
+ coll,
+ ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard),
+ to_set);
+ }
}
void PGBackend::rollback_append(
version_t old_version,
ObjectStore::Transaction *t) {
ceph_assert(!hoid.is_temp());
+ dout(20) << __func__ << " " << hoid << " " << old_version << dendl;
t->remove(
coll,
ghobject_t(hoid, ghobject_t::NO_GEN, get_parent()->whoami_shard().shard));
void PGBackend::rollback_extents(
version_t gen,
- const vector<pair<uint64_t, uint64_t> > &extents,
+ const uint64_t offset,
+ uint64_t length,
const hobject_t &hoid,
+ const uint64_t shard_size,
ObjectStore::Transaction *t) {
auto shard = get_parent()->whoami_shard().shard;
- for (auto &&extent: extents) {
+ if (offset >= shard_size) {
+ // extent on this shard is beyond the end of the object - nothing to do
+ dout(20) << __func__ << " " << hoid << " "
+ << offset << "~" << length << " is out of range "
+ << shard_size << dendl;
+ } else {
+ if (offset + length > shard_size) {
+ dout(20) << __func__ << " " << length << " is being truncated" << dendl;
+ // extent on this shard goes beyond end of the object - truncate length
+ length = shard_size - offset;
+ }
+ dout(20) << __func__ << " " << hoid << " " << offset << "~" << length
+ << dendl;
t->clone_range(
coll,
ghobject_t(hoid, gen, shard),
ghobject_t(hoid, ghobject_t::NO_GEN, shard),
- extent.first,
- extent.second,
- extent.first);
+ offset,
+ length,
+ offset);
}
- t->remove(
- coll,
- ghobject_t(hoid, gen, shard));
}
void PGBackend::trim_rollback_object(
version_t old_version,
ObjectStore::Transaction *t) {
ceph_assert(!hoid.is_temp());
+ dout(20) << __func__ << " trim " << hoid << " " << old_version << dendl;
t->remove(
coll, ghobject_t(hoid, old_version, get_parent()->whoami_shard().shard));
}
virtual void create() {}
virtual void update_snaps(const std::set<snapid_t> &old_snaps) {}
virtual void rollback_extents(
- version_t gen,
- const std::vector<std::pair<uint64_t, uint64_t> > &extents) {}
+ const version_t gen,
+ const std::vector<std::pair<uint64_t, uint64_t>> &extents,
+ const uint64_t object_size,
+ const std::vector<shard_id_set> &shards) {}
virtual ~Visitor() {}
};
void visit(Visitor *visitor) const;
rollback_info_completed = other.rollback_info_completed;
}
void claim_append(ObjectModDesc &other) {
- if (!can_local_rollback || rollback_info_completed)
+ if (!can_local_rollback || rollback_info_completed) {
return;
+ }
if (!other.can_local_rollback) {
mark_unrollbackable();
return;
encode(_id, bl);
}
void append(uint64_t old_size) {
- if (!can_local_rollback || rollback_info_completed)
+ if (!can_local_rollback || rollback_info_completed) {
return;
+ }
ENCODE_START(1, 1, bl);
append_id(APPEND);
encode(old_size, bl);
ENCODE_FINISH(bl);
}
void setattrs(std::map<std::string, std::optional<ceph::buffer::list>> &old_attrs) {
- if (!can_local_rollback || rollback_info_completed)
+ if (!can_local_rollback || rollback_info_completed) {
return;
+ }
ENCODE_START(1, 1, bl);
append_id(SETATTRS);
encode(old_attrs, bl);
ENCODE_FINISH(bl);
}
bool rmobject(version_t deletion_version) {
- if (!can_local_rollback || rollback_info_completed)
+ if (!can_local_rollback || rollback_info_completed) {
return false;
+ }
ENCODE_START(1, 1, bl);
append_id(DELETE);
encode(deletion_version, bl);
return true;
}
bool try_rmobject(version_t deletion_version) {
- if (!can_local_rollback || rollback_info_completed)
+ if (!can_local_rollback || rollback_info_completed) {
return false;
+ }
ENCODE_START(1, 1, bl);
append_id(TRY_DELETE);
encode(deletion_version, bl);
return true;
}
void create() {
- if (!can_local_rollback || rollback_info_completed)
+ if (!can_local_rollback || rollback_info_completed) {
return;
+ }
rollback_info_completed = true;
ENCODE_START(1, 1, bl);
append_id(CREATE);
ENCODE_FINISH(bl);
}
void update_snaps(const std::set<snapid_t> &old_snaps) {
- if (!can_local_rollback || rollback_info_completed)
+ if (!can_local_rollback || rollback_info_completed) {
return;
+ }
ENCODE_START(1, 1, bl);
append_id(UPDATE_SNAPS);
encode(old_snaps, bl);
ENCODE_FINISH(bl);
}
void rollback_extents(
- version_t gen, const std::vector<std::pair<uint64_t, uint64_t> > &extents) {
+ const version_t gen,
+ const std::vector<std::pair<uint64_t, uint64_t>> &extents,
+ const uint64_t object_size,
+ const std::vector<shard_id_set> &shards) {
+ ceph_assert(can_local_rollback);
+ ceph_assert(!rollback_info_completed);
+ if (max_required_version < 2) {
+ max_required_version = 2;
+ }
+ ENCODE_START(3, 2, bl);
+ append_id(ROLLBACK_EXTENTS);
+ encode(gen, bl);
+ encode(extents, bl);
+ encode(object_size, bl);
+ encode(shards, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ // Version for legacy EC (can be deleted when EC*L.cc is deleted.
+ void rollback_extents(
+ const version_t gen,
+ const std::vector<std::pair<uint64_t, uint64_t>> &extents) {
ceph_assert(can_local_rollback);
ceph_assert(!rollback_info_completed);
- if (max_required_version < 2)
+ if (max_required_version < 2) {
max_required_version = 2;
+ }
ENCODE_START(2, 2, bl);
append_id(ROLLBACK_EXTENTS);
encode(gen, bl);
* message buffer
*/
void trim_bl() const {
- if (bl.length() > 0)
+ if (bl.length() > 0) {
bl.rebuild();
+ }
}
void encode(ceph::buffer::list &bl) const;
void decode(ceph::buffer::list::const_iterator &bl);