Yuta HIGUCHI
Committed by Ray Milkey

Fix potential race conditions in HazelcastLeadershipService

Change-Id: Iac232652155830c8e054760ea371ffb5639cf464
...@@ -166,8 +166,8 @@ public class HazelcastLeadershipService implements LeadershipService, ...@@ -166,8 +166,8 @@ public class HazelcastLeadershipService implements LeadershipService,
166 checkArgument(path != null); 166 checkArgument(path != null);
167 Topic topic = topics.get(path); 167 Topic topic = topics.get(path);
168 if (topic != null) { 168 if (topic != null) {
169 - topic.stop();
170 topics.remove(path, topic); 169 topics.remove(path, topic);
170 + topic.stop();
171 } 171 }
172 } 172 }
173 173
...@@ -213,6 +213,7 @@ public class HazelcastLeadershipService implements LeadershipService, ...@@ -213,6 +213,7 @@ public class HazelcastLeadershipService implements LeadershipService,
213 topic = new Topic(topicName); 213 topic = new Topic(topicName);
214 Topic oldTopic = topics.putIfAbsent(topicName, topic); 214 Topic oldTopic = topics.putIfAbsent(topicName, topic);
215 if (oldTopic == null) { 215 if (oldTopic == null) {
216 + // encountered new topic, start periodic processing
216 topic.start(); 217 topic.start();
217 } else { 218 } else {
218 topic = oldTopic; 219 topic = oldTopic;
...@@ -285,7 +286,11 @@ public class HazelcastLeadershipService implements LeadershipService, ...@@ -285,7 +286,11 @@ public class HazelcastLeadershipService implements LeadershipService,
285 /** 286 /**
286 * Starts operation. 287 * Starts operation.
287 */ 288 */
288 - private void start() { 289 + private synchronized void start() {
290 + if (!isShutdown) {
291 + // already running
292 + return;
293 + }
289 isShutdown = false; 294 isShutdown = false;
290 String threadPoolName = "onos-leader-election-" + topicName + "-%d"; 295 String threadPoolName = "onos-leader-election-" + topicName + "-%d";
291 leaderElectionExecutor = Executors.newScheduledThreadPool(2, 296 leaderElectionExecutor = Executors.newScheduledThreadPool(2,
...@@ -303,13 +308,14 @@ public class HazelcastLeadershipService implements LeadershipService, ...@@ -303,13 +308,14 @@ public class HazelcastLeadershipService implements LeadershipService,
303 /** 308 /**
304 * Runs for leadership. 309 * Runs for leadership.
305 */ 310 */
306 - private void runForLeadership() { 311 + private synchronized void runForLeadership() {
307 if (isRunningForLeadership) { 312 if (isRunningForLeadership) {
308 return; // Nothing to do: already running 313 return; // Nothing to do: already running
309 } 314 }
310 if (isShutdown) { 315 if (isShutdown) {
311 start(); 316 start();
312 } 317 }
318 + isRunningForLeadership = true;
313 String lockHzId = "LeadershipService/" + topicName + "/lock"; 319 String lockHzId = "LeadershipService/" + topicName + "/lock";
314 String termHzId = "LeadershipService/" + topicName + "/term"; 320 String termHzId = "LeadershipService/" + topicName + "/term";
315 leaderLock = storeService.getHazelcastInstance().getLock(lockHzId); 321 leaderLock = storeService.getHazelcastInstance().getLock(lockHzId);
...@@ -326,7 +332,7 @@ public class HazelcastLeadershipService implements LeadershipService, ...@@ -326,7 +332,7 @@ public class HazelcastLeadershipService implements LeadershipService,
326 /** 332 /**
327 * Stops leadership election for the topic. 333 * Stops leadership election for the topic.
328 */ 334 */
329 - private void stop() { 335 + private synchronized void stop() {
330 isShutdown = true; 336 isShutdown = true;
331 isRunningForLeadership = false; 337 isRunningForLeadership = false;
332 // getLockFuture.cancel(true); 338 // getLockFuture.cancel(true);
...@@ -454,22 +460,22 @@ public class HazelcastLeadershipService implements LeadershipService, ...@@ -454,22 +460,22 @@ public class HazelcastLeadershipService implements LeadershipService,
454 continue; 460 continue;
455 } 461 }
456 462
457 - synchronized (this) {
458 - //
459 - // This instance is now the leader
460 - //
461 - log.info("Leader Elected for topic {}", topicName);
462 -
463 - updateTerm();
464 -
465 - leader = localNodeId;
466 - leadershipEvent = new LeadershipEvent(
467 - LeadershipEvent.Type.LEADER_ELECTED,
468 - new Leadership(topicName, localNodeId, myLastLeaderTerm));
469 - leaderTopic.publish(SERIALIZER.encode(leadershipEvent));
470 - }
471 -
472 try { 463 try {
464 + synchronized (this) {
465 + //
466 + // This instance is now the leader
467 + //
468 + log.info("Leader Elected for topic {}", topicName);
469 +
470 + updateTerm();
471 +
472 + leader = localNodeId;
473 + leadershipEvent = new LeadershipEvent(
474 + LeadershipEvent.Type.LEADER_ELECTED,
475 + new Leadership(topicName, localNodeId, myLastLeaderTerm));
476 + leaderTopic.publish(SERIALIZER.encode(leadershipEvent));
477 + }
478 +
473 // Sleep forever until interrupted 479 // Sleep forever until interrupted
474 Thread.sleep(Long.MAX_VALUE); 480 Thread.sleep(Long.MAX_VALUE);
475 } catch (InterruptedException e) { 481 } catch (InterruptedException e) {
...@@ -479,23 +485,24 @@ public class HazelcastLeadershipService implements LeadershipService, ...@@ -479,23 +485,24 @@ public class HazelcastLeadershipService implements LeadershipService,
479 // 485 //
480 log.debug("Leader Interrupted for topic {}", 486 log.debug("Leader Interrupted for topic {}",
481 topicName); 487 topicName);
482 - }
483 488
484 - synchronized (this) { 489 + } finally {
485 - // If we reach here, we should release the leadership 490 + synchronized (this) {
486 - log.debug("Leader Lock Released for topic {}", topicName); 491 + // If we reach here, we should release the leadership
487 - if ((leader != null) && 492 + log.debug("Leader Lock Released for topic {}", topicName);
488 - leader.equals(localNodeId)) { 493 + if ((leader != null) &&
489 - leader = null; 494 + leader.equals(localNodeId)) {
495 + leader = null;
496 + }
497 + leadershipEvent = new LeadershipEvent(
498 + LeadershipEvent.Type.LEADER_BOOTED,
499 + new Leadership(topicName, localNodeId, myLastLeaderTerm));
500 + leaderTopic.publish(SERIALIZER.encode(leadershipEvent));
501 + leaderLock.unlock();
490 } 502 }
491 - leadershipEvent = new LeadershipEvent(
492 - LeadershipEvent.Type.LEADER_BOOTED,
493 - new Leadership(topicName, localNodeId, myLastLeaderTerm));
494 - leaderTopic.publish(SERIALIZER.encode(leadershipEvent));
495 - leaderLock.unlock();
496 } 503 }
497 } 504 }
498 - 505 + isRunningForLeadership = false;
499 } 506 }
500 507
501 // Globally guarded by the leadership lock for this term 508 // Globally guarded by the leadership lock for this term
......