2727
2828import java .util .Map ;
2929import java .util .Set ;
30+ import java .util .concurrent .ConcurrentHashMap ;
31+
3032import org .apache .commons .lang3 .tuple .ImmutablePair ;
3133import org .apache .helix .metaclient .api .ConnectStateChangeListener ;
3234import org .apache .helix .metaclient .api .DataChangeListener ;
4042import org .apache .helix .metaclient .factories .MetaClientConfig ;
4143import org .apache .helix .metaclient .impl .zk .factory .ZkMetaClientConfig ;
4244import org .apache .helix .metaclient .impl .zk .factory .ZkMetaClientFactory ;
45+ import org .apache .helix .zookeeper .zkclient .ZkClient ;
4346import org .slf4j .Logger ;
4447import org .slf4j .LoggerFactory ;
4548
@@ -79,6 +82,8 @@ public class LeaderElectionClient implements AutoCloseable {
7982 private final static String PARTICIPANTS_ENTRY_PARENT = "/PARTICIPANTS/" ;
8083 ReElectListener _reElectListener = new ReElectListener ();
8184 ConnectStateListener _connectStateListener = new ConnectStateListener ();
85+ private final ConcurrentHashMap <String , Set <LeaderElectionListenerInterfaceAdapter >> _leaderChangeListener =
86+ new ConcurrentHashMap <>();
8287
8388 /**
8489 * Construct a LeaderElectionClient using a user passed in leaderElectionConfig. It creates a MetaClient
@@ -192,6 +197,7 @@ private void subscribeAndTryCreateLeaderEntry(String leaderPath) {
192197 _metaClient .subscribeDataChange (leaderPath + LEADER_ENTRY_KEY , _reElectListener , false );
193198 LeaderInfo leaderInfo = new LeaderInfo (LEADER_ENTRY_KEY );
194199 leaderInfo .setLeaderName (_participant );
200+ leaderInfo .setAcquiredTime ();
195201
196202 try {
197203 createPathIfNotExists (leaderPath );
@@ -349,6 +355,7 @@ public List<String> getParticipants(String leaderPath) {
349355 */
350356 public boolean subscribeLeadershipChanges (String leaderPath , LeaderElectionListenerInterface listener ) {
351357 LeaderElectionListenerInterfaceAdapter adapter = new LeaderElectionListenerInterfaceAdapter (leaderPath , listener );
358+ _leaderChangeListener .computeIfAbsent (leaderPath , k -> ConcurrentHashMap .newKeySet ()).add (adapter );
352359 _metaClient .subscribeDataChange (leaderPath + LEADER_ENTRY_KEY ,
353360 adapter , false /*skipWatchingNonExistNode*/ ); // we need to subscribe event when path is not there
354361 _metaClient .subscribeStateChanges (adapter );
@@ -364,6 +371,7 @@ public void unsubscribeLeadershipChanges(String leaderPath, LeaderElectionListen
364371 _metaClient .unsubscribeDataChange (leaderPath + LEADER_ENTRY_KEY , adapter
365372 );
366373 _metaClient .unsubscribeConnectStateChanges (adapter );
374+ _leaderChangeListener .get (leaderPath ).remove (adapter );
367375 }
368376
369377 @ Override
@@ -421,6 +429,23 @@ public void handleConnectStateChanged(MetaClientInterface.ConnectState prevState
421429 LOG .info ("Participant {} already in leader group {}." , _participant , leaderPath );
422430 }
423431 }
432+ // resubscribe the re-elect listener
433+ for (String leaderPath : _leaderGroups ) {
434+ LOG .info ("Resubscribe re-elect listener for leaderPath {}." , leaderPath );
435+ _metaClient .subscribeDataChange (leaderPath + LEADER_ENTRY_KEY , _reElectListener , false );
436+ }
437+
438+ // resubscribe to leader entry change since we are reconnected
439+ for (Map .Entry <String , Set <LeaderElectionListenerInterfaceAdapter >> entry : _leaderChangeListener .entrySet ()) {
440+ LOG .info ("Resubscribe leader change listener for leaderPath {}." , entry .getKey ());
441+ String leaderPath = entry .getKey ();
442+ Set <LeaderElectionListenerInterfaceAdapter > listeners = entry .getValue ();
443+ for (LeaderElectionListenerInterfaceAdapter listener : listeners ) {
444+ _metaClient .subscribeDataChange (leaderPath + LEADER_ENTRY_KEY ,
445+ listener , false /*skipWatchingNonExistNode*/ ); // we need to subscribe event when path is not there
446+ _metaClient .subscribeStateChanges (listener );
447+ }
448+ }
424449 // touch leader node to renew session ID
425450 touchLeaderNode ();
426451 }
@@ -436,11 +461,15 @@ private void touchLeaderNode() {
436461 for (String leaderPath : _leaderGroups ) {
437462 String key = leaderPath ;
438463 ImmutablePair <LeaderInfo , MetaClientInterface .Stat > tup = _metaClient .getDataAndStat (key );
464+ LOG .info ("touch leader node: current leader: {}, current participant: {}" ,
465+ tup .left .getLeaderName (), _participant );
439466 if (tup .left .getLeaderName ().equalsIgnoreCase (_participant )) {
440467 int expectedVersion = tup .right .getVersion ();
468+ LeaderInfo newInfo = new LeaderInfo (tup .left , tup .left .getId ());
469+ newInfo .setAcquiredTime ();
441470 try {
442471 LOG .info ("Try touch leader node for path {}" , _leaderGroups );
443- _metaClient .set (key , tup . left , expectedVersion );
472+ _metaClient .set (key , newInfo , expectedVersion );
444473 } catch (MetaClientNoNodeException ex ) {
445474 LOG .info ("leaderPath {} gone when retouch leader node." , key );
446475 } catch (MetaClientBadVersionException e ) {
0 commit comments