From 2b783c6126e7c774f949605570d6a6826c0e96e2 Mon Sep 17 00:00:00 2001 From: MorganaFuture Date: Sat, 4 Oct 2025 20:55:05 +0300 Subject: [PATCH] Fix crash when committing to deleted ETS table during member removal Fixes race condition in issue #528 where removing and re-adding a cluster member causes a crash in ra_mt:commit/1. Wrap ets:insert/2 in catch block to gracefully handle deleted tables. Return empty list instead of crashing. --- src/ra_mt.erl | 13 +++++++++---- test/ra_mt_SUITE.erl | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/ra_mt.erl b/src/ra_mt.erl index df25476e5..bfea116b2 100644 --- a/src/ra_mt.erl +++ b/src/ra_mt.erl @@ -155,10 +155,15 @@ commit(#?MODULE{tid = Tid, commit(Prev0) end, Staged = lists:reverse(Staged0), - true = ets:insert(Tid, Staged), - %% TODO: mt: could prev contain overwritten entries? - {PrevStaged ++ Staged, State#?MODULE{staged = undefined, - prev = Prev}}. + case catch ets:insert(Tid, Staged) of + true -> + %% TODO: mt: could prev contain overwritten entries? + {PrevStaged ++ Staged, State#?MODULE{staged = undefined, + prev = Prev}}; + {'EXIT', {badarg, _}} -> + {[], State#?MODULE{staged = undefined, + prev = Prev}} + end. -spec abort(state()) -> state(). abort(#?MODULE{staged = undefined} = State) -> diff --git a/test/ra_mt_SUITE.erl b/test/ra_mt_SUITE.erl index 4aff51ef9..4ef057992 100644 --- a/test/ra_mt_SUITE.erl +++ b/test/ra_mt_SUITE.erl @@ -34,6 +34,7 @@ all_tests() -> stage_commit, range_overlap, stage_commit_abort, + commit_after_table_deleted, perf ]. @@ -468,6 +469,25 @@ perf(_Config) -> ok. +commit_after_table_deleted(_Config) -> + Tid = ets:new(t1, [set, public]), + Mt0 = ra_mt:init(Tid), + + %% Stage some entries + {ok, Mt1} = ra_mt:stage({1, 1, <<"data1">>}, Mt0), + {ok, Mt2} = ra_mt:stage({2, 1, <<"data2">>}, Mt1), + + %% Simulate table deletion + true = ets:delete(Tid), + + %% Should return empty list since table is deleted + {Entries, _Mt3} = ra_mt:commit(Mt2), + + %% Should return empty entries since table was deleted + ?assertEqual([], Entries), + + ok. + %%% Util