Fix: PostgreSQL prepared statement purge race condition

The fix ensures that when the purge checks ref_count_client under write lock, it sees the latest value from concurrent threads holding raw pointers, preventing reading stale data.
pull/5353/head
Rahim Kanji 3 months ago
parent a360dc22ae
commit 230985e93e

@ -291,24 +291,22 @@ void PgSQL_STMT_Manager::ref_count_client___purge_stmts_if_needed() noexcept {
// meaning there are no other references (from client or server) to this prepared statement.
// So we can safely remove this entry.
if (global_stmt_info.use_count() == 1) {
// ref_count_client and ref_count_server should both be 0 in this case
assert(global_stmt_info->ref_count_client.load(std::memory_order_relaxed) == 0);
assert(global_stmt_info->ref_count_server.load(std::memory_order_relaxed) == 0);
// Atomic counters
num_stmt_with_ref_client_count_zero.fetch_sub(1, std::memory_order_relaxed);
num_stmt_with_ref_server_count_zero.fetch_sub(1, std::memory_order_relaxed);
// Free ID
free_stmt_ids.push(global_stmt_info->statement_id);
// Update totals
//stat_totals.s_total -= global_stmt_info->ref_count_server.load(std::memory_order_relaxed);
// Safe erase from map while iterating
it = map_stmt_hash_to_info.erase(it);
remaining_removals--;
// Use memory_order_acquire to see latest refcount modifications
// Since write lock prevents NEW references, only existing raw pointers can race
if (global_stmt_info->ref_count_client.load(std::memory_order_acquire) == 0 &&
global_stmt_info->ref_count_server.load(std::memory_order_acquire) == 0) {
// Atomic counters
num_stmt_with_ref_client_count_zero.fetch_sub(1, std::memory_order_relaxed);
num_stmt_with_ref_server_count_zero.fetch_sub(1, std::memory_order_relaxed);
// Free ID
free_stmt_ids.push(global_stmt_info->statement_id);
// Safe erase from map while iterating
it = map_stmt_hash_to_info.erase(it);
remaining_removals--;
}
} else {
++it;
}

Loading…
Cancel
Save