org.jboss.modcluster.ha.HAModClusterService Maven / Gradle / Ivy
The newest version!
/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.modcluster.ha;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.jboss.beans.metadata.api.annotations.Inject;
import org.jboss.beans.metadata.api.model.FromContext;
import org.jboss.ha.framework.interfaces.CachableMarshalledValue;
import org.jboss.ha.framework.interfaces.ClusterNode;
import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
import org.jboss.ha.framework.interfaces.HAPartition;
import org.jboss.ha.framework.interfaces.HASingletonElectionPolicy;
import org.jboss.ha.framework.server.EventFactory;
import org.jboss.ha.framework.server.HAServiceEvent;
import org.jboss.ha.framework.server.HAServiceEventFactory;
import org.jboss.ha.framework.server.HAServiceRpcHandler;
import org.jboss.ha.framework.server.HASingletonImpl;
import org.jboss.ha.framework.server.SimpleCachableMarshalledValue;
import org.jboss.modcluster.container.ContainerEventHandler;
import org.jboss.modcluster.container.Context;
import org.jboss.modcluster.container.Connector;
import org.jboss.modcluster.container.Engine;
import org.jboss.modcluster.container.Host;
import org.jboss.modcluster.ModClusterService;
import org.jboss.modcluster.container.Server;
import org.jboss.modcluster.Strings;
import org.jboss.modcluster.Utils;
import org.jboss.modcluster.advertise.AdvertiseListenerFactory;
import org.jboss.modcluster.advertise.impl.AdvertiseListenerFactoryImpl;
import org.jboss.modcluster.config.BalancerConfiguration;
import org.jboss.modcluster.config.MCMPHandlerConfiguration;
import org.jboss.modcluster.config.NodeConfiguration;
import org.jboss.modcluster.config.ha.HAConfiguration;
import org.jboss.modcluster.config.ha.impl.HAModClusterConfig;
import org.jboss.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler;
import org.jboss.modcluster.ha.rpc.DefaultRpcResponse;
import org.jboss.modcluster.ha.rpc.MCMPServerDiscoveryEvent;
import org.jboss.modcluster.ha.rpc.ModClusterServiceRpcHandler;
import org.jboss.modcluster.ha.rpc.ModClusterServiceStatus;
import org.jboss.modcluster.ha.rpc.PeerMCMPDiscoveryStatus;
import org.jboss.modcluster.ha.rpc.ResetRequestSourceRpcHandler;
import org.jboss.modcluster.ha.rpc.RpcResponse;
import org.jboss.modcluster.ha.rpc.RpcResponseFilter;
import org.jboss.modcluster.load.LoadBalanceFactorProvider;
import org.jboss.modcluster.load.LoadBalanceFactorProviderFactory;
import org.jboss.modcluster.load.SimpleLoadBalanceFactorProviderFactory;
import org.jboss.modcluster.mcmp.ContextFilter;
import org.jboss.modcluster.mcmp.MCMPConnectionListener;
import org.jboss.modcluster.mcmp.MCMPHandler;
import org.jboss.modcluster.mcmp.MCMPRequest;
import org.jboss.modcluster.mcmp.MCMPRequestFactory;
import org.jboss.modcluster.mcmp.MCMPResponseParser;
import org.jboss.modcluster.mcmp.MCMPServer;
import org.jboss.modcluster.mcmp.MCMPServerState;
import org.jboss.modcluster.mcmp.ResetRequestSource;
import org.jboss.modcluster.mcmp.ResetRequestSource.VirtualHost;
import org.jboss.modcluster.mcmp.impl.DefaultMCMPHandler;
import org.jboss.modcluster.mcmp.impl.DefaultMCMPRequestFactory;
import org.jboss.modcluster.mcmp.impl.DefaultMCMPResponseParser;
/**
* @author Paul Ferraro
*/
public class HAModClusterService extends HASingletonImpl implements HAModClusterServiceMBean,
ContainerEventHandler, LoadBalanceFactorProvider, MCMPConnectionListener, ContextFilter {
static final Object[] NULL_ARGS = new Object[0];
static final Class>[] NULL_TYPES = new Class[0];
static final Class>[] STRING_TYPES = new Class[] { String.class };
static final Class>[] STOP_TYPES = new Class[] { String.class, Long.TYPE, TimeUnit.class };
static final Class>[] CLUSTER_STATUS_COMPLETE_TYPES = new Class[] { Map.class };
static final Class>[] GET_CLUSTER_COORDINATOR_STATE_TYPES = new Class[] { Set.class };
// HAModClusterServiceMBean and ContainerEventHandler delegate
final ClusteredModClusterService service;
private final HAServiceRpcHandler rpcHandler;
final ModClusterServiceRpcHandler>, MCMPServerState, List>> rpcStub = new RpcStub();
final MCMPRequestFactory requestFactory;
private final MCMPResponseParser responseParser;
final MCMPHandler localHandler;
final ClusteredMCMPHandler clusteredHandler;
final ResetRequestSource resetRequestSource;
final Map proxyChangeDigest = new ConcurrentHashMap();
final ModClusterServiceDRMEntry drmEntry;
final String loadBalancingGroup;
private final boolean masterPerLoadBalancingGroup;
private final AtomicReference> replicantView = new AtomicReference>(
Collections. emptySet());
volatile int processStatusFrequency = 1;
volatile int latestLoad;
volatile int statusCount = 0;
@Deprecated
public HAModClusterService(HAPartition partition, HAModClusterConfig config,
LoadBalanceFactorProvider loadBalanceFactorProvider) {
this(config, loadBalanceFactorProvider, partition);
this.deprecatedConstructor(new Class>[] { HAPartition.class, HAModClusterConfig.class,
LoadBalanceFactorProvider.class }, new Class>[] { HAModClusterConfig.class, LoadBalanceFactorProvider.class,
HAPartition.class });
}
@Deprecated
public HAModClusterService(HAPartition partition, HAModClusterConfig config,
LoadBalanceFactorProvider loadBalanceFactorProvider, HASingletonElectionPolicy electionPolicy) {
this(config, loadBalanceFactorProvider, partition, electionPolicy);
this.deprecatedConstructor(new Class>[] { HAPartition.class, HAModClusterConfig.class,
LoadBalanceFactorProvider.class, HASingletonElectionPolicy.class }, new Class>[] { HAModClusterConfig.class,
LoadBalanceFactorProvider.class, HAPartition.class, HASingletonElectionPolicy.class });
}
private void deprecatedConstructor(Class>[] oldConstructorArgs, Class>[] newConstructorArgs) {
try {
Constructor oldConstructor = HAModClusterService.class.getConstructor(oldConstructorArgs);
Constructor newConstructor = HAModClusterService.class.getConstructor(newConstructorArgs);
this.log.warn(Strings.DEPRECATED.getString(oldConstructor, newConstructor));
} catch (NoSuchMethodException e) {
// Oh well...
}
}
public HAModClusterService(HAModClusterConfig config, LoadBalanceFactorProvider loadBalanceFactorProvider,
HAPartition partition) {
this(config, loadBalanceFactorProvider, partition, null);
}
public HAModClusterService(HAModClusterConfig config, LoadBalanceFactorProvider loadBalanceFactorProvider,
HAPartition partition, HASingletonElectionPolicy electionPolicy) {
super(new HAServiceEventFactory());
this.setHAPartition(partition);
this.setElectionPolicy(electionPolicy);
this.rpcHandler = new RpcHandler();
this.requestFactory = new DefaultMCMPRequestFactory();
this.responseParser = new DefaultMCMPResponseParser();
this.resetRequestSource = new ClusteredResetRequestSource(config, config, this.requestFactory, this, this);
this.localHandler = new DefaultMCMPHandler(config, this.resetRequestSource, this.requestFactory, this.responseParser);
this.clusteredHandler = new ClusteredMCMPHandlerImpl(this.localHandler, this, this);
this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), null);
this.service = new ClusteredModClusterService(config, config, config, new SimpleLoadBalanceFactorProviderFactory(
loadBalanceFactorProvider), this.requestFactory, this.responseParser, this.resetRequestSource,
this.clusteredHandler, new AdvertiseListenerFactoryImpl());
this.loadBalancingGroup = config.getLoadBalancingGroup();
this.masterPerLoadBalancingGroup = config.isMasterPerLoadBalancingGroup();
}
protected HAModClusterService(EventFactory eventFactory, HAConfiguration haConfig,
NodeConfiguration nodeConfig, BalancerConfiguration balancerConfig, MCMPHandlerConfiguration mcmpConfig,
LoadBalanceFactorProviderFactory loadBalanceFactorProviderFactory, HAPartition partition,
HASingletonElectionPolicy electionPolicy, MCMPRequestFactory requestFactory, MCMPResponseParser responseParser,
ResetRequestSource resetRequestSource, MCMPHandler localHandler, ClusteredMCMPHandler clusteredHandler,
AdvertiseListenerFactory advertiseListenerFactory) {
super(eventFactory);
this.setHAPartition(partition);
this.setElectionPolicy(electionPolicy);
this.rpcHandler = new RpcHandler();
this.requestFactory = requestFactory;
this.responseParser = responseParser;
this.resetRequestSource = resetRequestSource;
this.localHandler = localHandler;
this.clusteredHandler = clusteredHandler;
this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), null);
this.service = new ClusteredModClusterService(nodeConfig, balancerConfig, mcmpConfig, loadBalanceFactorProviderFactory,
requestFactory, responseParser, resetRequestSource, clusteredHandler, advertiseListenerFactory);
this.loadBalancingGroup = nodeConfig.getLoadBalancingGroup();
this.masterPerLoadBalancingGroup = haConfig.isMasterPerLoadBalancingGroup();
}
/**
* {@inheritDoc}
*
* @see org.jboss.modcluster.ha.HAModClusterServiceMBean#getProcessStatusFrequency()
*/
public int getProcessStatusFrequency() {
return this.processStatusFrequency;
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ha.HAModClusterServiceMBean#setProcessStatusFrequency(int)
*/
public void setProcessStatusFrequency(int processStatusFrequency) {
this.processStatusFrequency = processStatusFrequency;
}
public boolean disableDomain() {
return this.conjoin(this.rpcStub.disable(this.loadBalancingGroup));
}
public boolean enableDomain() {
return this.conjoin(this.rpcStub.enable(this.loadBalancingGroup));
}
public boolean stopDomain(long timeout, TimeUnit unit) {
return this.conjoin(this.rpcStub.stop(this.loadBalancingGroup, timeout, unit));
}
private boolean conjoin(List> responses) {
boolean success = true;
for (RpcResponse response : responses) {
Boolean result = response.getResult();
success &= ((result == null) || result.booleanValue());
}
return success;
}
/**
* {@inheritDoc}
*
* @see org.jboss.modcluster.mcmp.ContextFilter#getExcludedContexts()
*/
public Map> getExcludedContexts() {
return this.service.getExcludedContexts();
}
/**
* {@inheritDoc}
*
* @see org.jboss.modcluster.mcmp.ContextFilter#isAutoEnableContexts()
*/
public boolean isAutoEnableContexts() {
return this.service.isAutoEnableContexts();
}
/**
* {@inheritDoc}
*
* @see org.jboss.modcluster.mcmp.MCMPConnectionListener#isEstablished()
*/
public boolean isEstablished() {
return this.service.isEstablished();
}
/**
* {@inheritDoc}
*
* @see org.jboss.modcluster.mcmp.MCMPConnectionListener#connectionEstablished(java.net.InetAddress)
*/
public void connectionEstablished(InetAddress localAddress) {
this.service.connectionEstablished(localAddress);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.load.LoadBalanceFactorProvider#getLoadBalanceFactor()
*/
public int getLoadBalanceFactor(Engine engine) {
return this.service.getLoadBalanceFactor(engine);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#add(org.jboss.modcluster.Context)
*/
public void add(Context context) {
this.service.add(context);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#init(org.jboss.modcluster.Server)
*/
public void init(Server server) {
this.service.init(server);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#remove(org.jboss.modcluster.Context)
*/
public void remove(Context context) {
this.service.remove(context);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#shutdown()
*/
public void shutdown() {
this.service.shutdown();
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#start(org.jboss.modcluster.Context)
*/
public void start(Context context) {
this.service.start(context);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#start(org.jboss.modcluster.Server)
*/
public void start(Server server) {
this.service.start(server);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#status(org.jboss.modcluster.Engine)
*/
public void status(Engine engine) {
this.service.status(engine);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#stop(org.jboss.modcluster.Context)
*/
public void stop(Context context) {
this.service.stop(context);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ContainerEventHandler#stop(org.jboss.modcluster.Server)
*/
public void stop(Server server) {
this.service.stop(server);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#addProxy(java.lang.String, int)
*/
public void addProxy(String host, int port) {
this.service.addProxy(host, port);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#disable()
*/
public boolean disable() {
return this.service.disable();
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#disable(java.lang.String, java.lang.String)
*/
public boolean disableContext(String host, String path) {
return this.service.disableContext(host, path);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#ping()
*/
public Map ping() {
return this.service.ping();
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#ping(java.lang.String)
*/
public Map ping(String jvmRoute) {
return this.service.ping(jvmRoute);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#ping(java.lang.String, java.lang.String, int)
*/
public Map ping(String scheme, String hostname, int port) {
return this.service.ping(scheme, hostname, port);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#enable()
*/
public boolean enable() {
return this.service.enable();
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#enable(java.lang.String, java.lang.String)
*/
public boolean enableContext(String host, String path) {
return this.service.enableContext(host, path);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#getProxyConfiguration()
*/
public Map getProxyConfiguration() {
return this.service.getProxyConfiguration();
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#getProxyInfo()
*/
public Map getProxyInfo() {
return this.service.getProxyInfo();
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#refresh()
*/
public void refresh() {
this.service.refresh();
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#removeProxy(java.lang.String, int)
*/
public void removeProxy(String host, int port) {
this.service.removeProxy(host, port);
}
/**
* {@inhericDoc}
*
* @see org.jboss.modcluster.ModClusterServiceMBean#reset()
*/
public void reset() {
this.service.reset();
}
public boolean stop(long timeout, TimeUnit unit) {
return this.service.stop(timeout, unit);
}
public boolean stopContext(String host, String path, long timeout, TimeUnit unit) {
return this.service.stopContext(host, path, timeout, unit);
}
/**
* {@inhericDoc}
*
* @see org.jboss.ha.framework.server.HASingletonImpl#startSingleton()
*/
public void startSingleton() {
this.statusCount = this.processStatusFrequency - 1;
}
/**
* {@inhericDoc}
*
* @see org.jboss.ha.framework.server.HASingletonImpl#partitionTopologyChanged(java.util.List, int, boolean)
*/
protected void partitionTopologyChanged(List> newReplicants, int newViewId, boolean merge) {
@SuppressWarnings("unchecked")
Set replicants = new HashSet(
(List) newReplicants);
Set oldReplicants = this.replicantView.getAndSet(replicants);
super.partitionTopologyChanged(newReplicants, newViewId, merge);
if (this.isMasterNode()) {
// Determine dead members
oldReplicants.removeAll(replicants);
for (CachableMarshalledValue replicant : oldReplicants) {
ModClusterServiceDRMEntry entry = this.extractDRMEntry(replicant);
for (String jvmRoute : entry.getJvmRoutes()) {
MCMPRequest request = this.requestFactory.createPingRequest(jvmRoute);
Map responses = this.localHandler.sendRequest(request);
for (Map.Entry response : responses.entrySet()) {
MCMPServerState proxy = response.getKey();
// If ping fails, send REMOVE_APP * on behalf of crashed member
if ((proxy.getState() == MCMPServerState.State.OK)
&& !this.responseParser.parsePingResponse(response.getValue())) {
this.log.info(Strings.ENGINE_REMOVE_CRASHED.getString(jvmRoute, proxy.getSocketAddress(),
entry.getPeer()));
this.localHandler.sendRequest(this.requestFactory.createRemoveEngineRequest(jvmRoute));
}
}
}
}
}
}
/**
* {@inhericDoc}
*
* @see org.jboss.ha.framework.server.HAServiceImpl#setServiceHAName(java.lang.String)
*/
@Inject(fromContext = FromContext.NAME)
public void setServiceHAName(String haName) {
super.setServiceHAName(haName);
}
/**
* {@inhericDoc}
*
* @see org.jboss.ha.framework.server.HAServiceImpl#getHAServiceKey()
*/
public String getHAServiceKey() {
String name = this.getServiceHAName();
return ((this.loadBalancingGroup != null) && this.masterPerLoadBalancingGroup) ? name + ":" + this.loadBalancingGroup
: name;
}
/**
* {@inhericDoc}
*
* @see org.jboss.ha.framework.server.HASingletonImpl#getRpcHandler()
*/
protected HAServiceRpcHandler getRpcHandler() {
return this.rpcHandler;
}
/**
* {@inhericDoc}
*
* @see org.jboss.ha.framework.server.HAServiceImpl#getReplicant()
*/
protected Serializable getReplicant() {
return new SimpleCachableMarshalledValue(this.drmEntry);
}
/**
* {@inhericDoc}
*
* @see org.jboss.ha.framework.server.HASingletonImpl#getElectionCandidates()
*/
protected List getElectionCandidates() {
return this.findMasterCandidates(this.lookupDRMEntries());
}
List findMasterCandidates(Collection candidates) {
if (candidates == null)
return null;
List narrowed = new ArrayList(candidates.size());
ModClusterServiceDRMEntry champion = null;
for (ModClusterServiceDRMEntry candidate : candidates) {
if (champion == null) {
champion = candidate;
narrowed.add(candidate.getPeer());
} else {
int compFactor = candidate.compareTo(champion);
if (compFactor < 0) {
// New champ
narrowed.clear();
champion = candidate;
narrowed.add(candidate.getPeer());
} else if (compFactor == 0) {
// As good as our champ
narrowed.add(candidate.getPeer());
}
// else candidate didn't make the cut; continue
}
}
return narrowed;
}
List lookupDRMEntries() {
DistributedReplicantManager drm = this.getHAPartition().getDistributedReplicantManager();
@SuppressWarnings("unchecked")
List values = (List) drm.lookupReplicants(this.getHAServiceKey());
if (values == null)
return null;
List entries = new ArrayList(values.size());
for (CachableMarshalledValue value : values) {
entries.add(this.extractDRMEntry(value));
}
return entries;
}
ModClusterServiceDRMEntry lookupLocalDRMEntry() {
DistributedReplicantManager drm = this.getHAPartition().getDistributedReplicantManager();
return this.extractDRMEntry((CachableMarshalledValue) drm.lookupLocalReplicant(this.getHAServiceKey()));
}
void updateLocalDRM(ModClusterServiceDRMEntry entry) {
DistributedReplicantManager drm = this.getHAPartition().getDistributedReplicantManager();
try {
drm.add(this.getHAServiceKey(), this.createReplicant(entry));
} catch (Exception e) {
throw Utils.convertToUnchecked(e);
}
}
private Serializable createReplicant(ModClusterServiceDRMEntry entry) {
return new SimpleCachableMarshalledValue(entry);
}
private ModClusterServiceDRMEntry extractDRMEntry(CachableMarshalledValue replicant) {
if (replicant == null)
return null;
try {
Object entry = replicant.get();
// MODCLUSTER-88: This can happen if service was redeployed, and DRM contains objects from the obsolete classloader
if (!(entry instanceof ModClusterServiceDRMEntry)) {
// Force re-deserialization w/current classloader
replicant.toByteArray();
entry = replicant.get();
}
return (ModClusterServiceDRMEntry) entry;
} catch (Exception e) {
throw Utils.convertToUnchecked(e);
}
}
/**
* Client side stub of ModClusterServiceRpcHandler interface.
*/
class RpcStub
implements
ModClusterServiceRpcHandler>, MCMPServerState, List>> {
public RpcResponse