You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2018/09/27 12:54:33 UTC
[22/50] [abbrv] ignite git commit: IGNITE-9381 Clear class cache on
p2p undeploy - Fixes #4784.
IGNITE-9381 Clear class cache on p2p undeploy - Fixes #4784.
Signed-off-by: Alexey Goncharuk <al...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d40dcb3a
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d40dcb3a
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d40dcb3a
Branch: refs/heads/ignite-gg-14206
Commit: d40dcb3a8f25a5bb098662fa7270b69eb3cc3ab5
Parents: fe35a64
Author: Sergey Antonov <an...@gmail.com>
Authored: Wed Sep 26 16:55:06 2018 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Wed Sep 26 17:19:43 2018 +0300
----------------------------------------------------------------------
.../GridDeploymentPerVersionStore.java | 6 +
.../cache/CacheClassLoaderMarker.java | 24 ++
.../cache/GridCacheDeploymentManager.java | 2 +-
.../ignite/internal/util/IgniteUtils.java | 22 +-
.../ignite/p2p/P2PScanQueryUndeployTest.java | 250 +++++++++++++++++++
.../testsuites/IgniteP2PSelfTestSuite.java | 2 +
.../ignite/tests/p2p/AlwaysTruePredicate.java | 30 +++
7 files changed, 334 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/d40dcb3a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java
index 14aa49f..56a3f3e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/deployment/GridDeploymentPerVersionStore.java
@@ -1290,6 +1290,12 @@ public class GridDeploymentPerVersionStore extends GridDeploymentStoreAdapter {
ctx.cache().onUndeployed(ldr);
+ // Clear static class cache.
+ U.clearClassFromClassCache(ctx.cache().context().deploy().globalLoader(), sampleClassName());
+
+ for (String alias : deployedClassMap().keySet())
+ U.clearClassFromClassCache(ctx.cache().context().deploy().globalLoader(), alias);
+
// Clear optimized marshaller's cache.
if (ctx.config().getMarshaller() instanceof AbstractMarshaller)
((AbstractMarshaller)ctx.config().getMarshaller()).onUndeploy(ldr);
http://git-wip-us.apache.org/repos/asf/ignite/blob/d40dcb3a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClassLoaderMarker.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClassLoaderMarker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClassLoaderMarker.java
new file mode 100644
index 0000000..b575ec7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClassLoaderMarker.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * It's a marker interface for detecting GridCacheDeploymentManager$CacheClassLoader.
+ */
+public interface CacheClassLoaderMarker {
+ // Marker interface.
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/d40dcb3a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
index b70439a..b34da62 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
@@ -760,7 +760,7 @@ public class GridCacheDeploymentManager<K, V> extends GridCacheSharedManagerAdap
/**
* Cache class loader.
*/
- private class CacheClassLoader extends ClassLoader {
+ private class CacheClassLoader extends ClassLoader implements CacheClassLoaderMarker {
/** */
private final String[] p2pExclude;
http://git-wip-us.apache.org/repos/asf/ignite/blob/d40dcb3a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index 6320c9f..c5054ad 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -193,6 +193,7 @@ import org.apache.ignite.internal.events.DiscoveryCustomEvent;
import org.apache.ignite.internal.managers.communication.GridIoManager;
import org.apache.ignite.internal.managers.deployment.GridDeploymentInfo;
import org.apache.ignite.internal.mxbean.IgniteStandardMXBean;
+import org.apache.ignite.internal.processors.cache.CacheClassLoaderMarker;
import org.apache.ignite.internal.processors.cache.GridCacheAttributes;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
@@ -8694,7 +8695,13 @@ public abstract class IgniteUtils {
if (clsFilter != null && !clsFilter.apply(clsName))
throw new RuntimeException("Deserialization of class " + clsName + " is disallowed.");
- Class old = ldrMap.putIfAbsent(clsName, cls = Class.forName(clsName, true, ldr));
+ // Avoid class caching inside Class.forName
+ if (ldr instanceof CacheClassLoaderMarker)
+ cls = ldr.loadClass(clsName);
+ else
+ cls = Class.forName(clsName, true, ldr);
+
+ Class old = ldrMap.putIfAbsent(clsName, cls);
if (old != null)
cls = old;
@@ -8704,6 +8711,19 @@ public abstract class IgniteUtils {
}
/**
+ * Clears class associated with provided class loader from class cache.
+ *
+ * @param ldr Class loader.
+ * @param clsName Class name of clearing class.
+ */
+ public static void clearClassFromClassCache(ClassLoader ldr, String clsName){
+ ConcurrentMap<String, Class> map = classCache.get(ldr);
+
+ if (map!=null)
+ map.remove(clsName);
+ }
+
+ /**
* Clears class cache for provided loader.
*
* @param ldr Class loader.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d40dcb3a/modules/core/src/test/java/org/apache/ignite/p2p/P2PScanQueryUndeployTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/p2p/P2PScanQueryUndeployTest.java b/modules/core/src/test/java/org/apache/ignite/p2p/P2PScanQueryUndeployTest.java
new file mode 100644
index 0000000..73ce917
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/p2p/P2PScanQueryUndeployTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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.p2p;
+
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cache.query.ScanQuery;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.managers.communication.GridIoMessage;
+import org.apache.ignite.internal.managers.deployment.GridDeploymentRequest;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.lang.IgniteInClosure;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+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;
+
+/** */
+public class P2PScanQueryUndeployTest extends GridCommonAbstractTest {
+ /** Predicate classname. */
+ private static final String PREDICATE_CLASSNAME = "org.apache.ignite.tests.p2p.AlwaysTruePredicate";
+
+ /** */
+ private static final String TEST_PREDICATE_RESOURCE_NAME = U.classNameToResourceName(PREDICATE_CLASSNAME);
+
+ /** Cache name. */
+ private static final String CACHE_NAME = "test-cache";
+
+ /** Client instance name. */
+ private static final String CLIENT_INSTANCE_NAME = "client";
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ cfg.setPeerClassLoadingEnabled(true);
+
+ cfg.setCacheConfiguration(
+ new CacheConfiguration()
+ .setName(CACHE_NAME)
+ .setBackups(1)
+ );
+
+ cfg.setDiscoverySpi(
+ new TcpDiscoverySpi()
+ .setIpFinder(
+ new TcpDiscoveryVmIpFinder(true)
+ .setAddresses(Collections.singletonList("127.0.0.1:47500..47509"))
+ )
+ );
+
+ cfg.setCommunicationSpi(new MessageCountingCommunicationSpi());
+
+ if (igniteInstanceName.equals(CLIENT_INSTANCE_NAME))
+ cfg.setClientMode(true);
+
+ return cfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ super.beforeTest();
+
+ stopAllGrids();
+
+ MessageCountingCommunicationSpi.resetDeploymentRequestCounter();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ stopAllGrids();
+ }
+
+ /**
+ * Checks, that after client's reconnect to cluster will be redeployed from client node.
+ *
+ * @throws Exception if test failed.
+ */
+ public void testAfterClientDisconnect() throws Exception {
+ ClassLoader extClsLdr = new GridTestExternalClassLoader(new URL[] {new URL(GridTestProperties.getProperty("p2p.uri.cls"))});
+
+ assertFalse(classFound(getClass().getClassLoader(), PREDICATE_CLASSNAME));
+
+ Class predCls = extClsLdr.loadClass(PREDICATE_CLASSNAME);
+
+ startGrid(0);
+
+ Ignite client = startGrid(CLIENT_INSTANCE_NAME);
+
+ client.cluster().active(true);
+
+ awaitPartitionMapExchange();
+
+ IgniteCache<Integer, String> cache = client.getOrCreateCache(CACHE_NAME);
+
+ cache.put(1, "foo");
+
+ invokeScanQueryAndStopClient(client, predCls);
+
+ MessageCountingCommunicationSpi.resetDeploymentRequestCounter();
+
+ client = startGrid(CLIENT_INSTANCE_NAME);
+
+ invokeScanQueryAndStopClient(client, predCls);
+ }
+
+ /**
+ * @param client ignite instance.
+ * @param predCls loaded predicate class.
+ * @throws Exception if failed.
+ */
+ private void invokeScanQueryAndStopClient(Ignite client, Class predCls) throws Exception {
+ IgniteCache<Integer, String> cache = client.getOrCreateCache(CACHE_NAME);
+
+ assertEquals("Invalid number of sent grid deployment requests", 0, MessageCountingCommunicationSpi.deploymentRequestCount());
+
+ assertFalse(PREDICATE_CLASSNAME + " mustn't be cached! ", igniteUtilsCachedClasses().contains(PREDICATE_CLASSNAME));
+
+ cache.query(new ScanQuery<>((IgniteBiPredicate<Integer, String>)predCls.newInstance())).getAll();
+
+ // first request is GridDeployment.java 716 and second is GridDeployment.java 501
+ assertEquals("Invalid number of sent grid deployment requests", 2, MessageCountingCommunicationSpi.deploymentRequestCount());
+
+ assertTrue(PREDICATE_CLASSNAME + " must be cached! ", igniteUtilsCachedClasses().contains(PREDICATE_CLASSNAME));
+
+ client.close();
+
+ assertFalse(PREDICATE_CLASSNAME + " mustn't be cached! ", igniteUtilsCachedClasses().contains(PREDICATE_CLASSNAME));
+ }
+
+ /**
+ * @return All class names cached in IgniteUtils.classCache field
+ * @throws Exception if something wrong.
+ */
+ private Set<String> igniteUtilsCachedClasses() throws Exception {
+ Field f = IgniteUtils.class.getDeclaredField("classCache");
+
+ f.setAccessible(true);
+
+ ConcurrentMap<ClassLoader, ConcurrentMap<String, Class>> map =
+ (ConcurrentMap<ClassLoader, ConcurrentMap<String, Class>>)f.get(null);
+
+ return map.values().stream().flatMap(x -> x.keySet().stream()).collect(Collectors.toSet());
+ }
+
+ /**
+ * @param clsLdr classloader.
+ * @param name classname.
+ * @return true if class loaded by classloader, false if class not found.
+ */
+ private boolean classFound(ClassLoader clsLdr, String name) {
+ try {
+ clsLdr.loadClass(name);
+
+ return true;
+ }
+ catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ /** */
+ private static class MessageCountingCommunicationSpi extends TcpCommunicationSpi {
+ /** */
+ private static final AtomicInteger reqCnt = new AtomicInteger();
+
+ /** {@inheritDoc} */
+ @Override public void sendMessage(ClusterNode node,
+ Message msg,
+ IgniteInClosure<IgniteException> ackClosure
+ ) throws IgniteSpiException {
+ if (msg instanceof GridIoMessage && isDeploymentRequestMessage((GridIoMessage)msg))
+ reqCnt.incrementAndGet();
+
+ super.sendMessage(node, msg, ackClosure);
+ }
+
+ /**
+ * @return Number of deployment requests.
+ */
+ public static int deploymentRequestCount() {
+ return reqCnt.get();
+ }
+
+ /**
+ * Reset request counter.
+ */
+ public static void resetDeploymentRequestCounter() {
+ reqCnt.set(0);
+ }
+
+ /**
+ * Checks if it is a p2p deployment request message with test predicate resource.
+ *
+ * @param msg Message to check.
+ * @return {@code True} if this is a p2p message.
+ */
+ private boolean isDeploymentRequestMessage(GridIoMessage msg) {
+ try {
+ if (msg.message() instanceof GridDeploymentRequest) {
+ // rsrcName getter have only default access level. So, use reflection for access to field value.
+ GridDeploymentRequest req = (GridDeploymentRequest)msg.message();
+
+ Field f = GridDeploymentRequest.class.getDeclaredField("rsrcName");
+
+ f.setAccessible(true);
+
+ return f.get(req).equals(TEST_PREDICATE_RESOURCE_NAME);
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d40dcb3a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteP2PSelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteP2PSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteP2PSelfTestSuite.java
index 7218174..76b0aa0 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteP2PSelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteP2PSelfTestSuite.java
@@ -36,6 +36,7 @@ import org.apache.ignite.p2p.GridP2PSameClassLoaderSelfTest;
import org.apache.ignite.p2p.GridP2PTestTaskExecutionTest;
import org.apache.ignite.p2p.GridP2PTimeoutSelfTest;
import org.apache.ignite.p2p.GridP2PUndeploySelfTest;
+import org.apache.ignite.p2p.P2PScanQueryUndeployTest;
import org.apache.ignite.p2p.P2PStreamingClassLoaderTest;
import org.apache.ignite.p2p.SharedDeploymentTest;
import org.apache.ignite.testframework.GridTestUtils;
@@ -78,6 +79,7 @@ public class IgniteP2PSelfTestSuite extends TestSuite {
suite.addTest(new TestSuite(DeploymentClassLoaderCallableTest.class));
suite.addTest(new TestSuite(P2PStreamingClassLoaderTest.class));
suite.addTest(new TestSuite(SharedDeploymentTest.class));
+ suite.addTest(new TestSuite(P2PScanQueryUndeployTest.class));
GridTestUtils.addTestIfNeeded(suite, GridDeploymentMessageCountSelfTest.class, ignoredTests);
return suite;
http://git-wip-us.apache.org/repos/asf/ignite/blob/d40dcb3a/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/AlwaysTruePredicate.java
----------------------------------------------------------------------
diff --git a/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/AlwaysTruePredicate.java b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/AlwaysTruePredicate.java
new file mode 100644
index 0000000..3918f71
--- /dev/null
+++ b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/AlwaysTruePredicate.java
@@ -0,0 +1,30 @@
+/*
+ * 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.lang.IgniteBiPredicate;
+
+/**
+ *
+ */
+public class AlwaysTruePredicate implements IgniteBiPredicate<Object, Object> {
+ /** */
+ @Override public boolean apply(Object k, Object v) {
+ return new CacheDeploymentAlwaysTruePredicate().apply(k,v);
+ }
+}
\ No newline at end of file