Index: modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOnCachesStopTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOnCachesStopTest.java (revision 78faf08f08d98bde4457600f1e4ee0c39af2c66b) +++ modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOnCachesStopTest.java (date 1597718184221) @@ -23,6 +23,12 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.CtNewMethod; +import javassist.NotFoundException; import javax.cache.CacheException; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; @@ -61,7 +67,7 @@ import org.junit.Test; import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC; -import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; +import static org.apache.ignite.transactions.TransactionIsolation.*; /** * @@ -161,6 +167,101 @@ runTxOnCacheStop(true); } + /** + * Case: stop cache in transaction load + * interfere with the work of parallel threads forcing them to cleanup context before using it + * @throws Exception If failed. + */ + @Test + public void testTxOnCacheStopWithClassTransformation() throws Exception { + classTransformation(); + + runTxOnCacheStop(false); + } + + /** + * Blocking to arrange processing in the desired sequence. + */ + public static CountDownLatch latch; + + /** + * adding code to classes + * hold + * CacheObject.finishUnmarshal() + * until completing + * GridCacheContext.cleanup() + * @throws NotFoundException + * @throws CannotCompileException + */ + private void classTransformation() throws NotFoundException, CannotCompileException { + ClassPool classPool = ClassPool.getDefault(); + { + CtClass binaryObjectImpl = classPool.get("org.apache.ignite.internal.processors.cache.KeyCacheObjectImpl"); + + CtMethod finishUnmarshalOld = binaryObjectImpl.getDeclaredMethod("finishUnmarshal"); + + finishUnmarshalOld.setName("finishUnmarshalOld"); + + CtMethod finishUnmarshal = CtNewMethod.copy(finishUnmarshalOld, "finishUnmarshal", binaryObjectImpl, null); + + finishUnmarshal.setBody("{\n" + + " if(org.apache.ignite.internal.processors.cache.transactions.TxOnCachesStopTest.latch != null){\n" + + " try {\n" + + " org.apache.ignite.internal.processors.cache.transactions.TxOnCachesStopTest.latch.await(2500L, java.util.concurrent.TimeUnit.MILLISECONDS);\n" + + " }\n" + + " catch (java.lang.Exception e){\n" + + " }\n" + + " }\n" + + " return finishUnmarshalOld($$);\n" + + "}"); + + binaryObjectImpl.addMethod(finishUnmarshal); + + binaryObjectImpl.toClass(getClass().getClassLoader(), null); + } + + { + CtClass gridCacheContext = classPool.get("org.apache.ignite.internal.processors.cache.GridCacheContext"); + + CtMethod cleanupOld = gridCacheContext.getDeclaredMethod("cleanup"); + + cleanupOld.setName("cleanupOld"); + + CtMethod cleanup = CtNewMethod.copy(cleanupOld, "cleanup", gridCacheContext, null); + + cleanup.setBody("{\n" + + " cleanupOld();\n" + + " if(org.apache.ignite.internal.processors.cache.transactions.TxOnCachesStopTest.latch != null) {\n" + + " org.apache.ignite.internal.processors.cache.transactions.TxOnCachesStopTest.latch.countDown();\n" + + " }\n" + + "}"); + + gridCacheContext.addMethod(cleanup); + + gridCacheContext.toClass(getClass().getClassLoader(), null); + } + + { + CtClass cacheObjectByteArrayImpl = classPool.get("org.apache.ignite.internal.processors.cache.CacheObjectByteArrayImpl"); + + CtMethod finishUnmarshalOld = cacheObjectByteArrayImpl.getDeclaredMethod("finishUnmarshal"); + + finishUnmarshalOld.setName("finishUnmarshalOld"); + + CtMethod finishUnmarshal = CtNewMethod.copy(finishUnmarshalOld, "finishUnmarshal", cacheObjectByteArrayImpl, null); + + finishUnmarshal.setBody("{\n" + + " if ($1 == null)\n" + + " org.junit.Assert.fail(\"ctx is null, what will cause the error NullPointerException\");\n" + + " finishUnmarshalOld($$);\n" + + "}"); + + cacheObjectByteArrayImpl.addMethod(finishUnmarshal); + + cacheObjectByteArrayImpl.toClass(getClass().getClassLoader(), null); + } + } + /** * @param block {@code True} To block GridNearTxPrepareRequest message. */ @@ -295,8 +396,12 @@ spi.stopBlock(); }); + latch = new CountDownLatch(1); + cache.destroy(); + latch = null; + f.get(); } catch (Exception e) {