From b6cef4edfd87097580d2b56873cf911f4e4becba Mon Sep 17 00:00:00 2001 From: "masaki.yamakawa" Date: Tue, 30 Jan 2018 18:08:37 +0900 Subject: [PATCH 1/2] GEODE-4375: Fix problem that an exception occurs when transaction from CacheServer via Pool --- .../geode/internal/cache/TXCommitMessage.java | 6 +- ...BugTxCommitMessageDesiralizeDUnitTest.java | 619 ++++++++++++++++++ .../sanctionedDataSerializables.txt | 2 +- 3 files changed, 625 insertions(+), 2 deletions(-) create mode 100644 geode-core/src/test/java/org/apache/geode/internal/cache/BugTxCommitMessageDesiralizeDUnitTest.java diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java b/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java index 9b4cab23fe77..69f99ffba531 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java @@ -1384,7 +1384,11 @@ public void fromData(DataInput in) throws IOException, ClassNotFoundException { for (int i = 0; i < size; i++) { FarSideEntryOp entryOp = new FarSideEntryOp(); // shadowkey is not being sent to clients - entryOp.fromData(in, largeModCount, !this.msg.getDM().isLoner()); + LocalRegion region = getRegionByPath(msg.getDM(), + parentRegionPath != null ? parentRegionPath : regionPath); + boolean readShadowKey = + (region != null ? (region.getPoolName() == null) : !msg.getDM().isLoner()); + entryOp.fromData(in, largeModCount, readShadowKey); if (entryOp.versionTag != null && this.memberId != null) { entryOp.versionTag.setMemberID(this.memberId); } diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/BugTxCommitMessageDesiralizeDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/BugTxCommitMessageDesiralizeDUnitTest.java new file mode 100644 index 000000000000..cc1208301e3c --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/BugTxCommitMessageDesiralizeDUnitTest.java @@ -0,0 +1,619 @@ +/** + * 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; + +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.CacheTransactionManager; +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.EntryOperation; +import org.apache.geode.cache.PartitionAttributes; +import org.apache.geode.cache.PartitionAttributesFactory; +import org.apache.geode.cache.PartitionResolver; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionFactory; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.client.ClientCacheFactory; +import org.apache.geode.cache.client.ClientRegionFactory; +import org.apache.geode.cache.client.ClientRegionShortcut; +import org.apache.geode.cache.client.Pool; +import org.apache.geode.cache.client.PoolFactory; +import org.apache.geode.cache.client.PoolManager; +import org.apache.geode.cache.server.CacheServer; +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.internal.AvailablePort; +import org.apache.geode.internal.Version; +import org.apache.geode.test.dunit.Host; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase; +import org.apache.geode.test.junit.categories.DistributedTest; + +/** + * This test class tests the communication pattern of a transaction for replicate and partition + * region. There are five VMs that two CacheServers, CacheServer with Pool and two clients. The + * communicate of a transaction is the following three patterns. In addition, this test class also + * tests transactions from older version clients to check backwards compatibility.
+ *
    + *
  1. CacheServer (transaction)-> CacheServer
  2. + *
  3. Client (transaction)-> CacheServer
  4. + *
  5. Old version client (transaction)-> CacheServer
  6. + *
  7. CacheServer via Pool (transaction)-> CacheServer
  8. + *
+ */ +@Category(DistributedTest.class) +@SuppressWarnings("serial") +public class BugTxCommitMessageDesiralizeDUnitTest extends JUnit4DistributedTestCase { + + private static VM server1 = null; + private static VM server2 = null; + private static VM server3 = null; + private static VM client = null; + private static VM oldClient = null; + + private static GemFireCacheImpl cache; + + private static final String REPLICATE_REGION_NAME = + BugTxCommitMessageDesiralizeDUnitTest.class.getSimpleName() + "_ReplicateRegion"; + private static final String PARTITION_REGION_NAME = + BugTxCommitMessageDesiralizeDUnitTest.class.getSimpleName() + "_PartitionRegion"; + + private static String KEY1 = "KEY1"; + private static String KEY2 = "KEY2"; + + @Override + public final void postSetUp() throws Exception { + disconnectFromDS(); + Host host = Host.getHost(0); + server1 = host.getVM(0); // server + server2 = host.getVM(1); // server + server3 = host.getVM(2); // server with pool + client = host.getVM(3); // client + oldClient = host.getVM(4); // client old version + + int port1 = server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.createServerCache()); + int port2 = server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.createServerCache()); + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest + .createServerCacheWithPool(host.getHostName(), new Integer[] {port1, port2})); + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.createClientCache(host.getHostName(), + new Integer[] {port1, port2}, false)); + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest + .createClientCache(host.getHostName(), new Integer[] {port1, port2}, true)); + } + + @Override + public final void preTearDown() throws Exception { + closeCache(); + + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.closeCache()); + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.closeCache()); + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.closeCache()); + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.closeCache()); + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.closeCache()); + } + + public static void closeCache() throws Exception { + if (cache != null) { + cache.close(); + } + } + + @SuppressWarnings("deprecation") + public static int createServerCache() throws Exception { + Properties props = new Properties(); + BugTxCommitMessageDesiralizeDUnitTest test = new BugTxCommitMessageDesiralizeDUnitTest(); + DistributedSystem ds = test.getSystem(props); + ds.disconnect(); + cache = (GemFireCacheImpl) CacheFactory.create(test.getSystem()); + + RegionFactory rf1 = cache.createRegionFactory(RegionShortcut.REPLICATE); + rf1.create(REPLICATE_REGION_NAME); + + PartitionAttributesFactory paf2 = new PartitionAttributesFactory<>(); + PartitionAttributes pa2 = + paf2.setRedundantCopies(1).setPartitionResolver(new PartitionResolver() { + @Override + public Object getRoutingObject(EntryOperation opDetails) { + return opDetails.getKey().substring(0, 3); + } + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + @Override + public void close() {} + }).create(); + RegionFactory rf2 = + cache.createRegionFactory(RegionShortcut.PARTITION_REDUNDANT); + rf2.setPartitionAttributes(pa2); + rf2.create(PARTITION_REGION_NAME); + + CacheServer server = cache.addCacheServer(); + server.setPort(AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET)); + server.start(); + return server.getPort(); + } + + @SuppressWarnings("deprecation") + public static void createServerCacheWithPool(String hostName, Integer[] ports) throws Exception { + Properties props = new Properties(); + BugTxCommitMessageDesiralizeDUnitTest test = new BugTxCommitMessageDesiralizeDUnitTest(); + DistributedSystem ds = test.getSystem(props); + ds.disconnect(); + cache = (GemFireCacheImpl) CacheFactory.create(test.getSystem()); + + String poolName = "ClientPool"; + PoolFactory pf = PoolManager.createFactory().setSubscriptionEnabled(true); + for (int port : ports) { + pf.addServer(hostName, port); + } + Pool pool = pf.create(poolName); + + RegionFactory rf1 = cache.createRegionFactory(RegionShortcut.LOCAL); + rf1.setDataPolicy(DataPolicy.EMPTY); + rf1.setPoolName(pool.getName()); + Region region1 = rf1.create(REPLICATE_REGION_NAME); + region1.registerInterest("ALL_KEYS"); + + RegionFactory rf2 = cache.createRegionFactory(RegionShortcut.LOCAL); + rf2.setDataPolicy(DataPolicy.EMPTY); + rf2.setPoolName(pool.getName()); + Region region2 = rf2.create(PARTITION_REGION_NAME); + region2.registerInterest("ALL_KEYS"); + } + + @SuppressWarnings("deprecation") + public static void createClientCache(String hostName, Integer[] ports, boolean isOldVersion) + throws Exception { + Version version = null; + if (isOldVersion) { + version = Version.CURRENT; + setVersion("CURRENT", Version.GEODE_130); + } + + Properties props = new Properties(); + DistributedSystem ds = new BugTxCommitMessageDesiralizeDUnitTest().getSystem(props); + ds.disconnect(); + ClientCacheFactory ccf = new ClientCacheFactory(props); + ccf.setPoolSubscriptionEnabled(true); + for (int port : ports) { + ccf.addPoolServer(hostName, port); + } + cache = (GemFireCacheImpl) ccf.create(); + + ClientRegionFactory crf1 = + cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY); + Region region1 = crf1.create(REPLICATE_REGION_NAME); + region1.registerInterest("ALL_KEYS"); + + ClientRegionFactory crf2 = + cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY); + Region region2 = crf2.create(PARTITION_REGION_NAME); + region2.registerInterest("ALL_KEYS"); + + if (isOldVersion) { + setVersion("CURRENT", version); + } + } + + @SuppressWarnings("unchecked") + public static void doTxPuts(String regionName) throws Exception { + Region region = cache.getRegion(regionName); + + CacheTransactionManager txMngr = cache.getCacheTransactionManager(); + txMngr.begin(); + Integer value1 = region.get(KEY1); + if (value1 == null) { + value1 = 1; + } else { + value1++; + } + region.put(KEY1, value1); + + Integer value2 = region.get(KEY2); + if (value2 == null) { + value2 = 1000; + } else { + value2++; + } + region.put(KEY2, value2); + txMngr.commit(); + } + + @SuppressWarnings("unchecked") + public static void doTxPutsBoth(String regionNameReplicate, String regionNamePartition) + throws Exception { + Region regionReplicate = cache.getRegion(regionNameReplicate); + Region regionPartition = cache.getRegion(regionNamePartition); + + CacheTransactionManager txMngr = cache.getCacheTransactionManager(); + txMngr.begin(); + Integer valPart1 = regionPartition.get(KEY1); + if (valPart1 == null) { + valPart1 = 1500; + } else { + valPart1++; + } + regionPartition.put(KEY1, valPart1); + + Integer valPart2 = regionPartition.get(KEY2); + if (valPart2 == null) { + valPart2 = 2000; + } else { + valPart2++; + } + regionPartition.put(KEY2, valPart2); + + Integer valRepl1 = regionReplicate.get(KEY1); + if (valRepl1 == null) { + valRepl1 = 500; + } else { + valRepl1++; + } + regionReplicate.put(KEY1, valRepl1); + + Integer valRepl2 = regionReplicate.get(KEY2); + if (valRepl2 == null) { + valRepl2 = 1000; + } else { + valRepl2++; + } + regionReplicate.put(KEY2, valRepl2); + txMngr.commit(); + } + + @SuppressWarnings("unchecked") + public static List doGets(String regionName) throws Exception { + Region region = cache.getRegion(regionName); + + Integer value1 = region.get(KEY1); + Integer value2 = region.get(KEY2); + + return Arrays.asList(value1, value2); + } + + private static void setVersion(String field, Version value) throws Exception { + Field targetField = Version.class.getDeclaredField(field); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.set(targetField, + targetField.getModifiers() & ~Modifier.PRIVATE & ~Modifier.FINAL); + targetField.set(null, value); + } + + @Test + public void testServerToServerTxReplicate() throws Exception { + String regionName = REPLICATE_REGION_NAME; + + List beforeValues = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + } + + @Test + public void testClientToServerTxReplicate() throws Exception { + String regionName = REPLICATE_REGION_NAME; + + List beforeValues = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + assertThat(afterValues3, contains(expected1, expected2)); + } + + @Test + public void testOldClientToServerTxReplicate() throws Exception { + String regionName = REPLICATE_REGION_NAME; + + List beforeValues = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + assertThat(afterValues3, contains(expected1, expected2)); + } + + @Test + public void testServerToServerViaPoolTxReplicate() throws Exception { + String regionName = REPLICATE_REGION_NAME; + + List beforeValues = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + assertThat(afterValues3, contains(expected1, expected2)); + } + + @Test + public void testServerToServerTxPartition() throws Exception { + String regionName = PARTITION_REGION_NAME; + + List beforeValues = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + } + + @Test + public void testClientToServerTxPartition() throws Exception { + String regionName = PARTITION_REGION_NAME; + + List beforeValues = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + assertThat(afterValues3, contains(expected1, expected2)); + } + + @Test + public void testOldClientToServerTxPartition() throws Exception { + String regionName = PARTITION_REGION_NAME; + + List beforeValues = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + assertThat(afterValues3, contains(expected1, expected2)); + } + + @Test + public void testServerToServerViaPoolTxPartition() throws Exception { + String regionName = PARTITION_REGION_NAME; + + List beforeValues = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doTxPuts(regionName)); + List afterValues1 = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + List afterValues3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionName)); + + Integer expected1 = beforeValues.get(0) == null ? 1 : beforeValues.get(0) + 1; + Integer expected2 = beforeValues.get(1) == null ? 1000 : beforeValues.get(1) + 1000; + + assertThat(afterValues1, contains(expected1, expected2)); + assertThat(afterValues2, contains(expected1, expected2)); + assertThat(afterValues3, contains(expected1, expected2)); + } + + @Test + public void testServerToServerTxBoth() throws Exception { + String regionNameRepl = REPLICATE_REGION_NAME; + String regionNamePart = PARTITION_REGION_NAME; + + List beforeValuesRepl = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List beforeValuesPart = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + server1.invoke( + () -> BugTxCommitMessageDesiralizeDUnitTest.doTxPutsBoth(regionNameRepl, regionNamePart)); + List afterValuesRepl1 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesRepl2 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart1 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + List afterValuesPart2 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + + Integer expectedRepl1 = beforeValuesRepl.get(0) == null ? 500 : beforeValuesRepl.get(0) + 500; + Integer expectedRepl2 = beforeValuesRepl.get(1) == null ? 1000 : beforeValuesRepl.get(1) + 1000; + Integer expectedPart1 = beforeValuesPart.get(0) == null ? 1500 : beforeValuesPart.get(0) + 1500; + Integer expectedPart2 = beforeValuesPart.get(1) == null ? 2000 : beforeValuesPart.get(1) + 2000; + + assertThat(afterValuesRepl1, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesRepl2, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart1, contains(expectedPart1, expectedPart2)); + assertThat(afterValuesPart2, contains(expectedPart1, expectedPart2)); + } + + @Test + public void testClientToServerTxBoth() throws Exception { + String regionNameRepl = REPLICATE_REGION_NAME; + String regionNamePart = PARTITION_REGION_NAME; + + List beforeValuesRepl = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List beforeValuesPart = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + client.invoke( + () -> BugTxCommitMessageDesiralizeDUnitTest.doTxPutsBoth(regionNameRepl, regionNamePart)); + List afterValuesRepl1 = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart1 = + client.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + List afterValuesRepl2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + List afterValuesRepl3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + + Integer expectedRepl1 = beforeValuesRepl.get(0) == null ? 500 : beforeValuesRepl.get(0) + 500; + Integer expectedRepl2 = beforeValuesRepl.get(1) == null ? 1000 : beforeValuesRepl.get(1) + 1000; + Integer expectedPart1 = beforeValuesPart.get(0) == null ? 1500 : beforeValuesPart.get(0) + 1500; + Integer expectedPart2 = beforeValuesPart.get(1) == null ? 2000 : beforeValuesPart.get(1) + 2000; + + assertThat(afterValuesRepl1, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart1, contains(expectedPart1, expectedPart2)); + assertThat(afterValuesRepl2, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart2, contains(expectedPart1, expectedPart2)); + assertThat(afterValuesRepl3, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart3, contains(expectedPart1, expectedPart2)); + } + + @Test + public void testOldClientToServerTxBoth() throws Exception { + String regionNameRepl = REPLICATE_REGION_NAME; + String regionNamePart = PARTITION_REGION_NAME; + + List beforeValuesRepl = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List beforeValuesPart = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + oldClient.invoke( + () -> BugTxCommitMessageDesiralizeDUnitTest.doTxPutsBoth(regionNameRepl, regionNamePart)); + List afterValuesRepl1 = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart1 = + oldClient.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + List afterValuesRepl2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + List afterValuesRepl3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + + Integer expectedRepl1 = beforeValuesRepl.get(0) == null ? 500 : beforeValuesRepl.get(0) + 500; + Integer expectedRepl2 = beforeValuesRepl.get(1) == null ? 1000 : beforeValuesRepl.get(1) + 1000; + Integer expectedPart1 = beforeValuesPart.get(0) == null ? 1500 : beforeValuesPart.get(0) + 1500; + Integer expectedPart2 = beforeValuesPart.get(1) == null ? 2000 : beforeValuesPart.get(1) + 2000; + + assertThat(afterValuesRepl1, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart1, contains(expectedPart1, expectedPart2)); + assertThat(afterValuesRepl2, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart2, contains(expectedPart1, expectedPart2)); + assertThat(afterValuesRepl3, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart3, contains(expectedPart1, expectedPart2)); + } + + @Test + public void testServerToServerViaPoolTxBoth() throws Exception { + String regionNameRepl = REPLICATE_REGION_NAME; + String regionNamePart = PARTITION_REGION_NAME; + + List beforeValuesRepl = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List beforeValuesPart = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + server3.invoke( + () -> BugTxCommitMessageDesiralizeDUnitTest.doTxPutsBoth(regionNameRepl, regionNamePart)); + List afterValuesRepl1 = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart1 = + server3.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + List afterValuesRepl2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart2 = + server1.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + List afterValuesRepl3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNameRepl)); + List afterValuesPart3 = + server2.invoke(() -> BugTxCommitMessageDesiralizeDUnitTest.doGets(regionNamePart)); + + Integer expectedRepl1 = beforeValuesRepl.get(0) == null ? 500 : beforeValuesRepl.get(0) + 500; + Integer expectedRepl2 = beforeValuesRepl.get(1) == null ? 1000 : beforeValuesRepl.get(1) + 1000; + Integer expectedPart1 = beforeValuesPart.get(0) == null ? 1500 : beforeValuesPart.get(0) + 1500; + Integer expectedPart2 = beforeValuesPart.get(1) == null ? 2000 : beforeValuesPart.get(1) + 2000; + + assertThat(afterValuesRepl1, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart1, contains(expectedPart1, expectedPart2)); + assertThat(afterValuesRepl2, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart2, contains(expectedPart1, expectedPart2)); + assertThat(afterValuesRepl3, contains(expectedRepl1, expectedRepl2)); + assertThat(afterValuesPart3, contains(expectedPart1, expectedPart2)); + } +} diff --git a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt index 1c5a36d50457..9a2eee0cf225 100644 --- a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt +++ b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt @@ -1334,7 +1334,7 @@ fromData,16,2a2bb700042a2bb900050100b50002b1 toData,16,2a2bb700062b2ab40002b900070200b1 org/apache/geode/internal/cache/TXCommitMessage$RegionCommit,2 -fromData,181,2a2bb80058b5000b2a2bb80058b500202bb9005901003d1c9e009c2abb0053591cb70054b500512abb0053591cb70054b500552bb9005a01003e2a2bb8005bc0005cb5005d03360415041ca20069bb005e592ab7005f3a0519052b1d2ab40002b60060b9006101009a000704a7000403b600621905b80032c600162ab4005dc6000f1905b800322ab4005db600632ab400021905b600642ab400511905b4002cb60056572ab400551905b6005657840401a7ff97b1 +fromData,237,2a2bb8005ab5000b2a2bb8005ab5001f2bb9005b01003d1c9e00d42abb0055591cb70056b500532abb0055591cb70056b500572bb9005c01003e2a2bb8005dc0005eb5005f03360415041ca200a1bb0060592ab700613a052a2ab40002b600622ab4001fc6000a2ab4001fa700072ab4000bb6001e3a061906c600131906b60063c7000704a7001b03a700172ab40002b60062b9006401009a000704a7000403360719052b1d1507b600651905b80034c600162ab4005fc6000f1905b800342ab4005fb600662ab400021905b600672ab400531905b4002eb60058572ab400571905b6005857840401a7ff5fb1 toData,77,2ab40005c600152ab40005b600832ab400052bb60084a700362ab4000404a400292bb800854dbb0086591104002cb700874e2a2db700882a2db500052ab400052bb60084a700082a2bb70088b1 org/apache/geode/internal/cache/TXCommitMessage$RegionCommit$FarSideEntryOp,2 From 11f793845ffb1dbd4e420732d9e102b6fb43834d Mon Sep 17 00:00:00 2001 From: "masaki.yamakawa" Date: Wed, 31 Jan 2018 17:46:13 +0900 Subject: [PATCH 2/2] GEODE-4375: Fix problem that an exception occurs when transaction from CacheServer via Pool --- .../geode/internal/cache/TXCommitMessage.java | 20 ++++++++++++++----- .../sanctionedDataSerializables.txt | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java b/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java index 69f99ffba531..15ad7f6f5cdb 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/TXCommitMessage.java @@ -1384,11 +1384,7 @@ public void fromData(DataInput in) throws IOException, ClassNotFoundException { for (int i = 0; i < size; i++) { FarSideEntryOp entryOp = new FarSideEntryOp(); // shadowkey is not being sent to clients - LocalRegion region = getRegionByPath(msg.getDM(), - parentRegionPath != null ? parentRegionPath : regionPath); - boolean readShadowKey = - (region != null ? (region.getPoolName() == null) : !msg.getDM().isLoner()); - entryOp.fromData(in, largeModCount, readShadowKey); + entryOp.fromData(in, largeModCount, hasShadowKey(regionPath, parentRegionPath)); if (entryOp.versionTag != null && this.memberId != null) { entryOp.versionTag.setMemberID(this.memberId); } @@ -1399,6 +1395,20 @@ public void fromData(DataInput in) throws IOException, ClassNotFoundException { } } + private boolean hasShadowKey(String regionPath, String parentRegionPath) { + // in bucket region, regionPath is bucket name, use parentRegionPath + String path = parentRegionPath != null ? parentRegionPath : regionPath; + LocalRegion region = getRegionByPath(msg.getDM(), path); + + // default value is whether loner or not, region is null if destroyRegion executed + boolean readShadowKey = !msg.getDM().isLoner(); + if (region != null) { + // shadowkey is not being sent to clients + readShadowKey = region.getPoolName() == null; + } + return readShadowKey; + } + @Override public String toString() { StringBuilder result = new StringBuilder(64); diff --git a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt index 9a2eee0cf225..1a51bd02f83a 100644 --- a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt +++ b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt @@ -1334,7 +1334,7 @@ fromData,16,2a2bb700042a2bb900050100b50002b1 toData,16,2a2bb700062b2ab40002b900070200b1 org/apache/geode/internal/cache/TXCommitMessage$RegionCommit,2 -fromData,237,2a2bb8005ab5000b2a2bb8005ab5001f2bb9005b01003d1c9e00d42abb0055591cb70056b500532abb0055591cb70056b500572bb9005c01003e2a2bb8005dc0005eb5005f03360415041ca200a1bb0060592ab700613a052a2ab40002b600622ab4001fc6000a2ab4001fa700072ab4000bb6001e3a061906c600131906b60063c7000704a7001b03a700172ab40002b60062b9006401009a000704a7000403360719052b1d1507b600651905b80034c600162ab4005fc6000f1905b800342ab4005fb600662ab400021905b600672ab400531905b4002eb60058572ab400571905b6005857840401a7ff5fb1 +fromData,173,2a2bb8005ab5000b2a2bb8005ab5001f2bb9005b01003d1c9e00942abb0055591cb70056b500532abb0055591cb70056b500572bb9005c01003e2a2bb8005dc0005eb5005f03360415041ca20061bb0060592ab700613a0519052b1d2a2ab4000b2ab4001fb70062b600631905b80034c600162ab4005fc6000f1905b800342ab4005fb600642ab400021905b600652ab400531905b4002eb60058572ab400571905b6005857840401a7ff9fb1 toData,77,2ab40005c600152ab40005b600832ab400052bb60084a700362ab4000404a400292bb800854dbb0086591104002cb700874e2a2db700882a2db500052ab400052bb60084a700082a2bb70088b1 org/apache/geode/internal/cache/TXCommitMessage$RegionCommit$FarSideEntryOp,2