Experimental: Handle degraded deletions by comparing object versions with epochs
CAUTION! This version is not fool proof yet. If you purge data of an OSD by overwriting the disk with zeroes and restart it then the same data will also be removed from other replicas :-). I plan to add protection from this situation before merging it into master. The idea is to make each OSD store a random "cookie" on disk and remove itself from history automatically if the cookie doesn't match.
This commit is contained in:
+11
-4
@@ -10,18 +10,25 @@ function add_pg_history(new_pg_history, new_pg, prev_pgs, prev_pg_history, old_p
|
||||
if (!new_pg_history[new_pg])
|
||||
{
|
||||
new_pg_history[new_pg] = {
|
||||
osd_sets: {},
|
||||
osd_set_epochs: {},
|
||||
all_peers: {},
|
||||
epoch: 0,
|
||||
};
|
||||
}
|
||||
const nh = new_pg_history[new_pg], oh = prev_pg_history[old_pg];
|
||||
nh.osd_sets[prev_pgs[old_pg].join(' ')] = prev_pgs[old_pg];
|
||||
nh.osd_set_epochs[prev_pgs[old_pg].join(' ')] = { osd_set: prev_pgs[old_pg] };
|
||||
if (oh && oh.osd_sets && oh.osd_sets.length)
|
||||
{
|
||||
for (const pg of oh.osd_sets)
|
||||
{
|
||||
nh.osd_sets[pg.join(' ')] = pg.map(osd_num => Number(osd_num));
|
||||
nh.osd_set_epochs[pg.join(' ')] = { osd_set: pg.map(osd_num => Number(osd_num)) };
|
||||
}
|
||||
}
|
||||
if (oh && oh.osd_set_epochs && oh.osd_set_epochs.length)
|
||||
{
|
||||
for (const pg of oh.osd_set_epochs)
|
||||
{
|
||||
nh.osd_set_epochs[pg.osd_set.join(' ')] = { osd_set: pg.osd_set.map(osd_num => Number(osd_num)) };
|
||||
}
|
||||
}
|
||||
if (oh && oh.all_peers && oh.all_peers.length)
|
||||
@@ -39,7 +46,7 @@ function add_pg_history(new_pg_history, new_pg, prev_pgs, prev_pg_history, old_p
|
||||
|
||||
function finish_pg_history(merged_history)
|
||||
{
|
||||
merged_history.osd_sets = Object.values(merged_history.osd_sets);
|
||||
merged_history.osd_set_epochs = Object.values(merged_history.osd_set_epochs);
|
||||
merged_history.all_peers = Object.values(merged_history.all_peers);
|
||||
}
|
||||
|
||||
|
||||
+6
-13
@@ -286,7 +286,12 @@ const etcd_tree = {
|
||||
history: {
|
||||
/* <pool_id>: {
|
||||
<pg_id>: {
|
||||
osd_sets: osd_num_t[][],
|
||||
osd_set_epochs: {
|
||||
osd_set: osd_num_t[],
|
||||
min_epoch: uint64_t,
|
||||
max_epoch: uint64_t,
|
||||
}[],
|
||||
osd_sets: osd_num_t[][], // outdated
|
||||
all_peers: osd_num_t[],
|
||||
epoch: uint64_t,
|
||||
},
|
||||
@@ -968,18 +973,6 @@ class Mon
|
||||
osd_set,
|
||||
primary: this.pick_primary(pool_id, osd_set, up_osds, aff_osds),
|
||||
};
|
||||
if (prev_pgs[i] && prev_pgs[i].join(' ') != osd_set.join(' ') &&
|
||||
prev_pgs[i].filter(osd_num => osd_num).length > 0)
|
||||
{
|
||||
pg_history[i] = pg_history[i] || {};
|
||||
pg_history[i].osd_sets = pg_history[i].osd_sets || [];
|
||||
pg_history[i].osd_sets.push(prev_pgs[i]);
|
||||
}
|
||||
if (pg_history[i] && pg_history[i].osd_sets)
|
||||
{
|
||||
pg_history[i].osd_sets = Object.values(pg_history[i].osd_sets
|
||||
.reduce((a, c) => { a[c.join(' ')] = c; return a; }, {}));
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < new_pgs.length || i < prev_pgs.length; i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user