} else {
// primary is instructing us to trim
ObjectStore::Transaction *t = new ObjectStore::Transaction;
- pg->pg_log.trim(m->trim_to, pg->info);
+ PG::PGLogEntryHandler handler;
+ pg->pg_log.trim(&handler, m->trim_to, pg->info);
+ handler.apply(pg, t);
pg->dirty_info = true;
pg->write_if_dirty(*t);
int tr = store->queue_transaction(
}
void PG::remove_snap_mapped_object(
- ObjectStore::Transaction& t, const hobject_t& soid)
+ ObjectStore::Transaction &t, const hobject_t &soid)
{
t.remove(coll, soid);
- OSDriver::OSTransaction _t(osdriver.get_transaction(&t));
+ clear_object_snap_mapping(&t, soid);
+}
+
+void PG::clear_object_snap_mapping(
+ ObjectStore::Transaction *t, const hobject_t &soid)
+{
+ OSDriver::OSTransaction _t(osdriver.get_transaction(t));
if (soid.snap < CEPH_MAXSNAP) {
int r = snap_mapper.remove_oid(
soid,
}
}
-void PG::merge_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, int from)
+void PG::update_object_snap_mapping(
+ ObjectStore::Transaction *t, const hobject_t &soid, const set<snapid_t> &snaps)
{
- list<hobject_t> to_remove;
- pg_log.merge_log(t, oinfo, olog, from, info, to_remove, dirty_info, dirty_big_info);
- for(list<hobject_t>::iterator i = to_remove.begin();
- i != to_remove.end();
- ++i)
- remove_snap_mapped_object(t, *i);
+ OSDriver::OSTransaction _t(osdriver.get_transaction(t));
+ assert(soid.snap < CEPH_MAXSNAP);
+ int r = snap_mapper.remove_oid(
+ soid,
+ &_t);
+ if (!(r == 0 || r == -ENOENT)) {
+ derr << __func__ << ": remove_oid returned " << cpp_strerror(r) << dendl;
+ assert(0);
+ }
+ snap_mapper.add_oid(
+ soid,
+ snaps,
+ &_t);
+}
+
+void PG::merge_log(
+ ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, int from)
+{
+ PGLogEntryHandler rollbacker;
+ pg_log.merge_log(
+ t, oinfo, olog, from, info, &rollbacker, dirty_info, dirty_big_info);
+ rollbacker.apply(this, &t);
}
void PG::rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead)
{
- list<hobject_t> to_remove;
- pg_log.rewind_divergent_log(t, newhead, info, to_remove, dirty_info, dirty_big_info);
- for(list<hobject_t>::iterator i = to_remove.begin();
- i != to_remove.end();
- ++i)
- remove_snap_mapped_object(t, *i);
+ PGLogEntryHandler rollbacker;
+ pg_log.rewind_divergent_log(
+ t, newhead, info, &rollbacker, dirty_info, dirty_big_info);
+ rollbacker.apply(this, &t);
}
/*
dout(10) << "append_log adding " << keys.size() << " keys" << dendl;
t.omap_setkeys(coll_t::META_COLL, log_oid, keys);
-
- pg_log.trim(trim_to, info);
+ PGLogEntryHandler handler;
+ pg_log.trim(&handler, trim_to, info);
+ handler.apply(this, &t);
// update the local pg, pg log
dirty_info = true;
void proc_master_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog,
pg_missing_t& omissing, int from);
bool proc_replica_info(int from, const pg_info_t &info);
+
+
+ struct LogEntryTrimmer : public ObjectModDesc::Visitor {
+ const hobject_t &soid;
+ PG *pg;
+ ObjectStore::Transaction *t;
+ LogEntryTrimmer(const hobject_t &soid, PG *pg, ObjectStore::Transaction *t)
+ : soid(soid), pg(pg), t(t) {}
+ void rmobject(version_t old_version) {
+ pg->get_pgbackend()->trim_stashed_object(
+ soid,
+ old_version,
+ t);
+ }
+ };
+
+ struct SnapRollBacker : public ObjectModDesc::Visitor {
+ const hobject_t &soid;
+ PG *pg;
+ ObjectStore::Transaction *t;
+ SnapRollBacker(const hobject_t &soid, PG *pg, ObjectStore::Transaction *t)
+ : soid(soid), pg(pg), t(t) {}
+ void update_snaps(set<snapid_t> &snaps) {
+ pg->update_object_snap_mapping(t, soid, snaps);
+ }
+ void create() {
+ pg->clear_object_snap_mapping(
+ t,
+ soid);
+ }
+ };
+
+ struct PGLogEntryHandler : public PGLog::LogEntryHandler {
+ map<hobject_t, list<pg_log_entry_t> > to_rollback;
+ set<hobject_t> cannot_rollback;
+ set<hobject_t> to_remove;
+ list<pg_log_entry_t> to_trim;
+
+ // LogEntryHandler
+ void remove(const hobject_t &hoid) {
+ to_remove.insert(hoid);
+ }
+ void rollback(const pg_log_entry_t &entry) {
+ assert(!cannot_rollback.count(entry.soid));
+ to_rollback[entry.soid].push_back(entry);
+ }
+ void cant_rollback(const pg_log_entry_t &entry) {
+ to_rollback.erase(entry.soid);
+ cannot_rollback.insert(entry.soid);
+ }
+ void trim(const pg_log_entry_t &entry) {
+ to_trim.push_back(entry);
+ }
+
+ void apply(PG *pg, ObjectStore::Transaction *t) {
+ for (map<hobject_t, list<pg_log_entry_t> >::iterator i =
+ to_rollback.begin();
+ i != to_rollback.end();
+ ++i) {
+ for (list<pg_log_entry_t>::reverse_iterator j = i->second.rbegin();
+ j != i->second.rend();
+ ++j) {
+ assert(j->mod_desc.can_rollback());
+ pg->get_pgbackend()->rollback(j->soid, j->mod_desc, t);
+ SnapRollBacker rollbacker(j->soid, pg, t);
+ j->mod_desc.visit(&rollbacker);
+ }
+ }
+ for (set<hobject_t>::iterator i = to_remove.begin();
+ i != to_remove.end();
+ ++i) {
+ pg->get_pgbackend()->rollback_create(*i, t);
+ pg->remove_snap_mapped_object(*t, *i);
+ }
+ for (list<pg_log_entry_t>::reverse_iterator i = to_trim.rbegin();
+ i != to_trim.rend();
+ ++i) {
+ LogEntryTrimmer trimmer(i->soid, pg, t);
+ i->mod_desc.visit(&trimmer);
+ }
+ }
+ };
+
+ friend struct SnapRollBacker;
+ friend struct PGLogEntryHandler;
+ friend struct LogEntryTrimmer;
+ void update_object_snap_mapping(
+ ObjectStore::Transaction *t, const hobject_t &soid,
+ const set<snapid_t> &snaps);
+ void clear_object_snap_mapping(
+ ObjectStore::Transaction *t, const hobject_t &soid);
void remove_snap_mapped_object(
ObjectStore::Transaction& t, const hobject_t& soid);
void merge_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, int from);
virtual void rollback_setattrs(
const hobject_t &hoid,
map<string, boost::optional<bufferlist> > &old_attrs,
- ObjectStore::Transaction *t) { assert(0); }
+ ObjectStore::Transaction *t) = 0;
/// Rollback truncate
virtual void rollback_append(
const hobject_t &hoid,
uint64_t old_size,
- ObjectStore::Transaction *t) { assert(0); }
+ ObjectStore::Transaction *t) = 0;
/// Rollback unstash
virtual void rollback_unstash(
const hobject_t &hoid,
version_t old_version,
- ObjectStore::Transaction *t) { assert(0); }
+ ObjectStore::Transaction *t) = 0;
/// Rollback create
virtual void rollback_create(
const hobject_t &hoid,
- ObjectStore::Transaction *t) { assert(0); }
+ ObjectStore::Transaction *t) = 0;
/// Trim object stashed at stashed_version
virtual void trim_stashed_object(
const hobject_t &hoid,
- version_t stashed_version) { assert(0); }
+ version_t stashed_version,
+ ObjectStore::Transaction *t) = 0;
/// List objects in collection
virtual int objects_list_partial(
olog->can_rollback_to = can_rollback_to;
}
-void PGLog::IndexedLog::trim(eversion_t s, set<eversion_t> *trimmed)
+void PGLog::IndexedLog::trim(
+ LogEntryHandler *handler,
+ eversion_t s,
+ set<eversion_t> *trimmed)
{
if (complete_to != log.end() &&
complete_to->version <= s) {
generic_dout(20) << "trim " << e << dendl;
if (trimmed)
trimmed->insert(e.version);
+ handler->trim(e);
unindex(e); // remove from index,
log.pop_front(); // from log
}
t->omap_rmkeys(coll_t::META_COLL, infos_oid, keys_to_remove);
}
-void PGLog::trim(eversion_t trim_to, pg_info_t &info)
+void PGLog::trim(
+ LogEntryHandler *handler,
+ eversion_t trim_to,
+ pg_info_t &info)
{
// trim?
if (trim_to > log.tail) {
assert(trim_to <= info.last_complete);
dout(10) << "trim " << log << " to " << trim_to << dendl;
- log.trim(trim_to, &trimmed);
+ log.trim(handler, trim_to, &trimmed);
info.log_tail = log.tail;
}
}
<< " have " << i->second.have << dendl;
}
- list<pg_log_entry_t>::const_reverse_iterator pp = olog.log.rbegin();
+ list<pg_log_entry_t> divergent;
+ list<pg_log_entry_t>::const_iterator pp = olog.log.end();
eversion_t lu(oinfo.last_update);
while (true) {
- if (pp == olog.log.rend()) {
- if (pp != olog.log.rbegin()) // no last_update adjustment if we discard nothing!
+ if (pp == olog.log.begin()) {
+ if (pp != olog.log.end()) // no last_update adjustment if we discard nothing!
lu = olog.tail;
break;
}
+ --pp;
const pg_log_entry_t& oe = *pp;
// don't continue past the tail of our log.
- if (oe.version <= log.tail)
+ if (oe.version <= log.tail) {
break;
-
- if (!log.objects.count(oe.soid)) {
- dout(10) << " had " << oe << " new dne : divergent, ignoring" << dendl;
- ++pp;
- continue;
}
-
- const pg_log_entry_t& ne = *(log.objects.find(oe.soid)->second);
- if (ne.version == oe.version) {
- dout(10) << " had " << oe << " new " << ne << " : match, stopping" << dendl;
+
+ hash_map<hobject_t, pg_log_entry_t*>::const_iterator i =
+ log.objects.find(oe.soid);
+ if (i != log.objects.end() && i->second->version == oe.version) {
+ dout(10) << " had " << oe << " new " << *(i->second)
+ << " : match, stopping" << dendl;
lu = pp->version;
break;
}
- if (oe.soid > oinfo.last_backfill) {
- // past backfill line, don't care
- dout(10) << " had " << oe << " beyond last_backfill : skipping" << dendl;
- ++pp;
- continue;
- }
-
- if (ne.version > oe.version) {
- dout(10) << " had " << oe << " new " << ne << " : new will supercede" << dendl;
- } else {
- if (oe.is_delete()) {
- if (ne.is_delete()) {
- // old and new are delete
- dout(10) << " had " << oe << " new " << ne << " : both deletes" << dendl;
- } else {
- // old delete, new update.
- dout(10) << " had " << oe << " new " << ne << " : missing" << dendl;
- omissing.add(ne.soid, ne.version, eversion_t());
- }
- } else {
- if (ne.is_delete()) {
- // old update, new delete
- dout(10) << " had " << oe << " new " << ne << " : new will supercede" << dendl;
- omissing.rm(oe.soid, oe.version);
- } else {
- // old update, new update
- dout(10) << " had " << oe << " new " << ne << " : new will supercede" << dendl;
- omissing.revise_need(ne.soid, ne.version);
- }
- }
- }
-
- ++pp;
+ divergent.push_front(oe);
}
+ for (list<pg_log_entry_t>::iterator i = divergent.begin();
+ i != divergent.end();
+ ++i) {
+ _merge_old_entry(
+ t,
+ *i,
+ oinfo,
+ omissing,
+ olog.can_rollback_to,
+ 0,
+ 0);
+ }
+
if (lu < oinfo.last_update) {
dout(10) << " peer osd." << from << " last_update now " << lu << dendl;
oinfo.last_update = lu;
*
* return true if entry is not divergent.
*/
-bool PGLog::merge_old_entry(ObjectStore::Transaction& t, const pg_log_entry_t& oe, const pg_info_t& info, list<hobject_t>& remove_snap)
+bool PGLog::_merge_old_entry(
+ ObjectStore::Transaction& t,
+ const pg_log_entry_t &oe,
+ const pg_info_t& info,
+ pg_missing_t &missing,
+ eversion_t olog_can_rollback_to,
+ boost::optional<pair<eversion_t, hobject_t> > *new_divergent_prior,
+ LogEntryHandler *rollbacker) const
{
if (oe.soid > info.last_backfill) {
- dout(20) << "merge_old_entry had " << oe << " : beyond last_backfill" << dendl;
+ dout(20) << "merge_old_entry had " << oe
+ << " : beyond last_backfill" << dendl;
return false;
}
- if (log.objects.count(oe.soid)) {
- pg_log_entry_t &ne = *log.objects[oe.soid]; // new(er?) entry
+ hash_map<hobject_t, pg_log_entry_t*>::const_iterator objiter =
+ log.objects.find(oe.soid);
+ if (objiter != log.objects.end()) {
+ pg_log_entry_t &ne = *(objiter->second); // new(er?) entry
if (ne.version > oe.version) {
- dout(20) << "merge_old_entry had " << oe << " new " << ne << " : older, missing" << dendl;
- assert(ne.is_delete() || missing.is_missing(ne.soid));
+ dout(20) << "merge_old_entry had " << oe
+ << " new " << ne << " : older, missing" << dendl;
return false;
}
if (ne.version == oe.version) {
- dout(20) << "merge_old_entry had " << oe << " new " << ne << " : same" << dendl;
+ dout(20) << "merge_old_entry had " << oe
+ << " new " << ne << " : same" << dendl;
return true;
}
if (oe.is_delete()) {
if (ne.is_delete()) {
// old and new are delete
- dout(20) << "merge_old_entry had " << oe << " new " << ne << " : both deletes" << dendl;
+ dout(20) << "merge_old_entry had " << oe
+ << " new " << ne << " : both deletes" << dendl;
} else {
// old delete, new update.
- dout(20) << "merge_old_entry had " << oe << " new " << ne << " : missing" << dendl;
+ dout(20) << "merge_old_entry had " << oe
+ << " new " << ne << " : missing" << dendl;
missing.revise_need(ne.soid, ne.version);
+ if (rollbacker)
+ rollbacker->cant_rollback(oe);
}
} else {
if (ne.is_delete()) {
// old update, new delete
- dout(20) << "merge_old_entry had " << oe << " new " << ne << " : new delete supercedes" << dendl;
- missing.rm(oe.soid, oe.version);
+ dout(20) << "merge_old_entry had " << oe
+ << " new " << ne << " : new delete supercedes" << dendl;
+ if (rollbacker) {
+ rollbacker->remove(oe.soid);
+ rollbacker->cant_rollback(oe);
+ }
+ if (missing.is_missing(oe.soid))
+ missing.rm(oe.soid, oe.version);
} else {
// old update, new update
- dout(20) << "merge_old_entry had " << oe << " new " << ne << " : new item supercedes" << dendl;
- missing.revise_need(ne.soid, ne.version);
+ dout(20) << "merge_old_entry had " << oe
+ << " new " << ne << " : new item supercedes" << dendl;
+ if (oe.mod_desc.can_rollback() && oe.version > olog_can_rollback_to) {
+ dout(20) << __func__ << ": ne.version < oe.version && can rollback, "
+ << "rolling back " << oe << dendl;
+ if (rollbacker)
+ rollbacker->rollback(oe);
+ } else {
+ missing.revise_need(ne.soid, ne.version);
+ if (rollbacker)
+ rollbacker->cant_rollback(oe);
+ }
}
}
} else if (oe.op == pg_log_entry_t::CLONE) {
dout(20) << "merge_old_entry had " << oe
<< ", clone with no non-divergent log entries, "
<< "deleting" << dendl;
- remove_snap.push_back(oe.soid);
- if (missing.is_missing(oe.soid))
+ if (missing.is_missing(oe.soid)) {
missing.rm(oe.soid, missing.missing[oe.soid].need);
- } else if (oe.prior_version > info.log_tail) {
+ }
+
+ if (oe.mod_desc.can_rollback() && oe.version > olog_can_rollback_to) {
+ dout(20) << __func__ << ": rolling back " << oe << dendl;
+ if (rollbacker)
+ rollbacker->rollback(oe);
+ } else {
+ dout(20) << __func__ << ": had " << oe << " deleting" << dendl;
+ if (rollbacker)
+ rollbacker->remove(oe.soid);
+ }
+ } else if (oe.prior_version > info.log_tail && missing.is_missing(oe.soid)) {
/**
* oe.prior_version is a previously divergent log entry
* oe.soid must have already been handled and the missing
<< " oe.soid " << oe.soid
<< " must already have been merged" << dendl;
} else {
- if (!oe.is_delete()) {
- dout(20) << "merge_old_entry had " << oe << " deleting" << dendl;
- remove_snap.push_back(oe.soid);
- }
- dout(20) << "merge_old_entry had " << oe << " updating missing to "
- << oe.prior_version << dendl;
- if (oe.prior_version > eversion_t()) {
- add_divergent_prior(oe.prior_version, oe.soid);
- missing.revise_need(oe.soid, oe.prior_version);
- } else if (missing.is_missing(oe.soid)) {
- missing.rm(oe.soid, missing.missing[oe.soid].need);
+ if (oe.mod_desc.can_rollback() && oe.version > olog_can_rollback_to) {
+ dout(20) << __func__ << ": rolling back " << oe << dendl;
+ if (rollbacker)
+ rollbacker->rollback(oe);
+ } else {
+ if (!oe.is_delete()) {
+ if (rollbacker)
+ rollbacker->remove(oe.soid);
+ dout(20) << __func__ << ": had " << oe << " deleting" << dendl;
+ }
+ dout(20) << "merge_old_entry had " << oe << " updating missing to "
+ << oe.prior_version << dendl;
+ if (oe.prior_version > eversion_t()) {
+ if (new_divergent_prior)
+ *new_divergent_prior = make_pair(oe.prior_version, oe.soid);
+ missing.revise_need(oe.soid, oe.prior_version);
+ if (rollbacker)
+ rollbacker->cant_rollback(oe);
+ } else if (missing.is_missing(oe.soid)) {
+ missing.rm(oe.soid, missing.missing[oe.soid].need);
+ }
}
}
return false;
* @param newhead new head to rewind to
*/
void PGLog::rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead,
- pg_info_t &info, list<hobject_t>& remove_snap,
- bool &dirty_info, bool &dirty_big_info)
+ pg_info_t &info, LogEntryHandler *rollbacker,
+ bool &dirty_info, bool &dirty_big_info)
{
dout(10) << "rewind_divergent_log truncate divergent future " << newhead << dendl;
assert(newhead >= log.tail);
info.last_complete = newhead;
log.index();
- for (list<pg_log_entry_t>::iterator d = divergent.begin(); d != divergent.end(); ++d)
- merge_old_entry(t, *d, info, remove_snap);
+ for (list<pg_log_entry_t>::iterator d = divergent.begin();
+ d != divergent.end();
+ ++d) {
+ merge_old_entry(t, *d, info, rollbacker);
+ rollbacker->trim(*d);
+ }
+
+ if (info.last_update < log.can_rollback_to)
+ log.can_rollback_to = info.last_update;
dirty_info = true;
dirty_big_info = true;
void PGLog::merge_log(ObjectStore::Transaction& t,
pg_info_t &oinfo, pg_log_t &olog, int fromosd,
- pg_info_t &info, list<hobject_t>& remove_snap,
+ pg_info_t &info, LogEntryHandler *rollbacker,
bool &dirty_info, bool &dirty_big_info)
{
dout(10) << "merge_log " << olog << " from osd." << fromosd
// do we have divergent entries to throw out?
if (olog.head < log.head) {
- rewind_divergent_log(t, olog.head, info, remove_snap, dirty_info, dirty_big_info);
+ rewind_divergent_log(t, olog.head, info, rollbacker, dirty_info, dirty_big_info);
changed = true;
}
if (ne.soid <= info.last_backfill) {
missing.add_next_event(ne);
if (ne.is_delete())
- remove_snap.push_back(ne.soid);
+ rollbacker->remove(ne.soid);
}
}
log.index();
info.last_update = log.head = olog.head;
+
info.last_user_version = oinfo.last_user_version;
info.purged_snaps = oinfo.purged_snaps;
// process divergent items
- if (!divergent.empty()) {
- for (list<pg_log_entry_t>::iterator d = divergent.begin(); d != divergent.end(); ++d)
- merge_old_entry(t, *d, info, remove_snap);
+ for (list<pg_log_entry_t>::iterator d = divergent.begin();
+ d != divergent.end();
+ ++d) {
+ merge_old_entry(t, *d, info, rollbacker);
+ rollbacker->trim(*d);
}
+ // We cannot rollback into the new log entries
+ log.can_rollback_to = log.head;
+
changed = true;
}
struct PGLog {
////////////////////////////// sub classes //////////////////////////////
+ struct LogEntryHandler {
+ virtual void rollback(
+ const pg_log_entry_t &entry) = 0;
+ virtual void remove(
+ const hobject_t &hoid) = 0;
+ virtual void trim(
+ const pg_log_entry_t &entry) = 0;
+ virtual void cant_rollback(
+ const pg_log_entry_t &entry) = 0;
+ virtual ~LogEntryHandler() {}
+ };
/* Exceptions */
class read_log_error : public buffer::error {
caller_ops[e.reqid] = &(log.back());
}
- void trim(eversion_t s, set<eversion_t> *trimmed);
+ void trim(
+ LogEntryHandler *handler,
+ eversion_t s,
+ set<eversion_t> *trimmed);
ostream& print(ostream& out) const;
};
const hobject_t &log_oid,
ObjectStore::Transaction *t);
- void trim(eversion_t trim_to, pg_info_t &info);
+ void trim(
+ LogEntryHandler *handler,
+ eversion_t trim_to,
+ pg_info_t &info);
//////////////////// get or set log & missing ////////////////////
pg_missing_t& omissing, int from) const;
protected:
- bool merge_old_entry(ObjectStore::Transaction& t, const pg_log_entry_t& oe,
- const pg_info_t& info, list<hobject_t>& remove_snap);
+ bool _merge_old_entry(
+ ObjectStore::Transaction& t,
+ const pg_log_entry_t &oe,
+ const pg_info_t& info,
+ pg_missing_t &missing,
+ eversion_t olog_can_rollback_to,
+ boost::optional<pair<eversion_t, hobject_t> > *new_divergent_prior,
+ LogEntryHandler *rollbacker) const;
+ bool merge_old_entry(
+ ObjectStore::Transaction& t,
+ const pg_log_entry_t& oe,
+ const pg_info_t& info,
+ LogEntryHandler *rollbacker) {
+ boost::optional<pair<eversion_t, hobject_t> > new_divergent_prior;
+ bool merged = _merge_old_entry(
+ t, oe, info, missing,
+ log.can_rollback_to,
+ &new_divergent_prior,
+ rollbacker);
+ if (new_divergent_prior)
+ add_divergent_prior(
+ (*new_divergent_prior).first,
+ (*new_divergent_prior).second);
+ return merged;
+ }
public:
void rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead,
- pg_info_t &info, list<hobject_t>& remove_snap,
+ pg_info_t &info, LogEntryHandler *rollbacker,
bool &dirty_info, bool &dirty_big_info);
void merge_log(ObjectStore::Transaction& t, pg_info_t &oinfo, pg_log_t &olog, int from,
- pg_info_t &info, list<hobject_t>& remove_snap,
- bool &dirty_info, bool &dirty_big_info);
+ pg_info_t &info, LogEntryHandler *rollbacker,
+ bool &dirty_info, bool &dirty_big_info);
void write_log(ObjectStore::Transaction& t, const hobject_t &log_oid);
t->remove(coll, hoid);
t->collection_move_rename(
coll,
- ghobject_t(hoid, old_version, ghobject_t::NO_SHARD),
+ ghobject_t(hoid, old_version, 0),
coll,
hoid);
}
ObjectStore::Transaction *t) {
t->remove(coll, hoid);
}
+
+ void trim_stashed_object(
+ const hobject_t &hoid,
+ version_t old_version,
+ ObjectStore::Transaction *t) {
+ t->remove(coll, ghobject_t(hoid, old_version, 0));
+ }
+
private:
void issue_op(
const hobject_t &soid,
eversion_t head; // newest entry
eversion_t tail; // version prior to oldest
- // We can rollback rollback-able objects to can_rollback_to
+ // We can rollback rollback-able entries > can_rollback_to
eversion_t can_rollback_to;
list<pg_log_entry_t> log; // the actual log.
}
};
+struct TestHandler : public PGLog::LogEntryHandler {
+ list<hobject_t> &removed;
+ TestHandler(list<hobject_t> &removed) : removed(removed) {}
+
+ void rollback(
+ const pg_log_entry_t &entry) {}
+ void remove(
+ const hobject_t &hoid) {
+ removed.push_back(hoid);
+ }
+ void cant_rollback(const pg_log_entry_t &entry) {}
+ void trim(
+ const pg_log_entry_t &entry) {}
+};
+
TEST_F(PGLogTest, rewind_divergent_log) {
// newhead > log.tail : throw an assert
{
bool dirty_big_info = false;
log.tail = eversion_t(2, 1);
- EXPECT_THROW(rewind_divergent_log(t, eversion_t(1, 1), info, remove_snap,
+ TestHandler h(remove_snap);
+ EXPECT_THROW(rewind_divergent_log(t, eversion_t(1, 1), info, &h,
dirty_info, dirty_big_info),
FailedAssertion);
}
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 1);
e.soid.hash = 0x5;
EXPECT_FALSE(dirty_info);
EXPECT_FALSE(dirty_big_info);
- rewind_divergent_log(t, newhead, info, remove_snap,
+ TestHandler h(remove_snap);
+ rewind_divergent_log(t, newhead, info, &h,
dirty_info, dirty_big_info);
EXPECT_TRUE(log.objects.count(divergent));
eversion_t newhead;
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
info.log_tail = log.tail = eversion_t(1, 1);
newhead = eversion_t(1, 3);
EXPECT_FALSE(dirty_info);
EXPECT_FALSE(dirty_big_info);
- rewind_divergent_log(t, newhead, info, remove_snap,
+ TestHandler h(remove_snap);
+ rewind_divergent_log(t, newhead, info, &h,
dirty_info, dirty_big_info);
EXPECT_TRUE(missing.is_missing(divergent_object));
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
EXPECT_FALSE(missing.have_missing());
EXPECT_TRUE(log.empty());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
oe.op = pg_log_entry_t::CLONE;
oe.soid.snap = CEPH_NOSNAP;
- EXPECT_THROW(merge_old_entry(t, oe, info, remove_snap), FailedAssertion);
+ TestHandler h(remove_snap);
+ EXPECT_THROW(merge_old_entry(t, oe, info, &h), FailedAssertion);
oe.soid.snap = 1U;
missing.add(oe.soid, eversion_t(), eversion_t());
EXPECT_TRUE(missing.is_missing(oe.soid));
EXPECT_TRUE(log.empty());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
EXPECT_EQ(oe.soid, remove_snap.front());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
EXPECT_FALSE(missing.have_missing());
EXPECT_EQ(1U, log.log.size());
- EXPECT_TRUE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_TRUE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
list<hobject_t> remove_snap;
pg_log_entry_t ne;
+ ne.mod_desc.mark_unrollbackable();
ne.version = eversion_t(2,1);
log.add(ne);
{
log.log.front().op = pg_log_entry_t::DELETE;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
oe.version = eversion_t(1,1);
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
}
// if the newer entry is not DELETE, the object must be in missing
ne.op = pg_log_entry_t::MODIFY;
missing.add_next_event(ne);
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
oe.version = eversion_t(1,1);
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
missing.rm(ne.soid, ne.version);
}
- // throw if the newer entry is not DELETE and not in missing
- {
- pg_log_entry_t &ne = log.log.front();
- ne.op = pg_log_entry_t::MODIFY;
- pg_log_entry_t oe;
- oe.version = eversion_t(1,1);
-
- EXPECT_THROW(merge_old_entry(t, oe, info, remove_snap), FailedAssertion);
- }
-
EXPECT_FALSE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
EXPECT_TRUE(t.empty());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
pg_log_entry_t ne;
+ ne.mod_desc.mark_unrollbackable();
ne.version = eversion_t(1,1);
ne.op = pg_log_entry_t::DELETE;
log.add(ne);
EXPECT_FALSE(missing.have_missing());
EXPECT_EQ(1U, log.log.size());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
pg_log_entry_t ne;
+ ne.mod_desc.mark_unrollbackable();
ne.version = eversion_t(1,1);
ne.op = pg_log_entry_t::MODIFY;
log.add(ne);
eversion_t old_version(0, 0);
// if the object is not already in missing, add it
{
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_TRUE(missing.is_missing(ne.soid, ne.version));
EXPECT_FALSE(missing.is_missing(ne.soid, old_version));
missing.revise_need(ne.soid, old_version);
EXPECT_TRUE(missing.is_missing(ne.soid, old_version));
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_TRUE(missing.is_missing(ne.soid, ne.version));
EXPECT_FALSE(missing.is_missing(ne.soid, old_version));
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
pg_log_entry_t ne;
+ ne.mod_desc.mark_unrollbackable();
ne.version = eversion_t(1,1);
ne.op = pg_log_entry_t::DELETE;
log.add(ne);
EXPECT_TRUE(missing.is_missing(oe.soid));
EXPECT_EQ(1U, log.log.size());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
- EXPECT_TRUE(remove_snap.empty());
+ EXPECT_TRUE(remove_snap.size() > 0);
EXPECT_TRUE(t.empty());
EXPECT_FALSE(missing.have_missing());
EXPECT_EQ(1U, log.log.size());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
info.log_tail = eversion_t(1,1);
oe.op = pg_log_entry_t::MODIFY;
oe.prior_version = eversion_t(2,1);
+ missing_add(oe.soid, oe.prior_version, eversion_t());
EXPECT_FALSE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
EXPECT_TRUE(t.empty());
- EXPECT_FALSE(missing.have_missing());
EXPECT_TRUE(log.empty());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
EXPECT_TRUE(t.empty());
- EXPECT_FALSE(missing.have_missing());
EXPECT_TRUE(log.empty());
}
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
EXPECT_FALSE(missing.have_missing());
EXPECT_TRUE(log.empty());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_TRUE(is_dirty());
EXPECT_EQ(oe.soid, remove_snap.front());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
EXPECT_FALSE(missing.have_missing());
EXPECT_TRUE(log.empty());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_TRUE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
EXPECT_TRUE(missing.is_missing(oe.soid));
EXPECT_TRUE(log.empty());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
EXPECT_TRUE(remove_snap.empty());
ObjectStore::Transaction t;
pg_log_entry_t oe;
+ oe.mod_desc.mark_unrollbackable();
pg_info_t info;
list<hobject_t> remove_snap;
EXPECT_TRUE(missing.is_missing(oe.soid));
EXPECT_TRUE(log.empty());
- EXPECT_FALSE(merge_old_entry(t, oe, info, remove_snap));
+ TestHandler h(remove_snap);
+ EXPECT_FALSE(merge_old_entry(t, oe, info, &h));
EXPECT_FALSE(is_dirty());
EXPECT_EQ(oe.soid, remove_snap.front());
EXPECT_FALSE(dirty_info);
EXPECT_FALSE(dirty_big_info);
- merge_log(t, oinfo, olog, fromosd, info, remove_snap,
+ TestHandler h(remove_snap);
+ merge_log(t, oinfo, olog, fromosd, info, &h,
dirty_info, dirty_big_info);
EXPECT_FALSE(missing.have_missing());
EXPECT_FALSE(dirty_info);
EXPECT_FALSE(dirty_big_info);
- merge_log(t, oinfo, olog, fromosd, info, remove_snap,
+ TestHandler h(remove_snap);
+ merge_log(t, oinfo, olog, fromosd, info, &h,
dirty_info, dirty_big_info);
EXPECT_FALSE(missing.have_missing());
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 4);
e.soid.hash = 0x5;
EXPECT_FALSE(dirty_info);
EXPECT_FALSE(dirty_big_info);
- merge_log(t, oinfo, olog, fromosd, info, remove_snap,
+ TestHandler h(remove_snap);
+ merge_log(t, oinfo, olog, fromosd, info, &h,
dirty_info, dirty_big_info);
EXPECT_FALSE(missing.have_missing());
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 1);
e.soid.hash = 0x5;
EXPECT_FALSE(dirty_info);
EXPECT_FALSE(dirty_big_info);
- merge_log(t, oinfo, olog, fromosd, info, remove_snap,
+ TestHandler h(remove_snap);
+ merge_log(t, oinfo, olog, fromosd, info, &h,
dirty_info, dirty_big_info);
/* When the divergent entry is a DELETE and the authoritative
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 1);
e.soid.hash = 0x5;
EXPECT_FALSE(dirty_info);
EXPECT_FALSE(dirty_big_info);
- merge_log(t, oinfo, olog, fromosd, info, remove_snap,
+ TestHandler h(remove_snap);
+ merge_log(t, oinfo, olog, fromosd, info, &h,
dirty_info, dirty_big_info);
EXPECT_FALSE(missing.have_missing());
// olog has been trimmed
olog.tail = eversion_t(1, 1);
- ASSERT_THROW(merge_log(t, oinfo, olog, fromosd, info, remove_snap,
+ TestHandler h(remove_snap);
+ ASSERT_THROW(merge_log(t, oinfo, olog, fromosd, info, &h,
dirty_info, dirty_big_info), FailedAssertion);
}
+--------+-------+---------+
| |object | |
|version | hash | version |
- | | | |
- tail > (1,1) | x5 | |
+ tail > (0,0) | | |
+ | (1,1) | x5 | |
| | | |
| | | |
head > (1,2) | x3 | |
| | | |
- | | x9 | (2,3) < tail
- | | | |
+ | | | (2,3) < tail
+ | | x9 | (2,4) |
| | | |
- | | x5 | (2,4) < head
+ | | x5 | (2,5) < head
| | | |
+--------+-------+---------+
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
+ log.tail = eversion_t();
e.version = eversion_t(1, 1);
e.soid.hash = 0x5;
- log.tail = e.version;
log.log.push_back(e);
e.version = eversion_t(1, 2);
e.soid.hash = 0x3;
info.last_update = log.head;
- e.version = eversion_t(2, 3);
+ olog.tail = eversion_t(2, 3);
+ e.version = eversion_t(2, 4);
e.soid.hash = 0x9;
olog.log.push_back(e);
- e.version = eversion_t(2, 4);
+ e.version = eversion_t(2, 5);
e.soid.hash = 0x5;
olog.log.push_back(e);
olog.head = e.version;
}
- EXPECT_THROW(merge_log(t, oinfo, olog, fromosd, info, remove_snap,
+ TestHandler h(remove_snap);
+ EXPECT_THROW(merge_log(t, oinfo, olog, fromosd, info, &h,
dirty_info, dirty_big_info), FailedAssertion);
}
}
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 2);
e.soid.hash = 0x5;
EXPECT_EQ(olog.head, oinfo.last_complete);
}
- /* +--------------------------+
- | log olog |
- +--------+-------+---------+
- | |object | |
- |version | hash | version |
- | | | |
- tail > (1,1) | x5 | (1,1) < tail
- | | | |
- | | | |
- | (1,2) | x3 | (1,2) |
- | | | |
- | | | |
- | (1,3) | x9 | |
- | MODIFY | | |
- | | | |
- | | x7 | (1,4) |
- | | | |
- | (1,6) | x8 | (1,5) |
- | | | |
- | | x9 | (2,3) < head < last_backfill
- | | | DELETE |
- | | | |
- head > (1,7) | xa | (2,5) |
- | | | |
- +--------+-------+---------+
-
- The log entry (1,3) modifies the object x9 but the olog entry
- (2,3) deletes it : log is authoritative and the object is added
- to missing. x7 is divergent and ignored. x8 has a more recent
- version in the log and the olog entry is ignored. xa is past
- last_backfill and ignored.
-
- */
- {
+ {
clear();
ObjectStore::Transaction t;
pg_missing_t omissing;
int from = -1;
- eversion_t last_update(1, 2);
hobject_t divergent_object;
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
- e.version = eversion_t(1, 1);
- e.soid.hash = 0x5;
- log.tail = e.version;
- log.log.push_back(e);
- e.version = last_update;
- e.soid.hash = 0x3;
- log.log.push_back(e);
- e.version = eversion_t(1,3);
- e.soid.hash = 0x9;
- divergent_object = e.soid;
- e.op = pg_log_entry_t::MODIFY;
- log.log.push_back(e);
- e.version = eversion_t(1, 6);
- e.soid.hash = 0x8;
- log.log.push_back(e);
- e.version = eversion_t(1, 7);
- e.soid.hash = 0xa;
- log.log.push_back(e);
- log.head = e.version;
+ {
+ e.soid = divergent_object;
+ e.soid.hash = 0x1;
+ e.version = eversion_t(1, 1);
+ log.tail = e.version;
+ log.log.push_back(e);
+
+ e.soid = divergent_object;
+ e.version = eversion_t(1, 2);
+ log.tail = e.version;
+ log.log.push_back(e);
+
+ e.soid.hash = 0x3;
+ e.version = eversion_t(1, 4);
+ log.log.push_back(e);
+
+ e.soid.hash = 0x7;
+ e.version = eversion_t(1, 5);
+ log.log.push_back(e);
+
+ e.soid.hash = 0x8;
+ e.version = eversion_t(1, 6);
+ log.log.push_back(e);
+
+ e.soid.hash = 0x9;
+ e.op = pg_log_entry_t::DELETE;
+ e.version = eversion_t(2, 7);
+ log.log.push_back(e);
+
+ e.soid.hash = 0xa;
+ e.version = eversion_t(2, 8);
+ log.head = e.version;
+ log.log.push_back(e);
+ }
log.index();
- e.version = eversion_t(1, 1);
- e.soid.hash = 0x5;
- olog.tail = e.version;
- olog.log.push_back(e);
- e.version = last_update;
- e.soid.hash = 0x3;
- olog.log.push_back(e);
- e.version = eversion_t(1, 4); // divergent entry : will be ignored
- e.soid.hash = 0x7;
- olog.log.push_back(e);
- e.version = eversion_t(1, 5); // log has newer entry : it will be ignored
- e.soid.hash = 0x8;
- olog.log.push_back(e);
- e.version = eversion_t(2, 3);
- e.soid.hash = 0x9;
- oinfo.last_backfill = e.soid;
- e.op = pg_log_entry_t::DELETE;
- olog.log.push_back(e);
- e.version = eversion_t(2, 4);
- e.soid.hash = 0xa; // > last_backfill are ignored
- olog.log.push_back(e);
- olog.head = e.version;
-
+ {
+ e.soid = divergent_object;
+ e.soid.hash = 0x1;
+ e.version = eversion_t(1, 1);
+ olog.tail = e.version;
+ olog.log.push_back(e);
+
+ e.soid = divergent_object;
+ e.version = eversion_t(1, 2);
+ olog.log.push_back(e);
+
+ e.soid.hash = 0x3;
+ e.version = eversion_t(1, 4);
+ olog.log.push_back(e);
+
+ e.soid.hash = 0x7;
+ e.version = eversion_t(1, 5);
+ olog.log.push_back(e);
+
+ e.soid.hash = 0x8;
+ e.version = eversion_t(1, 6);
+ olog.log.push_back(e);
+
+ e.soid.hash = 0x9; // should be ignored, matches above
+ e.op = pg_log_entry_t::DELETE;
+ e.version = eversion_t(1, 7);
+ olog.log.push_back(e);
+
+ e.soid = divergent_object; // should be marked missing at version 1'2
+ e.op = pg_log_entry_t::MODIFY;
+ e.version = eversion_t(1, 8);
+ e.prior_version = eversion_t(1, 2);
+ olog.log.push_back(e);
+ olog.head = e.version;
+ }
oinfo.last_update = olog.head;
oinfo.last_complete = olog.head;
}
EXPECT_TRUE(t.empty());
EXPECT_TRUE(omissing.have_missing());
EXPECT_TRUE(omissing.is_missing(divergent_object));
- EXPECT_EQ(eversion_t(1, 3), omissing.missing[divergent_object].need);
- EXPECT_EQ(last_update, oinfo.last_update);
- EXPECT_EQ(last_update, oinfo.last_complete);
+ EXPECT_EQ(eversion_t(1, 2), omissing.missing[divergent_object].need);
+ EXPECT_EQ(eversion_t(1, 6), oinfo.last_update);
+ EXPECT_EQ(eversion_t(1, 1), oinfo.last_complete);
}
/* +--------------------------+
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 1);
e.soid.hash = 0x5;
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 1);
e.soid.hash = 0x5;
{
pg_log_entry_t e;
+ e.mod_desc.mark_unrollbackable();
e.version = eversion_t(1, 1);
e.soid.hash = 0x5;