/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.ee.web.sessmgmt;
import com.sun.appserv.util.cache.BaseCache;
import com.sun.appserv.ha.uow.ReplicableEntity;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;
import java.io.Serializable;
/**
*
* @author Larry White
*/
public class RollingUpgradeUtil {
public final static String LOGGER_MEM_REP
= ReplicationState.LOGGER_MEM_REP;
/**
* The logger to use for logging ALL web container related messages.
*/
private static final Logger _logger
= Logger.getLogger(LOGGER_MEM_REP);
private static ReplicationUtil replicationUtil = ReplicationUtil.createReplicationUtil();
public final static String BEKEY
= ReplicationState.BEKEY;
/**
* The logger to use for logging ALL web container related messages.
* @param owningInstanceName the owning instance name
* @param correctBuddyReplicaName the correct buddy replica name (for non-CLB case)
* @param state the ReplicationState to filter
* @param idsSet the set in which to collect filtered states
* @return true if this instance is the correct instance for this replica; otherwise false
*/
public static boolean filterOwnership(String owningInstanceName, String correctBuddyReplicaName, ReplicationState state, HashSet idsSet) {
boolean result = true;
long nextVersion = -1L;
String thisInstanceName = ReplicationUtil.getInstanceName();
String nextOwnerInstanceName = null;
String nextCorrectReplicaPartnerInstanceName = null;
String nextId = (String)state.getId();
if(replicationUtil.isInstanceLoadBalancedByCLB()) {
//CLB case
//use beKey for mapping instance ownership
String nextBeKey = (String)state.getProperty(BEKEY);
if(nextBeKey != null) {
nextOwnerInstanceName
= replicationUtil.getActualServerInstanceForBeKey(nextBeKey);
nextCorrectReplicaPartnerInstanceName
= replicationUtil.getFailoverServerInstanceForBeKey(nextBeKey);
if(nextOwnerInstanceName != null
&& nextOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
//return false if we are not the correct replica partner for this beKey
// if (nextCorrectReplicaPartnerInstanceName.equalsIgnoreCase(thisInstanceName)) {
nextVersion = state.getVersion();
idsSet.add(new FederatedQueryListElement(nextId, nextVersion, thisInstanceName, nextBeKey));
// } else {
// result = false;
// }
}
}
} else {
//non-CLB case
nextOwnerInstanceName = (String)state.getProperty(ReplicationState.ORIGINATING_INSTANCE_NAME);
if(nextOwnerInstanceName != null
&& nextOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
nextVersion = state.getVersion();
idsSet.add(new FederatedQueryListElement(nextId, nextVersion, ReplicationUtil.getInstanceName()));
//if we are a valid replica for owningInstanceName
// but not the correctBuddyReplica then return false
if(correctBuddyReplicaName != null &&
!correctBuddyReplicaName.equalsIgnoreCase(thisInstanceName)) {
result = false;
}
}
}
return result;
}
public static void filterOwnershipOfReplicas(String owningInstanceName,
ReplicationState state,
HashSet idsSet) {
String nextOwnerInstanceName = (String) state.getProperty(
ReplicationState.ORIGINATING_INSTANCE_NAME);
if (nextOwnerInstanceName != null
&& nextOwnerInstanceName.equalsIgnoreCase(owningInstanceName)) {
idsSet.add(state);
}
}
public static ConcurrentHashMap mergeQueryListIntoMap(List localSessionIdsList, ConcurrentHashMap sessionIdsMap) {
for(int i=0; i<localSessionIdsList.size(); i++) {
FederatedQueryListElement nextElement = (FederatedQueryListElement)localSessionIdsList.get(i);
if(nextElement != null) {
//get any existing element in the map
FederatedQueryListElement existingElement
= (FederatedQueryListElement)sessionIdsMap.get(nextElement.getId());
if(existingElement == null || existingElement.getVersion() < nextElement.getVersion()) {
sessionIdsMap.put(nextElement.getId(), nextElement);
}
}
}
return sessionIdsMap;
}
public static boolean isElementFromReplicationPartner(FederatedQueryListElement nextElement, String buddyInstanceName) {
String nextOwnerInstanceName = null;
boolean result = false;
String sourceInstance = nextElement.getSourceInstance();
if(sourceInstance == null) {
return result;
}
if(replicationUtil.isInstanceLoadBalancedByCLB()) {
/**
* The check below is wrong. getActualServerInstanceForBeKey(nextBeKey)
* will always return the name of our own instance, it will not be
* the name of replica partner.
*
* Probably the intention was to use getFailoverServerInstanceForBeKey(nextBeKey),
* but doing that is also wrong because the 'nextElement' would have come from somewhere else
* which need not necessarily be the current replica partner for this instance.
*
* Hence commenting it out, and setting the result to true always.
*/
/*
//CLB case
//use beKey for mapping instance ownership - compare to sourceInstance
String nextBeKey = nextElement.getBeKey();
if(nextBeKey != null) {
nextOwnerInstanceName
= replicationUtil.getActualServerInstanceForBeKey(nextBeKey);
if(nextOwnerInstanceName != null
&& nextOwnerInstanceName.equalsIgnoreCase(sourceInstance)) {
result=true;
}
}
*/
result = true;
} else {
//non-CLB case
if(sourceInstance.equals(buddyInstanceName)) {
result = true;
}
}
return result;
}
public static boolean shouldReplicateTo(String beKey, String owningInstanceName) {
if(replicationUtil.isInstanceLoadBalancedByCLB()) {
//use CLB beKey semantics
return owningInstanceName.equalsIgnoreCase(replicationUtil.getFailoverServerInstanceForBeKey(beKey));
} else {
//use ring topology semantics
ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
return owningInstanceName.equalsIgnoreCase(healthChecker.getReshapeReplicateToInstanceName(null, 0L));
}
}
/**
* send a rolling upgrade advisory message to a given instance
*
* @param mgr the ReplicationManager
* @param mode the mode
* @param command the command
* @param instanceName the instance to be sent the rolling upgrade advisory
*/
public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, String instanceName)
throws IOException {
//send rolling upgrade advisory to instanceName
sendRollingUpgradeAdvisory(mgr, mode, command, instanceName, -1L);
}
/**
* send a rolling upgrade advisory message to a given instance
*
* @param mgr the ReplicationManager
* @param mode the mode
* @param command the command
* @param instanceName the instance to be sent the rolling upgrade advisory
* @param waitTime the waitTime
*/
public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, String instanceName, long waitTime)
throws IOException {
//send rolling upgrade advisory to instanceName
ReplicationState loadAdvisoryState
= ReplicationState.createUnicastLoadAdvisoryState(mode, "id", mgr.getApplicationId(), 0L, ReplicationUtil.getInstanceName(), command);
if(waitTime != -1L) {
loadAdvisoryState.setProperty(ReplicationState.WAIT_TIME, new Long(waitTime));
}
JxtaReplicationSender sender
= JxtaReplicationSender.createInstance();
sender.sendOverPropagatedPipe(loadAdvisoryState, instanceName, false);
}
/**
* send a rolling upgrade advisory message to instance to trigger
* it to do rolling upgrade active cache restoration for the sending
* instance
*
* @param mode the mode of the manager
* @param command the command (message)
* @param className to be used in logging message
* @param methodName to be used in logging message
* @param instanceName the instance to be sent the rolling upgrade advisory
*/
public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, String className, String methodName, String instanceName) {
if(_logger.isLoggable(Level.FINE)) {
_logger.entering(className,
methodName,
new Object[] {instanceName});
}
try {
RollingUpgradeUtil.sendRollingUpgradeAdvisory(mgr, mode, command, instanceName);
} catch (IOException ex) {}
if(_logger.isLoggable(Level.FINE)) {
_logger.exiting(className,
methodName);
}
}
/**
* broadcast a rolling upgrade advisory message
*
* @param mgr the ReplicationManager
* @param mode the mode
* @param command the command
*/
public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command) {
//broadcast rolling upgrade advisory
sendRollingUpgradeAdvisory(mgr, mode, command, -1L);
}
/**
* broadcast a rolling upgrade advisory message
*
* @param mgr the ReplicationManager
* @param mode the mode
* @param command the command
* @param waitTime the waitTime
*/
public static void sendRollingUpgradeAdvisory(ReplicationManager mgr, String mode, String command, long waitTime) {
//broadcast rolling upgrade advisory
JxtaReplicationSender sender
= JxtaReplicationSender.createInstance();
//ok to use this method even while sending via broadcast in this case
ReplicationState rollingUpgradeAdvisoryState
= ReplicationState.createUnicastLoadAdvisoryState(mode, "id", mgr.getApplicationId(), 0L, ReplicationUtil.getInstanceName(), command);
if(waitTime != -1L) {
rollingUpgradeAdvisoryState.setProperty(ReplicationState.WAIT_TIME, new Long(waitTime));
}
sender.sendBroadcastQuery(rollingUpgradeAdvisoryState);
}
/**
* get the number of expected respondants
* for non-CLB case it will be one
* for CLB case it will be one less than the current cluster size
*
*/
public static int getNumberOfExpectedRespondants() {
int numberOfRespondants = 1;
if(ReplicationUtil.checkIsInstanceLoadBalancedByCLB()) {
numberOfRespondants = ReplicationUtil.getNumberExpectedRespondants();
}
return numberOfRespondants;
}
public static Object getObject(byte[] b) {
try {
return ReplicationState.getObjectValue(b);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static int doActiveCacheReconciliation(SessionStoreInterface storeInterface,
String reconcileCommand,
AtomicReference<CountDownLatch> signalReference,
long waitTime,
Map<String, ReplicationState> queryResponses) {
Set<ReplicationState> reconcilableActiveSessions =
sendSynchronousQuery(reconcileCommand, storeInterface.getMode(),
storeInterface.getApplicationId(), signalReference,
waitTime, queryResponses);
int sessionsActivated = activateSessions(reconcilableActiveSessions, storeInterface);
return sessionsActivated;
}
public static int doReplicaCacheReconciliation(SessionStoreInterface storeInterface,
String reconcileCommand,
AtomicReference<CountDownLatch> signalReference,
long waitTime,
Map<String, ReplicationState> queryResponses) {
Set<ReplicationState> reconcilableReplicaSessions =
sendSynchronousQuery(reconcileCommand, storeInterface.getMode(),
storeInterface.getApplicationId(), signalReference,
waitTime, queryResponses);
int savedReplicas = saveReplicas(reconcilableReplicaSessions, storeInterface);
// the ongoing transaction on the remote instance might have replicated
// the session to reconciling instance's replica cache which need to be purged.
// removeStaleReplicas(ReplicationUtil.getInstanceName(), storeInterface);
return savedReplicas;
}
public static int doPostActiveCacheReconcilation(SessionStoreInterface storeInterface,
String reconcileCommand,
AtomicReference<CountDownLatch> signalReference,
long waitTime,
Map<String, ReplicationState> queryResponses) {
Set<String> remotelyLockedSessions = sendSynchronousQuery(reconcileCommand, storeInterface.getMode(),
storeInterface.getApplicationId(), signalReference, waitTime, queryResponses);
int suspectSessions = 0;
for (ReplicableEntity session : storeInterface.getActiveCache().values()) {
if (session.isSuspect()) {
if (!remotelyLockedSessions.contains(session.getId())) {
session.setSuspect(false);
} else {
++suspectSessions;
}
}
}
return suspectSessions;
}
public static int activateSessions(Set<ReplicationState> reconcilableSessions,
SessionStoreInterface storeInterface) {
Iterator<ReplicationState> iter = reconcilableSessions.iterator();
int sessionsActivated = reconcilableSessions.size();
while (iter.hasNext()) {
ReplicationState state = iter.next();
ReplicableEntity session = storeInterface.deserialize(state);
storeInterface.activate(session); // activate will take care of checking the version.
iter.remove();
}
return sessionsActivated;
}
public static int saveReplicas(Set<ReplicationState> reconcilableSessions,
SessionStoreInterface storeInterface) {
Iterator<ReplicationState> iter = reconcilableSessions.iterator();
int savedReplicas = reconcilableSessions.size();
while (iter.hasNext()) {
ReplicationState state = iter.next();
storeInterface.putInReplicaCache(state);
iter.remove();
}
return savedReplicas;
}
public static int removeStaleReplicas(String reconcilingInstance,
SessionStoreInterface storeInterface) {
Set<String> replicasToBePurged = new HashSet<String>();
BaseCache replicaCache = storeInterface.getReplicaCache();
Iterator<ReplicationState> replicatedSessions = replicaCache.values();
List lbEnabledList = getLbEnabledList();
while (replicatedSessions.hasNext()) {
ReplicationState replica = replicatedSessions.next();
if (canRemoveReplica(replica, reconcilingInstance, lbEnabledList)) {
replicasToBePurged.add((String) replica.getId());
}
}
for (String id : replicasToBePurged) {
storeInterface.removeFromReplicaCache(id);
}
return replicasToBePurged.size();
}
// this method is executed by all other instances, in order to reconcile the
// active cache of the instance who issued the reconcileRequest.
public static Set<String> processActiveCacheReconciliationRequest(ReplicationState reconcileRequest,
SessionStoreInterface storeInterface,
String responseCommand,
boolean compress) {
Set<String> migratedActiveSessionIds = new HashSet<String>();
Set<ReplicationState> result = new HashSet<ReplicationState>();
if (replicationUtil.isInstanceLoadBalancedByCLB()) {
String reconilingInstance = reconcileRequest.getInstanceName();
Collection<ReplicableEntity> sessions = storeInterface.getActiveCache().values();
for (ReplicableEntity session : sessions) {
String beKey = session.getBeKey();
if(!session.isForegroundLocked() && // don't migrate if it is foreground locked. locked sessions will be lazily migrated.
isRightfulOwner(reconilingInstance, beKey)) {
/**
* Do not passivate the session now until it is activated in
* the reconciling instance. Otherwise, if the load is issued
* by the reconciling instance when the reconciliation is in progress
* then the load will return null because session would have
* been removed from the session manager after the passivation.
*/
// ReplicableEntity haSas = storeInterface.findSessionAndPassivate(session.getId());
ReplicableEntity haSas = session;
ReplicationState state = ReplicationState.createQueryResponseFrom(
haSas, reconcileRequest.getAppId(), reconcileRequest.getCommand(),
responseCommand, // TODO :: revisit this arg - should it be LOAD_SAS_COMMAND or something?
reconilingInstance, // origin is deliberately set to reconcilingInstance, so that we can copy this active session to our own replica.
compress, true);
result.add(state);
migratedActiveSessionIds.add(session.getId());
}
}
// If some other instance has failed during the rolling upgrade of an instance,
// then we should take care of that.
int reconciledFromReplica = 0;
BaseCache replicaCache = storeInterface.getReplicaCache();
Iterator<ReplicationState> replicatedSessions = replicaCache.values();
List lbEnabledList = getLbEnabledList();
while(replicatedSessions.hasNext()) {
ReplicationState replica = replicatedSessions.next();
String beKey = (String)replica.getProperty(ReplicationState.BEKEY);
if(isRightfulOwner(reconilingInstance, beKey) &&
!isOriginatingInstanceAlive(replica, lbEnabledList)) {
replica.setProperty(ReplicationState.ORIGINATING_INSTANCE_NAME,
reconilingInstance);
result.add(replica);
++reconciledFromReplica;
}
}
send(result,
reconcileRequest.getAppId(), reconcileRequest.getMode(),
responseCommand,
reconcileRequest.getInstanceName());
} else {
// TODO :: handle non clb case.
}
return migratedActiveSessionIds;
}
// this method is executed by all other instances, in order to reconcile the
// replica cache of the instance who issued the reconcileRequest.
public static void processReplicaCacheReconciliationRequest(ReplicationState reconcileRequest,
Map activeCache, String responseCommand, boolean compress) {
Set<ReplicationState> result = new HashSet<ReplicationState>();
if (replicationUtil.isInstanceLoadBalancedByCLB()) {
String reconilingInstance = reconcileRequest.getInstanceName();
Collection<ReplicableEntity> sessions = activeCache.values();
for (ReplicableEntity session : sessions) {
String beKey = session.getBeKey();
if (!session.isForegroundLocked() && // don't replicate the foreground locked sessions. The locked sessions will anyway be replicated duing UOW.saveAndUnlock();
isReplicaPartner(reconilingInstance, beKey)) {
ReplicationState state = ReplicationState.createQueryResponseFrom(
session, reconcileRequest.getAppId(), reconcileRequest.getMode(),
responseCommand, // TODO :: revisit this arg, should it be LOAD_SAS_COMMAND or something?
ReplicationUtil.getInstanceName(),
compress, true);
result.add(state);
}
}
}
send(result, reconcileRequest.getAppId(),
reconcileRequest.getMode(), responseCommand, reconcileRequest.getInstanceName());
}
public static void processPostActiveCacheReconciliationRequest(ReplicationState reconcileRequest,
SessionStoreInterface storeInterface,
Set<String> migratedActiveSessionIds,
boolean saveMigratedSessionToReplicCache,
String responseCommand) {
/**
* The following two steps should be only for in-mememory store.
* Also, this step should be performed after the reconciling instance has
* cleared the 'suspect' flag.
*/
String reconcilingInstance = reconcileRequest.getInstanceName();
int count = 0;
if (migratedActiveSessionIds != null) {
for (String id : migratedActiveSessionIds) {
ReplicableEntity session = storeInterface.findSessionAndPassivate(id);
if (session != null && saveMigratedSessionToReplicCache) {
ReplicationState state = ReplicationState.createQueryResponseFrom(
session, reconcileRequest.getAppId(), reconcileRequest.getCommand(),
responseCommand, // TODO :: revisit this arg - should it be LOAD_SAS_COMMAND or something?
reconcilingInstance, // origin is deliberately set to reconcilingInstance, so that we can copy this active session to our own replica.
false, // TODO :: revisit this param.
true);
storeInterface.putInReplicaCache(state);
++count;
}
}
}
int purgedStaleReplicas = removeStaleReplicas(reconcilingInstance, storeInterface);
send(new HashSet(),
reconcileRequest.getAppId(), reconcileRequest.getMode(),
responseCommand,
reconcileRequest.getInstanceName());
}
public static Set sendSynchronousQuery(
String command, String mode, String appId,
AtomicReference<CountDownLatch> signalReference, long waitTime,
Map<String, ReplicationState> remoteResponses) {
remoteResponses.clear();
ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
List<String> instances = healthChecker.getLbEnabledList();
CountDownLatch signal = new CountDownLatch(instances.size()-1);
signalReference.set(signal);
for(String destination : instances) {
if(!ReplicationUtil.getInstanceName().equalsIgnoreCase(destination)) {
send(new HashSet(), appId, mode, command, destination);
}
}
try {
// Wait till all the bulk road responses are received. The remote
// responses received will be available in the remoteResponses map.
signal.await(waitTime, TimeUnit.SECONDS);
} catch (Exception ex) {
// TODO :: handle exception
}
// process the remote responses
Set reconcilableSessions = new HashSet();
for (ReplicationState state : remoteResponses.values()) {
mergeQueryResponses(state, reconcilableSessions);
}
remoteResponses.clear();
return reconcilableSessions;
}
// send collection of objects via jxtasocketchannel.
public static void send(Collection object, String appId, String mode,
String command, String instanceName) {
byte[] byteArray = null;
try {
byteArray = ReplicationUtil.getByteArray((Serializable)object);
} catch (Exception ex) {
_logger.log(Level.WARNING, "Unable to serialize " + object +
", error = " + ex.getMessage());
}
//need a unique pseudo-id for this query
String id = appId + System.currentTimeMillis();
ReplicationState state = new ReplicationState(mode,
id, appId, 0L, 0L, 0L, null, null, ReplicationUtil.getInstanceName(),
command, byteArray, null, null);
if (object == null || object.isEmpty()) {
state.setNack(true);
}
JxtaSocketChannel channel = JxtaSocketChannel.getInstance();
channel.send(state, instanceName);
}
public static void mergeQueryResponses(ReplicationState queryResponse,
Set targetSet) {
Set values = (Set) getObject(queryResponse.getState());
Iterator iter = values.iterator();
while(iter.hasNext()) {
Object next = iter.next();
targetSet.add(next);
iter.remove();
}
}
/**
* @param instance Proposed replica partner.
* @param beKey beKey
* @return true if the beKey is owned by this instance AND the failoverInstance
* for the beKey is replicaPartner. Return false otherwise.
*/
public static boolean isReplicaPartner(String instance, String beKey) {
if (replicationUtil.isInstanceLoadBalancedByCLB()) {
if (beKey != null && instance.equalsIgnoreCase(
replicationUtil.getFailoverServerInstanceForBeKey(beKey)) &&
ReplicationUtil.getInstanceName().equalsIgnoreCase(
replicationUtil.getActualServerInstanceForBeKey(beKey))) {
return true;
} else {
return false;
}
} else {
// TODO :: handle non clb case.
return true;
}
}
// Return true if the stale replica can be removed.
// This method should be called only after ensuring that the reconcilingInstance
// has activated the sesson in its active cache.
public static boolean canRemoveReplica(ReplicationState state,
String reconcilingInstance,
List lbEnabledList) {
if (replicationUtil.isInstanceLoadBalancedByCLB()) {
String origin = (String) state.getProperty(
ReplicationState.ORIGINATING_INSTANCE_NAME);
String beKey = (String) state.getProperty(
ReplicationState.BEKEY);
if (isRightfulOwner(reconcilingInstance, beKey) &&
!reconcilingInstance.equalsIgnoreCase(origin) &&
isOriginatingInstanceAlive(state, lbEnabledList)) {
return true;
} else {
// TODO :: if the origin is not alive, then ideally we should
// TODO :: transfer those sessions to reconcilingInstance's active cache.
return false;
}
} else {
ReplicationHealthChecker healthChecker =
ReplicationHealthChecker.getInstance();
String replicatedFromInstanceName
= healthChecker.getReshapeReplicateFromInstanceName();
if(replicatedFromInstanceName != null &&
replicatedFromInstanceName.equalsIgnoreCase(reconcilingInstance)) {
return false;
} else {
return true;
}
}
}
public static boolean isRightfulOwner(String instance, String beKey) {
if (replicationUtil.isInstanceLoadBalancedByCLB()) {
if (beKey != null && instance.equalsIgnoreCase(
replicationUtil.getActualServerInstanceForBeKey(beKey))) {
return true;
} else {
return false;
}
} else {
// TODO :: handle non clb case.
return true;
}
}
public static List getLbEnabledList() {
ReplicationHealthChecker healthChecker =
ReplicationHealthChecker.getInstance();
return healthChecker.getLbEnabledList();
}
public static boolean isOriginatingInstanceAlive(ReplicationState state,
List lbEnabledList) {
String origin = (String) state.getProperty(
ReplicationState.ORIGINATING_INSTANCE_NAME);
if(lbEnabledList.contains(origin)) {
return true;
} else {
return false;
}
}
public static boolean canUseSuspectSession(ReplicableEntity session,
Map<String, ExpatListElement> expatMap,
ReentrantReadWriteLock expatLock
) {
if (session != null && expatMap != null && expatLock != null) {
ReentrantReadWriteLock.ReadLock readLock = expatLock.readLock();
if (readLock.tryLock()) {
try {
ExpatListElement expat = expatMap.get(session.getId());
if (expat != null && !expat.isFromActive() &&
session.getVersion() >= expat.getVersion()) {
session.setSuspect(false);
return true;
}
} finally {
readLock.unlock();
}
}
}
return false;
}
}