Implement PG epochs to prevent the "version split"

The "version split" is when:
- A block is written to 1 OSD out of 3, all of them die
- OSDs 2 and 3 come up, the same block is written to both of them
- The remaining OSD comes up. Now all 3 OSDs have the same version of the same object,
  but with different data.
This commit is contained in:
Vitaliy Filippov
2020-07-04 00:55:27 +03:00
parent e680d6c1c3
commit a7929931eb
9 changed files with 126 additions and 40 deletions
+10
View File
@@ -344,6 +344,7 @@ void pg_t::calc_object_states(int log_level)
st.log_level = log_level;
st.pg = this;
auto ps = peering_state;
epoch = 0;
for (auto it: ps->list_results)
{
auto nstab = it.second.stable_count;
@@ -354,6 +355,10 @@ void pg_t::calc_object_states(int log_level)
obj_ver_id *ov = it.second.buf;
for (uint64_t i = 0; i < n; i++, ov++)
{
if ((ov->version >> (64-PG_EPOCH_BITS)) > epoch)
{
epoch = (ov->version >> (64-PG_EPOCH_BITS));
}
st.list[start+i] = {
.oid = ov->oid,
.version = ov->version,
@@ -369,6 +374,11 @@ void pg_t::calc_object_states(int log_level)
std::sort(st.list.begin(), st.list.end());
// Walk over it and check object states
st.walk();
if (this->state & (PG_DEGRADED|PG_LEFT_ON_DEAD))
{
assert(epoch != ((1ul << PG_EPOCH_BITS)-1));
epoch++;
}
}
void pg_t::print_state()