blob: b730ad78d307bb94285b1812134b720908248a3d [file] [log] [blame]
/*
* 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.geode.internal.cache.execute;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.apache.logging.log4j.Logger;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.geode.cache.CacheTransactionManager;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.internal.cache.TXManagerImpl;
import org.apache.geode.internal.cache.TXStateProxyImpl;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.Invoke;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
import org.apache.geode.test.dunit.rules.DistributedRestoreSystemProperties;
@RunWith(JUnitParamsRunner.class)
@SuppressWarnings("serial")
public class PRSetOperationTXDUnitTest extends JUnit4CacheTestCase {
private static final Logger logger = LogService.getLogger();
private static final String REGION_NAME = "region1";
private Map<Long, String> testData;
private VM accessor = null;
private VM dataStore1 = null;
private VM dataStore2 = null;
private VM dataStore3 = null;
@Rule
public DistributedRestoreSystemProperties restoreSystemProperties =
new DistributedRestoreSystemProperties();
public PRSetOperationTXDUnitTest() {
super();
}
@Before
public void setup() {
testData = new HashMap<>();
testData.put(1L, "value1");
testData.put(2L, "value2");
testData.put(3L, "duplicateValue");
testData.put(4L, "duplicateValue");
}
@Override
public final void postSetUp() throws Exception {
disconnectAllFromDS(); // isolate this test from others to avoid periodic CacheExistsExceptions
Host host = Host.getHost(0);
dataStore1 = host.getVM(0);
dataStore2 = host.getVM(1);
dataStore3 = host.getVM(2);
accessor = host.getVM(3);
}
@Override
public final void preTearDownCacheTestCase() throws Exception {
Invoke.invokeInEveryVM(() -> verifyNoTxState());
}
@Test
@Parameters({"true", "false"})
public void testRegionKeysetWithTx(boolean disableSetOpToStartTx) throws Exception {
setupAndLoadRegion(disableSetOpToStartTx);
verifyRegionKeysetWithTx(disableSetOpToStartTx);
}
@Test
@Parameters({"true", "false"})
public void testRegionValuesWithTx(boolean disableSetOpToStartTx) throws Exception {
setupAndLoadRegion(disableSetOpToStartTx);
verifyRegionValuesWithTx(disableSetOpToStartTx);
}
@Test
@Parameters({"true", "false"})
public void testRegionEntriesWithTx(boolean disableSetOpToStartTx) throws Exception {
setupAndLoadRegion(disableSetOpToStartTx);
verifyRegionEntriesWithTx(disableSetOpToStartTx);
}
private void setupAndLoadRegion(boolean disableSetOpToStartTx) {
createRegion(disableSetOpToStartTx);
dataStore1.invoke(() -> loadRegion());
}
private void createRegion(boolean disableSetOpToStartTx) {
accessor.invoke(() -> createCache(disableSetOpToStartTx));
dataStore1.invoke(() -> createCache(disableSetOpToStartTx));
dataStore2.invoke(() -> createCache(disableSetOpToStartTx));
dataStore3.invoke(() -> createCache(disableSetOpToStartTx));
accessor.invoke(() -> createPR(true));
dataStore1.invoke(() -> createPR(false));
dataStore2.invoke(() -> createPR(false));
dataStore3.invoke(() -> createPR(false));
}
private void loadRegion() {
Region<Long, String> region = basicGetCache().getRegion(Region.SEPARATOR + REGION_NAME);
testData.forEach((k, v) -> region.put(k, v));
}
private void verifyRegionKeysetWithTx(boolean disableSetOpToStartTx) {
accessor.invoke(() -> verifyRegionKeysetWithTx(disableSetOpToStartTx, true));
dataStore1.invoke(() -> verifyRegionKeysetWithTx(disableSetOpToStartTx, false));
dataStore2.invoke(() -> verifyRegionKeysetWithTx(disableSetOpToStartTx, false));
dataStore3.invoke(() -> verifyRegionKeysetWithTx(disableSetOpToStartTx, false));
}
private void verifyRegionValuesWithTx(boolean disableSetOpToStartTx) {
accessor.invoke(() -> verifyRegionValuesWithTx(disableSetOpToStartTx, true));
dataStore1.invoke(() -> verifyRegionValuesWithTx(disableSetOpToStartTx, false));
dataStore2.invoke(() -> verifyRegionValuesWithTx(disableSetOpToStartTx, false));
dataStore3.invoke(() -> verifyRegionValuesWithTx(disableSetOpToStartTx, false));
}
private void verifyRegionEntriesWithTx(boolean disableSetOpToStartTx) {
accessor.invoke(() -> verifyRegionEntriesWithTx(disableSetOpToStartTx, true));
dataStore1.invoke(() -> verifyRegionEntriesWithTx(disableSetOpToStartTx, false));
dataStore2.invoke(() -> verifyRegionEntriesWithTx(disableSetOpToStartTx, false));
dataStore3.invoke(() -> verifyRegionEntriesWithTx(disableSetOpToStartTx, false));
}
private void verifyRegionKeysetWithTx(boolean disableSetOpToStartTx, boolean isAccessor) {
CacheTransactionManager txMgr = basicGetCache().getCacheTransactionManager();
Region<Long, String> region = basicGetCache().getRegion(Region.SEPARATOR + REGION_NAME);
try {
txMgr.begin();
Collection<Long> set = region.keySet();
set.forEach((key) -> assertTrue(testData.keySet().contains(key)));
} finally {
validateTXManager(disableSetOpToStartTx, isAccessor);
txMgr.rollback();
}
}
private void verifyRegionValuesWithTx(boolean disableSetOpToStartTx, boolean isAccessor) {
CacheTransactionManager txMgr = basicGetCache().getCacheTransactionManager();
Region<Long, String> region = basicGetCache().getRegion(Region.SEPARATOR + REGION_NAME);
try {
txMgr.begin();
Collection<String> set = region.values();
set.forEach((value) -> assertTrue(testData.values().contains(value)));
} finally {
validateTXManager(disableSetOpToStartTx, isAccessor);
txMgr.rollback();
}
}
private void verifyRegionEntriesWithTx(boolean disableSetOpToStartTx, boolean isAccessor) {
CacheTransactionManager txMgr = basicGetCache().getCacheTransactionManager();
Region<Long, String> region = basicGetCache().getRegion(Region.SEPARATOR + REGION_NAME);
try {
txMgr.begin();
Collection<Map.Entry<Long, String>> set = region.entrySet();
set.forEach((entry) -> {
assertTrue(testData.values().contains(entry.getValue()));
assertTrue(testData.keySet().contains(entry.getKey()));
});
} finally {
validateTXManager(disableSetOpToStartTx, isAccessor);
txMgr.rollback();
}
}
private void validateTXManager(boolean disableSetOpToStartTx, boolean isAccessor) {
assertNotNull(TXManagerImpl.getCurrentTXState());
if (disableSetOpToStartTx || isAccessor) {
assertFalse(((TXStateProxyImpl) TXManagerImpl.getCurrentTXState()).hasRealDeal());
} else {
assertTrue(((TXStateProxyImpl) TXManagerImpl.getCurrentTXState()).hasRealDeal());
}
}
private void verifyNoTxState() {
TXManagerImpl mgr = getCache().getTxManager();
assertEquals(0, mgr.hostedTransactionsInProgressForTest());
}
final String restoreSetOperationTransactionBehavior = "restoreSetOperationTransactionBehavior";
final String RESTORE_SET_OPERATION_PROPERTY =
(System.currentTimeMillis() % 2 == 0 ? DistributionConfig.GEMFIRE_PREFIX : "geode.")
+ restoreSetOperationTransactionBehavior;
private void createCache(boolean disableSetOpToStartTx) {
if (disableSetOpToStartTx) {
logger.info("setting system property {} to true ", RESTORE_SET_OPERATION_PROPERTY);
System.setProperty(RESTORE_SET_OPERATION_PROPERTY, "true");
}
getCache();
}
private void createPR(boolean isAccessor) {
basicGetCache().createRegionFactory(RegionShortcut.PARTITION)
.setPartitionAttributes(new PartitionAttributesFactory<Long, String>().setTotalNumBuckets(3)
.setLocalMaxMemory(isAccessor ? 0 : 1).create())
.create(REGION_NAME);
}
}