? output.diff Index: com/sun/enterprise/ee/cms/impl/jxta/ViewWindow.java =================================================================== RCS file: /cvs/shoal/gms/src/java/com/sun/enterprise/ee/cms/impl/jxta/ViewWindow.java,v retrieving revision 1.25 diff -c -w -r1.25 ViewWindow.java *** com/sun/enterprise/ee/cms/impl/jxta/ViewWindow.java 27 Jun 2008 21:40:51 -0000 1.25 --- com/sun/enterprise/ee/cms/impl/jxta/ViewWindow.java 30 Jun 2008 00:58:18 -0000 *************** *** 130,137 **** GMSMember member; SystemAdvertisement advert; int count = 0; final StringBuffer sb = ! new StringBuffer("GMS View Change Received for group ").append(groupName).append(" : Members in view for ").append("(before change analysis) are :\n"); for (SystemAdvertisement systemAdvertisement : view.getView()) { advert = systemAdvertisement; member = getGMSMember(advert); --- 130,138 ---- GMSMember member; SystemAdvertisement advert; int count = 0; + // the information of packet's advertisement is quite useful in the INFO level. final StringBuffer sb = ! new StringBuffer("GMS View Change Received for group ").append(groupName).append( " (" ).append( packet.getSystemAdvertisement().getName() ).append( ")").append(" : Members in view for ").append("(before change analysis) are :\n"); for (SystemAdvertisement systemAdvertisement : view.getView()) { advert = systemAdvertisement; member = getGMSMember(advert); *************** *** 217,246 **** } private void analyzeMasterChangeView(final EventPacket packet) { - if(views.size() == 1){ //views list only contains 1 view which is assumed to be the 1st view. - addNewMemberJoins(packet); - } - if (views.size() > 1 && - packet.getClusterView().getSize() != - views.get(views.size() - 2).size()) { determineAndAddNewMemberJoins(); } - } private void determineAndAddNewMemberJoins() { final List newMembership = views.get(views.size() - 1); String token; if (views.size() == 1) { - if (newMembership.size() > 1) { for (GMSMember member : newMembership) { token = member.getMemberToken(); ! if (!token.equals(getGMSContext().getServerIdentityToken())) { syncDSC(token); - } if (member.getMemberType().equalsIgnoreCase(CORETYPE)) { ! addJoinNotificationSignal(token, member.getGroupName(), ! member.getStartTime()); ! } } } } else if (views.size() > 1) { --- 218,236 ---- } private void analyzeMasterChangeView( final EventPacket packet ) { determineAndAddNewMemberJoins(); } private void determineAndAddNewMemberJoins() { final List newMembership = views.get(views.size() - 1); String token; if( views.size() == 1 ) { for( GMSMember member : newMembership ) { token = member.getMemberToken(); ! if( newMembership.size() > 1 && !token.equals( getGMSContext().getServerIdentityToken() ) ) syncDSC( token ); if( member.getMemberType().equalsIgnoreCase( CORETYPE ) ) { ! addJoinNotificationSignal( token, member.getGroupName(), member.getStartTime() ); } } } else if (views.size() > 1) { *************** *** 250,257 **** if (!oldMembers.contains(token)) { syncDSC(token); if (member.getMemberType().equalsIgnoreCase(CORETYPE)) { ! addJoinNotificationSignal(token, member.getGroupName(), ! member.getStartTime()); } } } --- 240,246 ---- if (!oldMembers.contains(token)) { syncDSC(token); if (member.getMemberType().equalsIgnoreCase(CORETYPE)) { ! addJoinNotificationSignal(token, member.getGroupName(), member.getStartTime()); } } } *************** *** 430,460 **** } private void addNewMemberJoins(final EventPacket packet) { ! final SystemAdvertisement advert = packet.getSystemAdvertisement(); ! final String token = advert.getName(); ! if (packet.getClusterView().getSize() > 1) { ! // TODO: Figure out a better way to sync ! syncDSC(token); ! } ! try { ! if (advert.getCustomTagValue( ! CustomTagNames.MEMBER_TYPE.toString()).equalsIgnoreCase(CORETYPE)) { ! addJoinNotificationSignal(token, ! advert.getCustomTagValue( ! CustomTagNames.GROUP_NAME.toString()), ! Long.valueOf(advert.getCustomTagValue( ! CustomTagNames.START_TIME.toString()))); ! } ! } catch (NoSuchFieldException e) { ! logger.log(Level.WARNING, ! new StringBuffer("The SystemAdvertisement did ") ! .append("not contain the ").append( ! e.getLocalizedMessage()) ! .append(" custom tag value:").toString()); ! } } private void addReadyMembers(final EventPacket packet) { final SystemAdvertisement advert = packet.getSystemAdvertisement(); final String token = advert.getName(); logger.log(Level.FINE, "Adding Joined And Ready member : " + token); --- 419,431 ---- } private void addNewMemberJoins(final EventPacket packet) { ! // we only notify join events when view is changed ! determineAndAddNewMemberJoins(); } private void addReadyMembers(final EventPacket packet) { + determineAndAddNewMemberJoins(); + final SystemAdvertisement advert = packet.getSystemAdvertisement(); final String token = advert.getName(); logger.log(Level.FINE, "Adding Joined And Ready member : " + token); Index: com/sun/enterprise/jxtamgmt/ClusterViewManager.java =================================================================== RCS file: /cvs/shoal/gms/src/java/com/sun/enterprise/jxtamgmt/ClusterViewManager.java,v retrieving revision 1.19 diff -c -w -r1.19 ClusterViewManager.java *** com/sun/enterprise/jxtamgmt/ClusterViewManager.java 11 Jun 2008 04:18:03 -0000 1.19 --- com/sun/enterprise/jxtamgmt/ClusterViewManager.java 25 Jun 2008 06:09:17 -0000 *************** *** 78,84 **** public void start() { //Self appointed as master and then discover so that we resolve to the right one ! setMaster(advertisement, true); } public void addClusterViewEventListener( --- 78,85 ---- public void start() { //Self appointed as master and then discover so that we resolve to the right one ! // avoid notifying listener ! setMaster(advertisement, false); } public void addClusterViewEventListener( *************** *** 352,375 **** * * @param newView list of advertisements * @param cvEvent the cluster event ! * @param authoritative whether the view is authoritative or not */ void addToView(final List newView, ! final boolean authoritative, final ClusterViewEvent cvEvent) { ! //TODO: need to review the use cases of the callers of method ! if (cvEvent == null) { return; - } - - if (authoritative) { boolean changed = addToView( newView ); ! if (changed) { ! //only if there are changes that we notify notifyListeners(cvEvent); } - } - } /** * Adds a list of advertisements to the view --- 353,369 ---- * * @param newView list of advertisements * @param cvEvent the cluster event ! * @param notifyForcefully if true, notifies registered listeners forcefully. if false, notifies listeners when view changed. */ void addToView( final List newView, ! final boolean notifyForcefully, final ClusterViewEvent cvEvent ) { ! if( cvEvent == null ) return; boolean changed = addToView( newView ); ! if( notifyForcefully || changed ) notifyListeners( cvEvent ); } /** * Adds a list of advertisements to the view *************** *** 379,389 **** */ private boolean addToView( final List newView ) { boolean changed = false; ! LOG.log( Level.FINER, "Resetting View" ); ! reset(); lockLog( "addToView()" ); viewLock.lock(); try { if( !newView.contains( manager.getSystemAdvertisement() ) ) { view.put( manager.getSystemAdvertisement().getID().toString(), manager.getSystemAdvertisement() ); --- 373,394 ---- */ private boolean addToView( final List newView ) { boolean changed = false; ! // We need old view's snapshot for becoming aware of changes before reset() ! // Though reset() also uses viewLock for view.clear(), ! // if reset() is called before addToView() acquires the viewLock, view can be changed in a short time ! // If view was changed in a short time, unexpected result occurred in becoming aware of changes ! // So for safety, if we need to become aware of real changes, snapshooting and view.clear() should be called in addToView()'s viewLock ! //reset(); lockLog( "addToView()" ); viewLock.lock(); + // old view's snapshot + TreeMap oldView = (TreeMap)view.clone(); + LOG.log( Level.FINER, "Resetting View" ); + // we should clear view after old view's snapshot + view.clear(); + view.put(advertisement.getID().toString(), advertisement); try { + // we don't need put manager.getSystemAdvertisement(). this operation is maybe duplicated. if( !newView.contains( manager.getSystemAdvertisement() ) ) { view.put( manager.getSystemAdvertisement().getID().toString(), manager.getSystemAdvertisement() ); *************** *** 393,399 **** new StringBuffer().append( "Adding " ) .append( elem.getID() ).append( " to view" ) .toString() ); ! if( !changed && !view.containsKey( elem.getID().toString() ) ) { changed = true; } // Always add the wire version of the adv --- 398,404 ---- new StringBuffer().append( "Adding " ) .append( elem.getID() ).append( " to view" ) .toString() ); ! if( !changed && !oldView.containsKey( elem.getID().toString() ) ) { changed = true; } // Always add the wire version of the adv *************** *** 405,411 **** return changed; } ! void notifyListeners(final ClusterViewEvent event) { LOG.log(Level.FINER, MessageFormat.format("Notifying the {0} to listeners, peer in event is {1}", event.getEvent().toString(), event.getAdvertisement().getName())); for (ClusterViewEventListener elem : cvListeners) { --- 410,417 ---- return changed; } ! // this method should be thread-safe ! synchronized void notifyListeners(final ClusterViewEvent event) { LOG.log(Level.FINER, MessageFormat.format("Notifying the {0} to listeners, peer in event is {1}", event.getEvent().toString(), event.getAdvertisement().getName())); for (ClusterViewEventListener elem : cvListeners) { Index: com/sun/enterprise/jxtamgmt/HealthMonitor.java =================================================================== RCS file: /cvs/shoal/gms/src/java/com/sun/enterprise/jxtamgmt/HealthMonitor.java,v retrieving revision 1.71 diff -c -w -r1.71 HealthMonitor.java *** com/sun/enterprise/jxtamgmt/HealthMonitor.java 4 Jun 2008 20:50:21 -0000 1.71 --- com/sun/enterprise/jxtamgmt/HealthMonitor.java 25 Jun 2008 06:03:21 -0000 *************** *** 630,635 **** --- 630,647 ---- void start() { if (!started) { + // ensure whether discovery is done. + // If masterNode.probeNode(entry) is called before master's discovery is not done, unexpected results can be occurred in the master selection algorithm. + if( masterNode.isDiscoveryInProgress() ) { + synchronized( masterNode.discoveryLock ) { + try { + masterNode.discoveryLock.wait(); + LOG.log( Level.FINEST, "start() waiting for masternode discovery to finish..." ); + } catch( InterruptedException e ) { + LOG.log( Level.FINEST, "MasterNode's DiscoveryLock Thread is interrupted " + e ); + } + } + } LOG.log(Level.FINE, "Starting HealthMonitor"); try { // create the pipe advertisement, to be used in creating the pipe Index: com/sun/enterprise/jxtamgmt/MasterNode.java =================================================================== RCS file: /cvs/shoal/gms/src/java/com/sun/enterprise/jxtamgmt/MasterNode.java,v retrieving revision 1.64 diff -c -w -r1.64 MasterNode.java *** com/sun/enterprise/jxtamgmt/MasterNode.java 11 Jun 2008 04:18:04 -0000 1.64 --- com/sun/enterprise/jxtamgmt/MasterNode.java 25 Jun 2008 06:00:53 -0000 *************** *** 239,244 **** --- 239,246 ---- //TODO add code to ensure whether this node should remain as master or resign (basically noop) if (manager.getNodeID().toString().compareTo(systemAdv.getID().toString()) >= 0) { LOG.log(Level.FINER, "Affirming Master Node role"); + // When affirming master node role, notify MASTER_CHANGE_EVNET in the master collison + clusterViewManager.notifyListeners( new ClusterViewEvent(ClusterViewEvents.MASTER_CHANGE_EVENT, manager.getSystemAdvertisement() ) ); } else { LOG.log(Level.FINER, "Resigning Master Node role in anticipation of a master node announcement"); clusterViewManager.setMaster(systemAdv, false); *************** *** 246,260 **** return false; } else { - clusterViewManager.setMaster(systemAdv, true); - masterAssigned = true; - synchronized (MASTERLOCK) { - MASTERLOCK.notifyAll(); - } - LOG.log(Level.FINE, "Discovered a Master node :" + systemAdv.getName()); - } return true; } /** * Creates a Master Collision Message. A collision message is used --- 248,256 ---- return false; } else { return true; } + } /** * Creates a Master Collision Message. A collision message is used *************** *** 474,480 **** LOG.log(Level.FINER, "Received a Master Node Announcement from Name :" + source.getName()); if (checkMaster(source)) { msgElement = msg.getMessageElement(NAMESPACE, AMASTERVIEW); ! if (msgElement != null) { final ArrayList newLocalView = (ArrayList) getObjectFromByteArray(msgElement); if (newLocalView != null) { LOG.log(Level.FINER, MessageFormat.format("Received an authoritative view from {0}, of size {1}" + --- 470,485 ---- LOG.log(Level.FINER, "Received a Master Node Announcement from Name :" + source.getName()); if (checkMaster(source)) { msgElement = msg.getMessageElement(NAMESPACE, AMASTERVIEW); ! if ( msgElement == null ) { ! clusterViewManager.setMaster( source, true ); ! masterAssigned = true; ! synchronized( MASTERLOCK ) { ! MASTERLOCK.notifyAll(); ! } ! LOG.log( Level.FINE, "Discovered a Master node :" + source.getName() ); ! return true; ! } ! final ArrayList newLocalView = (ArrayList) getObjectFromByteArray(msgElement); if (newLocalView != null) { LOG.log(Level.FINER, MessageFormat.format("Received an authoritative view from {0}, of size {1}" + *************** *** 483,492 **** } long seqID = getLongFromMessage(msg, NAMESPACE, MASTERVIEWSEQ); msgElement = msg.getMessageElement(NAMESPACE, VIEW_CHANGE_EVENT); ! if (msgElement != null) { LOG.log(Level.FINEST, "MasterNode:PMNA: Received Master View with Seq Id="+seqID + "Current sequence is "+clusterViewManager.getMasterViewID()); if (seqID <= clusterViewManager.getMasterViewID()) { LOG.log(Level.FINER, MessageFormat.format("Received an older clusterView sequence {0}." + " Current sequence :{1} discarding out of sequence view", seqID, clusterViewManager.getMasterViewID())); return true; --- 488,516 ---- } long seqID = getLongFromMessage(msg, NAMESPACE, MASTERVIEWSEQ); msgElement = msg.getMessageElement(NAMESPACE, VIEW_CHANGE_EVENT); ! if ( msgElement == null ) { ! clusterViewManager.setMaster( source, true ); ! masterAssigned = true; ! synchronized( MASTERLOCK ) { ! MASTERLOCK.notifyAll(); ! } ! LOG.log( Level.FINE, "Discovered a Master node :" + source.getName() ); ! LOG.log(Level.WARNING, "New View Received without corresponding ViewChangeEvent details"); ! //TODO according to the implementation MasterNode does not include VIEW_CHANGE_EVENT ! //when it announces a Authortative master view ! //throw new IOException("New View Received without corresponding ViewChangeEvent details"); ! return true; ! } ! LOG.log(Level.FINEST, "MasterNode:PMNA: Received Master View with Seq Id="+seqID + "Current sequence is "+clusterViewManager.getMasterViewID()); if (seqID <= clusterViewManager.getMasterViewID()) { + clusterViewManager.setMaster( source, true ); + masterAssigned = true; + synchronized( MASTERLOCK ) { + MASTERLOCK.notifyAll(); + } + LOG.log( Level.FINE, "Discovered a Master node :" + source.getName() ); LOG.log(Level.FINER, MessageFormat.format("Received an older clusterView sequence {0}." + " Current sequence :{1} discarding out of sequence view", seqID, clusterViewManager.getMasterViewID())); return true; *************** *** 495,500 **** --- 519,531 ---- (ClusterViewEvent) getObjectFromByteArray(msgElement); assert newLocalView != null; if (!newLocalView.contains(manager.getSystemAdvertisement())) { + // before calling sendSelfnodeAdvertisement(), new master setting should be done with new master's view + clusterViewManager.setMaster( newLocalView, source ); + masterAssigned = true; + synchronized( MASTERLOCK ) { + MASTERLOCK.notifyAll(); + } + LOG.log( Level.FINE, "Discovered a Master node :" + source.getName() ); LOG.log(Level.FINER, "New ClusterViewManager does not contain self. Publishing Self"); sendSelfNodeAdvertisement(source.getID(), null); //update the view once the the master node includes this node *************** *** 503,520 **** clusterViewManager.setMasterViewID(seqID); masterViewID.set(seqID); LOG.log(Level.FINER, "MN: New MasterViewID = "+clusterViewManager.getMasterViewID()); ! clusterViewManager.addToView(newLocalView, true, cvEvent); ! } else { ! LOG.log(Level.WARNING, "New View Received without corresponding ViewChangeEvent details"); ! //TODO according to the implementation MasterNode does not include VIEW_CHANGE_EVENT ! //when it announces a Authortative master view ! //throw new IOException("New View Received without corresponding ViewChangeEvent details"); ! } ! } ! } synchronized (MASTERLOCK) { MASTERLOCK.notifyAll(); } return true; } --- 534,553 ---- clusterViewManager.setMasterViewID(seqID); masterViewID.set(seqID); LOG.log(Level.FINER, "MN: New MasterViewID = "+clusterViewManager.getMasterViewID()); ! // new master setting should be done with new master's view ! // If master changed, MASTER_CHANGE_EVENT would be notified in setMaster() ! boolean masterChanged = clusterViewManager.setMaster( newLocalView, source ); ! masterAssigned = true; synchronized( MASTERLOCK ) { MASTERLOCK.notifyAll(); } + LOG.log( Level.FINE, "Discovered a Master node :" + source.getName() ); + if ( masterChanged && cvEvent.getEvent() != ClusterViewEvents.MASTER_CHANGE_EVENT ) + clusterViewManager.notifyListeners( cvEvent ); + else { + clusterViewManager.addToView(newLocalView, false, cvEvent); + } + } return true; } *************** *** 537,542 **** --- 570,578 ---- if ( msgElement == null ) { clusterViewManager.setMaster( source, true ); masterAssigned = true; + synchronized( MASTERLOCK ) { + MASTERLOCK.notifyAll(); + } return true; } final ArrayList newLocalView = *************** *** 545,550 **** --- 581,589 ---- if ( msgElement == null ) { clusterViewManager.setMaster( source, true ); masterAssigned = true; + synchronized( MASTERLOCK ) { + MASTERLOCK.notifyAll(); + } return true; } long seqID = getLongFromMessage(msg, NAMESPACE, MASTERVIEWSEQ); *************** *** 552,557 **** --- 591,599 ---- if (seqID <= clusterViewManager.getMasterViewID()) { clusterViewManager.setMaster( source, true ); masterAssigned = true; + synchronized( MASTERLOCK ) { + MASTERLOCK.notifyAll(); + } LOG.log(Level.FINER, MessageFormat.format("Received an older clusterView sequence {0} of size :{1}" + " Current sequence :{2} discarding out of sequence view", *************** *** 565,572 **** final ClusterViewEvent cvEvent = (ClusterViewEvent) getObjectFromByteArray(msgElement); if (!newLocalView.contains(manager.getSystemAdvertisement())) { ! clusterViewManager.setMaster( source, true ); masterAssigned = true; LOG.log(Level.FINER, "Received view does not contain self. Publishing self"); sendSelfNodeAdvertisement(source.getID(), null); //update the view once the the master node includes this node --- 607,618 ---- final ClusterViewEvent cvEvent = (ClusterViewEvent) getObjectFromByteArray(msgElement); if (!newLocalView.contains(manager.getSystemAdvertisement())) { ! // before calling sendSelfnodeAdvertisement(), new master setting should be done with new master's view ! clusterViewManager.setMaster( newLocalView, source ); masterAssigned = true; + synchronized( MASTERLOCK ) { + MASTERLOCK.notifyAll(); + } LOG.log(Level.FINER, "Received view does not contain self. Publishing self"); sendSelfNodeAdvertisement(source.getID(), null); //update the view once the the master node includes this node *************** *** 574,585 **** } clusterViewManager.setMasterViewID(seqID); masterViewID.set(seqID); boolean masterChanged = clusterViewManager.setMaster( newLocalView, source ); masterAssigned = true; ! if ( masterChanged ) clusterViewManager.notifyListeners( cvEvent ); else ! clusterViewManager.addToView(newLocalView, true, cvEvent); synchronized (MASTERLOCK) { MASTERLOCK.notifyAll(); } --- 620,633 ---- } clusterViewManager.setMasterViewID(seqID); masterViewID.set(seqID); + // new master setting should be done with new master's view + // If master changed, MASTER_CHANGE_EVENT would be notified in setMatser() boolean masterChanged = clusterViewManager.setMaster( newLocalView, source ); masterAssigned = true; ! if ( masterChanged && cvEvent.getEvent() != ClusterViewEvents.MASTER_CHANGE_EVENT ) clusterViewManager.notifyListeners( cvEvent ); else ! clusterViewManager.addToView(newLocalView, false, cvEvent); synchronized (MASTERLOCK) { MASTERLOCK.notifyAll(); } *************** *** 919,927 **** madv = clusterViewManager.getMasterCandidate(); } LOG.log(Level.FINER, "MasterNode: Master Candidate="+madv.getName()); //avoid notifying listeners ! clusterViewManager.setMaster(madv, false); ! masterAssigned = true; if (madv.getID().equals(localNodeID)) { LOG.log(Level.FINER, "MasterNode: Setting myself as MasterNode "); clusterViewManager.setMasterViewID(masterViewID.incrementAndGet()); --- 967,977 ---- madv = clusterViewManager.getMasterCandidate(); } LOG.log(Level.FINER, "MasterNode: Master Candidate="+madv.getName()); + // new master setting should be done with new master's view. So we put off setMaster() + // If master changed, MASTER_CHANGE_EVENT would be notified in setMatser() //avoid notifying listeners ! //clusterViewManager.setMaster(madv, false); ! //masterAssigned = true; if (madv.getID().equals(localNodeID)) { LOG.log(Level.FINER, "MasterNode: Setting myself as MasterNode "); clusterViewManager.setMasterViewID(masterViewID.incrementAndGet()); *************** *** 929,942 **** // generate view change event if (discoveryInProgress) { List list = discoveryView.getView(); final ClusterViewEvent cvEvent = new ClusterViewEvent(ClusterViewEvents.MASTER_CHANGE_EVENT, madv); ! clusterViewManager.addToView(list, true, cvEvent); } else { LOG.log(Level.FINER, "MasterNode: Notifying Local Listeners of Master Change"); final ClusterViewEvent cvEvent = new ClusterViewEvent(ClusterViewEvents.MASTER_CHANGE_EVENT, madv); clusterViewManager.notifyListeners(cvEvent); } ! } discoveryView.clear(); discoveryView.add(sysAdv); --- 979,1006 ---- // generate view change event if (discoveryInProgress) { List list = discoveryView.getView(); + // new master setting should be done with new master's view + // If master changed, MASTER_CHANGE_EVENT would be notified in setMatser() + boolean masterChanged = clusterViewManager.setMaster( list, madv ); + if ( !masterChanged ) { + // If master was not changed(this is normal case), we notify MASTER_CHANGE_EVENT forcefully. + // because if current member becomes a group leader, current member must receive own JoinNotification and GroupLeaderShipNotification. final ClusterViewEvent cvEvent = new ClusterViewEvent(ClusterViewEvents.MASTER_CHANGE_EVENT, madv); ! clusterViewManager.notifyListeners(cvEvent); ! } ! masterAssigned = true; } else { + clusterViewManager.setMaster(madv, false); + masterAssigned = true; LOG.log(Level.FINER, "MasterNode: Notifying Local Listeners of Master Change"); final ClusterViewEvent cvEvent = new ClusterViewEvent(ClusterViewEvents.MASTER_CHANGE_EVENT, madv); clusterViewManager.notifyListeners(cvEvent); } ! } else { ! // You must not call setMaster(). Though now current member doesn't set the master, ! // current member can receive the master change event through real group leader's announceMaster() later. ! //clusterViewManager.setMaster(madv, false); ! //masterAssigned = true; } discoveryView.clear(); discoveryView.add(sysAdv); *************** *** 944,954 **** if (madv.getID().equals(localNodeID)) { // this thread's job is done LOG.log(Level.FINER, "Assuming Master Node designation ..."); //broadcast we are the masternode if view size is more than one ! if (clusterViewManager.getViewSize() > 1) { LOG.log(Level.FINER, "MasterNode: announcing MasterNode assumption "); announceMaster(manager.getSystemAdvertisement()); ! } MASTERLOCK.notifyAll(); } } --- 1008,1020 ---- if (madv.getID().equals(localNodeID)) { // this thread's job is done LOG.log(Level.FINER, "Assuming Master Node designation ..."); + // In a short time, though one more member joined the group, clusterViewManager.getViewSize() could be equal to 1. + // so we should call announceMaster() for safety. //broadcast we are the masternode if view size is more than one ! //if (clusterViewManager.getViewSize() > 1) { LOG.log(Level.FINER, "MasterNode: announcing MasterNode assumption "); announceMaster(manager.getSystemAdvertisement()); ! //} MASTERLOCK.notifyAll(); } }