Trigger double autosync when switching PG state to prevent leaving garbage in non-immediate_commit clusters

This commit is contained in:
Vitaliy Filippov
2024-11-15 01:26:36 +03:00
parent 5864bd067c
commit 8202ee9d74
4 changed files with 34 additions and 2 deletions
+3 -1
View File
@@ -150,7 +150,7 @@ class osd_t
bool pg_config_applied = false; bool pg_config_applied = false;
bool etcd_reporting_pg_state = false; bool etcd_reporting_pg_state = false;
bool etcd_reporting_stats = false; bool etcd_reporting_stats = false;
int autosync_timer_id = -1, print_stats_timer_id = -1, slow_log_timer_id = -1; int print_stats_timer_id = -1, slow_log_timer_id = -1;
// peers and PGs // peers and PGs
@@ -168,6 +168,8 @@ class osd_t
object_id recovery_last_oid; object_id recovery_last_oid;
int recovery_pg_done = 0, recovery_done = 0; int recovery_pg_done = 0, recovery_done = 0;
osd_op_t *autosync_op = NULL; osd_op_t *autosync_op = NULL;
int autosync_copies_to_delete = 0;
int autosync_timer_id = -1;
// Scrubbing // Scrubbing
uint64_t scrub_nearest_ts = 0; uint64_t scrub_nearest_ts = 0;
+12
View File
@@ -645,6 +645,18 @@ void osd_t::remove_object_from_state(object_id & oid, pg_osd_set_state_t **objec
{ {
throw std::runtime_error("BUG: Invalid object state: "+std::to_string((*object_state)->state)); throw std::runtime_error("BUG: Invalid object state: "+std::to_string((*object_state)->state));
} }
if (changed && immediate_commit != IMMEDIATE_ALL)
{
// Trigger double automatic sync after changing PG state when we're running with fsyncs.
// First autosync commits all written objects and applies copies_to_delete_after_sync;
// Second autosync commits all deletions run by the first sync.
// Without it, rebalancing in a cluster without load may result in some small amount of
// garbage left on "extra" OSDs of the PG, because last deletions are not synced at all.
// FIXME: 1000% correct way is to switch PG state only after copies_to_delete_after_sync.
// But it's much more complicated.
unstable_write_count += autosync_writes;
autosync_copies_to_delete = 2;
}
if (changed && report) if (changed && report)
{ {
report_pg_state(pg); report_pg_state(pg);
+9
View File
@@ -9,6 +9,10 @@ void osd_t::autosync()
{ {
if (immediate_commit != IMMEDIATE_ALL && !autosync_op) if (immediate_commit != IMMEDIATE_ALL && !autosync_op)
{ {
if (autosync_copies_to_delete > 0)
{
autosync_copies_to_delete--;
}
autosync_op = new osd_op_t(); autosync_op = new osd_op_t();
autosync_op->op_type = OSD_OP_IN; autosync_op->op_type = OSD_OP_IN;
autosync_op->peer_fd = SELF_FD; autosync_op->peer_fd = SELF_FD;
@@ -29,6 +33,11 @@ void osd_t::autosync()
} }
delete autosync_op; delete autosync_op;
autosync_op = NULL; autosync_op = NULL;
if (autosync_copies_to_delete > 0)
{
// Trigger the second "copies_to_delete" autosync
autosync();
}
}; };
exec_op(autosync_op); exec_op(autosync_op);
} }
+10 -1
View File
@@ -213,6 +213,15 @@ resume_8:
{ {
goto resume_6; goto resume_6;
} }
if (immediate_commit == IMMEDIATE_NONE)
{
// Mark OSDs as dirty because deletions have to be synced too!
for (int i = 0; i < op_data->copies_to_delete_count; i++)
{
auto & chunk = op_data->copies_to_delete[i];
this->dirty_osds.insert(chunk.osd_num);
}
}
} }
for (int i = 0; i < op_data->dirty_pg_count; i++) for (int i = 0; i < op_data->dirty_pg_count; i++)
{ {
@@ -227,7 +236,7 @@ resume_8:
start_pg_peering(pg); start_pg_peering(pg);
} }
} }
// FIXME: Free those in the destructor? // FIXME: Free those in the destructor (not here)?
free(op_data->dirty_pgs); free(op_data->dirty_pgs);
op_data->dirty_pgs = NULL; op_data->dirty_pgs = NULL;
op_data->dirty_osds = NULL; op_data->dirty_osds = NULL;