blob: b7a3a1a966b0523a17fab3e738d6d0e651c0c1cd [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;
import static org.apache.geode.test.dunit.Host.getHost;
import static org.apache.geode.test.dunit.Invoke.invokeInEveryVM;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.apache.geode.cache.CacheTransactionManager;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.client.internal.LocatorTestBase;
import org.apache.geode.test.dunit.NetworkUtils;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
/**
* Client should NOT hang in tx commit when server does not define all regions.
*
* <pre>
* 1. Server side
* ServerA: creating only RegionA with replicated region and setting distributed-ack
* ServerB: creating only RegionB with replicated region and setting distributed-ack
* 2. Client side
* ClientTransactionA: put something and commit to RegionA with using transaction
* ClientTransactionB: put something and commit to RegionB with using transaction
*
* Start server processes
* (1) start ServerA
* (2) start ServerB
*
* Execute clients
* (1) execute ClientTransactionA -> you can finish it successfully.
* (2) execute ClientTransactionB -> no responses from ServerB while committing the transaction.
* Then if stopping ServerA process, then the response is back from ServerB.
* </pre>
*
* <p>
* TRAC #47667: Delay in Multi-transaction Committing for Replicated Regions with distributed-ack
* Scope
*
* <p>
* Better description of bug: Client hangs in tx commit when server does not define all regions.
* Underlying exception that caused the hang was:
*
* <pre>
* [severe 2013/05/15 17:53:07.037 PDT gemfire_2_1 <P2P message reader for mclaren(16125)<v1>:49192/33706 SHARED=true ORDERED=false UID=2> tid=0x31] Error deserializing message
* java.lang.IllegalArgumentException: Illegal initial capacity: -1
* at java.util.HashMap.<init>(HashMap.java:172)
* at java.util.HashMap.<init>(HashMap.java:199)
* at java.util.HashSet.<init>(HashSet.java:125)
* at com.gemstone.gemfire.internal.cache.TXRegionLockRequestImpl.readEntryKeySet(TXRegionLockRequestImpl.java:108)
* at com.gemstone.gemfire.internal.cache.TXRegionLockRequestImpl.fromData(TXRegionLockRequestImpl.java:89)
* at com.gemstone.gemfire.internal.cache.TXRegionLockRequestImpl.createFromData(TXRegionLockRequestImpl.java:135)
* at com.gemstone.gemfire.internal.cache.locks.TXLockBatch.fromData(TXLockBatch.java:111)
* at com.gemstone.gemfire.internal.DSFIDFactory.readTXLockBatch(DSFIDFactory.java:2474)
* at com.gemstone.gemfire.internal.DSFIDFactory.create(DSFIDFactory.java:726)
* at com.gemstone.gemfire.internal.InternalDataSerializer.basicReadObject(InternalDataSerializer.java:2632)
* at com.gemstone.gemfire.DataSerializer.readObject(DataSerializer.java:3217)
* at com.gemstone.gemfire.distributed.internal.locks.DLockRequestProcessor$DLockResponseMessage.fromData(DLockRequestProcessor.java:1228)
* at com.gemstone.gemfire.internal.DSFIDFactory.readDLockResponseMessage(DSFIDFactory.java:1325)
* at com.gemstone.gemfire.internal.DSFIDFactory.create(DSFIDFactory.java:235)
* at com.gemstone.gemfire.internal.InternalDataSerializer.readDSFID(InternalDataSerializer.java:2524)
* at com.gemstone.gemfire.internal.tcp.Connection.processNIOBuffer(Connection.java:3484)
* at com.gemstone.gemfire.internal.tcp.Connection.runNioReader(Connection.java:1794)
* at com.gemstone.gemfire.internal.tcp.Connection.run(Connection.java:1675)
* at java.lang.Thread.run(Thread.java:662)
* </pre>
*/
@SuppressWarnings("serial")
public class ClientTxCommitShouldNotHangRegressionTest extends LocatorTestBase {
private static ClientCache clientCache;
private String hostName;
private int locatorPort;
private String region1Name;
private String region2Name;
private VM client;
@Rule
public SerializableTestName testName = new SerializableTestName();
@Before
public void setUpTest() throws Exception {
VM locator = getHost(0).getVM(0);
VM server1 = getHost(0).getVM(1);
VM server2 = getHost(0).getVM(2);
client = getHost(0).getVM(3);
String uniqueName = getClass().getSimpleName() + "_" + testName.getMethodName();
region1Name = uniqueName + "_R1";
region2Name = uniqueName + "_R2";
hostName = NetworkUtils.getServerHostName();
locatorPort = locator.invoke("Start locator", () -> startLocator(hostName, ""));
String locators = getLocatorString(hostName, locatorPort);
server1.invoke("Start server",
() -> startBridgeServer(new String[] {region1Name}, locators, new String[] {region1Name}));
server2.invoke("Start server",
() -> startBridgeServer(new String[] {region2Name}, locators, new String[] {region2Name}));
client.invoke("Create client", () -> {
ClientCacheFactory ccf = new ClientCacheFactory();
ccf.addPoolLocator(hostName, locatorPort);
clientCache = ccf.create();
PoolManager.createFactory().addLocator(hostName, locatorPort).setServerGroup(region1Name)
.create(region1Name);
PoolManager.createFactory().addLocator(hostName, locatorPort).setServerGroup(region2Name)
.create(region2Name);
clientCache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
.setPoolName(region1Name).create(region1Name);
clientCache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
.setPoolName(region2Name).create(region2Name);
});
}
@After
public void tearDownTest() throws Exception {
disconnectAllFromDS();
invokeInEveryVM(() -> {
clientCache = null;
});
}
@Test
public void clientTxCommitShouldNotHangWhenServerDoesNotDefineAllRegions() {
client.invoke("insert data in transaction", () -> {
Region<Integer, String> region1 = clientCache.getRegion(region1Name);
Region<Integer, String> region2 = clientCache.getRegion(region2Name);
CacheTransactionManager transactionManager = clientCache.getCacheTransactionManager();
transactionManager.begin();
region1.put(1, "value1");
transactionManager.commit();
transactionManager.begin();
region2.put(2, "value2");
transactionManager.commit();
});
}
}