blob: 1d6dab1753c7ac0232225dd3684b4f76ec5570aa [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.processors.cache;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.binary.BinaryInvalidTypeException;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.configuration.DeploymentMode;
import org.apache.ignite.events.DiscoveryEvent;
import org.apache.ignite.events.Event;
import org.apache.ignite.internal.managers.deployment.GridDeployment;
import org.apache.ignite.internal.managers.deployment.GridDeploymentInfoBean;
import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheAdapter;
import org.apache.ignite.internal.util.lang.GridPeerDeployAware;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.CA;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.LT;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteBiTuple;
import org.apache.ignite.lang.IgniteUuid;
import org.jetbrains.annotations.Nullable;
import org.jsr166.ConcurrentLinkedHashMap;
import static org.apache.ignite.configuration.DeploymentMode.CONTINUOUS;
import static org.apache.ignite.configuration.DeploymentMode.ISOLATED;
import static org.apache.ignite.configuration.DeploymentMode.PRIVATE;
import static org.apache.ignite.events.EventType.EVT_NODE_FAILED;
import static org.apache.ignite.events.EventType.EVT_NODE_LEFT;
/**
* Deployment manager for cache.
*/
public class GridCacheDeploymentManager<K, V> extends GridCacheSharedManagerAdapter<K, V> {
/** Cache class loader */
private volatile ClassLoader globalLdr;
/** Undeploys. */
private final Map<String, List<CA>> undeploys = new HashMap<>();
/** Per-thread deployment context. */
private ConcurrentMap<IgniteUuid, CachedDeploymentInfo<K, V>> deps = new ConcurrentHashMap<>();
/** Discovery listener. */
private GridLocalEventListener discoLsnr;
/** Local deployment. */
private final AtomicReference<GridDeployment> locDep = new AtomicReference<>();
/** */
private final ThreadLocal<Boolean> ignoreOwnership = new ThreadLocal<Boolean>() {
@Override protected Boolean initialValue() {
return false;
}
};
/** */
private boolean depEnabled;
/** Class loader id for local thread. */
private final ThreadLocal<IgniteUuid> localLdrId = new ThreadLocal<>();
/** {@inheritDoc} */
@Override public void start0() throws IgniteCheckedException {
globalLdr = new CacheClassLoader(cctx.gridConfig().getClassLoader());
depEnabled = cctx.gridDeploy().enabled();
if (depEnabled) {
discoLsnr = new GridLocalEventListener() {
@Override public void onEvent(Event evt) {
assert evt.type() == EVT_NODE_FAILED || evt.type() == EVT_NODE_LEFT : "Unexpected event: " + evt;
UUID id = ((DiscoveryEvent)evt).eventNode().id();
if (log.isDebugEnabled())
log.debug("Processing node departure: " + id);
for (Map.Entry<IgniteUuid, CachedDeploymentInfo<K, V>> entry : deps.entrySet()) {
CachedDeploymentInfo<K, V> d = entry.getValue();
if (log.isDebugEnabled())
log.debug("Examining cached info: " + d);
if (d.senderId().equals(id) || d.removeParticipant(id)) {
deps.remove(entry.getKey(), d);
if (log.isDebugEnabled())
log.debug("Removed cached info [d=" + d + ", deps=" + deps + ']');
}
}
}
};
cctx.gridEvents().addLocalEventListener(discoLsnr, EVT_NODE_LEFT, EVT_NODE_FAILED);
}
}
/** {@inheritDoc} */
@Override protected void stop0(boolean cancel) {
if (discoLsnr != null)
cctx.gridEvents().removeLocalEventListener(discoLsnr);
}
/**
* @return Local-only class loader.
*/
public ClassLoader localLoader() {
GridDeployment dep = locDep.get();
return dep == null ? U.gridClassLoader() : dep.classLoader();
}
/**
* Gets distributed class loader. Note that
* {@link #p2pContext(UUID, IgniteUuid, String, DeploymentMode, Map)} must be
* called from the same thread prior to using this class loader, or the
* loading may happen for the wrong node or context.
*
* @return Cache class loader.
*/
public ClassLoader globalLoader() {
return globalLdr;
}
/**
* Callback on method enter.
*/
public void onEnter() {
// No-op.
}
/**
* @param ignore {@code True} to ignore.
*/
public boolean ignoreOwnership(boolean ignore) {
boolean old = ignoreOwnership.get();
ignoreOwnership.set(ignore);
return old;
}
/**
* Undeploy all queued up closures.
*
* @param ctx Cache context.
*/
public void unwind(GridCacheContext ctx) {
List<CA> q;
synchronized (undeploys) {
q = undeploys.remove(ctx.name());
}
if (q == null)
return;
int cnt = 0;
for (CA c : q) {
c.apply();
cnt++;
}
if (log.isDebugEnabled())
log.debug("Unwound undeploys count: " + cnt);
}
/**
* Undeploys given class loader.
*
* @param ldr Class loader to undeploy.
* @param ctx Grid cache context.
*/
public void onUndeploy(final ClassLoader ldr, final GridCacheContext<K, V> ctx) {
assert ldr != null;
if (log.isDebugEnabled())
log.debug("Received onUndeploy() request [ldr=" + ldr + ", cctx=" + cctx + ']');
synchronized (undeploys) {
List<CA> queue = undeploys.get(ctx.name());
if (queue == null)
undeploys.put(ctx.name(), queue = new ArrayList<>());
queue.add(new CA() {
@Override public void apply() {
onUndeploy0(ldr, ctx);
}
});
}
}
/**
* @param ldr Loader.
* @param cacheCtx Cache context.
*/
private void onUndeploy0(final ClassLoader ldr, final GridCacheContext<K, V> cacheCtx) {
GridCacheAdapter<K, V> cache = cacheCtx.cache();
Collection<KeyCacheObject> keys = new ArrayList<>();
addEntries(ldr, keys, cache);
if (cache.isNear())
addEntries(ldr, keys, (((GridNearCacheAdapter)cache).dht()));
if (log.isDebugEnabled())
log.debug("Finished searching keys for undeploy [keysCnt=" + keys.size() + ']');
cache.clearLocally(keys, true);
if (cacheCtx.isNear())
cacheCtx.near().dht().clearLocally(keys, true);
// Examine swap for entries to undeploy.
int swapUndeployCnt = cacheCtx.offheap().onUndeploy(ldr);
if (cacheCtx.userCache() && (!keys.isEmpty() || swapUndeployCnt != 0)) {
U.quietAndWarn(log, "");
U.quietAndWarn(
log,
"Cleared all cache entries for undeployed class loader [cacheName=" + cacheCtx.name() +
", undeployCnt=" + keys.size() + ", swapUndeployCnt=" + swapUndeployCnt +
", clsLdr=" + ldr.getClass().getName() + ']');
U.quietAndWarn(
log,
" ^-- Cache auto-undeployment happens in SHARED deployment mode " +
"(to turn off, switch to CONTINUOUS mode)");
U.quietAndWarn(log, "");
}
// Avoid class caching issues inside classloader.
globalLdr = new CacheClassLoader();
}
/**
* @param ldr Class loader.
* @param keys Keys.
* @param cache Cache.
*/
private void addEntries(ClassLoader ldr, Collection<KeyCacheObject> keys, GridCacheAdapter cache) {
GridCacheContext cacheCtx = cache.context();
for (GridCacheEntryEx e : (Iterable<GridCacheEntryEx>)cache.entries()) {
boolean undeploy = cacheCtx.isNear() ?
undeploy(ldr, e, cacheCtx.near()) || undeploy(ldr, e, cacheCtx.near().dht()) :
undeploy(ldr, e, cacheCtx.cache());
if (undeploy)
keys.add(e.key());
}
}
/**
* @param ldr Class loader.
* @param e Entry.
* @param cache Cache.
* @return {@code True} if need to undeploy.
*/
private boolean undeploy(ClassLoader ldr, GridCacheEntryEx e, GridCacheAdapter cache) {
KeyCacheObject key = e.key();
GridCacheEntryEx entry = cache.peekEx(key);
if (entry == null)
return false;
Object key0;
Object val0;
try {
CacheObject v = entry.peek();
key0 = key.value(cache.context().cacheObjectContext(), false);
assert key0 != null : "Key cannot be null for cache entry: " + e;
val0 = CU.value(v, cache.context(), false);
}
catch (GridCacheEntryRemovedException ignore) {
return false;
}
catch (BinaryInvalidTypeException ex) {
log.error("An attempt to undeploy cache with binary objects.", ex);
return false;
}
catch (IgniteCheckedException | IgniteException ignore) {
// Peek can throw runtime exception if unmarshalling failed.
return true;
}
ClassLoader keyLdr = U.detectObjectClassLoader(key0);
ClassLoader valLdr = U.detectObjectClassLoader(val0);
boolean res = F.eq(ldr, keyLdr) || F.eq(ldr, valLdr);
if (log.isDebugEnabled())
log.debug(S.toString("Finished examining entry",
"entryCls", e.getClass(), true,
"key", key0, true,
"keyCls", key0.getClass(), true,
"valCls", (val0 != null ? val0.getClass() : "null"), true,
"keyLdr", keyLdr, false,
"valLdr", valLdr, false,
"res", res, false));
return res;
}
/**
* @param sndId Sender node ID.
* @param ldrId Loader ID.
* @param userVer User version.
* @param mode Deployment mode.
* @param participants Node participants.
*/
public void p2pContext(
UUID sndId,
IgniteUuid ldrId,
String userVer,
DeploymentMode mode,
Map<UUID, IgniteUuid> participants
) throws IgnitePeerToPeerClassLoadingException {
localLdrId.set(ldrId);
assert depEnabled;
if (mode == PRIVATE || mode == ISOLATED) {
ClusterNode node = cctx.discovery().node(sndId);
if (node == null) {
if (log.isDebugEnabled())
log.debug("Ignoring p2p context (sender has left) [sndId=" + sndId + ", ldrId=" + ldrId +
", userVer=" + userVer + ", mode=" + mode + ", participants=" + participants + ']');
return;
}
boolean daemon = node.isDaemon();
// Always output in debug.
if (log.isDebugEnabled())
log.debug("Ignoring deployment in PRIVATE or ISOLATED mode [sndId=" + sndId + ", ldrId=" + ldrId +
", userVer=" + userVer + ", mode=" + mode + ", participants=" + participants +
", daemon=" + daemon + ']');
if (!daemon) {
LT.warn(log, "Ignoring deployment in PRIVATE or ISOLATED mode " +
"[sndId=" + sndId + ", ldrId=" + ldrId + ", userVer=" + userVer + ", mode=" + mode +
", participants=" + participants + ", daemon=" + daemon + ']');
}
return;
}
if (mode != cctx.gridConfig().getDeploymentMode()) {
LT.warn(log, "Local and remote deployment mode mismatch (please fix configuration and restart) " +
"[locDepMode=" + cctx.gridConfig().getDeploymentMode() + ", rmtDepMode=" + mode + ", rmtNodeId=" +
sndId + ']');
return;
}
if (log.isDebugEnabled())
log.debug("Setting p2p context [sndId=" + sndId + ", ldrId=" + ldrId + ", userVer=" + userVer +
", seqNum=" + ldrId.localId() + ", mode=" + mode + ", participants=" + participants +
", locDepOwner=false]");
CachedDeploymentInfo<K, V> depInfo;
while (true) {
depInfo = deps.get(ldrId);
if (depInfo == null) {
if (!sndId.equals(ldrId.globalId()) && participants == null) {
throw new IgnitePeerToPeerClassLoadingException("Failed to load class using class loader with " +
"given id (loader id doesn't match sender id and there are no more participants) " +
"[clsLdrId=" + ldrId + ", senderId=" + sndId + ", participants=null]");
}
depInfo = new CachedDeploymentInfo<>(sndId, ldrId, userVer, mode, participants);
CachedDeploymentInfo<K, V> old = deps.putIfAbsent(ldrId, depInfo);
if (old != null)
depInfo = old;
else
break;
}
if (participants != null) {
if (!depInfo.addParticipants(participants, cctx)) {
deps.remove(ldrId, depInfo);
continue;
}
}
break;
}
// Sender has left.
if (cctx.discovery().node(sndId) == null)
deps.remove(ldrId, depInfo);
if (participants != null) {
for (UUID id : participants.keySet()) {
if (cctx.discovery().node(id) == null) {
if (depInfo.removeParticipant(id))
deps.remove(ldrId, depInfo);
}
}
}
}
/**
* Gets a local class loader id.
*
* @return Class loader uuid.
*/
public IgniteUuid locLoaderId() {
return localLdrId.get();
}
/**
* Register local classes.
*
* @param objs Objects to register.
* @throws IgniteCheckedException If registration failed.
*/
public void registerClasses(Object... objs) throws IgniteCheckedException {
registerClasses(F.asList(objs));
}
/**
* Register local classes.
*
* @param objs Objects to register.
* @throws IgniteCheckedException If registration failed.
*/
public void registerClasses(Iterable<?> objs) throws IgniteCheckedException {
if (objs != null)
for (Object o : objs)
registerClass(o);
}
/**
* @param obj Object whose class to register.
* @throws IgniteCheckedException If failed.
*/
public void registerClass(Object obj) throws IgniteCheckedException {
if (obj == null)
return;
if (obj instanceof GridPeerDeployAware) {
GridPeerDeployAware p = (GridPeerDeployAware)obj;
registerClass(p.deployClass(), p.classLoader());
}
else
registerClass(obj instanceof Class ? (Class)obj : obj.getClass());
}
/**
* @param cls Class to register.
* @throws IgniteCheckedException If failed.
*/
public void registerClass(Class<?> cls) throws IgniteCheckedException {
if (cls == null)
return;
registerClass(cls, U.detectClassLoader(cls));
}
/**
* @param cls Class to register.
* @param ldr Class loader.
* @throws IgniteCheckedException If registration failed.
*/
public void registerClass(Class<?> cls, ClassLoader ldr) throws IgniteCheckedException {
assert cctx.deploymentEnabled();
if (cls == null || GridCacheInternal.class.isAssignableFrom(cls))
return;
if (ldr == null)
ldr = U.detectClassLoader(cls);
// Don't register remote class loaders.
if (U.p2pLoader(ldr))
return;
GridDeployment dep = locDep.get();
if (dep == null || (!ldr.equals(dep.classLoader()) && !U.hasParent(ldr, dep.classLoader()))) {
while (true) {
dep = locDep.get();
// Don't register remote class loaders.
if (dep != null && !dep.local())
return;
if (dep != null) {
ClassLoader curLdr = dep.classLoader();
if (curLdr.equals(ldr))
break;
// If current deployment is either system loader or GG loader,
// then we don't check it, as new loader is most likely wider.
if (!curLdr.equals(U.gridClassLoader()) && dep.deployedClass(cls.getName()).get1() != null)
// Local deployment can load this class already, so no reason
// to look for another class loader.
break;
}
GridDeployment newDep = cctx.gridDeploy().deploy(cls, ldr);
if (newDep != null) {
if (dep != null) {
// Check new deployment.
if (newDep.deployedClass(dep.sampleClassName()).get1() != null) {
if (locDep.compareAndSet(dep, newDep))
break; // While loop.
}
else
throw new IgniteCheckedException("Encountered incompatible class loaders for cache " +
"[class1=" + cls.getName() + ", class2=" + dep.sampleClassName() + ']');
}
else if (locDep.compareAndSet(null, newDep))
break; // While loop.
}
else
throw new IgniteCheckedException("Failed to deploy class for local deployment [clsName=" + cls.getName() +
", ldr=" + ldr + ']');
}
}
}
/**
* Prepares deployable object.
*
* @param deployable Deployable object.
*/
public void prepare(GridCacheDeployable deployable) throws IgnitePeerToPeerClassLoadingException {
assert depEnabled;
// Only set deployment info if it was not set automatically.
if (deployable.deployInfo() == null) {
GridDeploymentInfoBean dep = globalDeploymentInfo();
if (dep == null) {
GridDeployment locDep0 = locDep.get();
if (locDep0 != null) {
// Will copy sequence number to bean.
dep = new GridDeploymentInfoBean(locDep0);
checkDeploymentIsCorrect(dep, deployable, false);
}
}
else
checkDeploymentIsCorrect(dep, deployable, true);
if (dep != null)
deployable.prepare(dep);
if (log.isDebugEnabled())
log.debug("Prepared grid cache deployable [dep=" + dep + ", deployable=" + deployable + ']');
}
}
/**
* Checks if given deployment is correct to prepare a message.
*
* @param deployment Deployment.
* @param deployable Deployable message.
* @param failIfNotCorrect Flag determining whether to throw exception or just warn.
* @throws IgnitePeerToPeerClassLoadingException If deployment is incorrect.
*/
private void checkDeploymentIsCorrect(GridDeploymentInfoBean deployment, GridCacheDeployable deployable,
boolean failIfNotCorrect)
throws IgnitePeerToPeerClassLoadingException {
if (deployment.participants() == null
&& !cctx.localNode().id().equals(deployment.classLoaderId().globalId())) {
String msg = "Should not use deployment to prepare deployable, because local node id does not correspond " +
"with class loader id, and there are no more participants [locNodeId=" + cctx.localNode().id() +
", deployment=" + deployment + ", deployable=" + deployable + ", locDep=" + locDep.get() + "]";
if (failIfNotCorrect)
throw new IgnitePeerToPeerClassLoadingException(msg);
log.warning(msg);
}
}
/**
* @return First global deployment.
*/
@Nullable public GridDeploymentInfoBean globalDeploymentInfo() {
assert depEnabled;
// Do not return info if mode is CONTINUOUS.
// In this case deployment info will be set by GridCacheMessage.prepareObject().
if (cctx.gridConfig().getDeploymentMode() == CONTINUOUS)
return null;
IgniteUuid localLdrId0 = localLdrId.get();
if (localLdrId0 != null) {
GridDeploymentInfoBean deploymentInfoBean = getDepBean(deps.get(localLdrId.get()));
if (deploymentInfoBean != null)
return deploymentInfoBean;
}
for (CachedDeploymentInfo<K, V> d : deps.values()) {
GridDeploymentInfoBean deploymentInfoBean = getDepBean(d);
if (deploymentInfoBean != null)
return deploymentInfoBean;
}
return null;
}
/** */
@Nullable private GridDeploymentInfoBean getDepBean(CachedDeploymentInfo<K, V> d) {
if (d == null || cctx.discovery().node(d.senderId()) == null)
// Sender has left.
return null;
// Participants map.
Map<UUID, IgniteUuid> participants = d.participants();
if (participants != null) {
for (UUID id : participants.keySet()) {
if (cctx.discovery().node(id) != null) {
// At least 1 participant is still in the grid.
return new GridDeploymentInfoBean(
d.loaderId(),
d.userVersion(),
d.mode(),
participants
);
}
}
}
return null;
}
/** {@inheritDoc} */
@Override public void printMemoryStats() {
X.println(">>> ");
X.println(">>> Cache deployment manager memory stats [igniteInstanceName=" + cctx.igniteInstanceName() + ']');
X.println(">>> Undeploys: " + undeploys.size());
X.println(">>> Cached deployments: " + deps.size());
}
/**
* @param ldr Class loader to get ID for.
* @return ID for given class loader or {@code null} if given loader is not
* grid deployment class loader.
*/
@Nullable public IgniteUuid getClassLoaderId(@Nullable ClassLoader ldr) {
if (ldr == null)
return null;
return cctx.gridDeploy().getClassLoaderId(ldr);
}
/**
* @param ldrId Class loader ID.
* @return Class loader ID or {@code null} if loader not found.
*/
@Nullable public ClassLoader getClassLoader(IgniteUuid ldrId) {
assert ldrId != null;
GridDeployment dep = cctx.gridDeploy().getDeployment(ldrId);
return dep != null ? dep.classLoader() : null;
}
/**
* @return {@code True} if context class loader is global.
*/
public boolean isGlobalLoader() {
return cctx.gridDeploy().isGlobalLoader(Thread.currentThread().getContextClassLoader());
}
/**
* Cache class loader.
*/
private class CacheClassLoader extends ClassLoader implements CacheClassLoaderMarker {
/** */
private final String[] p2pExclude;
/**
* Sets context class loader as parent.
*/
private CacheClassLoader() {
this(U.detectClassLoader(GridCacheDeploymentManager.class));
}
/**
* Sets context class loader.
* If user's class loader is null then will be used default class loader.
*
* @param classLdr User's class loader.
*/
private CacheClassLoader(ClassLoader classLdr) {
super(classLdr != null ? classLdr : U.detectClassLoader(GridCacheDeploymentManager.class));
p2pExclude = cctx.gridConfig().getPeerClassLoadingLocalClassPathExclude();
}
/** {@inheritDoc} */
@Override public Class<?> loadClass(String name) throws ClassNotFoundException {
// Always delegate to deployment manager.
return findClass(name);
}
/** {@inheritDoc} */
@Override protected Class<?> findClass(String name) throws ClassNotFoundException {
// Try local deployment first.
if (!isLocallyExcluded(name)) {
GridDeployment d = cctx.gridDeploy().getLocalDeployment(name);
if (d != null) {
Class cls = d.deployedClass(name).get1();
if (cls != null)
return cls;
}
}
IgniteUuid curLdrId = localLdrId.get();
Throwable err = null;
if (curLdrId != null) {
CachedDeploymentInfo<K, V> t = deps.get(curLdrId);
if (t != null) {
IgniteBiTuple<Class<?>, Throwable> cls = tryToloadClassFromCacheDep(name, t);
if (cls != null) {
if (cls.get1() != null)
return cls.get1();
else
err = cls.get2();
}
}
}
for (CachedDeploymentInfo<K, V> t : deps.values()) {
IgniteBiTuple<Class<?>, Throwable> cls = tryToloadClassFromCacheDep(name, t);
if (cls != null) {
if (cls.get1() != null)
return cls.get1();
else if (err == null)
err = cls.get2();
}
}
try {
return getParent().loadClass(name);
}
catch (ClassNotFoundException e) {
if (err instanceof LinkageError)
U.warn(log, "Failed to load class [name=" + name + ']', err);
throw e;
}
}
/**
* @param name Name of resource.
* @param deploymentInfo Grid cached deployment info.
* @return Class if can to load resource with the <code>name</code> or {@code null} otherwise.
*/
@Nullable private IgniteBiTuple<Class<?>, Throwable> tryToloadClassFromCacheDep(
String name,
CachedDeploymentInfo<K, V> deploymentInfo
) {
UUID sndId = deploymentInfo.senderId();
IgniteUuid ldrId = deploymentInfo.loaderId();
String userVer = deploymentInfo.userVersion();
DeploymentMode mode = deploymentInfo.mode();
Map<UUID, IgniteUuid> participants = deploymentInfo.participants();
GridDeployment d = cctx.gridDeploy().getGlobalDeployment(
mode,
name,
name,
userVer,
sndId,
ldrId,
participants,
F.<ClusterNode>alwaysTrue());
return d != null ? d.deployedClass(name) : null;
}
/**
* @param name Name of the class.
* @return {@code True} if locally excluded.
*/
private boolean isLocallyExcluded(String name) {
if (p2pExclude != null) {
for (String path : p2pExclude) {
// Remove star (*) at the end.
if (path.endsWith("*"))
path = path.substring(0, path.length() - 1);
if (name.startsWith(path))
return true;
}
}
return false;
}
}
/**
*
*/
private static class CachedDeploymentInfo<K, V> {
/** */
private final UUID sndId;
/** */
private final IgniteUuid ldrId;
/** */
private final String userVer;
/** */
private final DeploymentMode depMode;
/** */
@GridToStringInclude
private Map<UUID, IgniteUuid> participants;
/** Read write lock for adding and removing participants. */
private final ReadWriteLock participantsLock = new ReentrantReadWriteLock();
/**
* @param sndId Sender.
* @param ldrId Loader ID.
* @param userVer User version.
* @param depMode Deployment mode.
* @param participants Participants.
*/
private CachedDeploymentInfo(UUID sndId, IgniteUuid ldrId, String userVer, DeploymentMode depMode,
Map<UUID, IgniteUuid> participants) {
assert sndId.equals(ldrId.globalId()) || participants != null : "[senderId=" + sndId +
", loaderGlobalId=" + ldrId.globalId() + ", participants is null]";
this.sndId = sndId;
this.ldrId = ldrId;
this.userVer = userVer;
this.depMode = depMode;
this.participants = F.isEmpty(participants) ? null : new ConcurrentLinkedHashMap<>(participants);
}
/**
* @param newParticipants Participants to add.
* @param cctx Cache context.
* @return {@code True} if cached info is valid.
*/
boolean addParticipants(Map<UUID, IgniteUuid> newParticipants, GridCacheSharedContext<K, V> cctx) {
participantsLock.readLock().lock();
try {
if (participants != null && participants.isEmpty())
return false;
for (Map.Entry<UUID, IgniteUuid> e : newParticipants.entrySet()) {
assert e.getKey().equals(e.getValue().globalId());
// Participant has been left.
if (cctx.discovery().node(e.getKey()) == null)
continue;
if (participants == null)
participants = new ConcurrentLinkedHashMap<>();
if (!participants.containsKey(e.getKey()))
participants.put(e.getKey(), e.getValue());
}
return true;
}
finally {
participantsLock.readLock().unlock();
}
}
/**
* @param leftNodeId Left node ID.
* @return {@code True} if participant has been removed and there are no participants left.
*/
boolean removeParticipant(UUID leftNodeId) {
assert leftNodeId != null;
participantsLock.writeLock().lock();
try {
return participants != null && participants.remove(leftNodeId) != null && participants.isEmpty();
}
finally {
participantsLock.writeLock().unlock();
}
}
/**
* @return Participants.
*/
Map<UUID, IgniteUuid> participants() {
return participants;
}
/**
* @return Sender ID.
*/
UUID senderId() {
return sndId;
}
/**
* @return Class loader ID.
*/
IgniteUuid loaderId() {
return ldrId;
}
/**
* @return User version.
*/
String userVersion() {
return userVer;
}
/**
* @return Deployment mode.
*/
public DeploymentMode mode() {
return depMode;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(CachedDeploymentInfo.class, this);
}
}
}