Eugene Nedzvetsky created GEODE-5486: ----------------------------------------
Summary: Two transactions with only read operations produce CommitConflictException if property gemfire.detectReadConflict=true Key: GEODE-5486 URL: https://issues.apache.org/jira/browse/GEODE-5486 Project: Geode Issue Type: Bug Components: transactions Reporter: Eugene Nedzvetsky Application was started with system property gemfire.detectReadConflict = true. Some transactions with only read operations(region#get, ....)were broken after that with an exception CommitConflictException: {code} java.util.concurrent.ExecutionException: org.apache.geode.cache.CommitConflictException: The key key1 in region /TXJReadConflictTest was being modified by another transaction locally. at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at org.apache.geode.TXJReadConflictTest.testDetectReadConflict(TXJReadConflictTest.java:131) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Caused by: org.apache.geode.cache.CommitConflictException: The key key1 in region /TXJReadConflictTest was being modified by another transaction locally. at org.apache.geode.internal.cache.TXReservationMgr.checkSetForConflict(TXReservationMgr.java:107) at org.apache.geode.internal.cache.TXReservationMgr.checkForConflict(TXReservationMgr.java:77) at org.apache.geode.internal.cache.TXReservationMgr.makeReservation(TXReservationMgr.java:56) at org.apache.geode.internal.cache.TXLockRequest.txLocalLock(TXLockRequest.java:151) at org.apache.geode.internal.cache.TXLockRequest.obtain(TXLockRequest.java:84) at org.apache.geode.internal.cache.TXState.reserveAndCheck(TXState.java:340) at org.apache.geode.internal.cache.TXState.commit(TXState.java:411) at org.apache.geode.internal.cache.TXStateProxyImpl.commit(TXStateProxyImpl.java:210) at org.apache.geode.internal.cache.TXManagerImpl.commit(TXManagerImpl.java:413) at org.apache.geode.TXJReadConflictTest.lambda$testDetectReadConflict$1(TXJReadConflictTest.java:126) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) {code} I reproduced this issue and created Integration test: {code} package org.apache.geode; /* * 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. */ import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; import static org.junit.Assert.fail; import java.util.Properties; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.locks.StampedLock; import org.apache.geode.cache.AttributesFactory; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheException; import org.apache.geode.cache.CacheFactory; import org.apache.geode.cache.CacheTransactionManager; import org.apache.geode.cache.Region; import org.apache.geode.cache.Scope; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.TXManagerImpl; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Tests basic detectReadConflict mode transaction functionality */ public class TXJReadConflictTest { private CacheTransactionManager txMgr; protected GemFireCacheImpl cache; protected Region<String, String> region; @Before public void setUpTXJUnitTest() throws Exception { System.setProperty("gemfire.detectReadConflicts", "true"); createCache(); } @After public void tearDownTXJUnitTest() { closeCache(); } private void closeCache() { if (this.cache != null) { if (this.txMgr != null) { try { this.txMgr.rollback(); } catch (IllegalStateException ignore) { } } this.region = null; this.txMgr = null; Cache c = this.cache; this.cache = null; c.close(); } } private void createCache() { Properties properties = new Properties(); properties.setProperty(MCAST_PORT, "0"); // loner this.cache = (GemFireCacheImpl) CacheFactory.create(DistributedSystem.connect(properties)); createRegion(); this.txMgr = this.cache.getCacheTransactionManager(); } private void createRegion() { AttributesFactory<String, String> attributesFactory = new AttributesFactory<>(); attributesFactory.setScope(Scope.DISTRIBUTED_NO_ACK); attributesFactory.setConcurrencyChecksEnabled(false); // test validation expects this behavior attributesFactory.setIndexMaintenanceSynchronous(true); this.region = this.cache.createRegion(getClass().getSimpleName(), attributesFactory.create()); } /** * Test that two transactions with only read operations don't produce CommitConflictException * This test fill some initial value on startup and after that create different threads with region#get operations * Sync two different threads commit time through lock */ @Test(/* no exception expected */) public void testDetectReadConflict() throws CacheException, ExecutionException, InterruptedException { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; //fill some initial key-value on start txMgrImpl.begin(); this.region.put("key1", "value1"); // non-tx txMgrImpl.commit(); ExecutorService executor = Executors.newFixedThreadPool(2); for (int i = 0; i < 20; i++) { final StampedLock lock = new StampedLock(); lock.asWriteLock().lock(); // Future<?> future1 = executor.submit(() -> { CacheTransactionManager txMgr2 = cache.getCacheTransactionManager(); txMgr2.begin(); region.get("key1"); // non-tx lock.asReadLock().lock(); txMgr2.commit(); }); Future<?> future2 = executor.submit(() -> { CacheTransactionManager txMgr3 = cache.getCacheTransactionManager(); txMgr3.begin(); region.get("key1"); // non-tx lock.asReadLock().lock(); txMgr3.commit(); }); pause(100); lock.asWriteLock().unlock(); future1.get(); future2.get(); } } private void pause(int msWait) { try { Thread.sleep(msWait); } catch (InterruptedException ignore) { fail("interrupted"); } } } {code} -- This message was sent by Atlassian JIRA (v7.6.3#76005)