ignite-3056: Service implementation class is required even if it's not expected to be deployed on current node (fixed)
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/bab0533d Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/bab0533d Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/bab0533d Branch: refs/heads/ignite-3163 Commit: bab0533d9b3e21759f44db1538bd5a3c7071db5a Parents: 3d6e179 Author: ashutak <[email protected]> Authored: Wed May 18 13:27:02 2016 +0300 Committer: ashutak <[email protected]> Committed: Wed May 18 14:01:55 2016 +0300 ---------------------------------------------------------------------- .../apache/ignite/IgniteSystemProperties.java | 15 ++ .../ignite/internal/IgniteNodeAttributes.java | 3 + .../discovery/GridDiscoveryManager.java | 31 +++ .../service/GridServiceAssignments.java | 10 +- .../service/GridServiceProcessor.java | 215 ++++++++++++++- .../service/LazyServiceConfiguration.java | 129 +++++++++ .../service/ServiceDescriptorImpl.java | 17 +- .../ignite/services/ServiceConfiguration.java | 14 +- .../ignite/spi/discovery/tcp/ServerImpl.java | 72 ++++++ .../GridDiscoveryManagerAttributesSelfTest.java | 63 +++++ ...yment2ClassLoadersDefaultMarshallerTest.java | 259 +++++++++++++++++++ ...eployment2ClassLoadersJdkMarshallerTest.java | 31 +++ ...ent2ClassLoadersOptimizedMarshallerTest.java | 31 +++ ...oymentClassLoadingDefaultMarshallerTest.java | 212 +++++++++++++++ ...DeploymentClassLoadingJdkMarshallerTest.java | 31 +++ ...mentClassLoadingOptimizedMarshallerTest.java | 31 +++ .../testsuites/IgniteKernalSelfTestSuite.java | 13 + .../apache/ignite/tests/p2p/NoopService.java | 41 +++ .../apache/ignite/tests/p2p/NoopService2.java | 41 +++ 19 files changed, 1229 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java index db1d093..50d60e8 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -429,6 +429,21 @@ public final class IgniteSystemProperties { "IGNITE_H2_INDEXING_CACHE_THREAD_USAGE_TIMEOUT"; /** + * Manages backward compatibility of {@link IgniteServices}. All nodes in cluster must have identical value + * of this property. + * <p> + * If property is {@code false} then node is not required to have service implementation class if service is not + * deployed on this node. + * <p> + * If the property is {@code true} then service implementation class is required on node even if service + * is not deployed on this node. + * <p> + * If the property is not set ({@code null}) then Ignite will automatically detect which compatibility mode + * should be used. + */ + public static final String IGNITE_SERVICES_COMPATIBILITY_MODE = "IGNITE_SERVICES_COMPATIBILITY_MODE"; + + /** * Enforces singleton. */ private IgniteSystemProperties() { http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java index 744439c..3425793 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java @@ -154,6 +154,9 @@ public final class IgniteNodeAttributes { /** Binary configuration. */ public static final String ATTR_BINARY_CONFIGURATION = ATTR_PREFIX + ".binary.config"; + /** Ignite services compatibility mode (can be {@code null}). */ + public static final String ATTR_SERVICES_COMPATIBILITY_MODE = ATTR_PREFIX + ".services.compatibility.enabled"; + /** * Enforces singleton. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java index 2779d6f..180904e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java @@ -78,6 +78,7 @@ import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.GridCacheAdapter; import org.apache.ignite.internal.processors.jobmetrics.GridJobMetrics; import org.apache.ignite.internal.processors.security.SecurityContext; +import org.apache.ignite.internal.processors.service.GridServiceProcessor; import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; import org.apache.ignite.internal.util.F0; import org.apache.ignite.internal.util.GridBoundedConcurrentOrderedMap; @@ -119,6 +120,7 @@ import org.jsr166.ConcurrentHashMap8; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.apache.ignite.IgniteSystemProperties.IGNITE_OPTIMIZED_MARSHALLER_USE_DEFAULT_SUID; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE; import static org.apache.ignite.IgniteSystemProperties.IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2; import static org.apache.ignite.events.EventType.EVT_CLIENT_NODE_DISCONNECTED; import static org.apache.ignite.events.EventType.EVT_CLIENT_NODE_RECONNECTED; @@ -128,10 +130,12 @@ import static org.apache.ignite.events.EventType.EVT_NODE_LEFT; import static org.apache.ignite.events.EventType.EVT_NODE_METRICS_UPDATED; import static org.apache.ignite.events.EventType.EVT_NODE_SEGMENTED; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_DEPLOYMENT_MODE; +import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_LATE_AFFINITY_ASSIGNMENT; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MACS; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_BINARY_STRING_SER_VER_2; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_DFLT_SUID; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_PEER_CLASSLOADING; +import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SERVICES_COMPATIBILITY_MODE; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_USER_NAME; import static org.apache.ignite.internal.IgniteVersionUtils.VER; import static org.apache.ignite.plugin.segmentation.SegmentationPolicy.NOOP; @@ -691,6 +695,8 @@ public class GridDiscoveryManager extends GridManagerAdapter<DiscoverySpi> { checkAttributes(discoCache().remoteNodes()); + ctx.service().initCompatibilityMode(discoCache().remoteNodes()); + // Start discovery worker. new IgniteThread(discoWrk).start(); @@ -1006,6 +1012,8 @@ public class GridDiscoveryManager extends GridManagerAdapter<DiscoverySpi> { false /* turned on and added to the attributes list by default only when BinaryMarshaller is used. */ : locMarshStrSerVer2; + Boolean locSrvcCompatibilityEnabled = locNode.attribute(ATTR_SERVICES_COMPATIBILITY_MODE); + for (ClusterNode n : nodes) { int rmtJvmMajVer = nodeJavaMajorVersion(n); @@ -1079,6 +1087,29 @@ public class GridDiscoveryManager extends GridManagerAdapter<DiscoverySpi> { ", locNodeId=" + locNode.id() + ", rmtNodeId=" + n.id() + ']'); } + if (n.version().compareToIgnoreTimestamp(GridServiceProcessor.LAZY_SERVICES_CFG_SINCE) >= 0) { + Boolean rmtSrvcCompatibilityEnabled = n.attribute(ATTR_SERVICES_COMPATIBILITY_MODE); + + if (!F.eq(locSrvcCompatibilityEnabled, rmtSrvcCompatibilityEnabled)) { + throw new IgniteCheckedException("Local node's " + IGNITE_SERVICES_COMPATIBILITY_MODE + + " property value differs from remote node's value " + + "(to make sure all nodes in topology have identical IgniteServices compatibility mode enabled, " + + "configure system property explicitly) " + + "[locSrvcCompatibilityEnabled=" + locSrvcCompatibilityEnabled + + ", rmtSrvcCompatibilityEnabled=" + rmtSrvcCompatibilityEnabled + + ", locNodeAddrs=" + U.addressesAsString(locNode) + + ", rmtNodeAddrs=" + U.addressesAsString(n) + + ", locNodeId=" + locNode.id() + ", rmtNodeId=" + n.id() + ']'); + } + } + else if (Boolean.FALSE.equals(locSrvcCompatibilityEnabled)) { + throw new IgniteCheckedException("Remote node doesn't support lazy services configuration and " + + "local node cannot join node because local node's " + + IGNITE_SERVICES_COMPATIBILITY_MODE + " property value explicitly set to 'false'" + + "[locNodeAddrs=" + U.addressesAsString(locNode) + + ", rmtNodeAddrs=" + U.addressesAsString(n) + + ", locNodeId=" + locNode.id() + ", rmtNodeId=" + n.id() + ']'); + } } if (log.isDebugEnabled()) http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java index c629a48..66b2816 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceAssignments.java @@ -26,7 +26,6 @@ import org.apache.ignite.internal.processors.cache.GridCacheInternal; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.lang.IgnitePredicate; -import org.apache.ignite.services.Service; import org.apache.ignite.services.ServiceConfiguration; /** @@ -75,13 +74,6 @@ public class GridServiceAssignments implements Serializable, GridCacheInternal { } /** - * @return Service. - */ - public Service service() { - return cfg.getService(); - } - - /** * @return Topology version. */ public long topologyVersion() { @@ -134,4 +126,4 @@ public class GridServiceAssignments implements Serializable, GridCacheInternal { @Override public String toString() { return S.toString(GridServiceAssignments.class, this); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java index b5634e9..97d9988 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java @@ -32,6 +32,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import javax.cache.Cache; import javax.cache.event.CacheEntryEvent; import javax.cache.event.CacheEntryListenerException; @@ -84,13 +85,17 @@ import org.apache.ignite.resources.IgniteInstanceResource; import org.apache.ignite.services.Service; import org.apache.ignite.services.ServiceConfiguration; import org.apache.ignite.services.ServiceDescriptor; +import org.apache.ignite.spi.IgniteNodeValidationResult; import org.apache.ignite.thread.IgniteThreadFactory; import org.jetbrains.annotations.Nullable; import org.jsr166.ConcurrentHashMap8; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE; +import static org.apache.ignite.IgniteSystemProperties.getString; import static org.apache.ignite.configuration.DeploymentMode.ISOLATED; import static org.apache.ignite.configuration.DeploymentMode.PRIVATE; import static org.apache.ignite.events.EventType.EVTS_DISCOVERY; +import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SERVICES_COMPATIBILITY_MODE; import static org.apache.ignite.internal.processors.cache.GridCacheUtils.UTILITY_CACHE_NAME; import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; @@ -100,9 +105,18 @@ import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_REA */ @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "ConstantConditions"}) public class GridServiceProcessor extends GridProcessorAdapter { + /** */ + public static final IgniteProductVersion LAZY_SERVICES_CFG_SINCE = IgniteProductVersion.fromString("1.5.22"); + + /** */ + private final Boolean srvcCompatibilitySysProp; + /** Time to wait before reassignment retries. */ private static final long RETRY_TIMEOUT = 1000; + /** */ + private final AtomicReference<ServicesCompatibilityState> compatibilityState; + /** Local service instances. */ private final Map<String, Collection<ServiceContextImpl>> locSvcs = new HashMap<>(); @@ -143,10 +157,19 @@ public class GridServiceProcessor extends GridProcessorAdapter { super(ctx); depExe = Executors.newSingleThreadExecutor(new IgniteThreadFactory(ctx.gridName(), "srvc-deploy")); + + String servicesCompatibilityMode = getString(IGNITE_SERVICES_COMPATIBILITY_MODE); + + srvcCompatibilitySysProp = servicesCompatibilityMode == null ? null : Boolean.valueOf(servicesCompatibilityMode); + + compatibilityState = new AtomicReference<>( + new ServicesCompatibilityState(srvcCompatibilitySysProp != null ? srvcCompatibilitySysProp : false, false)); } /** {@inheritDoc} */ @Override public void start() throws IgniteCheckedException { + ctx.addNodeAttribute(ATTR_SERVICES_COMPATIBILITY_MODE, srvcCompatibilitySysProp); + if (ctx.isDaemon()) return; @@ -390,8 +413,30 @@ public class GridServiceProcessor extends GridProcessorAdapter { public IgniteInternalFuture<?> deploy(ServiceConfiguration cfg) { A.notNull(cfg, "cfg"); + ServicesCompatibilityState state = markCompatibilityStateAsUsed(); + validate(cfg); + if (!state.srvcCompatibility) { + Marshaller marsh = ctx.config().getMarshaller(); + + LazyServiceConfiguration cfg0; + + try { + byte[] srvcBytes = marsh.marshal(cfg.getService()); + + cfg0 = new LazyServiceConfiguration(cfg, srvcBytes); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to marshal service with configured marshaller [srvc=" + cfg.getService() + + ", marsh=" + marsh + "]", e); + + return new GridFinishedFuture<>(e); + } + + cfg = cfg0; + } + GridServiceDeploymentFuture fut = new GridServiceDeploymentFuture(cfg); GridServiceDeploymentFuture old = depFuts.putIfAbsent(cfg.getName(), fut); @@ -487,6 +532,23 @@ public class GridServiceProcessor extends GridProcessorAdapter { } /** + * @return Compatibility state. + */ + private ServicesCompatibilityState markCompatibilityStateAsUsed() { + while (true) { + ServicesCompatibilityState state = compatibilityState.get(); + + if (state.used) + return state; + + ServicesCompatibilityState newState = new ServicesCompatibilityState(state.srvcCompatibility, true); + + if (compatibilityState.compareAndSet(state, newState)) + return newState; + } + } + + /** * @param name Service name. * @return Future. */ @@ -950,16 +1012,18 @@ public class GridServiceProcessor extends GridProcessorAdapter { } for (final ServiceContextImpl svcCtx : toInit) { - final Service svc = copyAndInject(assigns.service()); + final Service svc; try { + svc = copyAndInject(assigns.configuration()); + // Initialize service. svc.init(svcCtx); svcCtx.service(svc); } catch (Throwable e) { - log.error("Failed to initialize service (service will not be deployed): " + assigns.name(), e); + U.error(log, "Failed to initialize service (service will not be deployed): " + assigns.name(), e); synchronized (ctxs) { ctxs.removeAll(toInit); @@ -1020,26 +1084,40 @@ public class GridServiceProcessor extends GridProcessorAdapter { } /** - * @param svc Service. + * @param cfg Service configuration. * @return Copy of service. + * @throws IgniteCheckedException If failed. */ - private Service copyAndInject(Service svc) { + private Service copyAndInject(ServiceConfiguration cfg) throws IgniteCheckedException { Marshaller m = ctx.config().getMarshaller(); - try { - byte[] bytes = m.marshal(svc); + if (cfg instanceof LazyServiceConfiguration) { + byte[] bytes = ((LazyServiceConfiguration)cfg).serviceBytes(); - Service cp = m.unmarshal(bytes, - U.resolveClassLoader(svc.getClass().getClassLoader(), ctx.config())); + Service srvc = m.unmarshal(bytes, U.resolveClassLoader(null, ctx.config())); - ctx.resource().inject(cp); + ctx.resource().inject(srvc); - return cp; + return srvc; } - catch (IgniteCheckedException e) { - log.error("Failed to copy service (will reuse same instance): " + svc.getClass(), e); + else { + Service svc = cfg.getService(); + + try { + byte[] bytes = m.marshal(svc); + + Service cp = m.unmarshal(bytes, + U.resolveClassLoader(svc.getClass().getClassLoader(), ctx.config())); + + ctx.resource().inject(cp); - return svc; + return cp; + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to copy service (will reuse same instance): " + svc.getClass(), e); + + return svc; + } } } @@ -1136,6 +1214,73 @@ public class GridServiceProcessor extends GridProcessorAdapter { } } + /** {@inheritDoc} */ + @Nullable @Override public IgniteNodeValidationResult validateNode(ClusterNode node) { + IgniteNodeValidationResult res = super.validateNode(node); + + if (res != null) + return res; + + boolean rmtNodeIsOld = node.version().compareToIgnoreTimestamp(LAZY_SERVICES_CFG_SINCE) < 0; + + if (!rmtNodeIsOld) + return null; + + while (true) { + ServicesCompatibilityState state = compatibilityState.get(); + + if (state.srvcCompatibility) + return null; + + // Remote node is old and services are in not compatible mode. + if (!state.used) { + if (!compatibilityState.compareAndSet(state, new ServicesCompatibilityState(true, false))) + continue; + + return null; + } + + ClusterNode locNode = ctx.discovery().localNode(); + + return new IgniteNodeValidationResult(node.id(), "Local node uses IgniteServices and works in not " + + "compatible mode with old nodes (" + IGNITE_SERVICES_COMPATIBILITY_MODE + " system property can be " + + "set explicitly) [locNodeId=" + locNode.id() + ", rmtNodeId=" + node.id() + "]", + "Remote node uses IgniteServices and works in not compatible mode with old nodes " + + IGNITE_SERVICES_COMPATIBILITY_MODE + " system property can be set explicitly" + + "[locNodeId=" + node.id() + ", rmtNodeId=" + locNode.id() + "]"); + } + } + + /** + * @param nodes Remote nodes. + */ + public void initCompatibilityMode(Collection<ClusterNode> nodes) { + boolean mode; + + if (srvcCompatibilitySysProp == null) { + boolean clusterHasOldNode = false; + + for (ClusterNode n : nodes) { + if (n.version().compareToIgnoreTimestamp(LAZY_SERVICES_CFG_SINCE) < 0) { + clusterHasOldNode = true; + + break; + } + } + + mode = clusterHasOldNode; + } + else + mode = srvcCompatibilitySysProp; + + while (true) { + ServicesCompatibilityState state = compatibilityState.get(); + + if (compatibilityState.compareAndSet(state, new ServicesCompatibilityState(mode, state.used))) + return; + } + } + /** * Service deployment listener. */ @@ -1144,10 +1289,18 @@ public class GridServiceProcessor extends GridProcessorAdapter { @Override public void onUpdated(final Iterable<CacheEntryEvent<?, ?>> deps) { depExe.submit(new BusyRunnable() { @Override public void run0() { + boolean firstTime = true; + for (CacheEntryEvent<?, ?> e : deps) { if (!(e.getKey() instanceof GridServiceDeploymentKey)) continue; + if (firstTime) { + markCompatibilityStateAsUsed(); + + firstTime = false; + } + GridServiceDeployment dep; try { @@ -1303,12 +1456,20 @@ public class GridServiceProcessor extends GridProcessorAdapter { Iterator<Cache.Entry<Object, Object>> it = serviceEntries( ServiceDeploymentPredicate.INSTANCE); + boolean firstTime = true; + while (it.hasNext()) { Cache.Entry<Object, Object> e = it.next(); if (!(e.getKey() instanceof GridServiceDeploymentKey)) continue; + if (firstTime) { + markCompatibilityStateAsUsed(); + + firstTime = false; + } + GridServiceDeployment dep = (GridServiceDeployment)e.getValue(); try { @@ -1431,10 +1592,18 @@ public class GridServiceProcessor extends GridProcessorAdapter { @Override public void onUpdated(final Iterable<CacheEntryEvent<?, ?>> assignCol) throws CacheEntryListenerException { depExe.submit(new BusyRunnable() { @Override public void run0() { + boolean firstTime = true; + for (CacheEntryEvent<?, ?> e : assignCol) { if (!(e.getKey() instanceof GridServiceAssignmentsKey)) continue; + if (firstTime) { + markCompatibilityStateAsUsed(); + + firstTime = false; + } + GridServiceAssignments assigns; try { @@ -1596,4 +1765,24 @@ public class GridServiceProcessor extends GridProcessorAdapter { return serviceTopology(ignite.context().cache().utilityCache(), svcName); } } + + /** + * + */ + private static class ServicesCompatibilityState { + /** */ + private final boolean srvcCompatibility; + + /** */ + private final boolean used; + + /** + * @param srvcCompatibility Services compatibility mode ({@code true} if compatible with old nodes). + * @param used Services has been used. + */ + ServicesCompatibilityState(boolean srvcCompatibility, boolean used) { + this.srvcCompatibility = srvcCompatibility; + this.used = used; + } + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java new file mode 100644 index 0000000..e0add26 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfiguration.java @@ -0,0 +1,129 @@ +/* + * 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.service; + +import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.services.Service; +import org.apache.ignite.services.ServiceConfiguration; + +/** + * Lazy service configuration. + */ +public class LazyServiceConfiguration extends ServiceConfiguration { + /** */ + private static final long serialVersionUID = 0L; + + /** Service instance. */ + @GridToStringExclude + private transient Service srvc; + + /** */ + private String srvcClsName; + + /** */ + private byte[] srvcBytes; + + /** + * Default constructor. + */ + public LazyServiceConfiguration() { + // No-op. + } + + /** + * @param cfg Configuration. + * @param srvcBytes Marshaller service. + */ + public LazyServiceConfiguration(ServiceConfiguration cfg, byte[] srvcBytes) { + assert cfg.getService() != null : cfg; + assert srvcBytes != null; + + name = cfg.getName(); + totalCnt = cfg.getTotalCount(); + maxPerNodeCnt = cfg.getMaxPerNodeCount(); + cacheName = cfg.getCacheName(); + affKey = cfg.getAffinityKey(); + nodeFilter = cfg.getNodeFilter(); + this.srvcBytes = srvcBytes; + srvc = cfg.getService(); + srvcClsName = srvc.getClass().getName(); + } + + /** + * @return Service bytes. + */ + public byte[] serviceBytes() { + return srvcBytes; + } + + /** + * @return Service class name. + */ + public String serviceClassName() { + return srvcClsName; + } + + /** {@inheritDoc} */ + @Override public Service getService() { + assert srvc != null : this; + + return srvc; + } + + /** {@inheritDoc} */ + @SuppressWarnings("RedundantIfStatement") + @Override public boolean equalsIgnoreNodeFilter(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + LazyServiceConfiguration that = (LazyServiceConfiguration)o; + + if (maxPerNodeCnt != that.getMaxPerNodeCount()) + return false; + + if (totalCnt != that.getTotalCount()) + return false; + + if (affKey != null ? !affKey.equals(that.getAffinityKey()) : that.getAffinityKey() != null) + return false; + + if (cacheName != null ? !cacheName.equals(that.getCacheName()) : that.getCacheName() != null) + return false; + + if (name != null ? !name.equals(that.getName()) : that.getName() != null) + return false; + + if (!F.eq(srvcClsName, that.srvcClsName)) + return false; + + return true; + } + + /** {@inheritDoc} */ + @Override public String toString() { + String svcCls = srvc == null ? "" : srvc.getClass().getSimpleName(); + String nodeFilterCls = nodeFilter == null ? "" : nodeFilter.getClass().getSimpleName(); + + return S.toString(LazyServiceConfiguration.class, this, "svcCls", svcCls, "nodeFilterCls", nodeFilterCls); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java index 7671a2e..9ec3eb0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDescriptorImpl.java @@ -19,9 +19,11 @@ package org.apache.ignite.internal.processors.service; import java.util.Map; import java.util.UUID; +import org.apache.ignite.IgniteException; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.services.Service; +import org.apache.ignite.services.ServiceConfiguration; import org.apache.ignite.services.ServiceDescriptor; import org.jetbrains.annotations.Nullable; @@ -54,7 +56,20 @@ public class ServiceDescriptorImpl implements ServiceDescriptor { /** {@inheritDoc} */ @Override public Class<? extends Service> serviceClass() { - return dep.configuration().getService().getClass(); + ServiceConfiguration cfg = dep.configuration(); + + if (cfg instanceof LazyServiceConfiguration) { + String clsName = ((LazyServiceConfiguration)cfg).serviceClassName(); + + try { + return (Class<? extends Service>)Class.forName(clsName); + } + catch (ClassNotFoundException e) { + throw new IgniteException("Failed to find service class: " + clsName, e); + } + } + else + return dep.configuration().getService().getClass(); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java b/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java index 126ad47..6698dd4 100644 --- a/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/services/ServiceConfiguration.java @@ -55,27 +55,27 @@ public class ServiceConfiguration implements Serializable { private static final long serialVersionUID = 0L; /** Service name. */ - private String name; + protected String name; /** Service instance. */ @GridToStringExclude private Service svc; /** Total count. */ - private int totalCnt; + protected int totalCnt; /** Max per-node count. */ - private int maxPerNodeCnt; + protected int maxPerNodeCnt; /** Cache name. */ - private String cacheName; + protected String cacheName; /** Affinity key. */ - private Object affKey; + protected Object affKey; /** Node filter. */ @GridToStringExclude - private IgnitePredicate<ClusterNode> nodeFilter; + protected IgnitePredicate<ClusterNode> nodeFilter; /** * Gets service name. @@ -301,4 +301,4 @@ public class ServiceConfiguration implements Serializable { return S.toString(ServiceConfiguration.class, this, "svcCls", svcCls, "nodeFilterCls", nodeFilterCls); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index 7e0e17f..96192f5 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -71,6 +71,7 @@ import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.IgnitionEx; import org.apache.ignite.internal.events.DiscoveryCustomEvent; import org.apache.ignite.internal.processors.security.SecurityContext; +import org.apache.ignite.internal.processors.service.GridServiceProcessor; import org.apache.ignite.internal.util.GridBoundedLinkedHashSet; import org.apache.ignite.internal.util.GridConcurrentHashSet; import org.apache.ignite.internal.util.IgniteUtils; @@ -131,6 +132,7 @@ import org.jsr166.ConcurrentHashMap8; import static org.apache.ignite.IgniteSystemProperties.IGNITE_DISCOVERY_HISTORY_SIZE; import static org.apache.ignite.IgniteSystemProperties.IGNITE_OPTIMIZED_MARSHALLER_USE_DEFAULT_SUID; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE; import static org.apache.ignite.IgniteSystemProperties.IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2; import static org.apache.ignite.IgniteSystemProperties.getInteger; import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; @@ -142,6 +144,7 @@ import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_COMPACT_FOOTER; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_BINARY_STRING_SER_VER_2; import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_MARSHALLER_USE_DFLT_SUID; +import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_SERVICES_COMPATIBILITY_MODE; import static org.apache.ignite.spi.IgnitePortProtocol.TCP; import static org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoverySpiState.AUTH_FAILED; import static org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoverySpiState.CHECK_FAILED; @@ -3394,6 +3397,75 @@ class ServerImpl extends TcpDiscoveryImpl { return; } + final Boolean locSrvcCompatibilityEnabled = locNode.attribute(ATTR_SERVICES_COMPATIBILITY_MODE); + + if (node.version().compareToIgnoreTimestamp(GridServiceProcessor.LAZY_SERVICES_CFG_SINCE) >= 0) { + final Boolean rmtSrvcCompatibilityEnabled = node.attribute(ATTR_SERVICES_COMPATIBILITY_MODE); + + if (!F.eq(locSrvcCompatibilityEnabled, rmtSrvcCompatibilityEnabled)) { + utilityPool.submit( + new Runnable() { + @Override public void run() { + String errMsg = "Local node's " + IGNITE_SERVICES_COMPATIBILITY_MODE + + " property value differs from remote node's value " + + "(to make sure all nodes in topology have identical IgniteServices compatibility mode, " + + "configure system property explicitly) " + + "[locSrvcCompatibilityEnabled=" + locSrvcCompatibilityEnabled + + ", rmtSrvcCompatibilityEnabled=" + rmtSrvcCompatibilityEnabled + + ", locNodeAddrs=" + U.addressesAsString(locNode) + + ", rmtNodeAddrs=" + U.addressesAsString(node) + + ", locNodeId=" + locNode.id() + ", rmtNodeId=" + msg.creatorNodeId() + ']'; + + String sndMsg = "Local node's " + IGNITE_SERVICES_COMPATIBILITY_MODE + + " property value differs from remote node's value " + + "(to make sure all nodes in topology have identical IgniteServices compatibility mode, " + + "configure system property explicitly) " + + "[locSrvcCompatibilityEnabled=" + rmtSrvcCompatibilityEnabled + + ", rmtSrvcCompatibilityEnabled=" + locSrvcCompatibilityEnabled + + ", locNodeAddrs=" + U.addressesAsString(node) + ", locPort=" + node.discoveryPort() + + ", rmtNodeAddr=" + U.addressesAsString(locNode) + ", locNodeId=" + node.id() + + ", rmtNodeId=" + locNode.id() + ']'; + + nodeCheckError( + node, + errMsg, + sndMsg); + } + }); + + // Ignore join request. + return; + } + } + else if (Boolean.FALSE.equals(locSrvcCompatibilityEnabled)) { + utilityPool.submit( + new Runnable() { + @Override public void run() { + String errMsg = "Remote node doesn't support lazy services configuration and " + + "cannot be joined to local node because local node's " + + IGNITE_SERVICES_COMPATIBILITY_MODE + " property value explicitly set to 'false'" + + "[locNodeAddrs=" + U.addressesAsString(locNode) + + ", rmtNodeAddrs=" + U.addressesAsString(node) + + ", locNodeId=" + locNode.id() + ", rmtNodeId=" + node.id() + ']'; + + String sndMsg = "Local node doesn't support lazy services configuration and " + + "cannot be joined to local node because remote node's " + + IGNITE_SERVICES_COMPATIBILITY_MODE + " property value explicitly set to 'false'" + + "[locNodeAddrs=" + U.addressesAsString(node) + + ", rmtNodeAddrs=" + U.addressesAsString(locNode) + + ", locNodeId=" + node.id() + ", rmtNodeId=" + locNode.id() + ']'; + + nodeCheckError( + node, + errMsg, + sndMsg); + } + }); + + // Ignore join request. + return; + } + // Handle join. node.internalOrder(ring.nextNodeOrder()); http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java index 28380df..ba8fa5b 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManagerAttributesSelfTest.java @@ -29,6 +29,7 @@ import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import static org.apache.ignite.IgniteSystemProperties.IGNITE_OPTIMIZED_MARSHALLER_USE_DEFAULT_SUID; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICES_COMPATIBILITY_MODE; import static org.apache.ignite.IgniteSystemProperties.IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2; import static org.apache.ignite.configuration.DeploymentMode.CONTINUOUS; import static org.apache.ignite.configuration.DeploymentMode.SHARED; @@ -227,6 +228,68 @@ public abstract class GridDiscoveryManagerAttributesSelfTest extends GridCommonA /** * @throws Exception If failed. */ + public void testServiceCompatibilityEnabled() throws Exception { + String backup = System.getProperty(IGNITE_SERVICES_COMPATIBILITY_MODE); + + try { + doTestServiceCompatibilityEnabled(true, null, true); + doTestServiceCompatibilityEnabled(false, null, true); + doTestServiceCompatibilityEnabled(null, false, true); + doTestServiceCompatibilityEnabled(true, false, true); + doTestServiceCompatibilityEnabled(null, true, true); + doTestServiceCompatibilityEnabled(false, true, true); + + doTestServiceCompatibilityEnabled(true, true, false); + doTestServiceCompatibilityEnabled(false, false, false); + doTestServiceCompatibilityEnabled(null, null, false); + } + finally { + if (backup != null) + System.setProperty(IGNITE_SERVICES_COMPATIBILITY_MODE, backup); + else + System.clearProperty(IGNITE_SERVICES_COMPATIBILITY_MODE); + } + } + + /** + * @param first Service compatibility enabled flag for first node. + * @param second Service compatibility enabled flag for second node. + * @param fail Fail flag. + * @throws Exception If failed. + */ + private void doTestServiceCompatibilityEnabled(Object first, Object second, boolean fail) throws Exception { + try { + if (first != null) + System.setProperty(IGNITE_SERVICES_COMPATIBILITY_MODE, String.valueOf(first)); + else + System.clearProperty(IGNITE_SERVICES_COMPATIBILITY_MODE); + + startGrid(0); + + if (second != null) + System.setProperty(IGNITE_SERVICES_COMPATIBILITY_MODE, String.valueOf(second)); + else + System.clearProperty(IGNITE_SERVICES_COMPATIBILITY_MODE); + + try { + startGrid(1); + + if (fail) + fail("Node must not join"); + } + catch (Exception e) { + if (!fail) + fail("Node must join: " + e.getMessage()); + } + } + finally { + stopAllGrids(); + } + } + + /** + * @throws Exception If failed. + */ public void testDifferentDeploymentModes() throws Exception { startGrid(0); http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java new file mode 100644 index 0000000..e77ded7 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.java @@ -0,0 +1,259 @@ +/* + * 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.service; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.services.Service; +import org.apache.ignite.services.ServiceConfiguration; +import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; +import org.apache.ignite.testframework.GridTestExternalClassLoader; +import org.apache.ignite.testframework.config.GridTestProperties; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +/** + * Tests that not all nodes in cluster need user's service definition (only nodes according to filter). + */ +public class IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest extends GridCommonAbstractTest { + /** */ + private static final String NOOP_SERVICE_CLS_NAME = "org.apache.ignite.tests.p2p.NoopService"; + + /** */ + private static final String NOOP_SERVICE_2_CLS_NAME = "org.apache.ignite.tests.p2p.NoopService2"; + + /** IP finder. */ + private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); + + /** */ + private static final int GRID_CNT = 6; + + /** */ + private static final String NODE_NAME_ATTR = "NODE_NAME"; + + /** */ + private static final URL[] URLS; + + /** */ + private static ClassLoader extClsLdr1; + + /** */ + private static ClassLoader extClsLdr2; + + /** */ + private Set<String> grp1 = new HashSet<>(); + + /** */ + private Set<String> grp2 = new HashSet<>(); + + /** */ + private boolean client; + + /** + * Initialize URLs. + */ + static { + try { + URLS = new URL[] {new URL(GridTestProperties.getProperty("p2p.uri.cls"))}; + } + catch (MalformedURLException e) { + throw new RuntimeException("Define property p2p.uri.cls", e); + } + } + + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(gridName); + + cfg.setPeerClassLoadingEnabled(false); + + TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); + + discoSpi.setIpFinder(IP_FINDER); + + cfg.setDiscoverySpi(discoSpi); + + cfg.setMarshaller(marshaller()); + + cfg.setUserAttributes(Collections.singletonMap(NODE_NAME_ATTR, gridName)); + + if (grp1.contains(gridName)) + cfg.setClassLoader(extClsLdr1); + + if (grp2.contains(gridName)) + cfg.setClassLoader(extClsLdr2); + + cfg.setClientMode(client); + + return cfg; + } + + /** + * @return Marshaller. + */ + protected Marshaller marshaller() { + return null; + } + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + for (int i = 0; i < GRID_CNT; i += 2) + grp1.add(getTestGridName(i)); + + for (int i = 1; i < GRID_CNT; i += 2) + grp2.add(getTestGridName(i)); + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + extClsLdr1 = new GridTestExternalClassLoader(URLS, NOOP_SERVICE_2_CLS_NAME); + extClsLdr2 = new GridTestExternalClassLoader(URLS, NOOP_SERVICE_CLS_NAME); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + extClsLdr1 = null; + extClsLdr2 = null; + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** + * @throws Exception If failed. + */ + public void testServiceDeployment1() throws Exception { + startGrid(0).services().deploy(serviceConfig(true)); + + startGrid(1).services().deploy(serviceConfig(false)); + + client = true; + + startGrid(2).services().deploy(serviceConfig(true)); + + startGrid(3).services().deploy(serviceConfig(false)); + + for (int i = 0; i < 4; i++) + ignite(i).services().serviceDescriptors(); + + ignite(0).services().cancel("TestDeploymentService1"); + + ignite(1).services().cancel("TestDeploymentService2"); + } + + /** + * @throws Exception If failed. + */ + public void testServiceDeployment2() throws Exception { + for (int i = 0 ; i < 4; i++) + startGrid(i); + + client = true; + + for (int i = 4 ; i < 6; i++) + startGrid(i); + + ignite(4).services().deploy(serviceConfig(true)); + + ignite(5).services().deploy(serviceConfig(false)); + } + + /** + * @throws Exception If failed. + */ + public void testServiceDeployment3() throws Exception { + startGrid(0).services().deploy(serviceConfig(true)); + + startGrid(1); + + startGrid(2); + + stopGrid(0); + + awaitPartitionMapExchange(); + + ignite(1).services().deploy(serviceConfig(false)); + + startGrid(0); + } + + /** + * @param firstGrp First group flag. + * @return Service configuration. + * @throws Exception If failed. + */ + private ServiceConfiguration serviceConfig(final boolean firstGrp) throws Exception { + ServiceConfiguration srvCfg = new ServiceConfiguration(); + + srvCfg.setNodeFilter(new TestNodeFilter(firstGrp ? grp1 : grp2)); + + Class<Service> srvcCls; + + if (firstGrp) + srvcCls = (Class<Service>)extClsLdr1.loadClass(NOOP_SERVICE_CLS_NAME); + else + srvcCls = (Class<Service>)extClsLdr2.loadClass(NOOP_SERVICE_2_CLS_NAME); + + Service srvc = srvcCls.newInstance(); + + srvCfg.setService(srvc); + + srvCfg.setName("TestDeploymentService" + (firstGrp ? 1 : 2)); + + srvCfg.setMaxPerNodeCount(1); + + return srvCfg; + } + + /** + * + */ + private static class TestNodeFilter implements IgnitePredicate<ClusterNode> { + /** */ + private Set<String> grp; + + /** + * @param grp Group. + */ + private TestNodeFilter(Set<String> grp) { + this.grp = grp; + } + + /** {@inheritDoc} */ + @SuppressWarnings("SuspiciousMethodCalls") + @Override public boolean apply(ClusterNode node) { + Object gridName = node.attribute(NODE_NAME_ATTR); + + return grp.contains(gridName); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java new file mode 100644 index 0000000..f9e24c1 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.java @@ -0,0 +1,31 @@ +/* + * 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.service; + +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.marshaller.jdk.JdkMarshaller; + +/** + * Tests that not all nodes in cluster need user's service definition (only nodes according to filter). + */ +public class IgniteServiceDeployment2ClassLoadersJdkMarshallerTest + extends IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest{ + /** {@inheritDoc} */ + @Override protected Marshaller marshaller() { + return new JdkMarshaller(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java new file mode 100644 index 0000000..f2988cc --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.java @@ -0,0 +1,31 @@ +/* + * 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.service; + +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.marshaller.optimized.OptimizedMarshaller; + +/** + * Tests that not all nodes in cluster need user's service definition (only nodes according to filter). + */ +public class IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest + extends IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest{ + /** {@inheritDoc} */ + @Override protected Marshaller marshaller() { + return new OptimizedMarshaller(false); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java new file mode 100644 index 0000000..a8599f4 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.java @@ -0,0 +1,212 @@ +/* + * 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.service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.services.Service; +import org.apache.ignite.services.ServiceConfiguration; +import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +/** + * Tests that not all nodes in cluster need user's service definition (only nodes according to filter). + */ +public class IgniteServiceDeploymentClassLoadingDefaultMarshallerTest extends GridCommonAbstractTest { + /** */ + private static final String NOOP_SERVICE_CLS_NAME = "org.apache.ignite.tests.p2p.NoopService"; + + /** IP finder. */ + private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); + + /** */ + private static final int SERVER_NODE = 0; + + /** */ + private static final int SERVER_NODE_WITH_EXT_CLASS_LOADER = 1; + + /** */ + private static final int CLIENT_NODE = 2; + + /** */ + private static final int CLIENT_NODE_WITH_EXT_CLASS_LOADER = 3; + + /** */ + private static final String NODE_NAME_ATTR = "NODE_NAME"; + + /** */ + private static ClassLoader extClsLdr; + + /** */ + private Set<String> extClsLdrGrids = new HashSet<>(); + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(gridName); + + cfg.setPeerClassLoadingEnabled(false); + + TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); + + discoSpi.setIpFinder(IP_FINDER); + + cfg.setDiscoverySpi(discoSpi); + + cfg.setMarshaller(marshaller()); + + cfg.setUserAttributes(Collections.singletonMap(NODE_NAME_ATTR, gridName)); + + if (getTestGridName(CLIENT_NODE_WITH_EXT_CLASS_LOADER).equals(gridName) + || getTestGridName(CLIENT_NODE).equals(gridName)) + cfg.setClientMode(true); + + if (extClsLdrGrids.contains(gridName)) + cfg.setClassLoader(extClsLdr); + + return cfg; + } + + /** + * @return Marshaller. + */ + protected Marshaller marshaller() { + return null; + } + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + extClsLdrGrids.clear(); + + extClsLdrGrids.add(getTestGridName(SERVER_NODE_WITH_EXT_CLASS_LOADER)); + extClsLdrGrids.add(getTestGridName(CLIENT_NODE_WITH_EXT_CLASS_LOADER)); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + extClsLdr = getExternalClassLoader(); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + extClsLdr = null; + } + + /** + * @throws Exception If failed. + */ + public void testServiceDeployment1() throws Exception { + startGrid(SERVER_NODE); + + startGrid(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig()); + + startGrid(CLIENT_NODE); + + startGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig()); + + ignite(SERVER_NODE).services().serviceDescriptors(); + + ignite(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().serviceDescriptors(); + } + + /** + * @throws Exception If failed. + */ + public void testServiceDeployment2() throws Exception { + startGrid(SERVER_NODE); + + startGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig()); + + startGrid(CLIENT_NODE); + + startGrid(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig()); + } + + /** + * @throws Exception If failed. + */ + public void testServiceDeployment3() throws Exception { + startGrid(SERVER_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig()); + + startGrid(SERVER_NODE); + + startGrid(CLIENT_NODE); + + startGrid(CLIENT_NODE_WITH_EXT_CLASS_LOADER).services().deploy(serviceConfig()); + } + + /** + * @return Service configuration. + * @throws Exception If failed. + */ + private ServiceConfiguration serviceConfig() throws Exception { + ServiceConfiguration srvCfg = new ServiceConfiguration(); + + srvCfg.setNodeFilter(new TestNodeFilter(extClsLdrGrids)); + + Class<Service> srvcCls = (Class<Service>)extClsLdr.loadClass(NOOP_SERVICE_CLS_NAME); + + Service srvc = srvcCls.newInstance(); + + srvCfg.setService(srvc); + + srvCfg.setName("TestDeploymentService"); + + srvCfg.setMaxPerNodeCount(1); + + return srvCfg; + } + + /** + * + */ + private static class TestNodeFilter implements IgnitePredicate<ClusterNode> { + /** */ + private static final long serialVersionUID = 0; + + /** */ + private Set<String> grids; + + /** + * @param grids Grid names. + */ + private TestNodeFilter(Set<String> grids) { + this.grids = grids; + } + + /** {@inheritDoc} */ + @SuppressWarnings("SuspiciousMethodCalls") + @Override public boolean apply(ClusterNode node) { + return grids.contains(node.attribute(NODE_NAME_ATTR)); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java new file mode 100644 index 0000000..aeb68af --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingJdkMarshallerTest.java @@ -0,0 +1,31 @@ +/* + * 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.service; + +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.marshaller.jdk.JdkMarshaller; + +/** + * Tests that not all nodes in cluster need user's service definition (only nodes according to filter). + */ +public class IgniteServiceDeploymentClassLoadingJdkMarshallerTest + extends IgniteServiceDeploymentClassLoadingDefaultMarshallerTest { + /** {@inheritDoc} */ + @Override protected Marshaller marshaller() { + return new JdkMarshaller(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java new file mode 100644 index 0000000..cb0c911 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.java @@ -0,0 +1,31 @@ +/* + * 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.service; + +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.marshaller.optimized.OptimizedMarshaller; + +/** + * Tests that not all nodes in cluster need user's service definition (only nodes according to filter). + */ +public class IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest + extends IgniteServiceDeploymentClassLoadingDefaultMarshallerTest { + /** {@inheritDoc} */ + @Override protected Marshaller marshaller() { + return new OptimizedMarshaller(false); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java index a8d6e5c..28974ea 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java @@ -57,6 +57,12 @@ import org.apache.ignite.internal.processors.service.GridServiceProcessorStopSel import org.apache.ignite.internal.processors.service.GridServiceProxyNodeStopSelfTest; import org.apache.ignite.internal.processors.service.GridServiceReassignmentSelfTest; import org.apache.ignite.internal.processors.service.GridServiceSerializationSelfTest; +import org.apache.ignite.internal.processors.service.IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest; +import org.apache.ignite.internal.processors.service.IgniteServiceDeployment2ClassLoadersJdkMarshallerTest; +import org.apache.ignite.internal.processors.service.IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest; +import org.apache.ignite.internal.processors.service.IgniteServiceDeploymentClassLoadingDefaultMarshallerTest; +import org.apache.ignite.internal.processors.service.IgniteServiceDeploymentClassLoadingJdkMarshallerTest; +import org.apache.ignite.internal.processors.service.IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest; import org.apache.ignite.internal.processors.service.ServicePredicateAccessCacheTest; import org.apache.ignite.internal.util.GridStartupWithSpecifiedWorkDirectorySelfTest; import org.apache.ignite.internal.util.GridStartupWithUndefinedIgniteHomeSelfTest; @@ -130,6 +136,13 @@ public class IgniteKernalSelfTestSuite extends TestSuite { suite.addTestSuite(GridServiceSerializationSelfTest.class); suite.addTestSuite(GridServiceProxyNodeStopSelfTest.class); + suite.addTestSuite(IgniteServiceDeploymentClassLoadingDefaultMarshallerTest.class); + suite.addTestSuite(IgniteServiceDeploymentClassLoadingOptimizedMarshallerTest.class); + suite.addTestSuite(IgniteServiceDeploymentClassLoadingJdkMarshallerTest.class); + suite.addTestSuite(IgniteServiceDeployment2ClassLoadersDefaultMarshallerTest.class); + suite.addTestSuite(IgniteServiceDeployment2ClassLoadersOptimizedMarshallerTest.class); + suite.addTestSuite(IgniteServiceDeployment2ClassLoadersJdkMarshallerTest.class); + return suite; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java ---------------------------------------------------------------------- diff --git a/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java new file mode 100644 index 0000000..b3d06b2 --- /dev/null +++ b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService.java @@ -0,0 +1,41 @@ +/* + * 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.tests.p2p; + +import org.apache.ignite.services.Service; +import org.apache.ignite.services.ServiceContext; + +/** + * No-op service. + */ +public class NoopService implements Service { + /** {@inheritDoc} */ + @Override public void cancel(ServiceContext ctx) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void init(ServiceContext ctx) throws Exception { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void execute(ServiceContext ctx) throws Exception { + // No-op. + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/bab0533d/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java ---------------------------------------------------------------------- diff --git a/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java new file mode 100644 index 0000000..ad65d5b --- /dev/null +++ b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/NoopService2.java @@ -0,0 +1,41 @@ +/* + * 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.tests.p2p; + +import org.apache.ignite.services.Service; +import org.apache.ignite.services.ServiceContext; + +/** + * No-op service. + */ +public class NoopService2 implements Service { + /** {@inheritDoc} */ + @Override public void cancel(ServiceContext ctx) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void init(ServiceContext ctx) throws Exception { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void execute(ServiceContext ctx) throws Exception { + // No-op. + } +}
