void trim(const pg_log_entry_t &entry) override {
// TODO
}
+ void partial_write(pg_info_t *info, const pg_log_entry_t &entry) override {
+ // TODO
+ ceph_assert(entry.written_shards.empty() && info->partial_writes_last_complete.empty());
+ }
};
PGLog::LogEntryHandlerRef get_log_handler(
ceph::os::Transaction &t) final {
void trim(const pg_log_entry_t &entry) override {
pg->get_pgbackend()->trim(entry, t);
}
+ void partial_write(pg_info_t *info, const pg_log_entry_t &entry) override {
+ pg->get_pgbackend()->partial_write(info, entry);
+ }
};
void update_object_snap_mapping(
ghobject_t(hoid, v, get_parent()->whoami_shard().shard));
}
+void PGBackend::partial_write(
+ pg_info_t *info,
+ const pg_log_entry_t &entry)
+{
+ ceph_assert(info != nullptr);
+ auto dpp = get_parent()->get_dpp();
+ if (!entry.written_shards.empty()) {
+ ldpp_dout(dpp, 20) << __func__ << " version=" << entry.version
+ << " written_shards=" << entry.written_shards
+ << " present_shards=" << entry.present_shards
+ << " pwlc=" << info->partial_writes_last_complete
+ << dendl;
+ const pg_pool_t &pool = get_parent()->get_pool();
+ for (unsigned int shard = 0;
+ shard < get_parent()->get_pool().size;
+ shard++) {
+ if (pool.is_nonprimary_shard(shard_id_t(shard))) {
+ if (!entry.is_written_shard(shard_id_t(shard))) {
+ if (!info->partial_writes_last_complete.contains(shard_id_t(shard))) {
+ // 1st partial write since all logs were updated
+ info->partial_writes_last_complete[shard_id_t(shard)] =
+ std::pair(entry.prior_version, entry.version);
+ } else if (info->partial_writes_last_complete[shard_id_t(shard)]
+ .second.version + 1 == entry.version.version) {
+ // Subsequent partial write, version is sequential
+ info->partial_writes_last_complete[shard_id_t(shard)].second =
+ entry.version;
+ } else {
+ // Subsequent partial write, discontiguous versions
+ ldpp_dout(dpp, 20) << __func__ << " cannot update shard " << shard
+ << dendl;
+ }
+ } else {
+ // Log updated or shard absent, partial write entry not required
+ info->partial_writes_last_complete.erase(shard_id_t(shard));
+ }
+ }
+ }
+ ldpp_dout(dpp, 20) << __func__ << " after pwlc="
+ << info->partial_writes_last_complete << dendl;
+ } else {
+ // All shard updated - clear partial write data
+ if (!info->partial_writes_last_complete.empty()) {
+ ldpp_dout(dpp, 20) << __func__ << " clear pwlc" << dendl;
+ }
+ info->partial_writes_last_complete.clear();
+ }
+}
+
void PGBackend::remove(
const hobject_t &hoid,
ObjectStore::Transaction *t) {
const pg_log_entry_t &entry,
ObjectStore::Transaction *t);
+ void partial_write(
+ pg_info_t *info,
+ const pg_log_entry_t &entry);
+
void remove(
const hobject_t &hoid,
ObjectStore::Transaction *t);
for (auto &&oe: divergent) {
dout(10) << "merge_log divergent " << oe << dendl;
}
- log.roll_forward_to(log.head, rollbacker);
+ log.roll_forward_to(log.head, &info, rollbacker);
mempool::osd_pglog::list<pg_log_entry_t> new_entries;
new_entries.splice(new_entries.end(), olog.log, from, to);
virtual void try_stash(
const hobject_t &hoid,
version_t v) = 0;
+ virtual void partial_write(
+ pg_info_t *info,
+ const pg_log_entry_t &entry) = 0;
virtual ~LogEntryHandler() {}
};
using LogEntryHandlerRef = std::unique_ptr<LogEntryHandler>;
return *this;
}
- void trim_rollback_info_to(eversion_t to, LogEntryHandler *h) {
+ void trim_rollback_info_to(eversion_t to, pg_info_t *info, LogEntryHandler *h) {
advance_can_rollback_to(
to,
[&](pg_log_entry_t &entry) {
h->trim(entry);
+ h->partial_write(info, entry);
});
}
- bool roll_forward_to(eversion_t to, LogEntryHandler *h) {
+ bool roll_forward_to(eversion_t to, pg_info_t *info, LogEntryHandler *h) {
return advance_can_rollback_to(
to,
[&](pg_log_entry_t &entry) {
h->rollforward(entry);
+ h->partial_write(info, entry);
+ });
+ }
+
+ void skip_can_rollback_to_to_head(pg_info_t *info, LogEntryHandler *h) {
+ advance_can_rollback_to(
+ head,
+ [&](pg_log_entry_t &entry) {
+ h->partial_write(info, entry);
});
}
void roll_forward_to(
eversion_t roll_forward_to,
+ pg_info_t *info,
LogEntryHandler *h) {
if (log.roll_forward_to(
roll_forward_to,
+ info,
h))
dirty_log = true;
}
return log.get_can_rollback_to();
}
- void roll_forward(LogEntryHandler *h) {
+ void roll_forward(pg_info_t *info, LogEntryHandler *h) {
roll_forward_to(
log.head,
+ info,
h);
}
- void skip_rollforward() {
- log.skip_can_rollback_to_to_head();
+ void skip_rollforward(pg_info_t *info, LogEntryHandler *h) {
+ // Update pwlc during backfill
+ log.skip_can_rollback_to_to_head(info, h);
}
//////////////////// get or std::set log & missing ////////////////////
- void reset_backfill_claim_log(const pg_log_t &o, LogEntryHandler *h) {
- log.trim_rollback_info_to(log.head, h);
+ void reset_backfill_claim_log(const pg_log_t &o, pg_info_t *info, LogEntryHandler *h) {
+ log.trim_rollback_info_to(log.head, info, h);
log.claim_log_and_clear_rollback_info(o);
missing.clear();
mark_dirty_to(eversion_t::max());
}
if (acting_set_writeable()) {
PGLog::LogEntryHandlerRef rollbacker{pl->get_log_handler(t)};
- pg_log.roll_forward(rollbacker.get());
+ pg_log.roll_forward(&info, rollbacker.get());
}
}
}
PGLog::LogEntryHandlerRef handler{pl->get_log_handler(rctx.transaction)};
- pg_log.roll_forward(handler.get());
+ pg_log.roll_forward(&info, handler.get());
info.last_complete = info.last_update; // to fake out trim()
pg_log.reset_recovery_pointers();
// prepare log
PGLog::LogEntryHandlerRef handler{
source->pl->get_log_handler(rctx.transaction)};
- source->pg_log.roll_forward(handler.get());
+ source->pg_log.roll_forward(&info, handler.get());
source->info.last_complete = source->info.last_update; // to fake out trim()
source->pg_log.reset_recovery_pointers();
source->pg_log.trim(source->info.last_update, source->info);
rollbacker.get());
if (pg_committed_to && entries.rbegin()->soid > info.last_backfill) {
- pg_log.roll_forward(rollbacker.get());
+ pg_log.roll_forward(&info, rollbacker.get());
}
if (pg_committed_to && *pg_committed_to > pg_log.get_can_rollback_to()) {
- pg_log.roll_forward_to(*pg_committed_to, rollbacker.get());
+ pg_log.roll_forward_to(*pg_committed_to, &info, rollbacker.get());
last_rollback_info_trimmed_to_applied = *pg_committed_to;
}
* from the backend and we do not end up in a situation, where the
* object is deleted before we can _merge_object_divergent_entries().
*/
- pg_log.skip_rollforward();
+ pg_log.skip_rollforward(&info, handler.get());
}
for (auto p = logv.begin(); p != logv.end(); ++p) {
* above */
if (transaction_applied &&
p->soid > info.last_backfill) {
- pg_log.roll_forward(handler.get());
+ pg_log.roll_forward(&info, handler.get());
}
}
if (transaction_applied && roll_forward_to > pg_log.get_can_rollback_to()) {
pg_log.roll_forward_to(
roll_forward_to,
+ &info,
handler.get());
last_rollback_info_trimmed_to_applied = roll_forward_to;
}
* to roll it back anyway (and we'll be rolled forward shortly
* anyway) */
PGLog::LogEntryHandlerRef handler{pl->get_log_handler(t)};
- pg_log.roll_forward_to(v, handler.get());
+ pg_log.roll_forward_to(v, &info, handler.get());
}
psdout(10) << "got missing " << oid << " v " << v << dendl;
ps->dirty_big_info = true; // maybe.
PGLog::LogEntryHandlerRef rollbacker{pl->get_log_handler(t)};
- ps->pg_log.reset_backfill_claim_log(msg->log, rollbacker.get());
+ ps->pg_log.reset_backfill_claim_log(msg->log, &ps->info, rollbacker.get());
ps->pg_log.reset_backfill();
} else {
// clear log
PGLog::LogEntryHandlerRef rollbacker{pl->get_log_handler(t)};
- ps->pg_log.roll_forward(rollbacker.get());
+ ps->pg_log.roll_forward(&ps->info, rollbacker.get());
// adjust info to backfill
ps->info.set_last_backfill(hobject_t());
}
void trim(
const pg_log_entry_t &entry) override {}
+ void partial_write(
+ pg_info_t *info,
+ const pg_log_entry_t &entry) override {}
};
template <typename missing_t>
}
void trim(
const pg_log_entry_t &entry) override {}
+ void partial_write(
+ pg_info_t *info,
+ const pg_log_entry_t &entry) override {}
};
TEST_F(PGLogTest, rewind_divergent_log) {
add(e);
}
TestHandler h(remove_snap);
- roll_forward_to(eversion_t(1, 6), &h);
+ roll_forward_to(eversion_t(1, 6), &info, &h);
rewind_divergent_log(eversion_t(1, 5), info, &h,
dirty_info, dirty_big_info);
pg_log_t log;
- reset_backfill_claim_log(log, &h);
+ reset_backfill_claim_log(log, &info, &h);
}
}