2424import org .apache .iotdb .consensus .common .request .IConsensusRequest ;
2525import org .apache .iotdb .consensus .config .RatisConfig ;
2626import org .apache .iotdb .consensus .exception .RatisReadUnavailableException ;
27+ import org .apache .iotdb .consensus .ratis .utils .Utils ;
2728
29+ import org .apache .ratis .server .RaftServer ;
2830import org .apache .ratis .util .TimeDuration ;
2931import org .junit .After ;
3032import org .junit .Assert ;
3537
3638import java .io .File ;
3739import java .util .List ;
40+ import java .util .concurrent .CountDownLatch ;
41+ import java .util .concurrent .ExecutorService ;
42+ import java .util .concurrent .Executors ;
43+ import java .util .concurrent .Future ;
3844import java .util .concurrent .TimeUnit ;
3945import java .util .concurrent .atomic .AtomicBoolean ;
4046
@@ -46,6 +52,7 @@ public class RecoverReadTest {
4652 private static class SlowRecoverStateMachine extends TestUtils .IntegerCounter {
4753 private final TimeDuration stallDuration ;
4854 private final AtomicBoolean stallApply = new AtomicBoolean (false );
55+ private final CountDownLatch stopped = new CountDownLatch (1 );
4956
5057 private SlowRecoverStateMachine (TimeDuration stallDuration ) {
5158 this .stallDuration = stallDuration ;
@@ -70,6 +77,11 @@ public TSStatus write(IConsensusRequest request) {
7077 return super .write (request );
7178 }
7279
80+ @ Override
81+ public void stop () {
82+ stopped .countDown ();
83+ }
84+
7385 @ Override
7486 public boolean takeSnapshot (File snapshotDir ) {
7587 // allow no snapshot to ensure the raft log be replayed
@@ -126,6 +138,64 @@ public void tearUp() throws Exception {
126138 }
127139 }
128140
141+ @ Test
142+ public void stopWaitsForInFlightLeaderCheck () throws Exception {
143+ final ConsensusGroupId gid = miniCluster .getGid ();
144+ for (RatisConsensus server : miniCluster .getServers ()) {
145+ server .createLocalPeer (gid , miniCluster .getPeers ());
146+ }
147+ miniCluster .waitUntilActiveLeaderElectedAndReady ();
148+
149+ int leaderIndex = 0 ;
150+ while (!miniCluster .getServer (leaderIndex ).isLeader (gid )) {
151+ leaderIndex ++;
152+ }
153+ final RaftServer .Division leader =
154+ miniCluster
155+ .getServer (leaderIndex )
156+ .getServer ()
157+ .getDivision (Utils .fromConsensusGroupIdToRaftGroupId (gid ));
158+ final SlowRecoverStateMachine stateMachine =
159+ (SlowRecoverStateMachine ) miniCluster .getStateMachines ().get (leaderIndex );
160+ final CountDownLatch checkStarted = new CountDownLatch (1 );
161+ final CountDownLatch finishCheck = new CountDownLatch (1 );
162+ final CountDownLatch stopStarted = new CountDownLatch (1 );
163+ final ExecutorService executor = Executors .newFixedThreadPool (2 );
164+ try {
165+ final Future <?> check =
166+ executor .submit (
167+ () -> {
168+ // LeaderStateImpl performs its leadership checks under this monitor.
169+ synchronized (leader ) {
170+ checkStarted .countDown ();
171+ Assert .assertTrue (finishCheck .await (30 , TimeUnit .SECONDS ));
172+ leader .getRaftLog ().getLastEntryTermIndex ();
173+ }
174+ return null ;
175+ });
176+ Assert .assertTrue (checkStarted .await (30 , TimeUnit .SECONDS ));
177+ final Future <?> stop =
178+ executor .submit (
179+ () -> {
180+ stopStarted .countDown ();
181+ miniCluster .stop ();
182+ return null ;
183+ });
184+ Assert .assertTrue (stopStarted .await (30 , TimeUnit .SECONDS ));
185+ Assert .assertFalse (
186+ "The state machine must remain open until the in-flight leader check finishes" ,
187+ stateMachine .stopped .await (5 , TimeUnit .SECONDS ));
188+ finishCheck .countDown ();
189+ check .get (30 , TimeUnit .SECONDS );
190+ stop .get (30 , TimeUnit .SECONDS );
191+ Assert .assertEquals (0 , stateMachine .stopped .getCount ());
192+ } finally {
193+ finishCheck .countDown ();
194+ executor .shutdown ();
195+ Assert .assertTrue (executor .awaitTermination (30 , TimeUnit .SECONDS ));
196+ }
197+ }
198+
129199 /* mimics the situation before this patch */
130200 @ Test
131201 public void inconsistentReadAfterRestart () throws Exception {
0 commit comments