@@ -140,7 +140,7 @@ public X509Certificate[] getAcceptedIssuers() {
140
140
private SocketFactory socketFactory ;
141
141
private SSLSocketFactory sslSocketFactory ;
142
142
143
- private PacketChannel channel ;
143
+ private volatile PacketChannel channel ;
144
144
private volatile boolean connected ;
145
145
146
146
private ThreadFactory threadFactory ;
@@ -152,7 +152,10 @@ public X509Certificate[] getAcceptedIssuers() {
152
152
private volatile ExecutorService keepAliveThreadExecutor ;
153
153
private long keepAliveThreadShutdownTimeout = TimeUnit .SECONDS .toMillis (6 );
154
154
155
- private final Lock shutdownLock = new ReentrantLock ();
155
+ private final Lock connectLock = new ReentrantLock ();
156
+ private final Lock disconnectLock = new ReentrantLock ();
157
+ // used to prevent channel reinitialization after it was closed in #disconnectChannel().
158
+ private volatile boolean awaitingConnectTermination ;
156
159
157
160
/**
158
161
* Alias for BinaryLogClient("localhost", 3306, <no schema> = null, username, password).
@@ -397,69 +400,80 @@ public void setThreadFactory(ThreadFactory threadFactory) {
397
400
* @throws IOException if anything goes wrong while trying to connect
398
401
*/
399
402
public void connect () throws IOException {
400
- if (connected ) {
403
+ if (! connectLock . tryLock () ) {
401
404
throw new IllegalStateException ("BinaryLogClient is already connected" );
402
405
}
403
- GreetingPacket greetingPacket ;
404
406
try {
405
407
try {
406
- Socket socket = socketFactory != null ? socketFactory .createSocket () : new Socket ();
407
- socket .connect (new InetSocketAddress (hostname , port ));
408
- channel = new PacketChannel (socket );
409
- if (channel .getInputStream ().peek () == -1 ) {
410
- throw new EOFException ();
408
+ channel = establishConnection ();
409
+ if (awaitingConnectTermination ) {
410
+ throw new IOException ();
411
411
}
412
+ GreetingPacket greetingPacket = receiveGreeting ();
413
+ authenticate (greetingPacket );
414
+ connectionId = greetingPacket .getThreadId ();
415
+ if (binlogFilename == null ) {
416
+ fetchBinlogFilenameAndPosition ();
417
+ }
418
+ if (binlogPosition < 4 ) {
419
+ if (logger .isLoggable (Level .WARNING )) {
420
+ logger .warning ("Binary log position adjusted from " + binlogPosition + " to " + 4 );
421
+ }
422
+ binlogPosition = 4 ;
423
+ }
424
+ ChecksumType checksumType = fetchBinlogChecksum ();
425
+ if (checksumType != ChecksumType .NONE ) {
426
+ confirmSupportOfChecksum (checksumType );
427
+ }
428
+ requestBinaryLogStream ();
412
429
} catch (IOException e ) {
413
- throw new IOException ("Failed to connect to MySQL on " + hostname + ":" + port +
414
- ". Please make sure it's running." , e );
415
- }
416
- greetingPacket = receiveGreeting ();
417
- authenticate (greetingPacket );
418
- if (binlogFilename == null ) {
419
- fetchBinlogFilenameAndPosition ();
430
+ if (channel != null && channel .isOpen ()) {
431
+ channel .close ();
432
+ }
433
+ throw e ;
420
434
}
421
- if (binlogPosition < 4 ) {
422
- if (logger .isLoggable (Level .WARNING )) {
423
- logger .warning ("Binary log position adjusted from " + binlogPosition + " to " + 4 );
435
+ connected = true ;
436
+ if (logger .isLoggable (Level .INFO )) {
437
+ String position ;
438
+ synchronized (gtidSetAccessLock ) {
439
+ position = gtidSet != null ? gtidSet .toString () : binlogFilename + "/" + binlogPosition ;
424
440
}
425
- binlogPosition = 4 ;
441
+ logger .info ("Connected to " + hostname + ":" + port + " at " + position +
442
+ " (" + (blocking ? "sid:" + serverId + ", " : "" ) + "cid:" + connectionId + ")" );
426
443
}
427
- ChecksumType checksumType = fetchBinlogChecksum ();
428
- if (checksumType != ChecksumType .NONE ) {
429
- confirmSupportOfChecksum (checksumType );
444
+ synchronized (lifecycleListeners ) {
445
+ for (LifecycleListener lifecycleListener : lifecycleListeners ) {
446
+ lifecycleListener .onConnect (this );
447
+ }
430
448
}
431
- requestBinaryLogStream ();
432
- } catch (IOException e ) {
433
- if (channel != null && channel .isOpen ()) {
434
- channel .close ();
449
+ if (keepAlive && !isKeepAliveThreadRunning ()) {
450
+ spawnKeepAliveThread ();
435
451
}
436
- throw e ;
437
- }
438
- connected = true ;
439
- connectionId = greetingPacket .getThreadId ();
440
- if (logger .isLoggable (Level .INFO )) {
441
- String position ;
452
+ ensureEventDataDeserializer (EventType .ROTATE , RotateEventDataDeserializer .class );
442
453
synchronized (gtidSetAccessLock ) {
443
- position = gtidSet != null ? gtidSet .toString () : binlogFilename + "/" + binlogPosition ;
444
- }
445
- logger .info ("Connected to " + hostname + ":" + port + " at " + position +
446
- " (" + (blocking ? "sid:" + serverId + ", " : "" ) + "cid:" + connectionId + ")" );
447
- }
448
- synchronized (lifecycleListeners ) {
449
- for (LifecycleListener lifecycleListener : lifecycleListeners ) {
450
- lifecycleListener .onConnect (this );
454
+ if (gtidSet != null ) {
455
+ ensureEventDataDeserializer (EventType .GTID , GtidEventDataDeserializer .class );
456
+ }
451
457
}
458
+ listenForEventPackets ();
459
+ } finally {
460
+ connectLock .unlock ();
452
461
}
453
- if (keepAlive && !isKeepAliveThreadRunning ()) {
454
- spawnKeepAliveThread ();
455
- }
456
- ensureEventDataDeserializer (EventType .ROTATE , RotateEventDataDeserializer .class );
457
- synchronized (gtidSetAccessLock ) {
458
- if (gtidSet != null ) {
459
- ensureEventDataDeserializer (EventType .GTID , GtidEventDataDeserializer .class );
462
+ }
463
+
464
+ private PacketChannel establishConnection () throws IOException {
465
+ try {
466
+ Socket socket = socketFactory != null ? socketFactory .createSocket () : new Socket ();
467
+ socket .connect (new InetSocketAddress (hostname , port ));
468
+ PacketChannel channel = new PacketChannel (socket );
469
+ if (channel .getInputStream ().peek () == -1 ) {
470
+ throw new EOFException ();
460
471
}
472
+ return channel ;
473
+ } catch (IOException e ) {
474
+ throw new IOException ("Failed to connect to MySQL on " + hostname + ":" + port +
475
+ ". Please make sure it's running." , e );
461
476
}
462
- listenForEventPackets ();
463
477
}
464
478
465
479
private GreetingPacket receiveGreeting () throws IOException {
@@ -556,7 +570,7 @@ public void run() {
556
570
} catch (InterruptedException e ) {
557
571
// expected in case of disconnect
558
572
}
559
- shutdownLock .lock ();
573
+ disconnectLock .lock ();
560
574
try {
561
575
if (keepAliveThreadExecutor .isShutdown ()) {
562
576
return ;
@@ -580,7 +594,7 @@ public void run() {
580
594
}
581
595
}
582
596
} finally {
583
- shutdownLock .unlock ();
597
+ disconnectLock .unlock ();
584
598
}
585
599
}
586
600
}
@@ -895,7 +909,7 @@ public void registerLifecycleListener(LifecycleListener lifecycleListener) {
895
909
/**
896
910
* Unregister all lifecycle listener of specific type.
897
911
*/
898
- public synchronized void unregisterLifecycleListener (Class <? extends LifecycleListener > listenerClass ) {
912
+ public void unregisterLifecycleListener (Class <? extends LifecycleListener > listenerClass ) {
899
913
synchronized (lifecycleListeners ) {
900
914
Iterator <LifecycleListener > iterator = lifecycleListeners .iterator ();
901
915
while (iterator .hasNext ()) {
@@ -910,7 +924,7 @@ public synchronized void unregisterLifecycleListener(Class<? extends LifecycleLi
910
924
/**
911
925
* Unregister single lifecycle listener.
912
926
*/
913
- public synchronized void unregisterLifecycleListener (LifecycleListener eventListener ) {
927
+ public void unregisterLifecycleListener (LifecycleListener eventListener ) {
914
928
synchronized (lifecycleListeners ) {
915
929
lifecycleListeners .remove (eventListener );
916
930
}
@@ -922,14 +936,14 @@ public synchronized void unregisterLifecycleListener(LifecycleListener eventList
922
936
* As the result following {@link #connect()} resumes client from where it left off.
923
937
*/
924
938
public void disconnect () throws IOException {
925
- shutdownLock .lock ();
939
+ disconnectLock .lock ();
926
940
try {
927
941
if (isKeepAliveThreadRunning ()) {
928
942
keepAliveThreadExecutor .shutdownNow ();
929
943
}
930
944
disconnectChannel ();
931
945
} finally {
932
- shutdownLock .unlock ();
946
+ disconnectLock .unlock ();
933
947
}
934
948
if (isKeepAliveThreadRunning ()) {
935
949
waitForKeepAliveThreadToBeTerminated ();
@@ -959,6 +973,7 @@ private void disconnectChannel() throws IOException {
959
973
channel .close ();
960
974
}
961
975
} finally {
976
+ waitForConnectToTerminate ();
962
977
synchronized (lifecycleListeners ) {
963
978
for (LifecycleListener lifecycleListener : lifecycleListeners ) {
964
979
lifecycleListener .onDisconnect (this );
@@ -967,6 +982,16 @@ private void disconnectChannel() throws IOException {
967
982
}
968
983
}
969
984
985
+ private void waitForConnectToTerminate () {
986
+ awaitingConnectTermination = true ;
987
+ try {
988
+ connectLock .lock ();
989
+ connectLock .unlock ();
990
+ } finally {
991
+ awaitingConnectTermination = false ;
992
+ }
993
+ }
994
+
970
995
/**
971
996
* {@link BinaryLogClient}'s event listener.
972
997
*/
0 commit comments