in src/main/java/org/apache/sling/discovery/commons/providers/base/ViewStateManagerImpl.java [449:596]
boolean handleNewViewNonDelayed(final BaseTopologyView newView) {
logger.trace("handleNewViewNonDelayed: start");
lock.lock();
try{
logger.debug("handleNewViewNonDelayed: start, newView={}", newView);
if (!newView.isCurrent()) {
logger.error("handleNewViewNonDelayed: newView must be current");
throw new IllegalArgumentException("newView must be current");
}
modCnt++;
if (!isChanging) {
// verify if there is actually a change between previousView and newView
// if there isn't, then there is not much point in sending a CHANGING/CHANGED tuple
// at all
if (previousView!=null && (previousView.equals(newView) || equalsIgnoreSyncToken(newView))) {
// then nothing to send - the view has not changed, and we haven't
// sent the CHANGING event - so we should not do anything here
logger.debug("handleNewViewNonDelayed: we were not in changing state and new view matches old, so - ignoring");
return false;
}
if (previousView==null || !onlyDiffersInProperties(newView)) {
logger.debug("handleNewViewNonDelayed: implicitly triggering a handleChanging as we were not in changing state");
handleChanging();
logger.debug("handleNewViewNonDelayed: implicitly triggering of a handleChanging done");
}
}
if (!activated) {
// then all we can do is to pass this on to previoueView
logger.trace("handleNewViewNonDelayed: setting previousView to {}", newView);
previousView = newView;
// plus set the isChanging flag to false
logger.trace("handleNewViewNonDelayed: setting isChanging to false");
isChanging = false;
// other than that, we can't currently send any event, before activate
logger.debug("handleNewViewNonDelayed: not yet activated - ignoring");
return true;
}
// now check if the view indeed changed or if it was just the properties
if (!isChanging && onlyDiffersInProperties(newView)) {
// well then send a properties changed event only
// and that one does not go via consistencyservice
logSilencer.infoOrDebug("handleNewViewNonDelayed-propsChanged", "handleNewViewNonDelayed: properties changed to: "+newView);
previousView.setNotCurrent();
enqueueForAll(eventListeners, EventHelper.newPropertiesChangedEvent(previousView, newView));
logger.trace("handleNewViewNonDelayed: setting previousView to {}", newView);
previousView = newView;
return true;
}
final boolean invokeClusterSyncService;
if (consistencyService==null) {
logSilencer.infoOrDebug("handleNewViewNonDelayed-noSyncService", "handleNewViewNonDelayed: no ClusterSyncService set - continuing directly.");
invokeClusterSyncService = false;
} else {
// there used to be a distinction between:
// * if no previousView is set, then we should invoke the consistencyService
// * if one was set, then we only invoke it if any instance left the cluster
// this algorithm would not work though, as the newly joining instance
// would always have (previousView==null) - thus would always do the syncToken
// thingy - while the existing instances would think: ah, no instance left,
// so it is not so urgent to do the syncToken.
// at which point the joining instance would wait forever for a syncToken
// to arrive.
//
// which is a long way of saying: if the consistencyService is configured,
// then we always use it, hence:
logSilencer.infoOrDebug("handleNewViewNonDelayed-invokeSyncService", "handleNewViewNonDelayed: ClusterSyncService set - invoking...");
invokeClusterSyncService = true;
}
if (invokeClusterSyncService) {
// if "instances from the local cluster have been removed"
// then:
// run the set consistencyService
final int lastModCnt = modCnt;
logSilencer.infoOrDebug("handleNewViewNonDelayed-invokeWaitAsync", "handleNewViewNonDelayed: invoking waitForAsyncEvents, then clusterSyncService");
asyncEventSender.enqueue(new AsyncEvent() {
@Override
public String toString() {
return "the waitForAsyncEvents-flush-token-"+hashCode();
}
@Override
public void trigger() {
// when this event is triggered we're guaranteed to have
// no more async events - cos the async events are handled
// in a queue and this AsyncEvent was put at the end of the
// queue at enqueue time. So now e can go ahead.
// the plus using such a token event is that others when
// calling waitForAsyncEvent() will get blocked while this
// 'token async event' is handled. Which is what we explicitly want.
lock.lock();
try{
if (modCnt!=lastModCnt) {
logger.info("handleNewViewNonDelayed/waitForAsyncEvents.run: modCnt changed (from {} to {}) - ignoring",
lastModCnt, modCnt);
return;
}
logSilencer.infoOrDebug("waitForAsyncEvents-asyncRun", "handleNewViewNonDelayed/waitForAsyncEvents.run: done, now invoking consistencyService");
consistencyService.sync(newView,
new Runnable() {
public void run() {
logger.trace("consistencyService.callback.run: start. acquiring lock...");
lock.lock();
try{
logger.debug("consistencyService.callback.run: lock aquired. (modCnt should be {}, is {})", lastModCnt, modCnt);
if (modCnt!=lastModCnt) {
logger.info("consistencyService.callback.run: modCnt changed (from {} to {}) - ignoring",
lastModCnt, modCnt);
return;
}
logSilencer.infoOrDebug("consistencyService-callBackRun", "consistencyService.callback.run: invoking doHandleConsistent.");
// else:
doHandleConsistent(newView);
} finally {
lock.unlock();
logger.trace("consistencyService.callback.run: end.");
}
}
});
} finally {
lock.unlock();
}
}
});
} else {
// otherwise we're either told not to use any ClusterSyncService
// or using it is not applicable at this stage - so continue
// with sending the TOPOLOGY_CHANGED (or TOPOLOGY_INIT if there
// are any newly bound topology listeners) directly
logSilencer.infoOrDebug("handleNewViewNonDelayed-noSyncService-ignore", "handleNewViewNonDelayed: not invoking consistencyService, considering consistent now");
doHandleConsistent(newView);
}
logger.debug("handleNewViewNonDelayed: end");
return true;
} finally {
lock.unlock();
logger.trace("handleNewViewNonDelayed: finally");
}
}