You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@geode.apache.org by "Eugene Nedzvetsky (JIRA)" <ji...@apache.org> on 2018/07/27 15:17:00 UTC
[jira] [Updated] (GEODE-5486) Two transactions with only read
operations produce CommitConflictException if property
gemfire.detectReadConflict=true
[ https://issues.apache.org/jira/browse/GEODE-5486?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Eugene Nedzvetsky updated GEODE-5486:
-------------------------------------
Attachment: TXJReadConflictTest.java
> 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
> Priority: Major
> Attachments: TXJReadConflictTest.java
>
>
> 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)