PG::merge_old_entry: fix case for divergent prior_version

Previously, we asserted that a log entry with a divergent
prior_version must be a clone.  Consider the following
case:

6'11(6'2)  m foo
7'12(6'3) m bar
7'13(7'12) m bar

If this is merged with:

6'11(6'2)  m foo
8'12(6'4) m baz

we will hit the assert.

Merging a divergent entry with prior_version after current
tail, but not in the log implies that prior_version was a
divergent entry which we have already merged.  The missing
set and filestore collection must therefore have already
been adjusted.

Signed-off-by: Samuel Just <sam.just@inktank.com>
This commit is contained in:
Samuel Just 2012-11-05 11:33:13 -08:00
parent c4981b8128
commit fcbbebc3d8

View File

@ -384,29 +384,33 @@ bool PG::merge_old_entry(ObjectStore::Transaction& t, pg_log_entry_t& oe)
missing.revise_need(ne.soid, ne.version);
}
}
} else if (oe.prior_version > info.log_tail) {
} else if (oe.op == pg_log_entry_t::CLONE) {
assert(oe.soid.snap != CEPH_NOSNAP);
dout(20) << "merge_old_entry had " << oe
<< ", object with no non-divergent log entries, "
<< ", clone with no non-divergent log entries, "
<< "deleting" << dendl;
remove_object_with_snap_hardlinks(t, 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) {
/**
* oe.prior_version is a previously divergent log entry
* oe.soid must have already been handled and the missing
* set updated appropriately
*/
dout(20) << "merge_old_entry had oe " << oe
<< " with divergent prior_version " << oe.prior_version
<< " 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_object_with_snap_hardlinks(t, oe.soid);
}
dout(20) << "merge_old_entry had " << oe << " reverting to "
dout(20) << "merge_old_entry had " << oe << " updating missing to "
<< oe.prior_version << dendl;
if (oe.prior_version > eversion_t()) {
/* If missing.missing[oe.soid].need is before info.log_tail
* then we filled it in on a previous call to merge_old_entry
* and this entry refers to a previous divergent entry.
*/
if (!missing.is_missing(oe.soid) ||
missing.missing[oe.soid].need > info.log_tail) {
missing.revise_need(oe.soid, oe.prior_version);
}
missing.revise_need(oe.soid, oe.prior_version);
} else if (missing.is_missing(oe.soid)) {
missing.rm(oe.soid, missing.missing[oe.soid].need);
}