@@ -71,8 +71,10 @@ public void run() {
71
71
while (!Thread .currentThread ().isInterrupted ()) {
72
72
reconnect (0 , thumbstone );
73
73
try {
74
- state .awaitReconnection ();
75
- } catch (InterruptedException e ) {
74
+ state .awaitState (StateHelper .RECONNECT );
75
+ } catch (IllegalStateException ignored ) {
76
+ /* No-op. */
77
+ } catch (InterruptedException ignored ) {
76
78
Thread .currentThread ().interrupt ();
77
79
}
78
80
}
@@ -162,21 +164,22 @@ protected void connect(final SocketChannel channel) throws Exception {
162
164
}
163
165
164
166
protected void startThreads (String threadName ) throws InterruptedException {
165
- final CountDownLatch init = new CountDownLatch (2 );
166
- final AtomicInteger generationSync = new AtomicInteger (2 );
167
+ final CountDownLatch startedThreads = new CountDownLatch (2 );
168
+
169
+ /* Set RECONNECT state again once both reader and writer threads exit. */
170
+ final AtomicInteger exitedThreads = new AtomicInteger (2 );
171
+
167
172
reader = new Thread (new Runnable () {
168
173
@ Override
169
174
public void run () {
170
- init .countDown ();
175
+ startedThreads .countDown ();
171
176
if (state .acquire (StateHelper .READING )) {
172
177
try {
173
178
readThread ();
174
179
} finally {
175
180
state .release (StateHelper .READING );
176
- // avoid a case when this thread falls asleep here
177
- // after READING flag released and then can pollute the state
178
- if (generationSync .decrementAndGet () == 0 ) {
179
- state .trySignalForReconnection ();
181
+ if (exitedThreads .decrementAndGet () == 0 ) {
182
+ state .compareAndSet (StateHelper .UNINITIALIZED , StateHelper .RECONNECT );
180
183
}
181
184
}
182
185
}
@@ -185,33 +188,26 @@ public void run() {
185
188
writer = new Thread (new Runnable () {
186
189
@ Override
187
190
public void run () {
188
- init .countDown ();
191
+ startedThreads .countDown ();
189
192
if (state .acquire (StateHelper .WRITING )) {
190
193
try {
191
194
writeThread ();
192
195
} finally {
193
196
state .release (StateHelper .WRITING );
194
- // avoid a case when this thread falls asleep here
195
- // after WRITING flag released and then can pollute the state
196
- if (generationSync .decrementAndGet () == 0 ) {
197
- state .trySignalForReconnection ();
197
+ if (exitedThreads .decrementAndGet () == 0 ) {
198
+ state .compareAndSet (StateHelper .UNINITIALIZED , StateHelper .RECONNECT );
198
199
}
199
200
}
200
201
}
201
202
}
202
203
});
203
204
204
- // reconnection preparation is done
205
- // before reconnection the state will be released
206
- // reader/writer threads have been replaced by new ones
207
- // it's required to be sure that old r/w threads see correct
208
- // client's r/w references
209
205
state .release (StateHelper .RECONNECT );
210
206
211
207
configureThreads (threadName );
212
208
reader .start ();
213
209
writer .start ();
214
- init .await ();
210
+ startedThreads .await ();
215
211
}
216
212
217
213
protected void configureThreads (String threadName ) {
@@ -635,23 +631,12 @@ protected final class StateHelper {
635
631
636
632
private final AtomicInteger state ;
637
633
634
+ private final AtomicReference <CountDownLatch > nextReconnectLatch =
635
+ new AtomicReference <>(new CountDownLatch (1 ));
638
636
private final AtomicReference <CountDownLatch > nextAliveLatch =
639
637
new AtomicReference <>(new CountDownLatch (1 ));
640
-
641
638
private final CountDownLatch closedLatch = new CountDownLatch (1 );
642
639
643
- /**
644
- * The condition variable to signal a reconnection is needed from reader /
645
- * writer threads and waiting for that signal from the reconnection thread.
646
- *
647
- * The lock variable to access this condition.
648
- *
649
- * @see #awaitReconnection()
650
- * @see #trySignalForReconnection()
651
- */
652
- protected final ReentrantLock connectorLock = new ReentrantLock ();
653
- protected final Condition reconnectRequired = connectorLock .newCondition ();
654
-
655
640
protected StateHelper (int state ) {
656
641
this .state = new AtomicInteger (state );
657
642
}
@@ -722,7 +707,10 @@ protected boolean compareAndSet(int expect, int update) {
722
707
return false ;
723
708
}
724
709
725
- if (update == ALIVE ) {
710
+ if (update == RECONNECT ) {
711
+ CountDownLatch latch = nextReconnectLatch .getAndSet (new CountDownLatch (1 ));
712
+ latch .countDown ();
713
+ } else if (update == ALIVE ) {
726
714
CountDownLatch latch = nextAliveLatch .getAndSet (new CountDownLatch (1 ));
727
715
latch .countDown ();
728
716
onReconnect ();
@@ -732,18 +720,10 @@ protected boolean compareAndSet(int expect, int update) {
732
720
return true ;
733
721
}
734
722
735
- /**
736
- * Reconnection uses another way to await state via receiving a signal
737
- * instead of latches.
738
- */
739
723
protected void awaitState (int state ) throws InterruptedException {
740
- if (state == RECONNECT ) {
741
- awaitReconnection ();
742
- } else {
743
- CountDownLatch latch = getStateLatch (state );
744
- if (latch != null ) {
745
- latch .await ();
746
- }
724
+ CountDownLatch latch = getStateLatch (state );
725
+ if (latch != null ) {
726
+ latch .await ();
747
727
}
748
728
}
749
729
@@ -756,6 +736,13 @@ private CountDownLatch getStateLatch(int state) {
756
736
if (state == CLOSED ) {
757
737
return closedLatch ;
758
738
}
739
+ if (state == RECONNECT ) {
740
+ if (getState () == CLOSED ) {
741
+ throw new IllegalStateException ("State is CLOSED." );
742
+ }
743
+ CountDownLatch latch = nextReconnectLatch .get ();
744
+ return (getState () == RECONNECT ) ? null : latch ;
745
+ }
759
746
if (state == ALIVE ) {
760
747
if (getState () == CLOSED ) {
761
748
throw new IllegalStateException ("State is CLOSED." );
@@ -767,38 +754,6 @@ private CountDownLatch getStateLatch(int state) {
767
754
}
768
755
return null ;
769
756
}
770
-
771
- /**
772
- * Blocks until a reconnection signal will be received.
773
- *
774
- * @see #trySignalForReconnection()
775
- */
776
- private void awaitReconnection () throws InterruptedException {
777
- connectorLock .lock ();
778
- try {
779
- while (getState () != StateHelper .RECONNECT ) {
780
- reconnectRequired .await ();
781
- }
782
- } finally {
783
- connectorLock .unlock ();
784
- }
785
- }
786
-
787
- /**
788
- * Signals to the connector that reconnection process can be performed.
789
- *
790
- * @see #awaitReconnection()
791
- */
792
- private void trySignalForReconnection () {
793
- if (compareAndSet (StateHelper .UNINITIALIZED , StateHelper .RECONNECT )) {
794
- connectorLock .lock ();
795
- try {
796
- reconnectRequired .signal ();
797
- } finally {
798
- connectorLock .unlock ();
799
- }
800
- }
801
- }
802
757
}
803
758
804
759
protected static class TarantoolOp <V > extends CompletableFuture <V > {
0 commit comments