From 422ba31a825b11b323126b1e6e3f3700a46a4ac4 Mon Sep 17 00:00:00 2001 From: Alberto Gomez Date: Fri, 17 Jun 2022 12:41:04 +0200 Subject: [PATCH] Squashed commit of the following: commit 4ce6664631be9d371df66cddca656c19ec332762 Author: Alberto Gomez Date: Tue Dec 14 19:30:37 2021 +0100 Fix tests commit 77db403d47716562690242d805916225c50b9e8d Author: Alberto Gomez Date: Tue Dec 14 18:43:41 2021 +0100 Added exceptions to public API changes commit 8c2f77d71f618c2fd7f31088233b6a24539fd4f4 Author: Alberto Gomez Date: Tue Dec 14 17:52:24 2021 +0100 Use --type=TxGroupingParallelGatewaySender... as suggested in jbarrett's review commit cbe859d7a676d1a63c63bfd05cb8269f32f1d036 Author: Alberto Gomez Date: Mon Dec 13 12:36:50 2021 +0100 remove() refactored as suggested on jbarrett's review commit 43194d07d417d1b954b682604389a0da7d4c4ec5 Author: Alberto Gomez Date: Thu Dec 2 06:52:38 2021 +0100 Updated with Kirk's first review comments commit 0c3d8141ecf3fd8b477d8c37e09b46e2f4dc96a2 Author: Alberto Gomez Date: Fri Nov 5 08:16:10 2021 +0100 MODULE: Add gfsh create tx-grouping gw-sender cases. commit a7416a386ef32fc6a5ffb0797b276947c6f84f53 Author: Alberto Gomez Date: Fri Nov 5 08:15:46 2021 +0100 MODULE: Do not allow changing group-transaction-events commit 74f9274ce8c1e248353114a3d44ab0a555998d66 Author: Alberto Gomez Date: Fri Nov 5 08:15:28 2021 +0100 MODULE: Fix some GatewaySenderFactoryImpl tests commit 1959233c9a709ca8c95cea830dabd6249aeb5700 Author: Alberto Gomez Date: Fri Nov 5 08:13:54 2021 +0100 MODULE: Move remaining tx-grouping functionality and DUnit tests commit 5aa6bc7bc25d3f7d2f20d7b2ab9b31d40aacaedc Author: Jacob Barrett Date: Wed Oct 13 19:50:56 2021 -0700 MODULE: Move tests commit 07884e81bed83b8d4a4a7394636428373977b93c Author: Jacob Barrett Date: Wed Oct 13 19:24:12 2021 -0700 MODULE: ServiceLoader commit 0be467b0679cd10d77846ca530d7a1457acd99e8 Author: Jacob Barrett Date: Wed Oct 13 16:31:02 2021 -0700 MODULE: Stupid simple module. commit 477a823c7a68d6235ed1e068df04dfba0f1c1e26 Author: Jacob Barrett Date: Wed Oct 13 16:08:08 2021 -0700 MODULE: Remove AbstractGatwaySender.mustGroupTransactionEvents() commit f7c0d21921fd3045a7db1d46a9bd7bbeb119dfff Author: Jacob Barrett Date: Wed Oct 13 14:14:38 2021 -0700 MODULE: Create TX grouping sender impls. commit 35b072e07ff3335a437d10a4d16352801d10cf9d Author: Jacob Barrett Date: Wed Oct 13 14:01:04 2021 -0700 MODULE: Extract out TX grouping factories. commit 7a3d45cc89847312ee003dfc62eceaed642a108f Author: Jacob Barrett Date: Wed Oct 13 13:19:15 2021 -0700 MODULE: Split out some factories. commit ae74a4204a151464f58732106aa043c17e1d5486 Author: Jacob Barrett Date: Thu Sep 30 15:24:56 2021 -0700 MODULE: Extract interface for GatewaySenderAttributes. commit 8c2d23e2bf81334fa2957107e0dbf3e206fb47be Author: Jacob Barrett Date: Thu Sep 30 17:22:04 2021 -0700 GEODE-6588: Cleanup GatewaySenderFactoryImpl commit 2457963f4921afee694027bba901c0aafac3df85 Author: Jacob Barrett Date: Thu Sep 30 16:07:40 2021 -0700 GEODE-6588: Cleanup AbstractGatewaySender commit 042013dd3531f02ecafac856023b4a6ea4a95a6f Author: Jacob Barrett Date: Thu Sep 30 14:54:03 2021 -0700 GEODE-6588: Cleanup GatewaySenderAttributes --- .../src/test/resources/expected-pom.xml | 6 + .../main/resources/japicmp_exceptions.json | 8 +- .../SerialAsyncEventQueueImplJUnitTest.java | 6 +- .../internal/AsyncEventQueueFactoryImpl.java | 9 +- .../internal/ParallelAsyncEventQueueImpl.java | 6 + .../internal/SerialAsyncEventQueueImpl.java | 5 + .../cache/configuration/CacheConfig.java | 44 +- .../apache/geode/cache/wan/GatewaySender.java | 31 +- .../geode/cache/wan/GatewaySenderFactory.java | 5 +- .../cache/wan/AbstractGatewaySender.java | 245 +++---- .../cache/wan/GatewaySenderAttributes.java | 313 ++------- .../wan/GatewaySenderAttributesImpl.java | 363 +++++++++++ .../wan/InternalGatewaySenderFactory.java | 10 - .../wan/MutableGatewaySenderAttributes.java | 26 + .../ParallelGatewaySenderEventProcessor.java | 13 +- .../parallel/ParallelGatewaySenderQueue.java | 146 +---- .../SerialGatewaySenderEventProcessor.java | 13 +- .../wan/serial/SerialGatewaySenderQueue.java | 241 ++----- .../ParallelAsyncEventQueueCreation.java | 12 +- .../SerialAsyncEventQueueCreation.java | 12 +- .../internal/lang/SystemPropertyHelper.java | 7 - .../geode/management/GatewaySenderMXBean.java | 7 + .../internal/beans/GatewaySenderMBean.java | 6 + .../beans/GatewaySenderMBeanBridge.java | 4 + .../management/internal/i18n/CliStrings.java | 9 +- .../ParallelAsyncEventQueueImplTest.java | 22 +- .../SerialAsyncEventQueueImplTest.java | 10 +- .../cache/BucketRegionQueueJUnitTest.java | 8 +- .../ParallelGatewaySenderQueueJUnitTest.java | 72 +-- .../SerialGatewaySenderQueueJUnitTest.java | 135 ---- .../commands/AlterGatewaySenderCommand.java | 15 +- .../commands/CreateGatewaySenderCommand.java | 12 +- .../cli/commands/ListGatewayCommand.java | 3 +- .../functions/AlterGatewaySenderFunction.java | 6 - .../GatewaySenderCreateFunction.java | 12 +- .../functions/GatewaySenderFunctionArgs.java | 12 +- .../sanctioned-geode-gfsh-serializables.txt | 2 +- .../CreateGatewaySenderCommandTest.java | 3 +- geode-wan-txgrouping/build.gradle | 55 ++ .../txgrouping/TxGroupingBaseDUnitTest.java | 570 ++++++++++++++++ .../TxGroupingPartitionedRegionDUnitTest.java | 114 ++++ ...reateTxGroupingGatewaySenderDUnitTest.java | 109 ++++ .../parallel/TxGroupingParallelDUnitTest.java | 451 +++++++++++++ .../serial/TxGroupingSerialDUnitTest.java | 346 ++++++++++ .../WanTxGroupingConfigurationJUnitTest.java | 93 +++ .../CommonTxGroupingGatewaySenderFactory.java | 36 ++ .../txgrouping/TxGroupingGatewaySender.java | 26 + .../TxGroupingGatewaySenderProperties.java | 85 +++ ...GroupingParallelGatewaySenderCreation.java | 41 ++ .../TxGroupingParallelGatewaySenderImpl.java | 85 +++ .../TxGroupingParallelGatewaySenderQueue.java | 191 ++++++ ...upingParallelGatewaySenderTypeFactory.java | 56 ++ ...ntParallelGatewaySenderEventProcessor.java | 42 ++ ...teParallelGatewaySenderEventProcessor.java | 46 ++ ...rentSerialGatewaySenderEventProcessor.java | 46 ++ ...moteSerialGatewaySenderEventProcessor.java | 43 ++ ...TxGroupingSerialGatewaySenderCreation.java | 41 ++ .../TxGroupingSerialGatewaySenderImpl.java | 91 +++ .../TxGroupingSerialGatewaySenderQueue.java | 240 +++++++ ...roupingSerialGatewaySenderTypeFactory.java | 68 ++ ...ache.wan.internal.GatewaySenderTypeFactory | 17 + ...ngParallelGatewaySenderQueueJUnitTest.java | 242 +++++++ ...gParallelGatewaySenderTypeFactoryTest.java | 52 ++ ...pingSerialGatewaySenderQueueJUnitTest.java | 223 +++++++ ...ingSerialGatewaySenderTypeFactoryTest.java | 69 ++ .../src/test/resources/expected-pom.xml | 80 +++ geode-wan/build.gradle | 1 - .../cache/CacheXml70GatewayDUnitTest.java | 4 +- .../geode/internal/cache/wan/WANTestBase.java | 166 +---- ...atewaySenderOperationsDistributedTest.java | 73 --- .../ParallelWANPropagationDUnitTest.java | 114 ---- .../ParallelWANStatsDistributedTest.java | 612 +----------------- ...GatewaySenderAlterOperationsDUnitTest.java | 40 -- ...alGatewaySenderEventListenerDUnitTest.java | 381 ----------- ...ropagation_PartitionedRegionDUnitTest.java | 115 ---- .../serial/SerialWANStatsDistributedTest.java | 456 ------------- .../AlterGatewaySenderCommandDUnitTest.java | 10 +- ...eDestroyGatewaySenderCommandDUnitTest.java | 5 +- .../wan/misc/WANConfigurationJUnitTest.java | 41 +- .../internal/GatewaySenderFactoryImpl.java | 213 +++--- .../internal/GatewaySenderTypeFactory.java | 40 ++ .../ParallelGatewaySenderCreation.java | 14 +- .../parallel/ParallelGatewaySenderImpl.java | 18 +- .../ParallelGatewaySenderTypeFactory.java | 61 ++ ...ntParallelGatewaySenderEventProcessor.java | 14 +- ...teParallelGatewaySenderEventProcessor.java | 10 +- ...rentSerialGatewaySenderEventProcessor.java | 2 +- .../serial}/SerialGatewaySenderCreation.java | 9 +- .../serial/SerialGatewaySenderImpl.java | 26 +- .../SerialGatewaySenderTypeFactory.java | 66 ++ ...ache.wan.internal.GatewaySenderTypeFactory | 17 + .../GatewaySenderFactoryImplTest.java | 104 +++ .../ParallelGatewaySenderImplTest.java | 31 +- .../serial/SerialGatewaySenderImplTest.java | 15 +- .../SerialGatewaySenderTypeFactoryTest.java | 84 +++ settings.gradle | 1 + 96 files changed, 4917 insertions(+), 3243 deletions(-) create mode 100644 geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributesImpl.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/cache/wan/MutableGatewaySenderAttributes.java create mode 100644 geode-wan-txgrouping/build.gradle create mode 100644 geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingBaseDUnitTest.java create mode 100644 geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingPartitionedRegionDUnitTest.java create mode 100644 geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/cli/commands/CreateTxGroupingGatewaySenderDUnitTest.java create mode 100644 geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/parallel/TxGroupingParallelDUnitTest.java create mode 100644 geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/serial/TxGroupingSerialDUnitTest.java create mode 100644 geode-wan-txgrouping/src/integrationTest/java/org/apache/geode/internal/cache/wan/txgrouping/WanTxGroupingConfigurationJUnitTest.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/CommonTxGroupingGatewaySenderFactory.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySender.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySenderProperties.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderCreation.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderImpl.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueue.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactory.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteConcurrentParallelGatewaySenderEventProcessor.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteParallelGatewaySenderEventProcessor.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteConcurrentSerialGatewaySenderEventProcessor.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteSerialGatewaySenderEventProcessor.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderCreation.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderImpl.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueue.java create mode 100644 geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactory.java create mode 100644 geode-wan-txgrouping/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory create mode 100644 geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueueJUnitTest.java create mode 100644 geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactoryTest.java create mode 100644 geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueueJUnitTest.java create mode 100644 geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactoryTest.java create mode 100644 geode-wan-txgrouping/src/test/resources/expected-pom.xml delete mode 100644 geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventListenerDUnitTest.java create mode 100644 geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderTypeFactory.java rename {geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache => geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel}/ParallelGatewaySenderCreation.java (92%) create mode 100644 geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderTypeFactory.java rename {geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache => geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial}/SerialGatewaySenderCreation.java (94%) create mode 100644 geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactory.java create mode 100644 geode-wan/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory create mode 100644 geode-wan/src/test/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImplTest.java create mode 100644 geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactoryTest.java diff --git a/boms/geode-all-bom/src/test/resources/expected-pom.xml b/boms/geode-all-bom/src/test/resources/expected-pom.xml index f16020b7b6b5..4058d98cc289 100644 --- a/boms/geode-all-bom/src/test/resources/expected-pom.xml +++ b/boms/geode-all-bom/src/test/resources/expected-pom.xml @@ -876,6 +876,12 @@ ${version} compile + + org.apache.geode + geode-wan-txgrouping + ${version} + compile + org.apache.geode geode-web diff --git a/build-tools/geode-japicmp/src/main/resources/japicmp_exceptions.json b/build-tools/geode-japicmp/src/main/resources/japicmp_exceptions.json index 0fc957cc4e2d..94b20aea9f7d 100755 --- a/build-tools/geode-japicmp/src/main/resources/japicmp_exceptions.json +++ b/build-tools/geode-japicmp/src/main/resources/japicmp_exceptions.json @@ -9,5 +9,11 @@ "Method org.apache.geode.cache.query.IndexStatistics.getReadLockCountLong()": "Added new methods.", "Method org.apache.geode.management.MemberMXBean.getOffHeapFragments()": "Added new stat", "Method org.apache.geode.management.MemberMXBean.getOffHeapFreedChunks()": "Added new stat", - "Method org.apache.geode.management.MemberMXBean.getOffHeapLargestFragment()": "Added new stat" + "Method org.apache.geode.management.MemberMXBean.getOffHeapLargestFragment()": "Added new stat", + "Class org.apache.geode.cache.wan.GatewaySender":"Added to support new types of gatewaysenders", + "Method org.apache.geode.cache.wan.GatewaySender.getType()":"Added to support new types of gatewaysenders", + "Class org.apache.geode.cache.wan.GatewaySenderFactory":"Added to support new types of gatewaysenders", + "Method org.apache.geode.cache.wan.GatewaySenderFactory.setType(java.lang.String)":"Added to support new types of gatewaysenders", + "Class org.apache.geode.management.GatewaySenderMXBean":"Added to support new types of gatewaysenders", + "Method org.apache.geode.management.GatewaySenderMXBean.getType()":"Added to support new types of gatewaysenders" } diff --git a/geode-core/src/integrationTest/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplJUnitTest.java index 1adae4f07485..43f208fda456 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplJUnitTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplJUnitTest.java @@ -24,7 +24,7 @@ import org.apache.geode.cache.CacheFactory; import org.apache.geode.internal.cache.InternalCache; -import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributesImpl; import org.apache.geode.test.junit.categories.AEQTest; @Category({AEQTest.class}) @@ -55,7 +55,7 @@ public void tearDown() { @Test public void testStopClearsStats() { - GatewaySenderAttributes attrs = new GatewaySenderAttributes(); + GatewaySenderAttributesImpl attrs = new GatewaySenderAttributesImpl(); String tempId = AsyncEventQueueImpl.ASYNC_EVENT_QUEUE_PREFIX + "id"; attrs.setId(tempId); SerialAsyncEventQueueImpl queue = new SerialAsyncEventQueueImpl(cache, @@ -81,7 +81,7 @@ public void testStopClearsStats() { @Test public void testStopStart() { - GatewaySenderAttributes attrs = new GatewaySenderAttributes(); + GatewaySenderAttributesImpl attrs = new GatewaySenderAttributesImpl(); String tempId = AsyncEventQueueImpl.ASYNC_EVENT_QUEUE_PREFIX + "id"; attrs.setId(tempId); SerialAsyncEventQueueImpl queue = new SerialAsyncEventQueueImpl(cache, diff --git a/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/AsyncEventQueueFactoryImpl.java b/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/AsyncEventQueueFactoryImpl.java index 700cc4baeff9..f64557782fe9 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/AsyncEventQueueFactoryImpl.java +++ b/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/AsyncEventQueueFactoryImpl.java @@ -28,7 +28,7 @@ import org.apache.geode.cache.wan.GatewaySender.OrderPolicy; import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.internal.cache.wan.AsyncEventQueueConfigurationException; -import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributesImpl; import org.apache.geode.internal.cache.wan.InternalGatewaySender; import org.apache.geode.internal.cache.xmlcache.AsyncEventQueueCreation; import org.apache.geode.internal.cache.xmlcache.CacheCreation; @@ -53,13 +53,14 @@ public class AsyncEventQueueFactoryImpl implements AsyncEventQueueFactory { * Used internally to pass the attributes from this factory to the real GatewaySender it is * creating. */ - private final GatewaySenderAttributes gatewaySenderAttributes; + private final GatewaySenderAttributesImpl gatewaySenderAttributes; public AsyncEventQueueFactoryImpl(InternalCache cache) { - this(cache, new GatewaySenderAttributes(), DEFAULT_BATCH_TIME_INTERVAL); + this(cache, new GatewaySenderAttributesImpl(), DEFAULT_BATCH_TIME_INTERVAL); } - AsyncEventQueueFactoryImpl(InternalCache cache, GatewaySenderAttributes gatewaySenderAttributes, + AsyncEventQueueFactoryImpl(InternalCache cache, + GatewaySenderAttributesImpl gatewaySenderAttributes, int batchTimeInterval) { this.cache = cache; this.gatewaySenderAttributes = gatewaySenderAttributes; diff --git a/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImpl.java b/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImpl.java index 4afb51d8724e..662649f70cd7 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImpl.java +++ b/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImpl.java @@ -210,6 +210,11 @@ public void setModifiedEventId(EntryEventImpl clonedEvent) { clonedEvent.setEventId(newEventId); } + @Override + public String getType() { + return "ParallelAsyncEventQueue"; + } + private ThreadsMonitoring getThreadMonitorObj() { DistributionManager distributionManager = cache.getDistributionManager(); if (distributionManager != null) { @@ -218,4 +223,5 @@ private ThreadsMonitoring getThreadMonitorObj() { return null; } } + } diff --git a/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImpl.java b/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImpl.java index 1713feff76aa..b335b1511779 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImpl.java +++ b/geode-core/src/main/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImpl.java @@ -264,6 +264,11 @@ public void setModifiedEventId(EntryEventImpl clonedEvent) { clonedEvent.setEventId(newEventId); } + @Override + public String getType() { + return "SerialAsyncEventQueue"; + } + private ThreadsMonitoring getThreadMonitorObj() { DistributionManager distributionManager = cache.getDistributionManager(); if (distributionManager != null) { diff --git a/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java b/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java index 1176090e2be5..06955a807424 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java +++ b/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java @@ -2706,6 +2706,7 @@ public void setOverflowDirectory(String value) { * <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="remote-distributed-system-id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="parallel" type="{http://www.w3.org/2001/XMLSchema}boolean" /> + * <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="manual-start" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="socket-buffer-size" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="socket-read-timeout" type="{http://www.w3.org/2001/XMLSchema}string" /> @@ -2746,6 +2747,8 @@ public static class GatewaySender { protected String remoteDistributedSystemId; @XmlAttribute(name = "parallel") protected Boolean parallel; + @XmlAttribute(name = "type") + protected String type; @XmlAttribute(name = "manual-start") protected Boolean manualStart; @XmlAttribute(name = "socket-buffer-size") @@ -2913,11 +2916,26 @@ public void setRemoteDistributedSystemId(String value) { remoteDistributedSystemId = value; } + /** + * Gets the value of the mustGroupTransactionEvents property. + * + * possible object is + * {@link Boolean } + * + * @return the value of the property. + */ public Boolean mustGroupTransactionEvents() { return groupTransactionEvents; } - + /** + * Sets the value of the groupTransactionsEvent property. + * + * allowed object is + * {@link Boolean } + * + * @param value the value for the property. + */ public void setGroupTransactionEvents(Boolean value) { groupTransactionEvents = value; } @@ -2946,6 +2964,30 @@ public void setParallel(Boolean value) { parallel = value; } + /** + * Gets the value of the type property. + * + * possible object is + * {@link String } + * + * @return the type. + */ + public String getType() { + return type; + } + + /** + * Sets the value of the type property. + * + * allowed object is + * {@link String } + * + * @param value the type. + */ + public void setType(String value) { + this.type = value; + } + /** * Gets the value of the manualStart property. * diff --git a/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySender.java b/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySender.java index 7117f4621e51..4694ee967c6e 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySender.java +++ b/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySender.java @@ -17,8 +17,6 @@ import java.util.List; import org.apache.geode.annotations.Immutable; -import org.apache.geode.internal.lang.SystemProperty; -import org.apache.geode.internal.lang.SystemPropertyHelper; import org.apache.geode.util.internal.GeodeGlossary; /** @@ -155,32 +153,6 @@ public interface GatewaySender { int CONNECTION_RETRY_INTERVAL = Integer .getInteger(GeodeGlossary.GEMFIRE_PREFIX + "gateway-connection-retry-interval", 1000); - /** - * Number of times to retry to get events for a transaction from the gateway sender queue when - * group-transaction-events is set to true. - * When group-transaction-events is set to true and a batch ready to be sent does not contain - * all the events for all the transactions to which the events belong, the gateway sender will try - * to get the missing events of the transactions from the queue to add them to the batch - * before sending it. - * If the missing events are not in the queue when the gateway sender tries to get them - * it will retry for a maximum of times equal to the value set in this parameter before - * delivering the batch without the missing events and logging an error. - * Setting this parameter to a very low value could cause that under heavy load and - * group-transaction-events set to true, batches are sent with incomplete transactions. Setting it - * to a high value could cause that under heavy load and group-transaction-events set to true, - * batches are held for some time before being sent. - */ - int GET_TRANSACTION_EVENTS_FROM_QUEUE_RETRIES = - Integer.getInteger(GeodeGlossary.GEMFIRE_PREFIX + "get-transaction-events-from-queue-retries", - 10); - /** - * Milliseconds to wait before retrying to get events for a transaction from the - * gateway sender queue when group-transaction-events is true. - */ - int GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS = - SystemProperty.getProductIntegerProperty( - SystemPropertyHelper.GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS).orElse(1); - /** * The order policy. This enum is applicable only when concurrency-level is > 1. * @@ -423,10 +395,13 @@ enum OrderPolicy { */ boolean isParallel(); + String getType(); + /** * Returns groupTransactionEvents boolean property for this GatewaySender. * * @return groupTransactionEvents boolean property for this GatewaySender + * @deprecated use {@link #getType()}. * */ boolean mustGroupTransactionEvents(); diff --git a/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySenderFactory.java b/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySenderFactory.java index e4ed0bb31c6c..5c148d1f988b 100644 --- a/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySenderFactory.java +++ b/geode-core/src/main/java/org/apache/geode/cache/wan/GatewaySenderFactory.java @@ -51,6 +51,8 @@ public interface GatewaySenderFactory { */ GatewaySenderFactory setGroupTransactionEvents(boolean groupTransactionEvents); + GatewaySenderFactory setType(String type); + /** * Adds a GatewayEventFilter * @@ -212,7 +214,8 @@ public interface GatewaySenderFactory { * @param filter The GatewayEventSubstitutionFilter * @return this factory */ - GatewaySenderFactory setGatewayEventSubstitutionFilter(GatewayEventSubstitutionFilter filter); + GatewaySenderFactory setGatewayEventSubstitutionFilter( + GatewayEventSubstitutionFilter filter); /** * If true, receiver member id is checked by all dispatcher threads when the connection is diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/AbstractGatewaySender.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/AbstractGatewaySender.java index e5fa44a83e27..0408f02e93ff 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/AbstractGatewaySender.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/AbstractGatewaySender.java @@ -15,6 +15,7 @@ package org.apache.geode.internal.cache.wan; import static org.apache.geode.internal.statistics.StatisticsClockFactory.disabledClock; +import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast; import java.io.IOException; import java.util.ArrayList; @@ -28,6 +29,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.apache.geode.CancelCriterion; import org.apache.geode.CancelException; @@ -101,8 +103,6 @@ public abstract class AbstractGatewaySender implements InternalGatewaySender, Di protected int remoteDSId; - protected String locName; - protected int socketBufferSize; protected int socketReadTimeout; @@ -121,14 +121,11 @@ public abstract class AbstractGatewaySender implements InternalGatewaySender, Di protected volatile int alertThreshold; + @Deprecated protected boolean manualStart; protected boolean isParallel; - protected boolean groupTransactionEvents; - - protected int retriesToGetTransactionEventsFromQueue; - protected boolean isForInternalUse; protected boolean isDiskSynchronous; @@ -143,7 +140,7 @@ public abstract class AbstractGatewaySender implements InternalGatewaySender, Di protected boolean forwardExpirationDestroy; - protected GatewayEventSubstitutionFilter substitutionFilter; + protected GatewayEventSubstitutionFilter substitutionFilter; protected LocatorDiscoveryCallback locatorDiscoveryCallback; @@ -176,7 +173,7 @@ public abstract class AbstractGatewaySender implements InternalGatewaySender, Di private String expectedReceiverUniqueId = ""; - protected Object queuedEventsSync = new Object(); + protected final Object queuedEventsSync = new Object(); protected volatile boolean enqueuedAllTempQueueEvents = false; @@ -196,17 +193,16 @@ public abstract class AbstractGatewaySender implements InternalGatewaySender, Di Integer.getInteger("GatewaySender.QUEUE_SIZE_THRESHOLD", 5000); @MutableForTesting - public static int TOKEN_TIMEOUT = - Integer.getInteger("GatewaySender.TOKEN_TIMEOUT", 120000); + public static int TOKEN_TIMEOUT = Integer.getInteger("GatewaySender.TOKEN_TIMEOUT", 120000); /** - * The name of the DistributedLockService used when accessing the GatewaySender's meta data + * The name of the DistributedLockService used when accessing the GatewaySender's metadata * region. */ public static final String LOCK_SERVICE_NAME = "gatewayEventIdIndexMetaData_lockService"; /** - * The name of the GatewaySender's meta data region. + * The name of the GatewaySender's metadata region. */ protected static final String META_DATA_REGION_NAME = "gatewayEventIdIndexMetaData"; @@ -255,10 +251,8 @@ public AbstractGatewaySender(InternalCache cache, StatisticsClock statisticsCloc isConflation = attrs.isBatchConflationEnabled(); isPersistence = attrs.isPersistenceEnabled(); alertThreshold = attrs.getAlertThreshold(); - manualStart = attrs.isManualStart(); + copyDeprecatedAttributes(attrs); isParallel = attrs.isParallel(); - groupTransactionEvents = attrs.mustGroupTransactionEvents(); - retriesToGetTransactionEventsFromQueue = attrs.getRetriesToGetTransactionEventsFromQueue(); isForInternalUse = attrs.isForInternalUse(); diskStoreName = attrs.getDiskStoreName(); remoteDSId = attrs.getRemoteDSId(); @@ -266,7 +260,7 @@ public AbstractGatewaySender(InternalCache cache, StatisticsClock statisticsCloc transFilters = Collections.unmodifiableList(attrs.getGatewayTransportFilters()); listeners = attrs.getAsyncEventListeners(); substitutionFilter = attrs.getGatewayEventSubstitutionFilter(); - locatorDiscoveryCallback = attrs.getGatewayLocatoDiscoveryCallback(); + locatorDiscoveryCallback = attrs.getGatewayLocatorDiscoveryCallback(); isDiskSynchronous = attrs.isDiskSynchronous(); policy = attrs.getOrderPolicy(); dispatcherThreads = attrs.getDispatcherThreads(); @@ -293,6 +287,11 @@ public AbstractGatewaySender(InternalCache cache, StatisticsClock statisticsCloc forwardExpirationDestroy = attrs.isForwardExpirationDestroy(); } + @SuppressWarnings("deprecation") + private void copyDeprecatedAttributes(final GatewaySenderAttributes attrs) { + manualStart = attrs.isManualStart(); + } + public GatewaySenderAdvisor getSenderAdvisor() { return senderAdvisor; } @@ -351,7 +350,7 @@ public List getGatewayEventFilters() { } @Override - public GatewayEventSubstitutionFilter getGatewayEventSubstitutionFilter() { + public GatewayEventSubstitutionFilter getGatewayEventSubstitutionFilter() { return substitutionFilter; } @@ -378,15 +377,12 @@ public List getAsyncEventListeners() { return listeners; } - public boolean hasListeners() { - return !listeners.isEmpty(); - } - @Override public boolean isForwardExpirationDestroy() { return forwardExpirationDestroy; } + @Deprecated @Override public boolean isManualStart() { return manualStart; @@ -397,7 +393,7 @@ public int getMaximumQueueMemory() { return queueMemory; } - public int getMaximumMemeoryPerDispatcherQueue() { + public int getMaximumMemoryPerDispatcherQueue() { return maxMemoryPerDispatcherQueue; } @@ -560,19 +556,10 @@ public boolean isParallel() { return isParallel; } + @Deprecated @Override public boolean mustGroupTransactionEvents() { - return groupTransactionEvents; - } - - /** - * Returns retriesToGetTransactionEventsFromQueue int property for this GatewaySender. - * - * @return retriesToGetTransactionEventsFromQueue int property for this GatewaySender - * - */ - public int getRetriesToGetTransactionEventsFromQueue() { - return retriesToGetTransactionEventsFromQueue; + return false; } public boolean isForInternalUse() { @@ -589,7 +576,7 @@ public boolean isForInternalUse() { public abstract void stop(); /** - * Destroys the GatewaySender. Before destroying the sender, caller needs to to ensure that the + * Destroys the GatewaySender. Before destroying the sender, caller needs to ensure that the * sender is stopped so that all the resources (threads, connection pool etc.) will be released * properly. Stopping the sender is not handled in the destroy. Destroy is carried out in * following steps: 1. Take the lifeCycleLock. 2. If the sender is attached to any application @@ -731,19 +718,6 @@ public void setBatchTimeInterval(int batchTimeInterval) { } } - /** - * Set GroupTransactionEvents for this GatewaySender. - * - * Care must be taken to set this consistently across all gateway senders in the cluster and only - * when safe to do so. - * - * @since Geode 1.15 - * - */ - public void setGroupTransactionEvents(boolean groupTransactionEvents) { - this.groupTransactionEvents = groupTransactionEvents; - } - /** * Set GatewayEventFilters for this GatewaySender. * @@ -761,15 +735,13 @@ public void setGatewayEventFilters(List filters) { } } - public boolean beforeEnqueue(GatewayQueueEvent gatewayEvent) { - boolean enqueue = true; - for (GatewayEventFilter filter : getGatewayEventFilters()) { - enqueue = filter.beforeEnqueue(gatewayEvent); - if (!enqueue) { - return enqueue; + public boolean beforeEnqueue(final GatewayQueueEvent gatewayEvent) { + for (final GatewayEventFilter filter : getGatewayEventFilters()) { + if (!filter.beforeEnqueue(gatewayEvent)) { + return false; } } - return enqueue; + return true; } protected void stopProcessing() { @@ -847,23 +819,21 @@ public synchronized boolean setServerLocation(ServerLocation location) { return true; } - private class Stopper extends CancelCriterion { - final CancelCriterion stper; + private static class Stopper extends CancelCriterion { + final CancelCriterion stopper; Stopper(CancelCriterion stopper) { - stper = stopper; + this.stopper = stopper; } @Override public String cancelInProgress() { - // checkFailure(); // done by stopper - return stper.cancelInProgress(); + return stopper.cancelInProgress(); } @Override public RuntimeException generateCancelledException(Throwable e) { - RuntimeException result = stper.generateCancelledException(e); - return result; + return stopper.generateCancelledException(e); } } @@ -1013,7 +983,7 @@ public AbstractGatewaySenderEventProcessor getEventProcessor() { * * @return boolean True if the event is allowed. */ - private boolean checkForDistribution(EntryEventImpl event, GatewaySenderStats stats) { + private boolean checkForDistribution(EntryEventImpl event) { if (event.getRegion().getDataPolicy().equals(DataPolicy.NORMAL)) { return false; } @@ -1026,11 +996,6 @@ private boolean checkForDistribution(EntryEventImpl event, GatewaySenderStats st return true; } - public void distribute(EnumListenerEvent operation, EntryEventImpl event, - List allRemoteDSIds) { - distribute(operation, event, allRemoteDSIds, false); - } - public void distribute(EnumListenerEvent operation, EntryEventImpl event, List allRemoteDSIds, boolean isLastEventInTransaction) { @@ -1045,13 +1010,13 @@ public void distribute(EnumListenerEvent operation, EntryEventImpl event, final GatewaySenderStats stats = getStatistics(); stats.incEventsReceived(); - if (!checkForDistribution(event, stats)) { + if (!checkForDistribution(event)) { stats.incEventsNotQueued(); return; } // this filter is defined by Asif which exist in old wan too. new wan has - // other GatewaEventFilter. Do we need to get rid of this filter. Cheetah is + // other GatewayEventFilter. Do we need to get rid of this filter? Cheetah is // not considering this filter if (!filter.enqueueEvent(event)) { stats.incEventsFiltered(); @@ -1071,49 +1036,9 @@ public void distribute(EnumListenerEvent operation, EntryEventImpl event, } if (callbackArg instanceof GatewaySenderEventCallbackArgument) { - GatewaySenderEventCallbackArgument seca = (GatewaySenderEventCallbackArgument) callbackArg; - if (isDebugEnabled) { - logger.debug( - "{}: Event originated in {}. My DS id is {}. The remote DS id is {}. The recipients are: {}", - this, seca.getOriginatingDSId(), getMyDSId(), getRemoteDSId(), - seca.getRecipientDSIds()); - } - if (seca.getOriginatingDSId() == DEFAULT_DISTRIBUTED_SYSTEM_ID) { - if (isDebugEnabled) { - logger.debug( - "{}: Event originated in {}. My DS id is {}. The remote DS id is {}. The recipients are: {}", - this, seca.getOriginatingDSId(), getMyDSId(), getRemoteDSId(), - seca.getRecipientDSIds()); - } - - seca.setOriginatingDSId(getMyDSId()); - seca.initializeReceipientDSIds(allRemoteDSIds); - - } else { - // if the dispatcher is GatewaySenderEventCallbackDispatcher (which is the case of WBCL), - // skip the below check of remoteDSId. - // Fix for #46517 - AbstractGatewaySenderEventProcessor ep = getEventProcessor(); - // if manual-start is true, ep is null - if (ep == null || !(ep.getDispatcher() instanceof GatewaySenderEventCallbackDispatcher)) { - if (seca.getOriginatingDSId() == getRemoteDSId()) { - if (isDebugEnabled) { - logger.debug( - "{}: Event originated in {}. My DS id is {}. It is being dropped as remote is originator.", - this, seca.getOriginatingDSId(), getMyDSId()); - } - return; - } else if (seca.getRecipientDSIds().contains(getRemoteDSId())) { - if (isDebugEnabled) { - logger.debug( - "{}: Event originated in {}. My DS id is {}. The remote DS id is {}.. It is being dropped as remote ds is already a recipient. Recipients are: {}", - this, seca.getOriginatingDSId(), getMyDSId(), getRemoteDSId(), - seca.getRecipientDSIds()); - } - return; - } - } - seca.getRecipientDSIds().addAll(allRemoteDSIds); + if (handleGatewaySenderCallbackArgument(allRemoteDSIds, isDebugEnabled, + (GatewaySenderEventCallbackArgument) callbackArg)) { + return; } } else { GatewaySenderEventCallbackArgument geCallbackArg = @@ -1169,12 +1094,9 @@ public void distribute(EnumListenerEvent operation, EntryEventImpl event, if (ev == null) { getStopper().checkCancelInProgress(null); getCache().getDistributedSystem().getCancelCriterion().checkCancelInProgress(null); - // event processor will be null if there was an authorization - // problem - // connecting to the other site (bug #40681) - if (ev == null) { - throw new GatewayCancelledException("Event processor thread is gone"); - } + // event processor will be null if there was an authorization problem connecting to the + // other site + throw new GatewayCancelledException("Event processor thread is gone"); } // Get substitution value to enqueue if necessary @@ -1205,6 +1127,54 @@ this, getId(), operation, clonedEvent), } } + private boolean handleGatewaySenderCallbackArgument(final @NotNull List allRemoteDSIds, + final boolean isDebugEnabled, + final @NotNull GatewaySenderEventCallbackArgument argument) { + if (isDebugEnabled) { + logger.debug( + "{}: Event originated in {}. My DS id is {}. The remote DS id is {}. The recipients are: {}", + this, argument.getOriginatingDSId(), getMyDSId(), getRemoteDSId(), + argument.getRecipientDSIds()); + } + if (argument.getOriginatingDSId() == DEFAULT_DISTRIBUTED_SYSTEM_ID) { + if (isDebugEnabled) { + logger.debug( + "{}: Event originated in {}. My DS id is {}. The remote DS id is {}. The recipients are: {}", + this, argument.getOriginatingDSId(), getMyDSId(), getRemoteDSId(), + argument.getRecipientDSIds()); + } + + argument.setOriginatingDSId(getMyDSId()); + argument.initializeReceipientDSIds(allRemoteDSIds); + + } else { + // if the dispatcher is GatewaySenderEventCallbackDispatcher (which is the case of WBCL), + // skip the below check of remoteDSId. + AbstractGatewaySenderEventProcessor ep = getEventProcessor(); + // if manual-start is true, ep is null + if (ep == null || !(ep.getDispatcher() instanceof GatewaySenderEventCallbackDispatcher)) { + if (argument.getOriginatingDSId() == getRemoteDSId()) { + if (isDebugEnabled) { + logger.debug( + "{}: Event originated in {}. My DS id is {}. It is being dropped as remote is originator.", + this, argument.getOriginatingDSId(), getMyDSId()); + } + return true; + } else if (argument.getRecipientDSIds().contains(getRemoteDSId())) { + if (isDebugEnabled) { + logger.debug( + "{}: Event originated in {}. My DS id is {}. The remote DS id is {}.. It is being dropped as remote ds is already a recipient. Recipients are: {}", + this, argument.getOriginatingDSId(), getMyDSId(), getRemoteDSId(), + argument.getRecipientDSIds()); + } + return true; + } + } + argument.getRecipientDSIds().addAll(allRemoteDSIds); + } + return false; + } + private void recordDroppedEvent(EntryEventImpl event) { if (eventProcessor != null) { eventProcessor.registerEventDroppedInPrimaryQueue(event); @@ -1223,7 +1193,7 @@ int getTmpDroppedEventSize() { /** * During sender is getting started, if there are any cache operation on queue then that event - * will be stored in temp queue. Once sender is started, these event from tmp queue will be added + * will be stored in temp queue. Once sender is started, these events from tmp queue will be added * to sender queue. * * Apart from sender's start() method, this method also gets called from @@ -1278,7 +1248,7 @@ this, getId(), nextEvent.getOperation(), nextEvent), * tmpQueueEvents. * */ - public boolean removeFromTempQueueEvents(Object tailKey) { + public void removeFromTempQueueEvents(Object tailKey) { synchronized (queuedEventsSync) { Iterator itr = tmpQueuedEvents.iterator(); while (itr.hasNext()) { @@ -1291,20 +1261,19 @@ public boolean removeFromTempQueueEvents(Object tailKey) { } event.release(); itr.remove(); - return true; + return; } } - return false; } } /** * During sender is getting stopped, if there are any cache operation on queue then that event - * will be stored in temp queue. Once sender is started, these event from tmp queue will be + * will be stored in temp queue. Once sender is started, these events from tmp queue will be * cleared. */ public void clearTempEventsAfterSenderStopped() { - TmpQueueEvent nextEvent = null; + TmpQueueEvent nextEvent; while ((nextEvent = tmpQueuedEvents.poll()) != null) { nextEvent.release(); } @@ -1326,7 +1295,7 @@ public Object getSubstituteValue(EntryEventImpl clonedEvent, EnumListenerEvent o Object substituteValue = null; if (substitutionFilter != null) { try { - substituteValue = substitutionFilter.getSubstituteValue(clonedEvent); + substituteValue = substitutionFilter.getSubstituteValue(uncheckedCast(clonedEvent)); // If null is returned from the filter, null is set in the value if (substituteValue == null) { substituteValue = GatewaySenderEventImpl.TOKEN_NULL; @@ -1361,7 +1330,7 @@ protected void initializeEventIdIndex() { Region region = getEventIdIndexMetaDataRegion(); // Get or create the index - int index = 0; + final int index; String messagePrefix = null; if (region.containsKey(getId())) { index = region.get(getId()); @@ -1414,7 +1383,7 @@ private static synchronized Region initializeEventIdIndexMetaDa InternalRegionFactory factory = cache.createInternalRegionFactory(RegionShortcut.REPLICATE); - // Create a stats holder for the meta data stats + // Create a stats holder for the metadata stats final HasCachePerfStats statsHolder = () -> new CachePerfStats(cache.getDistributedSystem(), "RegionStats-" + META_DATA_REGION_NAME, sender.statisticsClock); factory.setIsUsedForMetaRegion(true); @@ -1489,7 +1458,7 @@ public ReentrantReadWriteLock getLifeCycleLock() { @Override public boolean waitUntilFlushed(long timeout, TimeUnit unit) throws InterruptedException { - boolean result = false; + final boolean result; if (isParallel()) { try { WaitUntilParallelGatewaySenderFlushedCoordinator coordinator = @@ -1547,7 +1516,7 @@ public EventWrapper(GatewaySenderEventImpl e) { * of the off-heap work, the GatewaySenderEventImpl no longer has a EntryEventImpl. So this class * allows us to defer creation of the GatewaySenderEventImpl until we are ready to actually * enqueue it. The caller is responsible for giving us an EntryEventImpl that we own and that we - * will release. This is done by making a copy/clone of the original event. This fixes bug 52029. + * will release. This is done by making a copy/clone of the original event. */ public static class TmpQueueEvent implements Releasable { private final EnumListenerEvent operation; @@ -1578,17 +1547,17 @@ public void release() { } } - protected GatewayQueueEvent getSynchronizationEvent(Object key, long timestamp) { - GatewayQueueEvent event = null; - for (RegionQueue queue : getQueues()) { - Region region = queue.getRegion(); + protected GatewayQueueEvent getSynchronizationEvent(Object key, long timestamp) { + GatewayQueueEvent event = null; + for (final RegionQueue queue : getQueues()) { + final Region region = uncheckedCast(queue.getRegion()); if (region == null) { continue; } - for (final Object o : region.values()) { - GatewaySenderEventImpl gsei = (GatewaySenderEventImpl) o; - if (gsei.getKey().equals(key) && gsei.getVersionTimeStamp() == timestamp) { - event = gsei; + for (final GatewaySenderEventImpl gatewaySenderEvent : region.values()) { + if (gatewaySenderEvent.getKey().equals(key) + && gatewaySenderEvent.getVersionTimeStamp() == timestamp) { + event = gatewaySenderEvent; logger.info("{}: Providing synchronization event for key={}; timestamp={}: {}", this, key, timestamp, event); getStatistics().incSynchronizationEventsProvided(); @@ -1599,7 +1568,7 @@ protected GatewayQueueEvent getSynchronizationEvent(Object key, long timestamp) return event; } - protected void putSynchronizationEvent(GatewayQueueEvent event) { + protected void putSynchronizationEvent(GatewayQueueEvent event) { if (eventProcessor != null) { lifeCycleLock.readLock().lock(); try { diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributes.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributes.java index 74f9c42685ba..3ea060f6b665 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributes.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributes.java @@ -14,314 +14,81 @@ */ package org.apache.geode.internal.cache.wan; -import java.util.ArrayList; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.client.internal.LocatorDiscoveryCallback; import org.apache.geode.cache.wan.GatewayEventFilter; import org.apache.geode.cache.wan.GatewayEventSubstitutionFilter; import org.apache.geode.cache.wan.GatewaySender; -import org.apache.geode.cache.wan.GatewaySender.OrderPolicy; import org.apache.geode.cache.wan.GatewayTransportFilter; -public class GatewaySenderAttributes { - - public static final boolean DEFAULT_IS_BUCKETSORTED = true; - public static final boolean DEFAULT_IS_META_QUEUE = false; - - - private int socketBufferSize = GatewaySender.DEFAULT_SOCKET_BUFFER_SIZE; - - private int socketReadTimeout = GatewaySender.DEFAULT_SOCKET_READ_TIMEOUT; - - private int maximumQueueMemory = GatewaySender.DEFAULT_MAXIMUM_QUEUE_MEMORY; - - private int batchSize = GatewaySender.DEFAULT_BATCH_SIZE; - - private int batchTimeInterval = GatewaySender.DEFAULT_BATCH_TIME_INTERVAL; - - private boolean isBatchConflationEnabled = GatewaySender.DEFAULT_BATCH_CONFLATION; - - private boolean isPersistenceEnabled = GatewaySender.DEFAULT_PERSISTENCE_ENABLED; - - private int alertThreshold = GatewaySender.DEFAULT_ALERT_THRESHOLD; - - private boolean manualStart = GatewaySender.DEFAULT_MANUAL_START; - - private String diskStoreName; - - private final List eventFilters = new ArrayList<>(); - - private final ArrayList transFilters = - new ArrayList<>(); - - private final List listeners = new ArrayList<>(); - - private GatewayEventSubstitutionFilter eventSubstitutionFilter; - - private String id; - - private int remoteDs = GatewaySender.DEFAULT_DISTRIBUTED_SYSTEM_ID; - - private LocatorDiscoveryCallback locatorDiscoveryCallback; - - private boolean isDiskSynchronous = GatewaySender.DEFAULT_DISK_SYNCHRONOUS; - - private OrderPolicy policy; - - private int dispatcherThreads = GatewaySender.DEFAULT_DISPATCHER_THREADS; - - private int parallelism = GatewaySender.DEFAULT_PARALLELISM_REPLICATED_REGION; - - private boolean isParallel = GatewaySender.DEFAULT_IS_PARALLEL; - - private boolean groupTransactionEvents = GatewaySender.DEFAULT_MUST_GROUP_TRANSACTION_EVENTS; - - private int retriesToGetTransactionEventsFromQueue = - GatewaySender.GET_TRANSACTION_EVENTS_FROM_QUEUE_RETRIES; - - private boolean isForInternalUse = GatewaySender.DEFAULT_IS_FOR_INTERNAL_USE; - - private boolean isBucketSorted = GatewaySenderAttributes.DEFAULT_IS_BUCKETSORTED; - - private boolean isMetaQueue = GatewaySenderAttributes.DEFAULT_IS_META_QUEUE; - - private boolean forwardExpirationDestroy = GatewaySender.DEFAULT_FORWARD_EXPIRATION_DESTROY; - - private boolean enforceThreadsConnectSameReceiver = - GatewaySender.DEFAULT_ENFORCE_THREADS_CONNECT_SAME_RECEIVER; - - public void setSocketBufferSize(int bufferSize) { - socketBufferSize = bufferSize; - } - - public void setSocketReadTimeout(int readTimeout) { - socketReadTimeout = readTimeout; - } - - public void setMaximumQueueMemory(int maxQueueMemory) { - maximumQueueMemory = maxQueueMemory; - } - - public void setBatchSize(int batchsize) { - batchSize = batchsize; - } - - public void setBatchTimeInterval(int batchtimeinterval) { - batchTimeInterval = batchtimeinterval; - } - - public void setBatchConflationEnabled(boolean batchConfEnabled) { - isBatchConflationEnabled = batchConfEnabled; - } - - public void setPersistenceEnabled(boolean persistenceEnabled) { - isPersistenceEnabled = persistenceEnabled; - } - - public void setAlertThreshold(int alertThresh) { - alertThreshold = alertThresh; - } - - public void setManualStart(boolean manualstart) { - manualStart = manualstart; - } - - public void setDiskStoreName(String diskstorename) { - diskStoreName = diskstorename; - } - - public void setEventSubstitutionFilter(GatewayEventSubstitutionFilter eventsubstitutionfilter) { - eventSubstitutionFilter = eventsubstitutionfilter; - } - - public void setId(String idString) { - id = idString; - } - - public void setRemoteDs(int rDs) { - remoteDs = rDs; - } - - public void setLocatorDiscoveryCallback(LocatorDiscoveryCallback locatorDiscCall) { - locatorDiscoveryCallback = locatorDiscCall; - } - - public void setDiskSynchronous(boolean diskSynchronous) { - isDiskSynchronous = diskSynchronous; - } - - public void setOrderPolicy(OrderPolicy orderpolicy) { - policy = orderpolicy; - } - - public void setDispatcherThreads(int dispatchThreads) { - dispatcherThreads = dispatchThreads; - } - - public void setParallelism(int tempParallelism) { - parallelism = tempParallelism; - } - - public void setParallel(boolean parallel) { - isParallel = parallel; - } - - public void setGroupTransactionEvents(boolean groupTransEvents) { - groupTransactionEvents = groupTransEvents; - } - - public void setRetriesToGetTransactionEventsFromQueue(int retries) { - retriesToGetTransactionEventsFromQueue = retries; - } - - public void setForInternalUse(boolean forInternalUse) { - isForInternalUse = forInternalUse; - } - - public void setBucketSorted(boolean bucketSorted) { - isBucketSorted = bucketSorted; - } - - public void setMetaQueue(boolean metaQueue) { - isMetaQueue = metaQueue; - } - - public void setForwardExpirationDestroy(boolean forwardexpirationdestroy) { - forwardExpirationDestroy = forwardexpirationdestroy; - } - - public void setEnforceThreadsConnectSameReceiver(boolean enforcethreadsconnectsamereceiver) { - enforceThreadsConnectSameReceiver = enforcethreadsconnectsamereceiver; - } - - public int getSocketBufferSize() { - return socketBufferSize; - } - - public boolean isDiskSynchronous() { - return isDiskSynchronous; - } - - public int getSocketReadTimeout() { - return socketReadTimeout; - } - - public String getDiskStoreName() { - return diskStoreName; - } - - public int getMaximumQueueMemory() { - return maximumQueueMemory; - } +public interface GatewaySenderAttributes { + int getSocketBufferSize(); - public int getBatchSize() { - return batchSize; - } + boolean isDiskSynchronous(); - public int getBatchTimeInterval() { - return batchTimeInterval; - } + int getSocketReadTimeout(); - public boolean isBatchConflationEnabled() { - return isBatchConflationEnabled; - } + String getDiskStoreName(); - public boolean isPersistenceEnabled() { - return isPersistenceEnabled; - } + int getMaximumQueueMemory(); - public int getAlertThreshold() { - return alertThreshold; - } + int getBatchSize(); - public List getGatewayEventFilters() { - return eventFilters; - } + int getBatchTimeInterval(); - public List getGatewayTransportFilters() { - return transFilters; - } + boolean isBatchConflationEnabled(); - public List getAsyncEventListeners() { - return listeners; - } + boolean isPersistenceEnabled(); - public LocatorDiscoveryCallback getGatewayLocatoDiscoveryCallback() { - return locatorDiscoveryCallback; - } + int getAlertThreshold(); - public boolean isManualStart() { - return manualStart; - } + @NotNull + List getGatewayEventFilters(); - public boolean isParallel() { - return isParallel; - } + @NotNull + List getGatewayTransportFilters(); - public boolean mustGroupTransactionEvents() { - return groupTransactionEvents; - } + @NotNull + List getAsyncEventListeners(); - public int getRetriesToGetTransactionEventsFromQueue() { - return retriesToGetTransactionEventsFromQueue; - } + @Nullable + LocatorDiscoveryCallback getGatewayLocatorDiscoveryCallback(); - public boolean isForInternalUse() { - return isForInternalUse; - } + @Deprecated + boolean isManualStart(); - public void addGatewayEventFilter(GatewayEventFilter filter) { - eventFilters.add(filter); - } + boolean isParallel(); - public void addGatewayTransportFilter(GatewayTransportFilter filter) { - transFilters.add(filter); - } + boolean mustGroupTransactionEvents(); - public void addAsyncEventListener(AsyncEventListener listener) { - listeners.add(listener); - } + boolean isForInternalUse(); - public String getId() { - return id; - } + String getId(); - public int getRemoteDSId() { - return remoteDs; - } + int getRemoteDSId(); - public int getDispatcherThreads() { - return dispatcherThreads; - } + int getDispatcherThreads(); - public int getParallelismForReplicatedRegion() { - return parallelism; - } + int getParallelismForReplicatedRegion(); - public OrderPolicy getOrderPolicy() { - return policy; - } + @Nullable + GatewaySender.OrderPolicy getOrderPolicy(); - public boolean isBucketSorted() { - return isBucketSorted; - } + boolean isBucketSorted(); - public GatewayEventSubstitutionFilter getGatewayEventSubstitutionFilter() { - return eventSubstitutionFilter; - } + @Nullable + GatewayEventSubstitutionFilter getGatewayEventSubstitutionFilter(); - public boolean isMetaQueue() { - return isMetaQueue; - } + boolean isMetaQueue(); - public boolean isForwardExpirationDestroy() { - return forwardExpirationDestroy; - } + boolean isForwardExpirationDestroy(); - public boolean getEnforceThreadsConnectSameReceiver() { - return enforceThreadsConnectSameReceiver; - } + boolean getEnforceThreadsConnectSameReceiver(); + String getType(); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributesImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributesImpl.java new file mode 100644 index 000000000000..87addac4e0df --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/GatewaySenderAttributesImpl.java @@ -0,0 +1,363 @@ +/* + * 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.wan; + +import java.util.ArrayList; +import java.util.List; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.asyncqueue.AsyncEventListener; +import org.apache.geode.cache.client.internal.LocatorDiscoveryCallback; +import org.apache.geode.cache.wan.GatewayEventFilter; +import org.apache.geode.cache.wan.GatewayEventSubstitutionFilter; +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.GatewaySender.OrderPolicy; +import org.apache.geode.cache.wan.GatewayTransportFilter; + +public class GatewaySenderAttributesImpl implements MutableGatewaySenderAttributes { + + private static final boolean DEFAULT_IS_BUCKET_SORTED = true; + + private static final boolean DEFAULT_IS_META_QUEUE = false; + + private int socketBufferSize = GatewaySender.DEFAULT_SOCKET_BUFFER_SIZE; + + private int socketReadTimeout = GatewaySender.DEFAULT_SOCKET_READ_TIMEOUT; + + private int maximumQueueMemory = GatewaySender.DEFAULT_MAXIMUM_QUEUE_MEMORY; + + private int batchSize = GatewaySender.DEFAULT_BATCH_SIZE; + + private int batchTimeInterval = GatewaySender.DEFAULT_BATCH_TIME_INTERVAL; + + private boolean isBatchConflationEnabled = GatewaySender.DEFAULT_BATCH_CONFLATION; + + private boolean isPersistenceEnabled = GatewaySender.DEFAULT_PERSISTENCE_ENABLED; + + private int alertThreshold = GatewaySender.DEFAULT_ALERT_THRESHOLD; + + @Deprecated + private boolean manualStart = GatewaySender.DEFAULT_MANUAL_START; + + private String diskStoreName; + + private final List eventFilters = new ArrayList<>(); + + private final ArrayList transFilters = new ArrayList<>(); + + private final List listeners = new ArrayList<>(); + + private GatewayEventSubstitutionFilter eventSubstitutionFilter; + + private String id; + + private int remoteDs = GatewaySender.DEFAULT_DISTRIBUTED_SYSTEM_ID; + + private LocatorDiscoveryCallback locatorDiscoveryCallback; + + private boolean isDiskSynchronous = GatewaySender.DEFAULT_DISK_SYNCHRONOUS; + + private OrderPolicy orderPolicy; + + private int dispatcherThreads = GatewaySender.DEFAULT_DISPATCHER_THREADS; + + private int parallelism = GatewaySender.DEFAULT_PARALLELISM_REPLICATED_REGION; + + private boolean isParallel = GatewaySender.DEFAULT_IS_PARALLEL; + + private boolean groupTransactionEvents = GatewaySender.DEFAULT_MUST_GROUP_TRANSACTION_EVENTS; + + private String type; + + private boolean isForInternalUse = GatewaySender.DEFAULT_IS_FOR_INTERNAL_USE; + + private boolean isBucketSorted = GatewaySenderAttributesImpl.DEFAULT_IS_BUCKET_SORTED; + + private boolean isMetaQueue = GatewaySenderAttributesImpl.DEFAULT_IS_META_QUEUE; + + private boolean forwardExpirationDestroy = GatewaySender.DEFAULT_FORWARD_EXPIRATION_DESTROY; + + private boolean enforceThreadsConnectSameReceiver = + GatewaySender.DEFAULT_ENFORCE_THREADS_CONNECT_SAME_RECEIVER; + + public void setSocketBufferSize(int bufferSize) { + socketBufferSize = bufferSize; + } + + public void setSocketReadTimeout(int readTimeout) { + socketReadTimeout = readTimeout; + } + + public void setMaximumQueueMemory(int maxQueueMemory) { + maximumQueueMemory = maxQueueMemory; + } + + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + } + + public void setBatchTimeInterval(int batchTimeInterval) { + this.batchTimeInterval = batchTimeInterval; + } + + public void setBatchConflationEnabled(boolean batchConfEnabled) { + isBatchConflationEnabled = batchConfEnabled; + } + + public void setPersistenceEnabled(boolean persistenceEnabled) { + isPersistenceEnabled = persistenceEnabled; + } + + public void setAlertThreshold(int alertThresh) { + alertThreshold = alertThresh; + } + + @Deprecated + public void setManualStart(boolean manualStart) { + this.manualStart = manualStart; + } + + public void setDiskStoreName(String diskStoreName) { + this.diskStoreName = diskStoreName; + } + + public void setEventSubstitutionFilter( + @Nullable GatewayEventSubstitutionFilter eventSubstitutionFilter) { + this.eventSubstitutionFilter = eventSubstitutionFilter; + } + + public void setId(String idString) { + id = idString; + } + + public void setRemoteDs(int rDs) { + remoteDs = rDs; + } + + public void setLocatorDiscoveryCallback(@Nullable LocatorDiscoveryCallback locatorDiscCall) { + locatorDiscoveryCallback = locatorDiscCall; + } + + public void setDiskSynchronous(boolean diskSynchronous) { + isDiskSynchronous = diskSynchronous; + } + + @Override + public void setOrderPolicy(final @Nullable OrderPolicy orderPolicy) { + this.orderPolicy = orderPolicy; + } + + public void setDispatcherThreads(int dispatchThreads) { + dispatcherThreads = dispatchThreads; + } + + public void setParallelism(int tempParallelism) { + parallelism = tempParallelism; + } + + public void setParallel(boolean parallel) { + isParallel = parallel; + } + + public void setGroupTransactionEvents(boolean groupTransEvents) { + groupTransactionEvents = groupTransEvents; + } + + public void setType(String type) { + this.type = type; + isParallel = type.contains("Parallel") ? true : false; + } + + public void setForInternalUse(boolean forInternalUse) { + isForInternalUse = forInternalUse; + } + + public void setBucketSorted(boolean bucketSorted) { + isBucketSorted = bucketSorted; + } + + public void setMetaQueue(boolean metaQueue) { + isMetaQueue = metaQueue; + } + + public void setForwardExpirationDestroy(boolean forwardExpirationDestroy) { + this.forwardExpirationDestroy = forwardExpirationDestroy; + } + + public void setEnforceThreadsConnectSameReceiver(boolean enforceThreadsConnectSameReceiver) { + this.enforceThreadsConnectSameReceiver = enforceThreadsConnectSameReceiver; + } + + @Override + public int getSocketBufferSize() { + return socketBufferSize; + } + + @Override + public boolean isDiskSynchronous() { + return isDiskSynchronous; + } + + @Override + public int getSocketReadTimeout() { + return socketReadTimeout; + } + + @Override + public String getDiskStoreName() { + return diskStoreName; + } + + @Override + public int getMaximumQueueMemory() { + return maximumQueueMemory; + } + + @Override + public int getBatchSize() { + return batchSize; + } + + @Override + public int getBatchTimeInterval() { + return batchTimeInterval; + } + + @Override + public boolean isBatchConflationEnabled() { + return isBatchConflationEnabled; + } + + @Override + public boolean isPersistenceEnabled() { + return isPersistenceEnabled; + } + + @Override + public int getAlertThreshold() { + return alertThreshold; + } + + @Override + public @NotNull List getGatewayEventFilters() { + return eventFilters; + } + + @Override + public @NotNull List getGatewayTransportFilters() { + return transFilters; + } + + @Override + public @NotNull List getAsyncEventListeners() { + return listeners; + } + + @Override + public @Nullable LocatorDiscoveryCallback getGatewayLocatorDiscoveryCallback() { + return locatorDiscoveryCallback; + } + + @Override + @Deprecated + public boolean isManualStart() { + return manualStart; + } + + @Override + public boolean isParallel() { + return isParallel; + } + + @Override + public boolean mustGroupTransactionEvents() { + return groupTransactionEvents; + } + + @Override + public boolean isForInternalUse() { + return isForInternalUse; + } + + public void addGatewayEventFilter(GatewayEventFilter filter) { + eventFilters.add(filter); + } + + public void addGatewayTransportFilter(GatewayTransportFilter filter) { + transFilters.add(filter); + } + + public void addAsyncEventListener(AsyncEventListener listener) { + listeners.add(listener); + } + + @Override + public String getId() { + return id; + } + + @Override + public int getRemoteDSId() { + return remoteDs; + } + + @Override + public int getDispatcherThreads() { + return dispatcherThreads; + } + + @Override + public int getParallelismForReplicatedRegion() { + return parallelism; + } + + @Override + public @Nullable OrderPolicy getOrderPolicy() { + return orderPolicy; + } + + @Override + public boolean isBucketSorted() { + return isBucketSorted; + } + + @Override + public @Nullable GatewayEventSubstitutionFilter getGatewayEventSubstitutionFilter() { + return eventSubstitutionFilter; + } + + @Override + public boolean isMetaQueue() { + return isMetaQueue; + } + + @Override + public boolean isForwardExpirationDestroy() { + return forwardExpirationDestroy; + } + + @Override + public boolean getEnforceThreadsConnectSameReceiver() { + return enforceThreadsConnectSameReceiver; + } + + @Override + public String getType() { + return type; + } + +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/InternalGatewaySenderFactory.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/InternalGatewaySenderFactory.java index 6b941c846015..18641fa15390 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/InternalGatewaySenderFactory.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/InternalGatewaySenderFactory.java @@ -27,17 +27,7 @@ public interface InternalGatewaySenderFactory extends GatewaySenderFactory { GatewaySenderFactory setBucketSorted(boolean bucketSorted); - GatewaySender create(String senderIdFromAsyncEventQueueId); - void configureGatewaySender(GatewaySender senderCreation); GatewaySenderFactory setLocatorDiscoveryCallback(LocatorDiscoveryCallback myLocatorCallback); - - /** - * Sets the maximum number of retries to get events from the queue - * to complete a transaction when groupTransactionEvents is true. - * - * @param retries the maximum number of retries. - */ - GatewaySenderFactory setRetriesToGetTransactionEventsFromQueue(int retries); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/MutableGatewaySenderAttributes.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/MutableGatewaySenderAttributes.java new file mode 100644 index 000000000000..4ccc5a43d6df --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/MutableGatewaySenderAttributes.java @@ -0,0 +1,26 @@ +/* + * 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.wan; + +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.wan.GatewaySender.OrderPolicy; + +public interface MutableGatewaySenderAttributes extends GatewaySenderAttributes { + + void setOrderPolicy(@Nullable OrderPolicy orderPolicy); + +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderEventProcessor.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderEventProcessor.java index f01e227bced9..cccc3e3d4a16 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderEventProcessor.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderEventProcessor.java @@ -20,6 +20,7 @@ import java.util.concurrent.BlockingQueue; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.apache.geode.cache.CacheException; import org.apache.geode.cache.EntryEvent; @@ -77,8 +78,8 @@ protected void initializeMessageQueue(String id, boolean cleanQueues) { logger.debug("The target Regions are(PGSEP) {}", targetRs); } - ParallelGatewaySenderQueue queue = - new ParallelGatewaySenderQueue(sender, targetRs, index, nDispatcher, cleanQueues); + final ParallelGatewaySenderQueue queue = + createParallelGatewaySenderQueue(sender, targetRs, index, nDispatcher, cleanQueues); queue.start(); this.queue = queue; @@ -88,6 +89,14 @@ protected void initializeMessageQueue(String id, boolean cleanQueues) { } } + protected @NotNull ParallelGatewaySenderQueue createParallelGatewaySenderQueue( + final @NotNull AbstractGatewaySender sender, + final @NotNull Set> targetRegions, final int index, final int dispatcherThreads, + final boolean cleanQueues) { + return new ParallelGatewaySenderQueue(sender, targetRegions, index, dispatcherThreads, + cleanQueues); + } + @Override public int eventQueueSize() { ParallelGatewaySenderQueue queue = (ParallelGatewaySenderQueue) getQueue(); diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueue.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueue.java index 678286c92b3f..dcfa4482c09f 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueue.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueue.java @@ -16,14 +16,12 @@ import static org.apache.geode.cache.Region.SEPARATOR; import static org.apache.geode.cache.wan.GatewaySender.DEFAULT_BATCH_SIZE; -import static org.apache.geode.cache.wan.GatewaySender.GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS; import static org.apache.geode.internal.cache.LocalRegion.InitializationLevel.BEFORE_INITIAL_IMAGE; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; @@ -34,10 +32,10 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.apache.geode.CancelException; import org.apache.geode.SystemFailure; @@ -56,7 +54,6 @@ import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionDestroyedException; import org.apache.geode.cache.RegionShortcut; -import org.apache.geode.cache.TransactionId; import org.apache.geode.cache.asyncqueue.internal.AsyncEventQueueImpl; import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.distributed.internal.InternalDistributedSystem; @@ -162,14 +159,14 @@ boolean getCleanQueues() { * The peekedEventsProcessing queue is used when the batch size is reduced due to a * MessageTooLargeException */ - private final BlockingQueue peekedEventsProcessing = - new LinkedBlockingQueue<>(); + protected BlockingQueue peekedEventsProcessing = + new LinkedBlockingQueue(); /** * The peekedEventsProcessingInProgress boolean denotes that processing existing peeked events is * in progress */ - private boolean peekedEventsProcessingInProgress = false; + protected boolean peekedEventsProcessingInProgress = false; public final AbstractGatewaySender sender; @@ -245,8 +242,7 @@ private Object deserialize(Object serializedBytes) { private final MetaRegionFactory metaRegionFactory; public ParallelGatewaySenderQueue(AbstractGatewaySender sender, Set> userRegions, - int idx, - int nDispatcher, boolean cleanQueues) { + int idx, int nDispatcher, boolean cleanQueues) { this(sender, userRegions, idx, nDispatcher, new MetaRegionFactory(), cleanQueues); } @@ -1340,10 +1336,7 @@ public List peek(int batchSize, int timeToWait) throws InterruptedException, Cac } } - if (batch.size() > 0) { - peekEventsFromIncompleteTransactions(batch, prQ); - } - + postProcessBatch(prQ, batch); if (isDebugEnabled) { logger.debug("{}: Peeked a batch of {} entries. The size of the queue is {}. localSize is {}", @@ -1356,6 +1349,9 @@ public List peek(int batchSize, int timeToWait) throws InterruptedException, Cac return batch; } + protected void postProcessBatch(final @NotNull PartitionedRegion partitionedRegion, + final @NotNull List batch) {} + private boolean stopPeekingDueToTime(int timeToWait, long end) { final boolean isDebugEnabled = logger.isDebugEnabled(); // If time to wait is -1 (don't wait) or time interval has elapsed @@ -1372,78 +1368,6 @@ private boolean stopPeekingDueToTime(int timeToWait, long end) { return false; } - protected boolean mustGroupTransactionEvents() { - return sender.mustGroupTransactionEvents(); - } - - @VisibleForTesting - void peekEventsFromIncompleteTransactions(List batch, - PartitionedRegion prQ) { - if (!mustGroupTransactionEvents()) { - return; - } - - Map incompleteTransactionIdsInBatch = - getIncompleteTransactionsInBatch(batch); - if (incompleteTransactionIdsInBatch.size() == 0) { - return; - } - - int retries = 0; - while (true) { - for (Iterator> iter = - incompleteTransactionIdsInBatch.entrySet().iterator(); iter.hasNext();) { - Map.Entry pendingTransaction = iter.next(); - TransactionId transactionId = pendingTransaction.getKey(); - int bucketId = pendingTransaction.getValue(); - List events = peekEventsWithTransactionId(prQ, bucketId, transactionId); - for (Object object : events) { - GatewaySenderEventImpl event = (GatewaySenderEventImpl) object; - batch.add(event); - peekedEvents.add(event); - if (logger.isDebugEnabled()) { - logger.debug( - "Peeking extra event: {}, bucketId: {}, isLastEventInTransaction: {}, batch size: {}", - event.getKey(), bucketId, event.isLastEventInTransaction(), batch.size()); - } - if (event.isLastEventInTransaction()) { - iter.remove(); - } - } - } - if (incompleteTransactionIdsInBatch.size() == 0 || - retries >= sender.getRetriesToGetTransactionEventsFromQueue()) { - break; - } - retries++; - try { - Thread.sleep(GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - if (incompleteTransactionIdsInBatch.size() > 0) { - logger.warn("Not able to retrieve all events for transactions: {} after {} retries of {}ms", - incompleteTransactionIdsInBatch, retries, GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); - stats.incBatchesWithIncompleteTransactions(); - } - } - - private Map getIncompleteTransactionsInBatch( - List batch) { - Map incompleteTransactionsInBatch = new HashMap<>(); - for (GatewaySenderEventImpl event : batch) { - if (event.getTransactionId() != null) { - if (event.isLastEventInTransaction()) { - incompleteTransactionsInBatch.remove(event.getTransactionId()); - } else { - incompleteTransactionsInBatch.put(event.getTransactionId(), event.getBucketId()); - } - } - } - return incompleteTransactionsInBatch; - } - @VisibleForTesting static long calculateTimeToSleep(long timeToWait) { if (timeToWait <= 0) { @@ -1518,20 +1442,10 @@ private void addPeekedEvents(List batch, int batchSize) } } - private void addPreviouslyPeekedEvents(List batch, int batchSize) { - Set incompleteTransactionsInBatch = new HashSet<>(); - for (int i = 0; i < batchSize || incompleteTransactionsInBatch.size() != 0; i++) { - GatewaySenderEventImpl event = peekedEventsProcessing.remove(); - batch.add(event); - if (mustGroupTransactionEvents()) { - if (event.getTransactionId() != null) { - if (event.isLastEventInTransaction()) { - incompleteTransactionsInBatch.remove(event.getTransactionId()); - } else { - incompleteTransactionsInBatch.add(event.getTransactionId()); - } - } - } + protected void addPreviouslyPeekedEvents(final @NotNull List batch, + final int batchSize) { + for (int i = 0; i < batchSize; i++) { + batch.add(peekedEventsProcessing.remove()); if (peekedEventsProcessing.isEmpty()) { resetLastPeeked = false; peekedEventsProcessingInProgress = false; @@ -1590,38 +1504,6 @@ protected Object peekAhead(PartitionedRegion prQ, int bucketId) throws CacheExce // finished with peeked object. } - protected List peekEventsWithTransactionId(PartitionedRegion prQ, int bucketId, - TransactionId transactionId) throws CacheException { - List objects; - BucketRegionQueue brq = getBucketRegionQueueByBucketId(prQ, bucketId); - - try { - Predicate hasTransactionIdPredicate = - getHasTransactionIdPredicate(transactionId); - Predicate isLastEventInTransactionPredicate = - getIsLastEventInTransactionPredicate(); - objects = - brq.getElementsMatching(hasTransactionIdPredicate, isLastEventInTransactionPredicate); - } catch (BucketRegionQueueUnavailableException e) { - // BucketRegionQueue unavailable. Can be due to the BucketRegionQueue being destroyed. - return Collections.emptyList(); - } - - return objects; // OFFHEAP: ok since callers are careful to do destroys on region queue after - // finished with peeked objects. - } - - @VisibleForTesting - public static Predicate getIsLastEventInTransactionPredicate() { - return GatewaySenderEventImpl::isLastEventInTransaction; - } - - @VisibleForTesting - public static Predicate getHasTransactionIdPredicate( - TransactionId transactionId) { - return x -> transactionId.equals(x.getTransactionId()); - } - protected BucketRegionQueue getBucketRegionQueueByBucketId(final PartitionedRegion prQ, final int bucketId) { return (BucketRegionQueue) prQ.getDataStore().getLocalBucketById(bucketId); @@ -2125,7 +2007,7 @@ public int size(PartitionedRegion pr, int bucketId) throws ForceReattemptExcepti throw new RuntimeException("This method(size)is not supported by ParallelGatewaySenderQueue"); } - static class MetaRegionFactory { + public static class MetaRegionFactory { ParallelGatewaySenderQueueMetaRegion newMetataRegion(InternalCache cache, final String prQName, final RegionAttributes ra, AbstractGatewaySender sender) { ParallelGatewaySenderQueueMetaRegion meta = diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventProcessor.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventProcessor.java index 2caad0cc49a0..c5bc0cf06104 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventProcessor.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventProcessor.java @@ -29,15 +29,18 @@ import java.util.stream.Collectors; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.apache.geode.CancelException; import org.apache.geode.SystemFailure; import org.apache.geode.cache.CacheException; +import org.apache.geode.cache.CacheListener; import org.apache.geode.cache.EntryEvent; import org.apache.geode.cache.Operation; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionDestroyedException; +import org.apache.geode.cache.asyncqueue.AsyncEvent; import org.apache.geode.cache.wan.GatewayQueueEvent; import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.distributed.DistributedSystem; @@ -47,6 +50,7 @@ import org.apache.geode.internal.cache.EnumListenerEvent; import org.apache.geode.internal.cache.EventID; import org.apache.geode.internal.cache.LocalRegion; +import org.apache.geode.internal.cache.RegionQueue; import org.apache.geode.internal.cache.wan.AbstractGatewaySender; import org.apache.geode.internal.cache.wan.AbstractGatewaySender.EventWrapper; import org.apache.geode.internal.cache.wan.AbstractGatewaySenderEventProcessor; @@ -126,13 +130,20 @@ protected void initializeMessageQueue(String id, boolean cleanQueues) { final SerialSecondaryGatewayListener listener = getAndInitializeCacheListener(); // Create the region queue - queue = new SerialGatewaySenderQueue(sender, regionName, listener, cleanQueues); + queue = createRegionQueue(sender, regionName, listener, cleanQueues); if (logger.isDebugEnabled()) { logger.debug("Created queue: {}", queue); } } + protected @NotNull RegionQueue createRegionQueue(final @NotNull AbstractGatewaySender sender, + final @NotNull String regionName, + final @NotNull CacheListener> listener, + final boolean cleanQueues) { + return new SerialGatewaySenderQueue(sender, regionName, listener, cleanQueues); + } + @Nullable private SerialSecondaryGatewayListener getAndInitializeCacheListener() { if (!sender.isPrimary()) { diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueue.java b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueue.java index e76ec400f0a8..b182210b6cce 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueue.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueue.java @@ -15,23 +15,17 @@ package org.apache.geode.internal.cache.wan.serial; import static org.apache.geode.cache.wan.GatewaySender.DEFAULT_BATCH_SIZE; -import static org.apache.geode.cache.wan.GatewaySender.GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS; import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast; import java.util.ArrayList; -import java.util.Collections; import java.util.Deque; import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; import org.apache.logging.log4j.Logger; @@ -55,7 +49,6 @@ import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.Scope; import org.apache.geode.cache.TimeoutException; -import org.apache.geode.cache.TransactionId; import org.apache.geode.cache.asyncqueue.AsyncEvent; import org.apache.geode.cache.asyncqueue.internal.AsyncEventQueueImpl; import org.apache.geode.internal.cache.CachedDeserializable; @@ -89,7 +82,7 @@ */ public class SerialGatewaySenderQueue implements RegionQueue { - private static final Logger logger = LogService.getLogger(); + protected static final Logger logger = LogService.getLogger(); /** * The key into the Region used when taking entries from the queue. This value is @@ -111,23 +104,7 @@ public class SerialGatewaySenderQueue implements RegionQueue { */ private final AtomicLong lastPeekedId = new AtomicLong(-1); - private final Deque peekedIds = new LinkedBlockingDeque<>(); - - /** - * Contains the set of peekedIds that were peeked to complete a transaction - * inside a batch when groupTransactionEvents is set. - */ - private final Set extraPeekedIds = ConcurrentHashMap.newKeySet(); - - /** - * Contains the set of peekedIds that were peeked to complete a transaction - * inside a batch when groupTransactionEvents is set and whose event has been - * removed from the queue because an ack has been received from the receiver. - * Elements from this set are deleted when the event with the previous id - * is removed. - */ - private final Set extraPeekedIdsRemovedButPreviousIdNotRemoved = - ConcurrentHashMap.newKeySet(); + protected final Deque peekedIds = new LinkedBlockingDeque<>(); /** * The name of the Region backing this queue @@ -137,7 +114,7 @@ public class SerialGatewaySenderQueue implements RegionQueue { /** * The Region backing this queue */ - private Region> region; + protected Region> region; /** * The name of the DiskStore to overflow this queue @@ -172,7 +149,7 @@ public class SerialGatewaySenderQueue implements RegionQueue { */ private final Map> indexes; - private final GatewaySenderStats stats; + protected final GatewaySenderStats stats; /** * The maximum allowed key before the keys are rolled over @@ -185,9 +162,9 @@ public class SerialGatewaySenderQueue implements RegionQueue { private static final boolean NO_ACK = Boolean.getBoolean(GeodeGlossary.GEMFIRE_PREFIX + "gateway-queue-no-ack"); - private volatile long lastDispatchedKey = -1; + protected volatile long lastDispatchedKey = -1; - private volatile long lastDestroyedKey = -1; + protected volatile long lastDestroyedKey = -1; public static final int DEFAULT_MESSAGE_SYNC_INTERVAL = 1; @@ -196,17 +173,17 @@ public class SerialGatewaySenderQueue implements RegionQueue { private final BatchRemovalThread removalThread; - private final AbstractGatewaySender sender; + protected AbstractGatewaySender sender = null; private final MetaRegionFactory metaRegionFactory; public SerialGatewaySenderQueue(AbstractGatewaySender abstractSender, String regionName, - CacheListener> listener, boolean cleanQueues) { + CacheListener listener, boolean cleanQueues) { this(abstractSender, regionName, listener, cleanQueues, new MetaRegionFactory()); } public SerialGatewaySenderQueue(AbstractGatewaySender abstractSender, String regionName, - CacheListener> listener, boolean cleanQueues, + CacheListener listener, boolean cleanQueues, MetaRegionFactory metaRegionFactory) { // The queue starts out with headKey and tailKey equal to -1 to force // them to be initialized from the region. @@ -224,8 +201,8 @@ public SerialGatewaySenderQueue(AbstractGatewaySender abstractSender, String reg } else { isDiskSynchronous = false; } - maximumQueueMemory = abstractSender.getMaximumMemeoryPerDispatcherQueue(); - stats = abstractSender.getStatistics(); + this.maximumQueueMemory = abstractSender.getMaximumMemoryPerDispatcherQueue(); + this.stats = abstractSender.getStatistics(); initializeRegion(abstractSender, listener); // Increment queue size. Fix for bug 51988. stats.incQueueSize(region.size()); @@ -307,15 +284,11 @@ public synchronized void remove() throws CacheException { if (peekedIds.isEmpty()) { return; } - boolean wasEmpty = lastDispatchedKey == lastDestroyedKey; - Long key = peekedIds.remove(); - boolean isExtraPeekedId = extraPeekedIds.contains(key); - if (!isExtraPeekedId) { - updateHeadKey(key); - lastDispatchedKey = key; - } else { - extraPeekedIdsRemovedButPreviousIdNotRemoved.add(key); - } + final boolean wasEmpty = lastDispatchedKey == lastDestroyedKey; + final Long key = peekedIds.remove(); + + preProcessRemovedKey(key); + removeIndex(key); // Remove the entry at that key with a callback arg signifying it is // a WAN queue so that AbstractRegionEntry.destroy can get the value @@ -334,18 +307,7 @@ public synchronized void remove() throws CacheException { } } - // For those extraPeekedIds removed that are consecutive to lastDispatchedKey: - // - Update lastDispatchedKey with them so that they are removed - // by the batch removal thread. - // - Update the head key with them. - // - Remove them from extraPeekedIds. - long tmpKey = lastDispatchedKey; - while (extraPeekedIdsRemovedButPreviousIdNotRemoved.contains(tmpKey = inc(tmpKey))) { - extraPeekedIdsRemovedButPreviousIdNotRemoved.remove(tmpKey); - extraPeekedIds.remove(tmpKey); - updateHeadKey(tmpKey); - lastDispatchedKey = tmpKey; - } + postProcessRemovedKey(); if (wasEmpty) { synchronized (this) { @@ -360,6 +322,14 @@ public synchronized void remove() throws CacheException { } } + protected void preProcessRemovedKey(final Long key) { + updateHeadKey(key); + lastDispatchedKey = key; + } + + protected void postProcessRemovedKey() {} + + /** * This method removes batchSize entries from the queue. It will only remove entries that were * previously peeked. @@ -439,9 +409,8 @@ public Object peek() throws CacheException { } } } - if (batch.size() > 0) { - peekEventsFromIncompleteTransactions(batch, lastKey); - } + + postProcessBatch(batch, lastKey); if (isTraceEnabled) { logger.trace("{}: Peeked a batch of {} entries", this, batch.size()); @@ -451,79 +420,7 @@ public Object peek() throws CacheException { // so no need to worry about off-heap refCount. } - @VisibleForTesting - void peekEventsFromIncompleteTransactions(List> batch, long lastKey) { - if (!mustGroupTransactionEvents()) { - return; - } - - Set incompleteTransactionIdsInBatch = getIncompleteTransactionsInBatch(batch); - if (incompleteTransactionIdsInBatch.size() == 0) { - return; - } - - int retries = 0; - while (true) { - for (Iterator iter = incompleteTransactionIdsInBatch.iterator(); iter - .hasNext();) { - TransactionId transactionId = iter.next(); - List keyAndEventPairs = - peekEventsWithTransactionId(transactionId, lastKey); - if (keyAndEventPairs.size() > 0 - && ((GatewaySenderEventImpl) (keyAndEventPairs.get(keyAndEventPairs.size() - 1)).event) - .isLastEventInTransaction()) { - for (KeyAndEventPair object : keyAndEventPairs) { - GatewaySenderEventImpl event = (GatewaySenderEventImpl) object.event; - batch.add(event); - peekedIds.add(object.key); - extraPeekedIds.add(object.key); - if (logger.isDebugEnabled()) { - logger.debug( - "Peeking extra event: {}, isLastEventInTransaction: {}, batch size: {}", - event.getKey(), event.isLastEventInTransaction(), batch.size()); - } - } - iter.remove(); - } - } - if (incompleteTransactionIdsInBatch.size() == 0 || - retries >= sender.getRetriesToGetTransactionEventsFromQueue()) { - break; - } - retries++; - try { - Thread.sleep(GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - if (incompleteTransactionIdsInBatch.size() > 0) { - logger.warn("Not able to retrieve all events for transactions: {} after {} retries of {}ms", - incompleteTransactionIdsInBatch, retries, GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); - stats.incBatchesWithIncompleteTransactions(); - } - } - - protected boolean mustGroupTransactionEvents() { - return sender.mustGroupTransactionEvents(); - } - - private Set getIncompleteTransactionsInBatch(List> batch) { - Set incompleteTransactionsInBatch = new HashSet<>(); - for (Object object : batch) { - if (object instanceof GatewaySenderEventImpl) { - GatewaySenderEventImpl event = (GatewaySenderEventImpl) object; - if (event.getTransactionId() != null) { - if (event.isLastEventInTransaction()) { - incompleteTransactionsInBatch.remove(event.getTransactionId()); - } else { - incompleteTransactionsInBatch.add(event.getTransactionId()); - } - } - } - } - return incompleteTransactionsInBatch; - } + protected void postProcessBatch(final List> batch, final long lastKey) {} @Override public String toString() { @@ -640,7 +537,7 @@ private void removeOldEntry(Conflatable object, Long tailKey) throws CacheExcept /** * Does a get that gets the value without fault values in from disk. */ - private AsyncEvent optimalGet(Long k) { + protected AsyncEvent optimalGet(Long k) { // Get the object at that key (to remove the index). LocalRegion lr = (LocalRegion) region; Object o = null; @@ -662,7 +559,7 @@ private void removeOldEntry(Conflatable object, Long tailKey) throws CacheExcept /* * this must be invoked under synchronization */ - private void removeIndex(Long qkey) { + protected void removeIndex(Long qkey) { // Determine whether conflation is enabled for this queue and object if (enableConflation) { // only call get after checking enableConflation for bug 40508 @@ -705,7 +602,7 @@ private boolean before(long a, long b) { return a < b ^ a - b > (MAXIMUM_KEY / 2); } - private long inc(long value) { + protected long inc(long value) { long val = value + 1; val = val == MAXIMUM_KEY ? 0 : val; return val; @@ -717,7 +614,6 @@ private long inc(long value) { */ public void resetLastPeeked() { peekedIds.clear(); - extraPeekedIds.clear(); lastPeekedId.set(-1); } @@ -753,11 +649,11 @@ private Long getCurrentKey() { } @VisibleForTesting - static class KeyAndEventPair { + public static class KeyAndEventPair { public final long key; public final AsyncEvent event; - KeyAndEventPair(Long key, AsyncEvent event) { + public KeyAndEventPair(Long key, AsyncEvent event) { this.key = key; this.event = event; } @@ -786,7 +682,7 @@ public KeyAndEventPair peekAhead() throws CacheException { // does not save anything since GatewayBatchOp needs to GatewayEventImpl // in object form. while (before(currentKey, getTailKey())) { - if (!extraPeekedIds.contains(currentKey)) { + if (!skipPeekedKey(currentKey)) { object = getObjectInSerialSenderQueue(currentKey); if (object != null) { break; @@ -796,12 +692,7 @@ public KeyAndEventPair peekAhead() throws CacheException { logger.trace("{}: Trying head key + offset: {}", this, currentKey); } currentKey = inc(currentKey); - // When mustGroupTransactionEvents is true, conflation cannot be enabled. - // Therefore, if we reach here, it would not be due to a conflated event - // but rather to an extra peeked event already sent. - if (!mustGroupTransactionEvents() && stats != null) { - stats.incEventsNotQueuedConflated(); - } + incrementEventsNotQueueConflated(); } if (logger.isDebugEnabled()) { @@ -816,49 +707,14 @@ public KeyAndEventPair peekAhead() throws CacheException { return null; } - private List peekEventsWithTransactionId(TransactionId transactionId, - long lastKey) { - Predicate hasTransactionIdPredicate = - x -> transactionId.equals(x.getTransactionId()); - Predicate isLastEventInTransactionPredicate = - GatewaySenderEventImpl::isLastEventInTransaction; - - return getElementsMatching(hasTransactionIdPredicate, isLastEventInTransactionPredicate, - lastKey); + protected boolean skipPeekedKey(Long currentKey) { + return false; } - /** - * This method returns a list of objects that fulfill the matchingPredicate - * If a matching object also fulfills the endPredicate then the method - * stops looking for more matching objects. - */ - List getElementsMatching(Predicate condition, - Predicate stopCondition, - long lastKey) { - GatewaySenderEventImpl event; - List elementsMatching = new ArrayList<>(); - - long currentKey = lastKey; - - while ((currentKey = inc(currentKey)) != getTailKey()) { - if (extraPeekedIds.contains(currentKey)) { - continue; - } - event = (GatewaySenderEventImpl) optimalGet(currentKey); - if (event == null) { - continue; - } - - if (condition.test(event)) { - elementsMatching.add(new KeyAndEventPair(currentKey, event)); - - if (stopCondition.test(event)) { - break; - } - } + protected void incrementEventsNotQueueConflated() { + if (stats != null) { + stats.incEventsNotQueuedConflated(); } - - return elementsMatching; } /** @@ -867,7 +723,7 @@ List getElementsMatching(Predicate cond * * @return the value of the tail key */ - private long getTailKey() throws CacheException { + protected long getTailKey() throws CacheException { long tlKey; // Test whether tailKey = -1. If so, the queue has just been created. // Go into the region to get the value of TAIL_KEY. If it is null, then @@ -995,7 +851,7 @@ private long getHeadKey() throws CacheException { * Increments the value of the head key by one. * */ - private void updateHeadKey(long destroyedKey) throws CacheException { + protected void updateHeadKey(long destroyedKey) throws CacheException { headKey = inc(destroyedKey); if (logger.isTraceEnabled()) { logger.trace("{}: Incremented HEAD_KEY for region {} to {}", this, region.getName(), @@ -1013,7 +869,7 @@ private void updateHeadKey(long destroyedKey) throws CacheException { * null. */ private void initializeRegion(AbstractGatewaySender sender, - CacheListener> listener) { + CacheListener listener) { final InternalCache gemCache = sender.getCache(); region = gemCache.getRegion(regionName); if (region == null) { @@ -1286,17 +1142,12 @@ public void shutdown() { } @VisibleForTesting - long getLastPeekedId() { + public long getLastPeekedId() { return lastPeekedId.get(); } - @VisibleForTesting - Set getExtraPeekedIds() { - return Collections.unmodifiableSet(extraPeekedIds); - } - public static class SerialGatewaySenderQueueMetaRegion extends DistributedRegion { - final AbstractGatewaySender sender; + AbstractGatewaySender sender; protected SerialGatewaySenderQueueMetaRegion(String regionName, RegionAttributes attrs, LocalRegion parentRegion, InternalCache cache, AbstractGatewaySender sender, @@ -1399,7 +1250,7 @@ public boolean virtualPut(EntryEventImpl event, boolean ifNew, boolean ifOld, } } - static class MetaRegionFactory { + protected static class MetaRegionFactory { SerialGatewaySenderQueueMetaRegion newMetaRegion(InternalCache cache, final String regionName, final RegionAttributes ra, diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ParallelAsyncEventQueueCreation.java b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ParallelAsyncEventQueueCreation.java index b299925fbdb6..4d906fb93dd0 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ParallelAsyncEventQueueCreation.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ParallelAsyncEventQueueCreation.java @@ -16,8 +16,6 @@ import static org.apache.geode.internal.statistics.StatisticsClockFactory.disabledClock; -import java.util.List; - import org.apache.geode.CancelCriterion; import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.distributed.internal.DistributionAdvisee; @@ -26,7 +24,6 @@ import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.cache.EntryEventImpl; -import org.apache.geode.internal.cache.EnumListenerEvent; import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.internal.cache.wan.AbstractGatewaySender; import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; @@ -38,10 +35,6 @@ public ParallelAsyncEventQueueCreation(InternalCache cache, GatewaySenderAttribu super(cache, disabledClock(), attrs); } - @Override - public void distribute(EnumListenerEvent operation, EntryEventImpl event, - List remoteDSIds) {} - @Override public void start() {} @@ -56,6 +49,11 @@ public void rebalance() { throw new UnsupportedOperationException(); } + @Override + public String getType() { + return "ParallelAsyncEventQueue"; + } + @Override public void fillInProfile(Profile profile) {} diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/SerialAsyncEventQueueCreation.java b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/SerialAsyncEventQueueCreation.java index 4b44799e0690..e48016ac8729 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/SerialAsyncEventQueueCreation.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/SerialAsyncEventQueueCreation.java @@ -16,8 +16,6 @@ import static org.apache.geode.internal.statistics.StatisticsClockFactory.disabledClock; -import java.util.List; - import org.apache.geode.CancelCriterion; import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.distributed.internal.DistributionAdvisee; @@ -26,7 +24,6 @@ import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.cache.EntryEventImpl; -import org.apache.geode.internal.cache.EnumListenerEvent; import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.internal.cache.wan.AbstractGatewaySender; import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; @@ -37,10 +34,6 @@ public SerialAsyncEventQueueCreation(InternalCache cache, GatewaySenderAttribute super(cache, disabledClock(), attrs); } - @Override - public void distribute(EnumListenerEvent operation, EntryEventImpl event, - List remoteDSIds) {} - @Override public void start() {} @@ -55,6 +48,11 @@ public void rebalance() { throw new UnsupportedOperationException(); } + @Override + public String getType() { + return "SerialAsyncEventQueue"; + } + @Override public void fillInProfile(Profile profile) {} diff --git a/geode-core/src/main/java/org/apache/geode/internal/lang/SystemPropertyHelper.java b/geode-core/src/main/java/org/apache/geode/internal/lang/SystemPropertyHelper.java index 3efb25a71c99..1ee51b99b754 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/lang/SystemPropertyHelper.java +++ b/geode-core/src/main/java/org/apache/geode/internal/lang/SystemPropertyHelper.java @@ -99,13 +99,6 @@ public class SystemPropertyHelper { */ public static final String PARALLEL_DISK_STORE_RECOVERY = "parallelDiskStoreRecovery"; - /** - * Milliseconds to wait before retrying to get events for a transaction from the - * gateway sender queue when group-transaction-events is true. - */ - public static final String GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS = - "get-transaction-events-from-queue-wait-time-ms"; - /** * Milliseconds to wait for the client to re-authenticate back before unregister this client * proxy. If client re-authenticate back successfully within this period, messages will continue diff --git a/geode-core/src/main/java/org/apache/geode/management/GatewaySenderMXBean.java b/geode-core/src/main/java/org/apache/geode/management/GatewaySenderMXBean.java index 6831c2ce505d..489be950207e 100644 --- a/geode-core/src/main/java/org/apache/geode/management/GatewaySenderMXBean.java +++ b/geode-core/src/main/java/org/apache/geode/management/GatewaySenderMXBean.java @@ -325,6 +325,13 @@ public interface GatewaySenderMXBean { */ boolean isParallel(); + String getType(); + + /** + * + * @deprecated Use {@link #getType()}. + */ + @Deprecated boolean mustGroupTransactionEvents(); /** diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBean.java b/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBean.java index 6f6638173269..6262deb7ac56 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBean.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBean.java @@ -229,6 +229,12 @@ public boolean isParallel() { return bridge.isParallel(); } + @Override + public String getType() { + return bridge.getType(); + } + + @Deprecated @Override public boolean mustGroupTransactionEvents() { return bridge.mustGroupTransactionEvents(); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBeanBridge.java b/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBeanBridge.java index a4d4aeafd12e..df0feeded143 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBeanBridge.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/beans/GatewaySenderMBeanBridge.java @@ -363,4 +363,8 @@ public boolean isConnected() { public int getEventsExceedingAlertThreshold() { return getStatistic(StatsKey.GATEWAYSENDER_EVENTS_EXCEEDING_ALERT_THRESHOLD).intValue(); } + + public String getType() { + return sender.getType(); + } } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java b/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java index 26d5ed7da28b..f4802d4e2587 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java @@ -2277,10 +2277,15 @@ public class CliStrings { "Ensure that all the events of a transaction are sent in the same batch, i.e., they are never spread across different batches.\n" + "Only allowed on serial gateway senders with 1 dispatcher thread or on parallel ones.\n" + "Note that in order to work for a transaction, the regions to which the transaction \n" - + "events belong must be replicated by the same set of senders with this flag enabled."; + + "events belong must be replicated by the same set of senders with this flag enabled.\n" + + "Deprecated: Since Geode 1.15. Type must be used instead\";"; public static final String CREATE_GATEWAYSENDER__PARALLEL = "parallel"; public static final String CREATE_GATEWAYSENDER__PARALLEL__HELP = - "Whether this is Parallel GatewaySender."; + "Whether this is Parallel GatewaySender.\n" + + "Deprecated: Since Geode 1.15. Type must be used instead\";"; + public static final String CREATE_GATEWAYSENDER__TYPE = "type"; + public static final String CREATE_GATEWAYSENDER__TYPE__HELP = + "Type of the GatewaySender: SerialGatewaySender|ParallelGatewaySender|"; @Deprecated public static final String CREATE_GATEWAYSENDER__MANUALSTART = "manual-start"; @Deprecated diff --git a/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImplTest.java b/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImplTest.java index 15879f35b920..7846454a7d87 100644 --- a/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImplTest.java +++ b/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/ParallelAsyncEventQueueImplTest.java @@ -16,6 +16,8 @@ */ package org.apache.geode.cache.asyncqueue.internal; +import static org.apache.geode.cache.wan.GatewaySender.DEFAULT_DISTRIBUTED_SYSTEM_ID; +import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -43,20 +45,18 @@ @Category(AEQTest.class) public class ParallelAsyncEventQueueImplTest { - private InternalCache cache; - private StatisticsClock statisticsClock; - private StatisticsFactory statsFactory; - private GatewaySenderAttributes attrs; private ParallelAsyncEventQueueImpl asyncEventQueue; @Before public void setUp() { - cache = mock(InternalCache.class, RETURNS_DEEP_STUBS); - statisticsClock = mock(StatisticsClock.class); - statsFactory = mock(StatisticsFactory.class); - attrs = new GatewaySenderAttributes(); - attrs.setParallel(true); - attrs.setId("AsyncEventQueue_"); + InternalCache cache = mock(InternalCache.class, RETURNS_DEEP_STUBS); + StatisticsClock statisticsClock = mock(StatisticsClock.class); + StatisticsFactory statsFactory = mock(StatisticsFactory.class); + GatewaySenderAttributes attrs = mock(GatewaySenderAttributes.class); + when(attrs.isParallel()).thenReturn(true); + when(attrs.getId()).thenReturn("AsyncEventQueue_"); + when(attrs.getDispatcherThreads()).thenReturn(1); + when(attrs.getRemoteDSId()).thenReturn(DEFAULT_DISTRIBUTED_SYSTEM_ID); InternalDistributedSystem system = mock(InternalDistributedSystem.class); when(cache.getInternalDistributedSystem()).thenReturn(system); @@ -72,7 +72,7 @@ public void setUp() { when(cache.getGatewaySenderLockService()).thenReturn(distributedLockService); LocalRegion region = mock(LocalRegion.class); - when(cache.getRegion(any())).thenReturn(region); + when(cache.getRegion(any())).thenReturn(uncheckedCast(region)); when(region.containsKey(any())).thenReturn(true); when(region.get(any())).thenReturn(1); diff --git a/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplTest.java b/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplTest.java index 63b659a710d3..757452327505 100644 --- a/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplTest.java +++ b/geode-core/src/test/java/org/apache/geode/cache/asyncqueue/internal/SerialAsyncEventQueueImplTest.java @@ -17,6 +17,7 @@ package org.apache.geode.cache.asyncqueue.internal; import static org.apache.geode.cache.wan.GatewaySender.DEFAULT_DISTRIBUTED_SYSTEM_ID; +import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; @@ -54,7 +55,6 @@ public class SerialAsyncEventQueueImplTest { private StatisticsFactory statisticsFactory; private GatewaySenderAttributes gatewaySenderAttributes; private StatisticsClock statisticsClock; - private InternalRegionFactory regionFactory; AbstractGatewaySenderEventProcessor eventProcessor1; AbstractGatewaySenderEventProcessor eventProcessor2; @@ -63,9 +63,9 @@ public class SerialAsyncEventQueueImplTest { public void setUp() throws Exception { cache = Fakes.cache(); when(cache.getRegion(any())).thenReturn(null); - regionFactory = mock(InternalRegionFactory.class); - when(regionFactory.create(any())).thenReturn(mock(LocalRegion.class)); - when(cache.createInternalRegionFactory(any())).thenReturn(regionFactory); + InternalRegionFactory regionFactory = mock(InternalRegionFactory.class); + when(regionFactory.create(any())).thenReturn(mock(uncheckedCast(LocalRegion.class))); + when(cache.createInternalRegionFactory(any())).thenReturn(uncheckedCast(regionFactory)); statisticsFactory = mock(StatisticsFactory.class); when(statisticsFactory.createAtomicStatistics(any(), any())).thenReturn(mock(Statistics.class)); @@ -121,7 +121,7 @@ public void whenStartedShouldCreateEventProcessor() { } @Test - public void whenStartedwithCleanShouldCreateEventProcessor() { + public void whenStartedWithCleanShouldCreateEventProcessor() { serialAsyncEventQueue = createSerialAsyncEventQueueImplSpy(); serialAsyncEventQueue.startWithCleanQueue(); diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/BucketRegionQueueJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/BucketRegionQueueJUnitTest.java index 6643695ea085..581f261dfa49 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/BucketRegionQueueJUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/BucketRegionQueueJUnitTest.java @@ -39,7 +39,6 @@ import org.apache.geode.internal.cache.wan.GatewaySenderEventImpl; import org.apache.geode.internal.cache.wan.GatewaySenderStats; import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderHelper; -import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderQueue; import org.apache.geode.internal.statistics.DummyStatisticsFactory; import org.apache.geode.test.fake.Fakes; @@ -169,9 +168,9 @@ public void testGetElementsMatchingWithParallelGatewaySenderQueuePredicatesAndSo bucketRegionQueue.addToQueue(8L, event7); Predicate hasTransactionIdPredicate = - ParallelGatewaySenderQueue.getHasTransactionIdPredicate(tx1); + x -> tx1.equals(x.getTransactionId()); Predicate isLastEventInTransactionPredicate = - ParallelGatewaySenderQueue.getIsLastEventInTransactionPredicate(); + GatewaySenderEventImpl::isLastEventInTransaction; List objects = bucketRegionQueue.getElementsMatching(hasTransactionIdPredicate, isLastEventInTransactionPredicate); @@ -183,8 +182,7 @@ public void testGetElementsMatchingWithParallelGatewaySenderQueuePredicatesAndSo assertEquals(1, objects.size()); assertEquals(objects, Arrays.asList(event7)); - hasTransactionIdPredicate = - ParallelGatewaySenderQueue.getHasTransactionIdPredicate(tx2); + hasTransactionIdPredicate = x -> tx2.equals(x.getTransactionId()); objects = bucketRegionQueue.getElementsMatching(hasTransactionIdPredicate, isLastEventInTransactionPredicate); assertEquals(2, objects.size()); diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueueJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueueJUnitTest.java index 92d1601d8bb6..809ddde0f0bd 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueueJUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderQueueJUnitTest.java @@ -335,71 +335,6 @@ public void isDREventReturnsFalseForPartitionedRegionEvent() { assertThat(queue.isDREvent(cache, event)).isFalse(); } - @Test - public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInMaxSizeBatch() - throws Exception { - - GatewaySenderEventImpl event1 = createGatewaySenderEventImpl(1, false); - GatewaySenderEventImpl event2 = createGatewaySenderEventImpl(2, false); - GatewaySenderEventImpl event3 = createGatewaySenderEventImpl(1, true); - GatewaySenderEventImpl event4 = createGatewaySenderEventImpl(2, true); - GatewaySenderEventImpl event5 = createGatewaySenderEventImpl(3, false); - GatewaySenderEventImpl event6 = createGatewaySenderEventImpl(3, true); - - Queue backingList = new LinkedList<>(); - backingList.add(event1); - backingList.add(event2); - backingList.add(event3); - backingList.add(event4); - backingList.add(event5); - backingList.add(event6); - - BucketRegionQueue bucketRegionQueue = mockBucketRegionQueue(backingList); - - TestableParallelGatewaySenderQueue queue = new TestableParallelGatewaySenderQueue(sender, - Collections.emptySet(), 0, 1, metaRegionFactory); - queue.setGroupTransactionEvents(true); - queue.setMockedAbstractBucketRegionQueue(bucketRegionQueue); - - List peeked = queue.peek(3, 100); - assertEquals(4, peeked.size()); - List peekedAfter = queue.peek(3, 100); - assertEquals(2, peekedAfter.size()); - } - - @Test - public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInBatchByTime() - throws Exception { - - GatewaySenderEventImpl event1 = createGatewaySenderEventImpl(1, false); - GatewaySenderEventImpl event2 = createGatewaySenderEventImpl(2, false); - GatewaySenderEventImpl event3 = createGatewaySenderEventImpl(1, true); - GatewaySenderEventImpl event4 = createGatewaySenderEventImpl(2, true); - GatewaySenderEventImpl event5 = createGatewaySenderEventImpl(3, false); - GatewaySenderEventImpl event6 = createGatewaySenderEventImpl(3, true); - - Queue backingList = new LinkedList<>(); - backingList.add(event1); - backingList.add(event2); - backingList.add(event3); - backingList.add(null); - backingList.add(event4); - backingList.add(event5); - backingList.add(event6); - - BucketRegionQueue bucketRegionQueue = mockBucketRegionQueue(backingList); - - TestableParallelGatewaySenderQueue queue = new TestableParallelGatewaySenderQueue(sender, - Collections.emptySet(), 0, 1, metaRegionFactory); - queue.setGroupTransactionEvents(true); - queue.setMockedAbstractBucketRegionQueue(bucketRegionQueue); - - List peeked = queue.peek(-1, 1); - assertEquals(4, peeked.size()); - List peekedAfter = queue.peek(-1, 100); - assertEquals(2, peekedAfter.size()); - } - @Test public void peekDoesNotGetExtraEventsWhenNotMustGroupTransactionEventsAndNotAllEventsForTransactionsInBatchMaxSize() throws Exception { @@ -482,7 +417,7 @@ public void peekEventsFromIncompleteTransactionsDoesNotThrowConcurrentModificati List batch = new ArrayList<>(Arrays.asList(event1, event2)); PartitionedRegion mockBucketRegion = mockPR("bucketRegion"); - queue.peekEventsFromIncompleteTransactions(batch, mockBucketRegion); + queue.postProcessBatch(mockBucketRegion, batch); } @@ -710,11 +645,6 @@ public void setGroupTransactionEvents(boolean groupTransactionEvents) { this.groupTransactionEvents = groupTransactionEvents; } - @Override - public boolean mustGroupTransactionEvents() { - return groupTransactionEvents; - } - @Override public boolean areLocalBucketQueueRegionsPresent() { return true; diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueueJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueueJUnitTest.java index 88ec275fd85d..9e8119fa7b59 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueueJUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderQueueJUnitTest.java @@ -14,20 +14,13 @@ */ package org.apache.geode.internal.cache.wan.serial; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -104,51 +97,6 @@ public void setup() { when(metaRegionFactory.newMetaRegion(any(), any(), any(), any())).thenReturn(mockMetaRegion); } - @Test - public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInMaxSizeBatch() { - TestableSerialGatewaySenderQueue queue = new TestableSerialGatewaySenderQueue(sender, - QUEUE_REGION, metaRegionFactory); - queue.setGroupTransactionEvents(true); - - List> peeked = queue.peek(3, 100); - assertEquals(4, peeked.size()); - List> peekedAfter = queue.peek(3, 100); - assertEquals(3, peekedAfter.size()); - } - - @Test - public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInBatchByTime() { - GatewaySenderEventImpl event1 = createMockGatewaySenderEventImpl(1, false, region); - GatewaySenderEventImpl event2 = createMockGatewaySenderEventImpl(2, false, region); - GatewaySenderEventImpl event3 = createMockGatewaySenderEventImpl(1, true, region); - GatewaySenderEventImpl event4 = createMockGatewaySenderEventImpl(2, true, region); - SerialGatewaySenderQueue.KeyAndEventPair eventPair1 = - new SerialGatewaySenderQueue.KeyAndEventPair(0L, event1); - SerialGatewaySenderQueue.KeyAndEventPair eventPair2 = - new SerialGatewaySenderQueue.KeyAndEventPair(1L, event2); - SerialGatewaySenderQueue.KeyAndEventPair eventPair3 = - new SerialGatewaySenderQueue.KeyAndEventPair(2L, event3); - - TestableSerialGatewaySenderQueue realQueue = new TestableSerialGatewaySenderQueue(sender, - QUEUE_REGION, metaRegionFactory); - - TestableSerialGatewaySenderQueue queue = spy(realQueue); - queue.setGroupTransactionEvents(true); - - doAnswer(invocation -> eventPair1) - .doAnswer(invocation -> eventPair2) - .doAnswer(invocation -> eventPair3) - .doAnswer(invocation -> null) - .when(queue).peekAhead(); - - doAnswer(invocation -> Collections - .singletonList(new SerialGatewaySenderQueue.KeyAndEventPair(1L, event4))) - .when(queue).getElementsMatching(any(), any(), anyLong()); - - List> peeked = queue.peek(-1, 1); - assertEquals(4, peeked.size()); - } - @Test public void peekDoesNotGetExtraEventsWhenNotMustGroupTransactionEventsAndNotAllEventsForTransactionsInBatchMaxSize() { TestableSerialGatewaySenderQueue queue = new TestableSerialGatewaySenderQueue(sender, @@ -162,80 +110,6 @@ public void peekDoesNotGetExtraEventsWhenNotMustGroupTransactionEventsAndNotAllE assertEquals(1, peekedAfter.size()); } - @Test - public void peekDoesNotGetExtraEventsWhenNotMustGroupTransactionEventsAndNotAllEventsForTransactionsInBatchByTime() { - GatewaySenderEventImpl event1 = createMockGatewaySenderEventImpl(1, false, region); - GatewaySenderEventImpl event2 = createMockGatewaySenderEventImpl(2, false, region); - GatewaySenderEventImpl event3 = createMockGatewaySenderEventImpl(1, true, region); - GatewaySenderEventImpl event4 = createMockGatewaySenderEventImpl(2, true, region); - SerialGatewaySenderQueue.KeyAndEventPair eventPair1 = - new SerialGatewaySenderQueue.KeyAndEventPair(0L, event1); - SerialGatewaySenderQueue.KeyAndEventPair eventPair2 = - new SerialGatewaySenderQueue.KeyAndEventPair(1L, event2); - SerialGatewaySenderQueue.KeyAndEventPair eventPair3 = - new SerialGatewaySenderQueue.KeyAndEventPair(2L, event3); - - TestableSerialGatewaySenderQueue realQueue = new TestableSerialGatewaySenderQueue(sender, - QUEUE_REGION, metaRegionFactory); - - TestableSerialGatewaySenderQueue queue = spy(realQueue); - queue.setGroupTransactionEvents(false); - - doAnswer(invocation -> eventPair1) - .doAnswer(invocation -> eventPair2) - .doAnswer(invocation -> eventPair3) - .doAnswer(invocation -> null) - .when(queue).peekAhead(); - - doAnswer(invocation -> Collections - .singletonList(new SerialGatewaySenderQueue.KeyAndEventPair(2L, event4))) - .when(queue).getElementsMatching(any(), any(), anyLong()); - - List> peeked = queue.peek(-1, 1); - assertEquals(3, peeked.size()); - } - - @Test - public void peekEventsFromIncompleteTransactionsDoesNotThrowConcurrentModificationExceptionWhenCompletingTwoTransactions() { - GatewaySenderEventImpl event1 = createMockGatewaySenderEventImpl(1, false, region); - GatewaySenderEventImpl event2 = createMockGatewaySenderEventImpl(2, false, region); - - TestableSerialGatewaySenderQueue queue = new TestableSerialGatewaySenderQueue(sender, - QUEUE_REGION, metaRegionFactory); - - queue.setGroupTransactionEvents(true); - - @SuppressWarnings("unchecked") - List> batch = new ArrayList(Arrays.asList(event1, event2)); - queue.peekEventsFromIncompleteTransactions(batch, 0); - } - - @Test - public void removeExtraPeekedEventDoesNotRemoveFromExtraPeekedIdsUntilPreviousEventIsRemoved() { - TestableSerialGatewaySenderQueue queue = new TestableSerialGatewaySenderQueue(sender, - QUEUE_REGION, metaRegionFactory); - queue.setGroupTransactionEvents(true); - List> peeked = queue.peek(3, -1); - assertEquals(4, peeked.size()); - assertThat(queue.getLastPeekedId()).isEqualTo(2); - assertThat(queue.getExtraPeekedIds().contains(5L)).isTrue(); - - - for (Object ignored : peeked) { - queue.remove(); - } - assertThat(queue.getExtraPeekedIds().contains(5L)).isTrue(); - - peeked = queue.peek(3, -1); - assertEquals(3, peeked.size()); - assertThat(queue.getExtraPeekedIds().contains(5L)).isTrue(); - - for (Object ignored : peeked) { - queue.remove(); - } - assertThat(queue.getExtraPeekedIds().contains(5L)).isFalse(); - } - private GatewaySenderEventImpl createMockGatewaySenderEventImpl(int transactionId, boolean isLastEventInTransaction, Region region) { GatewaySenderEventImpl event = mock(GatewaySenderEventImpl.class); @@ -287,15 +161,6 @@ public TestableSerialGatewaySenderQueue(final AbstractGatewaySender sender, super(sender, regionName, null, false, metaRegionFactory); } - public void setGroupTransactionEvents(boolean groupTransactionEvents) { - this.groupTransactionEvents = groupTransactionEvents; - } - - @Override - public boolean mustGroupTransactionEvents() { - return groupTransactionEvents; - } - @Override protected void addOverflowStatisticsToMBean(Cache cache, AbstractGatewaySender sender) {} diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/AlterGatewaySenderCommand.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/AlterGatewaySenderCommand.java index 415366216410..9647408f394c 100644 --- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/AlterGatewaySenderCommand.java +++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/AlterGatewaySenderCommand.java @@ -113,18 +113,9 @@ public ResultModel alterGatewaySender(@CliOption(key = CliStrings.ALTER_GATEWAYS "alter-gateway-sender cannot be performed for --batch-time-interval values smaller then -1."); } - if (groupTransactionEvents != null && groupTransactionEvents - && !oldConfiguration.mustGroupTransactionEvents()) { - if (!oldConfiguration.isParallel() && (oldConfiguration.getDispatcherThreads() == null - || Integer.parseInt(oldConfiguration.getDispatcherThreads()) > 1)) { - return ResultModel.createError( - "alter-gateway-sender cannot be performed for --group-transaction-events attribute if serial sender and dispatcher-threads is greater than 1."); - } - - if (oldConfiguration.isEnableBatchConflation()) { - return ResultModel.createError( - "alter-gateway-sender cannot be performed for --group-transaction-events attribute if batch-conflation is enabled."); - } + if (groupTransactionEvents != null && groupTransactionEvents) { + return ResultModel.createError( + "alter-gateway-sender cannot be performed for --group-transaction-events attribute."); } Set dsMembers = findMembers(onGroup, onMember); diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommand.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommand.java index b02c6f1dbe41..37ee1c9b335b 100644 --- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommand.java +++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommand.java @@ -76,16 +76,20 @@ public ResultModel createGatewaySender( help = CliStrings.CREATE_GATEWAYSENDER__MEMBER__HELP) String[] onMember, - @CliOption(key = CliStrings.CREATE_GATEWAYSENDER__GROUPTRANSACTIONEVENTS, + @SuppressWarnings("deprecation") @CliOption( + key = CliStrings.CREATE_GATEWAYSENDER__GROUPTRANSACTIONEVENTS, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = CliStrings.CREATE_GATEWAYSENDER__GROUPTRANSACTIONEVENTS__HELP) boolean groupTransactionEvents, - @CliOption(key = CliStrings.CREATE_GATEWAYSENDER__PARALLEL, + @SuppressWarnings("deprecation") @CliOption(key = CliStrings.CREATE_GATEWAYSENDER__PARALLEL, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = CliStrings.CREATE_GATEWAYSENDER__PARALLEL__HELP) boolean parallel, + @CliOption(key = CliStrings.CREATE_GATEWAYSENDER__TYPE, + help = CliStrings.CREATE_GATEWAYSENDER__TYPE__HELP) String type, + // Users must avoid this feature, it might cause data loss and other issues during startup. @SuppressWarnings("deprecation") @CliOption( key = CliStrings.CREATE_GATEWAYSENDER__MANUALSTART, @@ -146,7 +150,7 @@ public ResultModel createGatewaySender( help = CliStrings.CREATE_GATEWAYSENDER__ENFORCE_THREADS_CONNECT_SAME_RECEIVER__HELP) Boolean enforceThreadsConnectSameReceiver) { CacheConfig.GatewaySender configuration = - buildConfiguration(id, remoteDistributedSystemId, parallel, manualStart, + buildConfiguration(id, remoteDistributedSystemId, parallel, type, manualStart, socketBufferSize, socketReadTimeout, enableBatchConflation, batchSize, batchTimeInterval, enablePersistence, diskStoreName, diskSynchronous, maxQueueMemory, alertThreshold, dispatcherThreads, orderPolicy == null ? null : orderPolicy.name(), @@ -220,6 +224,7 @@ private boolean verifyAllCurrentVersion(Set members) { private CacheConfig.GatewaySender buildConfiguration(String id, Integer remoteDSId, Boolean parallel, + String type, Boolean manualStart, Integer socketBufferSize, Integer socketReadTimeout, @@ -241,6 +246,7 @@ private CacheConfig.GatewaySender buildConfiguration(String id, Integer remoteDS sender.setId(id); sender.setRemoteDistributedSystemId(int2string(remoteDSId)); sender.setParallel(parallel); + sender.setType(type); sender.setManualStart(manualStart); sender.setSocketBufferSize(int2string(socketBufferSize)); sender.setSocketReadTimeout(int2string(socketReadTimeout)); diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/ListGatewayCommand.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/ListGatewayCommand.java index c0984adf5aee..bf8c1ab1292f 100644 --- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/ListGatewayCommand.java +++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/ListGatewayCommand.java @@ -156,8 +156,7 @@ protected void accumulateListGatewayResult(ResultModel result, gatewaySenders.accumulate(CliStrings.RESULT_HOST_MEMBER, memberToBean.getKey()); gatewaySenders.accumulate(CliStrings.RESULT_REMOTE_CLUSTER, memberToBean.getValue().getRemoteDSId() + ""); - gatewaySenders.accumulate(CliStrings.RESULT_TYPE, memberToBean.getValue().isParallel() - ? CliStrings.SENDER_PARALLEL : CliStrings.SENDER_SERIAL); + gatewaySenders.accumulate(CliStrings.RESULT_TYPE, memberToBean.getValue().getType()); gatewaySenders.accumulate(CliStrings.RESULT_STATUS, getStatus(memberToBean.getValue())); gatewaySenders.accumulate(CliStrings.RESULT_QUEUED_EVENTS, memberToBean.getValue().getEventQueueSize() + ""); diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/AlterGatewaySenderFunction.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/AlterGatewaySenderFunction.java index 1169cb2f624f..77ae264d9311 100644 --- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/AlterGatewaySenderFunction.java +++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/AlterGatewaySenderFunction.java @@ -95,12 +95,6 @@ private GatewaySender alterGatewaySender(Cache cache, ((AbstractGatewaySender) gateway).setBatchTimeInterval(batchTimeInterval); } - Boolean groupTransactionEvents = gatewaySenderCreateArgs.mustGroupTransactionEvents(); - if (groupTransactionEvents != null) { - ((AbstractGatewaySender) gateway) - .setGroupTransactionEvents(groupTransactionEvents); - } - List gatewayEventFilters = gatewaySenderCreateArgs.getGatewayEventFilter(); if (gatewayEventFilters != null) { List filters = new ArrayList<>(); diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderCreateFunction.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderCreateFunction.java index 9d26114ddff0..f38617089e28 100644 --- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderCreateFunction.java +++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderCreateFunction.java @@ -82,9 +82,15 @@ private GatewaySender createGatewaySender(Cache cache, GatewaySenderFunctionArgs gatewaySenderCreateArgs) { GatewaySenderFactory gateway = cache.createGatewaySenderFactory(); - Boolean isParallel = gatewaySenderCreateArgs.isParallel(); - if (isParallel != null) { - gateway.setParallel(isParallel); + String type = gatewaySenderCreateArgs.getType(); + if (type != null) { + gateway.setType(type); + gateway.setParallel(type.contains("Parallel")); + } else { + Boolean isParallel = gatewaySenderCreateArgs.isParallel(); + if (isParallel != null) { + gateway.setParallel(isParallel); + } } Boolean groupTransactionEvents = gatewaySenderCreateArgs.mustGroupTransactionEvents(); diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderFunctionArgs.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderFunctionArgs.java index 640e69bd2c6e..25914c13af42 100644 --- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderFunctionArgs.java +++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/GatewaySenderFunctionArgs.java @@ -31,6 +31,7 @@ public class GatewaySenderFunctionArgs implements Serializable { private final Integer remoteDSId; private final Boolean parallel; private final Boolean groupTransactionEvents; + private final String type; private final Boolean manualStart; private final Integer socketBufferSize; private final Integer socketReadTimeout; @@ -52,8 +53,13 @@ public class GatewaySenderFunctionArgs implements Serializable { public GatewaySenderFunctionArgs(CacheConfig.GatewaySender sender) { id = sender.getId(); remoteDSId = string2int(sender.getRemoteDistributedSystemId()); - parallel = sender.isParallel(); groupTransactionEvents = sender.mustGroupTransactionEvents(); + type = sender.getType(); + if (type != null) { + parallel = sender.getType().contains("Parallel"); + } else { + parallel = sender.isParallel(); + } manualStart = sender.isManualStart(); socketBufferSize = string2int(sender.getSocketBufferSize()); socketReadTimeout = string2int(sender.getSocketReadTimeout()); @@ -107,6 +113,10 @@ public Boolean mustGroupTransactionEvents() { return groupTransactionEvents; } + public String getType() { + return type; + } + public Boolean isManualStart() { return manualStart; } diff --git a/geode-gfsh/src/main/resources/org/apache/geode/gfsh/internal/management/sanctioned-geode-gfsh-serializables.txt b/geode-gfsh/src/main/resources/org/apache/geode/gfsh/internal/management/sanctioned-geode-gfsh-serializables.txt index e9a15586e71a..77eeba187f1d 100644 --- a/geode-gfsh/src/main/resources/org/apache/geode/gfsh/internal/management/sanctioned-geode-gfsh-serializables.txt +++ b/geode-gfsh/src/main/resources/org/apache/geode/gfsh/internal/management/sanctioned-geode-gfsh-serializables.txt @@ -67,7 +67,7 @@ org/apache/geode/management/internal/cli/functions/GatewayReceiverCreateFunction org/apache/geode/management/internal/cli/functions/GatewaySenderCreateFunction,true,8746830191680509335 org/apache/geode/management/internal/cli/functions/GatewaySenderDestroyFunction,true,1 org/apache/geode/management/internal/cli/functions/GatewaySenderDestroyFunctionArgs,true,3848480256348119530,id:java/lang/String,ifExists:boolean -org/apache/geode/management/internal/cli/functions/GatewaySenderFunctionArgs,true,4636678328980816780,alertThreshold:java/lang/Integer,batchSize:java/lang/Integer,batchTimeInterval:java/lang/Integer,diskStoreName:java/lang/String,diskSynchronous:java/lang/Boolean,dispatcherThreads:java/lang/Integer,enableBatchConflation:java/lang/Boolean,enablePersistence:java/lang/Boolean,enforceThreadsConnectSameReceiver:java/lang/Boolean,gatewayEventFilters:java/util/List,gatewayTransportFilters:java/util/List,groupTransactionEvents:java/lang/Boolean,id:java/lang/String,manualStart:java/lang/Boolean,maxQueueMemory:java/lang/Integer,orderPolicy:java/lang/String,parallel:java/lang/Boolean,remoteDSId:java/lang/Integer,socketBufferSize:java/lang/Integer,socketReadTimeout:java/lang/Integer +org/apache/geode/management/internal/cli/functions/GatewaySenderFunctionArgs,true,4636678328980816780,alertThreshold:java/lang/Integer,batchSize:java/lang/Integer,batchTimeInterval:java/lang/Integer,diskStoreName:java/lang/String,diskSynchronous:java/lang/Boolean,dispatcherThreads:java/lang/Integer,enableBatchConflation:java/lang/Boolean,enablePersistence:java/lang/Boolean,enforceThreadsConnectSameReceiver:java/lang/Boolean,gatewayEventFilters:java/util/List,gatewayTransportFilters:java/util/List,groupTransactionEvents:java/lang/Boolean,id:java/lang/String,manualStart:java/lang/Boolean,maxQueueMemory:java/lang/Integer,orderPolicy:java/lang/String,parallel:java/lang/Boolean,remoteDSId:java/lang/Integer,socketBufferSize:java/lang/Integer,socketReadTimeout:java/lang/Integer,type:java/lang/String org/apache/geode/management/internal/cli/functions/GetMemberConfigInformationFunction,true,1 org/apache/geode/management/internal/cli/functions/GetRegionDescriptionFunction,true,1 org/apache/geode/management/internal/cli/functions/GetRegionsFunction,true,1 diff --git a/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommandTest.java b/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommandTest.java index 783dd4e763ac..7d6007f731c7 100644 --- a/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommandTest.java +++ b/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/CreateGatewaySenderCommandTest.java @@ -340,12 +340,11 @@ public void booleanArgumentsShouldUseTheCustomParameterValueWhenSpecified() { functionResults.add(cliFunctionResult); gfsh.executeAndAssertThat(command, "create gateway-sender --member=xyz --id=testGateway --remote-distributed-system-id=1" - + " --parallel=false" + " --manual-start=false" + " --disk-synchronous=false" + " --enable-persistence=false" + " --enable-batch-conflation=false" - + " --group-transaction-events=false") + + " --type=SerialGatewaySender") .statusIsSuccess(); verify(command).executeAndGetFunctionResult(any(), argsArgumentCaptor.capture(), any()); diff --git a/geode-wan-txgrouping/build.gradle b/geode-wan-txgrouping/build.gradle new file mode 100644 index 000000000000..65c0b201b026 --- /dev/null +++ b/geode-wan-txgrouping/build.gradle @@ -0,0 +1,55 @@ +/* + * 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. + */ + +plugins { + id 'standard-subproject-configuration' + id 'geode-publish-java' +} + +dependencies { + // main + api(platform(project(':boms:geode-all-bom'))) + compileOnly(platform(project(':boms:geode-all-bom'))) + + compileOnly('org.jetbrains:annotations') + + implementation(project(':geode-logging')) + implementation(project(':geode-membership')) + implementation(project(':geode-serialization')) + implementation(project(':geode-tcp-server')) + implementation(project(':geode-core')) + implementation(project(':geode-wan')) + + + // test + testImplementation(project(':geode-junit')) + testImplementation('org.assertj:assertj-core') + testImplementation('junit:junit') + testImplementation('org.mockito:mockito-core') + + integrationTestImplementation(project(':geode-junit')) + integrationTestImplementation('org.assertj:assertj-core') + integrationTestImplementation('junit:junit') + + distributedTestImplementation(project(':geode-dunit')) + distributedTestImplementation(project(':geode-junit')) + + distributedTestImplementation('org.awaitility:awaitility') + distributedTestImplementation('junit:junit') + distributedTestImplementation('org.assertj:assertj-core') + distributedTestImplementation('pl.pragmatists:JUnitParams') +} diff --git a/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingBaseDUnitTest.java b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingBaseDUnitTest.java new file mode 100644 index 000000000000..8579575020d5 --- /dev/null +++ b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingBaseDUnitTest.java @@ -0,0 +1,570 @@ +/* + * 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.wan.txgrouping; + +import static org.apache.geode.cache.Region.SEPARATOR; +import static org.apache.geode.distributed.ConfigurationProperties.DISTRIBUTED_SYSTEM_ID; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.REMOTE_LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.START_LOCATOR; +import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts; +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.apache.geode.test.dunit.VM.getVM; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import org.apache.geode.cache.CacheTransactionManager; +import org.apache.geode.cache.DiskStore; +import org.apache.geode.cache.DiskStoreFactory; +import org.apache.geode.cache.PartitionAttributesFactory; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionFactory; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.TransactionException; +import org.apache.geode.cache.wan.GatewayReceiver; +import org.apache.geode.cache.wan.GatewayReceiverFactory; +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.GatewaySenderFactory; +import org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySender; +import org.apache.geode.distributed.LocatorLauncher; +import org.apache.geode.distributed.ServerLauncher; +import org.apache.geode.internal.cache.CacheServerImpl; +import org.apache.geode.internal.cache.CustomerIDPartitionResolver; +import org.apache.geode.internal.cache.PartitionedRegion; +import org.apache.geode.internal.cache.RegionQueue; +import org.apache.geode.internal.cache.execute.data.CustId; +import org.apache.geode.internal.cache.execute.data.Order; +import org.apache.geode.internal.cache.execute.data.OrderId; +import org.apache.geode.internal.cache.execute.data.Shipment; +import org.apache.geode.internal.cache.execute.data.ShipmentId; +import org.apache.geode.internal.cache.tier.sockets.CacheServerStats; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.GatewayReceiverStats; +import org.apache.geode.internal.cache.wan.GatewaySenderStats; +import org.apache.geode.internal.cache.wan.InternalGatewaySenderFactory; +import org.apache.geode.internal.cache.wan.parallel.ConcurrentParallelGatewaySenderQueue; +import org.apache.geode.test.dunit.Invoke; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.dunit.rules.CacheRule; +import org.apache.geode.test.dunit.rules.DistributedRule; +import org.apache.geode.test.junit.categories.WanTest; +import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder; +import org.apache.geode.test.junit.runners.GeodeParamsRunner; + +@Category({WanTest.class}) +@RunWith(GeodeParamsRunner.class) +public class TxGroupingBaseDUnitTest implements Serializable { + + protected static final String REGION_NAME = "TheRegion"; + + protected final String shipmentRegionName = "ShipmentsRegion"; + protected final String customerRegionName = "CustomersRegion"; + protected final String orderRegionName = "OrdersRegion"; + + protected static LocatorLauncher locatorLauncher; + protected static ServerLauncher serverLauncher; + + protected VM londonLocatorVM; + protected VM newYorkLocatorVM; + protected VM newYorkServerVM; + protected VM londonServer1VM; + protected VM londonServer2VM; + protected VM londonServer3VM; + protected VM londonServer4VM; + protected VM[] londonServersVM; + + protected String newYorkName; + + protected int londonId; + protected int newYorkId; + + protected int londonLocatorPort; + protected int newYorkLocatorPort; + + protected int newYorkReceiverPort; + + @Rule + public DistributedRule distributedRule = new DistributedRule(); + + @Rule + public CacheRule cacheRule = new CacheRule(); + + @Rule + public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder(); + + private static List dispatcherThreads = new ArrayList<>(Arrays.asList(1, 3, 5)); + // this will be set for each test method run with one of the values from above list + private static int numDispatcherThreadsForTheRun = 1; + + @Before + public void setUp() { + londonLocatorVM = getVM(0); + newYorkLocatorVM = getVM(1); + newYorkServerVM = getVM(2); + londonServer1VM = getVM(3); + londonServer2VM = getVM(4); + londonServer3VM = getVM(5); + londonServer4VM = getVM(6); + londonServersVM = new VM[] {londonServer1VM, londonServer2VM, londonServer3VM, londonServer4VM}; + + newYorkName = "ny"; + + londonId = 1; + newYorkId = 2; + + int[] ports = getRandomAvailableTCPPorts(3); + londonLocatorPort = ports[0]; + newYorkLocatorPort = ports[1]; + newYorkReceiverPort = ports[2]; + + newYorkLocatorVM.invoke("start New York locator", () -> { + Properties config = createLocatorConfig(newYorkId, newYorkLocatorPort, londonLocatorPort); + cacheRule.createCache(config); + }); + + londonLocatorVM.invoke("start London locator", () -> { + Properties config = createLocatorConfig(londonId, londonLocatorPort, newYorkLocatorPort); + cacheRule.createCache(config); + }); + Collections.shuffle(dispatcherThreads); + int dispatcherThreadsNo = dispatcherThreads.get(0); + Invoke.invokeInEveryVM(() -> setNumDispatcherThreadsForTheRun(dispatcherThreadsNo)); + + } + + @After + public void tearDown() { + newYorkServerVM.invoke(() -> { + if (serverLauncher != null) { + serverLauncher.stop(); + serverLauncher = null; + } + }); + + for (VM server : londonServersVM) { + server.invoke(() -> { + if (serverLauncher != null) { + serverLauncher.stop(); + serverLauncher = null; + } + }); + } + + newYorkLocatorVM.invoke(() -> { + if (locatorLauncher != null) { + locatorLauncher.stop(); + locatorLauncher = null; + } + }); + + londonLocatorVM.invoke(() -> { + if (locatorLauncher != null) { + locatorLauncher.stop(); + locatorLauncher = null; + } + }); + } + + protected Properties createLocatorConfig(int systemId, int locatorPort, int remoteLocatorPort) { + Properties config = new Properties(); + config.setProperty(DISTRIBUTED_SYSTEM_ID, String.valueOf(systemId)); + config.setProperty(LOCATORS, "localhost[" + locatorPort + ']'); + config.setProperty(REMOTE_LOCATORS, "localhost[" + remoteLocatorPort + ']'); + config.setProperty(START_LOCATOR, + "localhost[" + locatorPort + "],server=true,peer=true,hostname-for-clients=localhost"); + return config; + } + + protected void startServerWithSender(int systemId, int locatorPort, int remoteSystemId, + String remoteName, String type, int batchSize) + throws IOException { + startServerWithSender(systemId, locatorPort, remoteSystemId, remoteName, type, batchSize, 0); + } + + protected void startServerWithSender(int systemId, int locatorPort, int remoteSystemId, + String remoteName, String type, int batchSize, + int dispatcherThreads) throws IOException { + cacheRule.createCache(createServerConfig(locatorPort)); + + String uniqueName = "server-" + systemId; + File[] dirs = new File[] {temporaryFolder.newFolder(uniqueName)}; + + GatewaySenderFactory senderFactory = createGatewaySenderFactory(dirs, uniqueName); + senderFactory.setType(type); + senderFactory.setBatchSize(batchSize); + if (dispatcherThreads > 0) { + senderFactory.setDispatcherThreads(dispatcherThreads); + } + GatewaySender sender = senderFactory.create(remoteName, remoteSystemId); + if (sender instanceof TxGroupingGatewaySender) { + ((TxGroupingGatewaySender) sender).setRetriesToGetTransactionEventsFromQueue(1000); + } + sender.start(); + } + + protected void startServerWithReceiver(int locatorPort, + int receiverPort) throws IOException { + startServerWithReceiver(locatorPort, receiverPort, true); + } + + protected void startServerWithReceiver(int locatorPort, + int receiverPort, boolean start) throws IOException { + cacheRule.createCache(createServerConfig(locatorPort)); + + GatewayReceiverFactory receiverFactory = createGatewayReceiverFactory(receiverPort); + GatewayReceiver receiver = receiverFactory.create(); + if (start) { + receiver.start(); + } + } + + protected void startReceiver() throws IOException { + cacheRule.getCache().getGatewayReceivers().iterator().next().start(); + } + + protected GatewayReceiverFactory createGatewayReceiverFactory(int receiverPort) { + GatewayReceiverFactory receiverFactory = cacheRule.getCache().createGatewayReceiverFactory(); + + receiverFactory.setStartPort(receiverPort); + receiverFactory.setEndPort(receiverPort); + receiverFactory.setManualStart(true); + return receiverFactory; + } + + protected Properties createServerConfig(int locatorPort) { + Properties config = new Properties(); + config.setProperty(LOCATORS, "localhost[" + locatorPort + ']'); + return config; + } + + protected GatewaySenderFactory createGatewaySenderFactory(File[] dirs, String diskStoreName) { + InternalGatewaySenderFactory senderFactory = + (InternalGatewaySenderFactory) cacheRule.getCache().createGatewaySenderFactory(); + + senderFactory.setMaximumQueueMemory(100); + senderFactory.setBatchSize(10); + senderFactory.setBatchConflationEnabled(false); + senderFactory.setManualStart(true); + senderFactory.setDispatcherThreads(numDispatcherThreadsForTheRun); + senderFactory.setOrderPolicy(GatewaySender.DEFAULT_ORDER_POLICY); + + DiskStoreFactory dsf = cacheRule.getCache().createDiskStoreFactory(); + DiskStore store = dsf.setDiskDirs(dirs).create(diskStoreName); + senderFactory.setDiskStoreName(store.getName()); + + return senderFactory; + } + + protected boolean isRunning(GatewaySender sender) { + return sender != null && sender.isRunning(); + } + + protected void validateRegionSize(String regionName, final int regionSize) { + final Region r = cacheRule.getCache().getRegion(SEPARATOR + regionName); + assertThat(r).isNotNull(); + await().untilAsserted(() -> assertThat(r.keySet().size()).isEqualTo(regionSize)); + } + + protected List getSenderStats(String senderId, final int expectedQueueSize) { + AbstractGatewaySender sender = + (AbstractGatewaySender) cacheRule.getCache().getGatewaySender(senderId); + GatewaySenderStats statistics = sender.getStatistics(); + if (expectedQueueSize != -1) { + final RegionQueue regionQueue; + regionQueue = sender.getQueues().toArray(new RegionQueue[1])[0]; + if (sender.isParallel()) { + ConcurrentParallelGatewaySenderQueue parallelGatewaySenderQueue = + (ConcurrentParallelGatewaySenderQueue) regionQueue; + PartitionedRegion pr = + parallelGatewaySenderQueue.getRegions().toArray(new PartitionedRegion[1])[0]; + } + await() + .untilAsserted(() -> assertThat(regionQueue.size()).isEqualTo(expectedQueueSize)); + } + List stats = new ArrayList<>(); + stats.add(statistics.getEventQueueSize()); + stats.add(statistics.getEventsReceived()); + stats.add(statistics.getEventsQueued()); + stats.add(statistics.getEventsDistributed()); + stats.add(statistics.getBatchesDistributed()); + stats.add(statistics.getBatchesRedistributed()); + stats.add(statistics.getEventsFiltered()); + stats.add(statistics.getEventsNotQueuedConflated()); + stats.add(statistics.getEventsConflatedFromBatches()); + stats.add(statistics.getConflationIndexesMapSize()); + stats.add(statistics.getSecondaryEventQueueSize()); + stats.add(statistics.getEventsProcessedByPQRM()); + stats.add(statistics.getEventsExceedingAlertThreshold()); + stats.add((int) statistics.getBatchesWithIncompleteTransactions()); + return stats; + } + + protected GatewaySender getGatewaySender(String senderId) { + Set senders = cacheRule.getCache().getGatewaySenders(); + GatewaySender sender = null; + for (GatewaySender s : senders) { + if (s.getId().equals(senderId)) { + sender = s; + break; + } + } + return sender; + } + + protected void doTxPuts(String regionName, final long putsPerTransaction, + final long transactions) { + doTxPuts(regionName, putsPerTransaction, transactions, 0); + } + + protected void doTxPuts(String regionName, final long putsPerTransaction, + final long transactions, long initialKeyId) { + Region region = cacheRule.getCache().getRegion(Region.SEPARATOR + regionName); + CacheTransactionManager mgr = cacheRule.getCache().getCacheTransactionManager(); + for (int i = 0; i < transactions; i++) { + long keyId = initialKeyId + (i * putsPerTransaction); + doOneTxWithPuts(region, mgr, putsPerTransaction, keyId); + } + } + + private void doOneTxWithPuts(Region region, CacheTransactionManager mgr, + long putsPerTransaction, long initialKeyId) { + mgr.begin(); + for (int j = 0; j < putsPerTransaction; j++) { + long key = initialKeyId + j; + String value = "Value_" + key; + region.put(key, value); + } + mgr.commit(); + } + + protected void checkGatewayReceiverStats(int processBatches, int eventsReceived, + int creates) { + checkGatewayReceiverStats(processBatches, eventsReceived, creates, false); + } + + protected void checkGatewayReceiverStats(int processBatches, int eventsReceived, + int creates, boolean isExact) { + Set gatewayReceivers = cacheRule.getCache().getGatewayReceivers(); + GatewayReceiver receiver = gatewayReceivers.iterator().next(); + CacheServerStats stats = ((CacheServerImpl) receiver.getServer()).getAcceptor().getStats(); + + assertThat(stats).isInstanceOf(GatewayReceiverStats.class); + GatewayReceiverStats gatewayReceiverStats = (GatewayReceiverStats) stats; + if (isExact) { + assertThat(gatewayReceiverStats.getProcessBatchRequests()).isEqualTo(processBatches); + } else { + assertThat(gatewayReceiverStats.getProcessBatchRequests()) + .isGreaterThanOrEqualTo(processBatches); + } + assertThat(eventsReceived).isEqualTo(gatewayReceiverStats.getEventsReceived()); + assertThat(creates).isEqualTo(gatewayReceiverStats.getCreateRequest()); + } + + protected void doTxPutsWithRetryIfError(String regionName, final long putsPerTransaction, + final long transactions, long initialKeyId) { + Region region = cacheRule.getCache().getRegion(Region.SEPARATOR + regionName); + CacheTransactionManager mgr = cacheRule.getCache().getCacheTransactionManager(); + for (int i = 0; i < transactions; i++) { + long keyId = initialKeyId + (i * putsPerTransaction); + doOneTxWithPutsWithRetryIfError(region, mgr, putsPerTransaction, keyId); + } + } + + private void doOneTxWithPutsWithRetryIfError(Region region, + CacheTransactionManager mgr, long putsPerTransaction, long initialKeyId) { + while (true) { + try { + mgr.begin(); + for (int j = 0; j < putsPerTransaction; j++) { + long key = initialKeyId + j; + String value = "Value_" + key; + region.put(key, value); + } + mgr.commit(); + return; + } catch (TransactionException ignore) { + } catch (IllegalStateException ignore) { + try { + mgr.rollback(); + } catch (Exception ignored) { + } + } + } + } + + public void createCustomerOrderShipmentPartitionedRegion(String senderId) { + createCustomerOrderShipmentPartitionedRegion(senderId, 0); + } + + public void createCustomerOrderShipmentPartitionedRegion(String senderId, int redundantCopies) { + RegionFactory fact = + cacheRule.getCache().createRegionFactory(RegionShortcut.PARTITION); + if (senderId != null) { + fact.addGatewaySenderId(senderId); + } + + PartitionAttributesFactory paf = new PartitionAttributesFactory(); + paf.setPartitionResolver(new CustomerIDPartitionResolver("CustomerIDPartitionResolver")); + paf.setRedundantCopies(redundantCopies); + fact.setPartitionAttributes(paf.create()); + fact.create(customerRegionName); + + paf = new PartitionAttributesFactory(); + paf.setRedundantCopies(redundantCopies); + paf.setColocatedWith(customerRegionName) + .setPartitionResolver(new CustomerIDPartitionResolver("CustomerIDPartitionResolver")); + fact = cacheRule.getCache().createRegionFactory(RegionShortcut.PARTITION); + if (senderId != null) { + fact.addGatewaySenderId(senderId); + } + fact.setPartitionAttributes(paf.create()); + fact.create(orderRegionName); + + paf = new PartitionAttributesFactory(); + paf.setRedundantCopies(redundantCopies); + paf.setColocatedWith(orderRegionName) + .setPartitionResolver(new CustomerIDPartitionResolver("CustomerIDPartitionResolver")); + fact = cacheRule.getCache().createRegionFactory(RegionShortcut.PARTITION); + if (senderId != null) { + fact.addGatewaySenderId(senderId); + } + fact.setPartitionAttributes(paf.create()); + fact.create(shipmentRegionName); + } + + public void doOrderAndShipmentPutsInsideTransactions(int customerId, int eventsPerTransaction, + int transactions) { + doOrderAndShipmentPutsInsideTransactions(customerId, eventsPerTransaction, transactions, false); + } + + public void doOrderAndShipmentPutsInsideTransactions(int customerId, int eventsPerTransaction, + int transactions, boolean retryIfError) { + CacheTransactionManager cacheTransactionManager = + cacheRule.getCache().getCacheTransactionManager(); + for (int i = 0; i < transactions; i++) { + int keyId = i * eventsPerTransaction; + if (retryIfError) { + doOneTxOrderAndShipmentPutsWithRetryIfError(cacheTransactionManager, keyId, + eventsPerTransaction, customerId); + } else { + doOneTxOrderAndShipmentPuts(cacheTransactionManager, keyId, eventsPerTransaction, + customerId); + } + } + } + + private void doOneTxOrderAndShipmentPuts( + CacheTransactionManager cacheTransactionManager, int keyId, int eventsPerTransaction, + int customerId) { + cacheTransactionManager.begin(); + doOneOrderAndShipmentPuts(keyId, eventsPerTransaction, customerId); + cacheTransactionManager.commit(); + } + + private void doOneTxOrderAndShipmentPutsWithRetryIfError( + CacheTransactionManager cacheTransactionManager, int keyId, int eventsPerTransaction, + int customerId) { + while (true) { + try { + cacheTransactionManager.begin(); + doOneOrderAndShipmentPuts(keyId, eventsPerTransaction, customerId); + cacheTransactionManager.commit(); + break; + } catch (TransactionException exception) { + } catch (IllegalStateException exception) { + try { + cacheTransactionManager.rollback(); + } catch (Exception ignored) { + } + } + } + } + + private void doOneOrderAndShipmentPuts(int keyId, int eventsPerTransaction, int customerId) { + Region orderRegion = cacheRule.getCache().getRegion(orderRegionName); + Region shipmentRegion = cacheRule.getCache().getRegion(shipmentRegionName); + OrderId orderId = new OrderId(keyId, new CustId(customerId)); + orderRegion.put(orderId, new Order()); + for (int i = 0; i < eventsPerTransaction - 1; i++) { + ShipmentId shipmentId = new ShipmentId(keyId + i, orderId); + shipmentRegion.put(shipmentId, new Shipment()); + } + } + + protected Integer getRegionSize(String regionName) { + final Region r = cacheRule.getCache().getRegion(SEPARATOR + regionName); + return r.keySet().size(); + } + + protected void checkGatewayReceiverStatsHA(int processBatches, int eventsReceived, + int creates) { + Set gatewayReceivers = cacheRule.getCache().getGatewayReceivers(); + GatewayReceiver receiver = gatewayReceivers.iterator().next(); + CacheServerStats stats = ((CacheServerImpl) receiver.getServer()).getAcceptor().getStats(); + assertThat(stats).isInstanceOf(GatewayReceiverStats.class); + + GatewayReceiverStats gatewayReceiverStats = (GatewayReceiverStats) stats; + assertThat(gatewayReceiverStats.getProcessBatchRequests()) + .isGreaterThanOrEqualTo(processBatches); + assertThat(gatewayReceiverStats.getEventsReceived()).isGreaterThanOrEqualTo(eventsReceived); + assertThat(gatewayReceiverStats.getCreateRequest()).isGreaterThanOrEqualTo(creates); + } + + protected void putGivenKeyValues(String regionName, Map keyValues) { + Region r = cacheRule.getCache().getRegion(SEPARATOR + regionName); + assertThat(r).isNotNull(); + for (Object key : keyValues.keySet()) { + r.put(key, keyValues.get(key)); + } + } + + protected void checkConflatedStats(String senderId, final int eventsConflated) { + GatewaySenderStats statistics = getGatewaySenderStats(senderId); + assertThat(statistics.getEventsNotQueuedConflated()).isEqualTo(eventsConflated); + } + + protected GatewaySenderStats getGatewaySenderStats(String senderId) { + GatewaySender sender = cacheRule.getCache().getGatewaySender(senderId); + return ((AbstractGatewaySender) sender).getStatistics(); + } + + protected void validateGatewaySenderQueueAllBucketsDrained(final String senderId) { + GatewaySender sender = getGatewaySender(senderId); + final AbstractGatewaySender abstractSender = (AbstractGatewaySender) sender; + await().untilAsserted(() -> assertThat(abstractSender.getEventQueueSize()).isEqualTo(0)); + await() + .untilAsserted(() -> assertThat(abstractSender.getSecondaryEventQueueSize()).isEqualTo(0)); + } + + public static void setNumDispatcherThreadsForTheRun(int numThreads) { + numDispatcherThreadsForTheRun = numThreads; + } +} diff --git a/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingPartitionedRegionDUnitTest.java b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingPartitionedRegionDUnitTest.java new file mode 100644 index 000000000000..5a48897bc576 --- /dev/null +++ b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/TxGroupingPartitionedRegionDUnitTest.java @@ -0,0 +1,114 @@ +/* + * 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.wan.txgrouping; + +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import junitparams.Parameters; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.internal.cache.execute.data.CustId; +import org.apache.geode.internal.cache.execute.data.Order; +import org.apache.geode.internal.cache.execute.data.OrderId; +import org.apache.geode.test.dunit.AsyncInvocation; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.junit.categories.WanTest; +import org.apache.geode.test.junit.runners.GeodeParamsRunner; + +@Category({WanTest.class}) +@RunWith(GeodeParamsRunner.class) +public class TxGroupingPartitionedRegionDUnitTest extends TxGroupingBaseDUnitTest { + @Test + @Parameters({"TxGroupingParallelGatewaySender", "TxGroupingSerialGatewaySender"}) + public void testPartitionedRegionPropagationWithGroupTransactionEventsAndMixOfEventsInAndNotInTransactions( + String type) + throws Exception { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort, true); + createCustomerOrderShipmentPartitionedRegion(null); + }); + + int batchSize = 10; + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, type, + batchSize, type.contains("Parallel") ? 2 : 1); + createCustomerOrderShipmentPartitionedRegion(newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + int customers = 4; + int transactionsPerCustomer = 1000; + int ordersPerCustomerNotInTransactions = 1000; + + final Map keyValuesNotInTransactions = new HashMap<>(); + for (int custId = 0; custId < customers; custId++) { + for (int i = 0; i < ordersPerCustomerNotInTransactions; i++) { + CustId custIdObject = new CustId(custId); + OrderId orderId = + new OrderId(i + ordersPerCustomerNotInTransactions * customers, custIdObject); + keyValuesNotInTransactions.put(orderId, new Order()); + } + } + + // eventsPerTransaction is 1 (orders) + 3 (shipments) + int eventsPerTransaction = 4; + List> putsInTransactionsInvocationList = new ArrayList<>(customers); + for (int i = 0; i < customers; i++) { + final int customerId = i; + putsInTransactionsInvocationList.add( + londonServer1VM.invokeAsync( + () -> doOrderAndShipmentPutsInsideTransactions(customerId, eventsPerTransaction, + transactionsPerCustomer))); + } + + AsyncInvocation putsNotInTransactionsInvocation = + londonServer2VM.invokeAsync( + () -> putGivenKeyValues(orderRegionName, keyValuesNotInTransactions)); + + for (AsyncInvocation putsInTransactionInvocation : putsInTransactionsInvocationList) { + putsInTransactionInvocation.await(); + } + putsNotInTransactionsInvocation.await(); + + int entries = + ordersPerCustomerNotInTransactions * customers + transactionsPerCustomer * customers; + + for (VM londonServer : londonServersVM) { + londonServer.invoke(() -> validateRegionSize(orderRegionName, entries)); + } + + newYorkServerVM.invoke(() -> validateRegionSize(orderRegionName, entries)); + + for (VM londonServer : londonServersVM) { + londonServer.invoke(() -> checkConflatedStats(newYorkName, 0)); + } + + for (VM londonServer : londonServersVM) { + londonServer.invoke(() -> validateGatewaySenderQueueAllBucketsDrained(newYorkName)); + } + } +} diff --git a/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/cli/commands/CreateTxGroupingGatewaySenderDUnitTest.java b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/cli/commands/CreateTxGroupingGatewaySenderDUnitTest.java new file mode 100644 index 000000000000..47d7680210a2 --- /dev/null +++ b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/cli/commands/CreateTxGroupingGatewaySenderDUnitTest.java @@ -0,0 +1,109 @@ +/* + * 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.wan.txgrouping.cli.commands; + +import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException; + +import java.util.Properties; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import org.apache.geode.test.dunit.rules.ClusterStartupRule; +import org.apache.geode.test.dunit.rules.MemberVM; +import org.apache.geode.test.junit.assertions.CommandResultAssert; +import org.apache.geode.test.junit.rules.GfshCommandRule; + +public class CreateTxGroupingGatewaySenderDUnitTest { + + @Rule + public ClusterStartupRule cluster = new ClusterStartupRule(); + + @Rule + public GfshCommandRule gfsh = new GfshCommandRule(); + + private MemberVM locator; + + @Before + public void before() throws Exception { + locator = cluster.startLocatorVM(0); + cluster.startServerVM(1, new Properties(), locator.getPort()); + gfsh.connectAndVerify(locator); + } + + @Test + public void createTxGroupingParallelGatewaySender() { + addIgnoredException("could not get remote locator"); + + String createCommandString = + "create gateway-sender --id=sender1 --remote-distributed-system-id=1 --type=TxGroupingParallelGatewaySender"; + + // Check command status and output + CommandResultAssert createCommand = + gfsh.executeAndAssertThat(createCommandString).statusIsSuccess(); + createCommand + .hasTableSection() + .hasColumn("Member") + .containsExactly("server-1"); + + + String listCommandString = "list gateways --senders-only"; + CommandResultAssert listCommand = + gfsh.executeAndAssertThat(listCommandString).statusIsSuccess(); + + listCommand + .hasTableSection() + .hasColumn("GatewaySender Id") + .containsExactly("sender1"); + + listCommand + .hasTableSection() + .hasColumn("Type") + .containsExactly("TxGroupingParallelGatewaySender"); + } + + @Test + public void createTxGroupingSerialGatewaySender() { + addIgnoredException("could not get remote locator"); + + String createCommandString = + "create gateway-sender --id=sender1 --remote-distributed-system-id=1 --dispatcher-threads=1 --type=TxGroupingSerialGatewaySender"; + + // Check command status and output + CommandResultAssert createCommand = + gfsh.executeAndAssertThat(createCommandString).statusIsSuccess(); + createCommand + .hasTableSection() + .hasColumn("Member") + .containsExactly("server-1"); + + + String listCommandString = "list gateways --senders-only"; + CommandResultAssert listCommand = + gfsh.executeAndAssertThat(listCommandString).statusIsSuccess(); + + listCommand + .hasTableSection() + .hasColumn("GatewaySender Id") + .containsExactly("sender1"); + + listCommand + .hasTableSection() + .hasColumn("Type") + .containsExactly("TxGroupingSerialGatewaySender"); + } +} diff --git a/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/parallel/TxGroupingParallelDUnitTest.java b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/parallel/TxGroupingParallelDUnitTest.java new file mode 100644 index 000000000000..4b8b0aa6a729 --- /dev/null +++ b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/parallel/TxGroupingParallelDUnitTest.java @@ -0,0 +1,451 @@ +/* + * 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.wan.txgrouping.parallel; + +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import junitparams.Parameters; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import org.apache.geode.cache.PartitionAttributesFactory; +import org.apache.geode.cache.RegionDestroyedException; +import org.apache.geode.cache.RegionFactory; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderImpl; +import org.apache.geode.cache.wan.internal.txgrouping.parallel.TxGroupingParallelGatewaySenderImpl; +import org.apache.geode.internal.cache.ForceReattemptException; +import org.apache.geode.internal.cache.execute.data.CustId; +import org.apache.geode.internal.cache.execute.data.Customer; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.txgrouping.TxGroupingBaseDUnitTest; +import org.apache.geode.internal.util.ArrayUtils; +import org.apache.geode.test.dunit.AsyncInvocation; +import org.apache.geode.test.dunit.IgnoredException; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.junit.categories.WanTest; +import org.apache.geode.test.junit.runners.GeodeParamsRunner; + +@Category({WanTest.class}) +@RunWith(GeodeParamsRunner.class) +public class TxGroupingParallelDUnitTest extends TxGroupingBaseDUnitTest { + @Test + @Parameters({TxGroupingParallelGatewaySenderImpl.TYPE, ParallelGatewaySenderImpl.TYPE}) + public void testPRParallelPropagationWithVsWithoutGroupTransactionEvents( + String type) { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort); + createCustomerOrderShipmentPartitionedRegion(null); + }); + + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, type, + 10); + createCustomerOrderShipmentPartitionedRegion(newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + // 3 transactions of 4 events each are sent so that the batch would + // initially contain the first 2 transactions complete and the first + // 2 events of the last transaction (10 entries). + // If --group-transaction-events is configured in the senders, the remaining + // 2 events of the last transaction are added to the batch which makes + // that only one batch of 12 events is sent. + // If --group-transaction-events is not configured in the senders, the + // remaining 2 events of the last transaction are added to the second batch + // which makes that 2 batches will be sent, one with 10 events and + // one with 2. + int transactions = 3; + int eventsPerTransaction = 4; + londonServer1VM.invoke( + () -> doOrderAndShipmentPutsInsideTransactions(0, eventsPerTransaction, transactions)); + + int entries = transactions * eventsPerTransaction; + + londonServer1VM.invoke(() -> validateRegionSize(orderRegionName, transactions)); + londonServer1VM.invoke(() -> validateRegionSize(shipmentRegionName, transactions * 3)); + + List senderStatsLondonServers = getSenderStats(newYorkName, 0, londonServersVM); + + int expectedBatchesSent = type.equals(TxGroupingParallelGatewaySenderImpl.TYPE) ? 1 : 2; + // queue size: + assertThat(senderStatsLondonServers.get(0)).isEqualTo(0); + // eventsReceived: + assertThat(senderStatsLondonServers.get(1)).isEqualTo(entries); + // events queued: + assertThat(senderStatsLondonServers.get(2)).isEqualTo(entries); + // events distributed: + assertThat(senderStatsLondonServers.get(3)).isEqualTo(entries); + // batches distributed: + assertThat(senderStatsLondonServers.get(4)).isEqualTo(expectedBatchesSent); + // batches redistributed: + assertThat(senderStatsLondonServers.get(5)).isEqualTo(0); + // events not queued conflated: + assertThat(senderStatsLondonServers.get(7)).isEqualTo(0); + // batches with incomplete transactions: + assertThat(senderStatsLondonServers.get(13)).isEqualTo(0); + } + + @Test + @Parameters({"true", "false"}) + public void testPRParallelPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( + boolean isBatchesRedistributed) throws InterruptedException { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort, !isBatchesRedistributed); + createCustomerOrderShipmentPartitionedRegion(null); + }); + + int batchSize = 10; + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, + TxGroupingParallelGatewaySenderImpl.TYPE, + batchSize); + createCustomerOrderShipmentPartitionedRegion(newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + // batchSize is 10. Each transaction will contain 1 order + 3 shipments = 4 events. + // As a result, all batches will contain extra events to complete the + // transactions it will deliver. + int shipmentsPerTransaction = 3; + int eventsPerTransaction = shipmentsPerTransaction + 1; + int transactions = 300; + + int clients = 4; + for (int i = 0; i < clients; i++) { + final Map custKeyValue = new HashMap<>(); + custKeyValue.put(new CustId(i), new Customer()); + londonServer1VM.invoke(() -> putGivenKeyValues(customerRegionName, custKeyValue)); + } + + List> asyncInvocations = new ArrayList<>(clients); + + for (int i = 0; i < clients; i++) { + final int intCustId = i; + AsyncInvocation asyncInvocation = + londonServer1VM.invokeAsync(() -> doOrderAndShipmentPutsInsideTransactions( + intCustId, eventsPerTransaction, transactions)); + asyncInvocations.add(asyncInvocation); + } + + for (AsyncInvocation asyncInvocation : asyncInvocations) { + asyncInvocation.await(); + } + + londonServer1VM.invoke(() -> validateRegionSize(customerRegionName, clients)); + londonServer1VM.invoke(() -> validateRegionSize(orderRegionName, transactions * clients)); + londonServer1VM.invoke(() -> validateRegionSize(shipmentRegionName, + transactions * shipmentsPerTransaction * clients)); + + if (isBatchesRedistributed) { + // wait for batches to be redistributed and then start the receiver + londonServer1VM.invoke(() -> await() + .until(() -> getSenderStats(newYorkName, -1).get(5) > 0)); + newYorkServerVM.invoke("start New York receiver", this::startReceiver); + } + + // Check that all entries have been written in the receiver + newYorkServerVM.invoke( + () -> validateRegionSize(customerRegionName, clients)); + newYorkServerVM.invoke( + () -> validateRegionSize(orderRegionName, transactions * clients)); + newYorkServerVM.invoke( + () -> validateRegionSize(shipmentRegionName, + shipmentsPerTransaction * transactions * clients)); + + checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated(newYorkName, + isBatchesRedistributed); + } + + @Test + public void testPRParallelPropagationWithGroupTransactionEventsWithIncompleteTransactionsWhenTransactionEntriesOnNotColocatedBuckets() { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort); + createPartitionedRegion(REGION_NAME, null); + }); + + int dispatcherThreads = 2; + londonServer1VM.invoke("create London server " + londonServer1VM.getId(), () -> { + startServerWithSender(londonServer1VM.getId(), londonLocatorPort, newYorkId, newYorkName, + TxGroupingParallelGatewaySenderImpl.TYPE, 10, dispatcherThreads); + createPartitionedRegion(REGION_NAME, newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + + // Adding events in transactions + // Transactions will contain objects assigned to different buckets but given that there is only + // one server, there will be no TransactionDataNotCollocatedException. + // With this and by using more than one dispatcher thread, we will provoke that + // it will be impossible for the batches to have complete transactions as some + // events for a transaction will be handled by one dispatcher thread and some other events by + // another thread. + int entriesPerTransaction = 3; + int transactions = 10; + int entries = transactions * entriesPerTransaction; + + londonServer1VM + .invoke(() -> doTxPuts(REGION_NAME, 3, 10)); + + londonServer1VM.invoke(() -> validateRegionSize(REGION_NAME, entries)); + + ArrayList senderStatsLondonServer1 = + (ArrayList) londonServer1VM.invoke(() -> getSenderStats(newYorkName, 0)); + + // The number of batches will be 4 because each + // dispatcher thread (there are 2) will send half the number of entries, + // each on 2 batches. + int batches = 4; + // queue size: + assertThat(senderStatsLondonServer1.get(0)).isEqualTo(0); + // eventsReceived: + assertThat(senderStatsLondonServer1.get(1)).isEqualTo(entries); + // events queued: + assertThat(senderStatsLondonServer1.get(2)).isEqualTo(entries); + // events distributed: + assertThat(senderStatsLondonServer1.get(3)).isEqualTo(entries); + // batches distributed: + assertThat(senderStatsLondonServer1.get(4)).isEqualTo(batches); + // batches redistributed: + assertThat(senderStatsLondonServer1.get(5)).isEqualTo(0); + // events not queued conflated: + assertThat(senderStatsLondonServer1.get(7)).isEqualTo(0); + // batches with incomplete transactions + assertThat(senderStatsLondonServer1.get(13)).isEqualTo(batches); + + newYorkServerVM.invoke(() -> checkGatewayReceiverStats(batches, entries, entries)); + } + + @Test + @Parameters({TxGroupingParallelGatewaySenderImpl.TYPE, ParallelGatewaySenderImpl.TYPE}) + public void testPRParallelPropagationWithVsWithoutGroupTransactionEventsWithBatchRedistribution( + String type) { + londonServer1VM.invoke("create London server " + londonServer1VM.getId(), () -> { + startServerWithSender(londonServer1VM.getId(), londonLocatorPort, newYorkId, newYorkName, + type, 10); + createCustomerOrderShipmentPartitionedRegion(newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + + newYorkServerVM.invoke("create New York server with receiver stopped", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort, false); + createCustomerOrderShipmentPartitionedRegion(null); + }); + + // 6 transactions of 4 events each are sent with batch size = 10 + // - With group transaction events: + // The first batch would initially contain the first 2 transactions complete and the first + // 2 events of the next transaction (10 entries). + // As --group-transaction-events is configured in the senders, the remaining + // 2 events of the second transaction are added to the batch which makes + // the first batch to be sent with 12 events. The same happens with the + // second batch which will contain 12 events too. + // - Without group-transaction-events 3 batches will be sent. 2 + // with 10 events and one with 4. + int transactions = 6; + int eventsPerTransaction = 4; + int expectedBatchesSent; + if (type.endsWith(TxGroupingParallelGatewaySenderImpl.TYPE)) { + expectedBatchesSent = 2; + } else { + expectedBatchesSent = 3; + } + londonServer1VM.invoke( + () -> doOrderAndShipmentPutsInsideTransactions(0, eventsPerTransaction, transactions)); + + int entries = transactions * eventsPerTransaction; + + londonServer1VM.invoke(() -> validateRegionSize(orderRegionName, transactions)); + londonServer1VM.invoke(() -> validateRegionSize(shipmentRegionName, transactions * 3)); + + // wait for batches to be redistributed and then start the receiver + londonServer1VM.invoke(() -> await() + .until(() -> getSenderStats(newYorkName, -1).get(5) > 0)); + + newYorkServerVM.invoke("Start New York receiver", this::startReceiver); + + ArrayList senderStatsLondonServer1 = + (ArrayList) londonServer1VM.invoke(() -> getSenderStats(newYorkName, 0)); + + // queue size: + assertThat(senderStatsLondonServer1.get(0)).isEqualTo(0); + // events received: + assertThat(senderStatsLondonServer1.get(1)).isEqualTo(entries); + // events queued: + assertThat(senderStatsLondonServer1.get(2)).isEqualTo(entries); + // events distributed: + assertThat(senderStatsLondonServer1.get(3)).isEqualTo(entries); + // batches distributed: + assertThat(senderStatsLondonServer1.get(4)).isEqualTo(expectedBatchesSent); + // batches redistributed: + assertThat(senderStatsLondonServer1.get(5)).isGreaterThan(0); + // events not queued conflated: + assertThat(senderStatsLondonServer1.get(7)).isEqualTo(0); + } + + @Test + public void testParallelPropagationHAWithGroupTransactionEvents() throws Exception { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort); + createPartitionedRegion(orderRegionName, null); + createPartitionedRegion(shipmentRegionName, null); + }); + + int batchSize = 11; + int redundantCopies = 3; + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, + TxGroupingParallelGatewaySenderImpl.TYPE, + batchSize, redundantCopies); + createCustomerOrderShipmentPartitionedRegion(newYorkName, redundantCopies); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + // putsPerTransaction = 1 order + 3 shipments + int putsPerTransaction = 4; + int transactions = 1000; + AsyncInvocation asyncPutInvocation = + londonServer2VM.invokeAsync( + () -> doOrderAndShipmentPutsInsideTransactions(0, putsPerTransaction, transactions, + true)); + + newYorkServerVM.invoke(() -> await() + .untilAsserted(() -> assertThat(getRegionSize(shipmentRegionName)).isGreaterThan(40))); + AsyncInvocation killServerInvocation = + londonServer1VM.invokeAsync(() -> cacheRule.getCache().close()); + + asyncPutInvocation.await(); + killServerInvocation.await(); + + int entries = transactions * putsPerTransaction; + newYorkServerVM + .invoke(() -> validateRegionSize(shipmentRegionName, transactions * 3)); + newYorkServerVM + .invoke(() -> validateRegionSize(orderRegionName, transactions)); + + List londonServerStats = + getSenderStats(newYorkName, 0, (VM[]) ArrayUtils.remove(londonServersVM, 0)); + + // queue size + assertThat(londonServerStats.get(0)).isEqualTo(0); + + // eventsReceived + // We may see 4 retried events (as transactions are made of 4 events) on all members due to + // the kill + assertThat(londonServerStats.get(1)) + .isLessThanOrEqualTo((entries + putsPerTransaction) * redundantCopies); + assertThat(londonServerStats.get(1)).isGreaterThanOrEqualTo(entries * redundantCopies); + + // queuedEvents + assertThat(londonServerStats.get(2)) + .isLessThanOrEqualTo((entries + putsPerTransaction) * redundantCopies); + assertThat(londonServerStats.get(2)).isGreaterThanOrEqualTo(entries * redundantCopies); + + // batches redistributed + assertThat(londonServerStats.get(5)).isEqualTo(0); + + // batchesReceived is equal to numberOfEntries/(batchSize+1) + // As transactions are 4 events long, for each batch it will always be necessary to + // add one more entry to the 11 events batch in order to have complete transactions in the + // batch. + int batchesReceived = (entries) / (batchSize + 1); + newYorkServerVM.invoke(() -> checkGatewayReceiverStatsHA(batchesReceived, entries, entries)); + } + + private void checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated(String senderId, + boolean isBatchesRedistributed) { + List senderStatsLondonServers = getSenderStats(senderId, 0, londonServersVM); + + // queue size: + assertThat(senderStatsLondonServers.get(0)).isEqualTo(0); + // batches redistributed: + int batchesRedistributed = senderStatsLondonServers.get(5); + if (isBatchesRedistributed) { + assertThat(batchesRedistributed).isGreaterThan(0); + } else { + assertThat(batchesRedistributed).isEqualTo(0); + } + // batches with incomplete transactions + assertThat(senderStatsLondonServers.get(13)).isEqualTo(0); + + for (VM londonServer : londonServersVM) { + londonServer.invoke(() -> validateGatewaySenderQueueAllBucketsDrained(senderId)); + } + } + + protected void validateGatewaySenderQueueAllBucketsDrained(final String senderId) { + try (IgnoredException ignoredE1 = addIgnoredException(RegionDestroyedException.class); + IgnoredException ignoredE2 = addIgnoredException(ForceReattemptException.class)) { + GatewaySender sender = getGatewaySender(senderId); + final AbstractGatewaySender abstractSender = (AbstractGatewaySender) sender; + await().untilAsserted(() -> assertThat(abstractSender.getEventQueueSize()).isEqualTo(0)); + await().untilAsserted( + () -> assertThat(abstractSender.getSecondaryEventQueueSize()).isEqualTo(0)); + } + } + + public void createPartitionedRegion(String regionName, String senderId) { + createPartitionedRegion(regionName, senderId, 0); + } + + public void createPartitionedRegion(String regionName, String senderId, int redundantCopies) { + RegionFactory fact = + cacheRule.getCache().createRegionFactory(RegionShortcut.PARTITION); + if (senderId != null) { + fact.addGatewaySenderId(senderId); + } + PartitionAttributesFactory pfact = new PartitionAttributesFactory(); + pfact.setRedundantCopies(redundantCopies); + pfact.setTotalNumBuckets(10); + fact.setPartitionAttributes(pfact.create()); + fact.create(regionName); + } + + protected List getSenderStats(String senderId, int expectedQueueSize, + VM[] servers) { + List stats = null; + for (VM server : servers) { + List serverStats = + server.invoke(() -> getSenderStats(senderId, expectedQueueSize)); + if (stats == null) { + stats = serverStats; + } else { + for (int i = 0; i < stats.size(); i++) { + stats.set(i, stats.get(i) + serverStats.get(i)); + } + } + } + return stats; + } +} diff --git a/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/serial/TxGroupingSerialDUnitTest.java b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/serial/TxGroupingSerialDUnitTest.java new file mode 100644 index 000000000000..7f256c33a171 --- /dev/null +++ b/geode-wan-txgrouping/src/distributedTest/java/org/apache/geode/internal/cache/wan/txgrouping/serial/TxGroupingSerialDUnitTest.java @@ -0,0 +1,346 @@ +/* + * 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.wan.txgrouping.serial; + +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import junitparams.Parameters; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import org.apache.geode.cache.CacheClosedException; +import org.apache.geode.cache.RegionFactory; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.internal.serial.SerialGatewaySenderImpl; +import org.apache.geode.cache.wan.internal.txgrouping.serial.TxGroupingSerialGatewaySenderImpl; +import org.apache.geode.internal.cache.ForceReattemptException; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.GatewaySenderStats; +import org.apache.geode.internal.cache.wan.txgrouping.TxGroupingBaseDUnitTest; +import org.apache.geode.test.dunit.AsyncInvocation; +import org.apache.geode.test.dunit.IgnoredException; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.junit.categories.WanTest; +import org.apache.geode.test.junit.runners.GeodeParamsRunner; + +@Category({WanTest.class}) +@RunWith(GeodeParamsRunner.class) +public class TxGroupingSerialDUnitTest extends TxGroupingBaseDUnitTest { + @Test + @Parameters({TxGroupingSerialGatewaySenderImpl.TYPE, SerialGatewaySenderImpl.TYPE}) + public void testReplicatedSerialPropagationWithVsWithoutGroupTransactionEvents( + String type) { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort); + createReplicatedRegion(REGION_NAME, null); + }); + + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, type, 10, + 1); + createReplicatedRegion(REGION_NAME, newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + // 4 transactions of 3 events each are sent so that the first batch + // would initially contain the first 3 transactions complete and the first + // event of the next transaction (10 entries). + // If --group-transaction-events is configured in the senders, the remaining + // events of the third transaction are added to the batch which makes + // that the batch is sent with 12 events. + // If --group-transaction-events is not configured in the senders, the remaining + // events of the third transaction are added to the next batch which makes + // that the 2 batches are sent. One with 10 events and another one + // with 2 events. + final int transactions = 4; + final int eventsPerTransaction = 3; + final int entries = transactions * eventsPerTransaction; + int expectedBatchesSent = type.equals(TxGroupingSerialGatewaySenderImpl.TYPE) ? 1 : 2; + londonServer2VM + .invoke(() -> doTxPuts(REGION_NAME, eventsPerTransaction, transactions)); + + newYorkServerVM.invoke(() -> validateRegionSize(REGION_NAME, entries)); + + newYorkServerVM + .invoke(() -> checkGatewayReceiverStats(expectedBatchesSent, entries, entries, true)); + + londonServer1VM.invoke(() -> checkQueueStats(newYorkName, 0, entries, entries, entries)); + londonServer1VM.invoke(() -> checkBatchStats(newYorkName, expectedBatchesSent, false)); + londonServer1VM.invoke(() -> checkConflatedStats(newYorkName)); + + // wait until queue is empty + londonServer2VM.invoke(() -> await() + .until(() -> getSenderStats(newYorkName, -1).get(0) == 0)); + + londonServer2VM.invoke(() -> checkQueueStats(newYorkName, 0, entries, 0, 0)); + londonServer2VM.invoke(() -> checkBatchStats(newYorkName, 0, false)); + londonServer2VM.invoke(() -> checkConflatedStats(newYorkName)); + } + + @Test + @Parameters({"true", "false"}) + public void testReplicatedSerialPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( + boolean isBatchRedistributed) throws InterruptedException { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort, !isBatchRedistributed); + createReplicatedRegion(REGION_NAME, null); + }); + int batchSize = 10; + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, + TxGroupingSerialGatewaySenderImpl.TYPE, + batchSize, 1); + createReplicatedRegion(REGION_NAME, newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + int clients = 2; + int eventsPerTransaction = batchSize + 1; + int transactions = 200; + int entries = eventsPerTransaction * transactions * clients; + int entriesPerInvocation = (entries) / clients; + + List> putAsyncInvocations = new ArrayList<>(clients); + for (int i = 0; i < clients; i++) { + final int index = i; + AsyncInvocation asyncInvocation = + londonServer1VM.invokeAsync(() -> doTxPuts(REGION_NAME, + eventsPerTransaction, transactions, index * entriesPerInvocation)); + putAsyncInvocations.add(asyncInvocation); + } + + for (AsyncInvocation invocation : putAsyncInvocations) { + invocation.await(); + } + + if (isBatchRedistributed) { + // wait for batches to be redistributed and then start the receiver + londonServer1VM.invoke(() -> await() + .until(() -> getSenderStats(newYorkName, -1).get(5) > 0)); + newYorkServerVM.invoke(this::startReceiver); + } + + newYorkServerVM.invoke(() -> validateRegionSize(REGION_NAME, entries)); + + checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated(isBatchRedistributed); + } + + @Test + + @Parameters({TxGroupingSerialGatewaySenderImpl.TYPE, SerialGatewaySenderImpl.TYPE}) + public void testReplicatedSerialPropagationWithVsWithoutGroupTransactionEventsWithBatchRedistribution( + String type) { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort, false); + createReplicatedRegion(REGION_NAME, null); + }); + + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, type, 10, + 1); + createReplicatedRegion(REGION_NAME, newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + // 8 transactions of 3 events each are sent. + // - With group-transaction-events + // The first batch would initially contain the first 3 transactions complete + // and the first event of the next transaction (10 entries). + // As --group-transaction-events is configured in the senders, the remaining + // events of the third transaction are added to the batch which makes + // that the first batch is sent with 12 events. The same happens with the + // second batch which will contain 12 events too. + // - Without group-transaction-events 3 batches are sent, 2 with 10 events + // and one with 4. + final int transactions = 8; + final int eventsPerTransaction = 3; + final int entries = transactions * eventsPerTransaction; + int expectedBatchesSent = type.equals(TxGroupingSerialGatewaySenderImpl.TYPE) ? 2 : 3; + + londonServer2VM + .invoke(() -> doTxPuts(REGION_NAME, eventsPerTransaction, transactions)); + + // wait for batches to be redistributed and then start the receiver + londonServer1VM.invoke(() -> await() + .untilAsserted(() -> assertThat(getSenderStats(newYorkName, -1).get(5)).isGreaterThan(0))); + + newYorkServerVM.invoke(this::startReceiver); + + newYorkServerVM.invoke(() -> validateRegionSize(REGION_NAME, entries)); + + + newYorkServerVM + .invoke(() -> checkGatewayReceiverStats(expectedBatchesSent, entries, entries, true)); + + londonServer1VM.invoke(() -> checkQueueStats(newYorkName, 0, entries, entries, entries)); + londonServer1VM.invoke(() -> checkBatchStats(newYorkName, expectedBatchesSent, true)); + + // wait until queue is empty + londonServer2VM.invoke(() -> getSenderStats(newYorkName, 0)); + + londonServer2VM.invoke(() -> checkQueueStats(newYorkName, 0, entries, 0, 0)); + londonServer2VM.invoke(() -> checkBatchStats(newYorkName, 0, false)); + } + + @Test + public void testReplicatedSerialPropagationHAWithGroupTransactionEvents() throws Exception { + newYorkServerVM.invoke("create New York server", () -> { + startServerWithReceiver(newYorkLocatorPort, newYorkReceiverPort); + createReplicatedRegion(REGION_NAME, null); + }); + + int batchSize = 9; + for (VM server : londonServersVM) { + server.invoke("create London server " + server.getId(), () -> { + startServerWithSender(server.getId(), londonLocatorPort, newYorkId, newYorkName, + TxGroupingSerialGatewaySenderImpl.TYPE, batchSize, 1); + createReplicatedRegion(REGION_NAME, newYorkName); + GatewaySender sender = cacheRule.getCache().getGatewaySender(newYorkName); + await().untilAsserted(() -> assertThat(isRunning(sender)).isTrue()); + }); + } + + int putsPerTransaction = 2; + int transactions = 5000; + AsyncInvocation putsInvocation1 = + londonServer3VM.invokeAsync( + () -> doTxPutsWithRetryIfError(REGION_NAME, putsPerTransaction, transactions, 0)); + AsyncInvocation putsInvocation2 = + londonServer4VM.invokeAsync( + () -> doTxPutsWithRetryIfError(REGION_NAME, putsPerTransaction, transactions, + putsPerTransaction * transactions)); + + newYorkServerVM.invoke(() -> await() + .untilAsserted(() -> assertThat(getRegionSize(REGION_NAME)).isGreaterThan(40))); + + AsyncInvocation killServerAsyncInvocation = + londonServer1VM.invokeAsync(() -> killPrimarySender(newYorkName)); + Boolean isKilled = killServerAsyncInvocation.get(); + if (!isKilled) { + AsyncInvocation killServerAsyncInvocation2 = + londonServer2VM.invokeAsync(() -> killPrimarySender(newYorkName)); + killServerAsyncInvocation2.await(); + } + putsInvocation1.await(); + putsInvocation2.await(); + killServerAsyncInvocation.await(); + + int entries = 2 * putsPerTransaction * transactions; + londonServer2VM.invoke(() -> validateRegionSize(REGION_NAME, entries)); + newYorkServerVM.invoke(() -> validateRegionSize(REGION_NAME, entries)); + + // batchesReceived is equal to numberOfEntries/(batchSize+1) + // As transactions are 2 events long, for each batch it will always be necessary to + // add one more entry to the 9 events batch in order to have complete transactions in the batch. + int batchesReceived = entries / (batchSize + 1); + newYorkServerVM.invoke(() -> checkGatewayReceiverStatsHA(batchesReceived, entries, entries)); + + londonServer2VM.invoke(() -> checkStats_Failover(newYorkName, entries)); + } + + private void checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated( + boolean isBatchesRedistributed) { + // Wait for sender queues to be empty + List> londonServersStats = new ArrayList(londonServersVM.length); + for (VM londonServer : londonServersVM) { + londonServersStats.add(londonServer.invoke(() -> getSenderStats(newYorkName, 0))); + } + + int queueSize = londonServersStats.stream().map(x -> x.get(0)).reduce(0, Integer::sum); + assertThat(queueSize).isEqualTo(0); + + // batches redistributed: + int batchesRedistributed = + londonServersStats.stream().map(x -> x.get(5)).reduce(0, Integer::sum); + if (isBatchesRedistributed) { + assertThat(batchesRedistributed).isGreaterThan(0); + } else { + assertThat(batchesRedistributed).isEqualTo(0); + } + } + + private void createReplicatedRegion(String regionName, String senderId) { + RegionFactory fact = + cacheRule.getCache().createRegionFactory(RegionShortcut.REPLICATE); + if (senderId != null) { + fact.addGatewaySenderId(senderId); + } + fact.create(regionName); + } + + private void checkQueueStats(String senderId, final int queueSize, final int eventsReceived, + final int eventsQueued, final int eventsDistributed) { + GatewaySenderStats statistics = getGatewaySenderStats(senderId); + assertThat(statistics.getEventQueueSize()).isEqualTo(queueSize); + assertThat(statistics.getEventsReceived()).isEqualTo(eventsReceived); + assertThat(statistics.getEventsQueued()).isEqualTo(eventsQueued); + assertThat(statistics.getEventsDistributed()).isGreaterThanOrEqualTo(eventsDistributed); + } + + private void checkBatchStats(String senderId, final int batches, + final boolean batchesRedistributed) { + GatewaySenderStats statistics = getGatewaySenderStats(senderId); + assertThat(statistics.getBatchesDistributed()).isEqualTo(batches); + + if (batchesRedistributed) { + assertThat(statistics.getBatchesRedistributed()).isGreaterThan(0); + } else { + assertThat(statistics.getBatchesRedistributed()).isEqualTo(0); + } + } + + private void checkConflatedStats(String senderId) { + GatewaySenderStats statistics = getGatewaySenderStats(senderId); + assertThat(statistics.getEventsNotQueuedConflated()).isEqualTo(0); + } + + private void checkStats_Failover(String senderId, final int eventsReceived) { + GatewaySenderStats statistics = getGatewaySenderStats(senderId); + assertThat(statistics.getEventsReceived()).isEqualTo(eventsReceived); + assertThat((statistics.getEventsQueued() + statistics.getUnprocessedTokensAddedByPrimary() + + statistics.getUnprocessedEventsRemovedByPrimary())).isEqualTo(eventsReceived); + } + + private boolean killPrimarySender(String senderId) { + try (IgnoredException ignoredException1 = + IgnoredException.addIgnoredException("Could not connect"); + IgnoredException ignoredException2 = + IgnoredException.addIgnoredException(CacheClosedException.class.getName()); + IgnoredException ignoredException3 = + IgnoredException.addIgnoredException(ForceReattemptException.class.getName())) { + AbstractGatewaySender sender = (AbstractGatewaySender) getGatewaySender(senderId); + if (sender.isPrimary()) { + cacheRule.getCache().close(); + return true; + } + return false; + } + } +} diff --git a/geode-wan-txgrouping/src/integrationTest/java/org/apache/geode/internal/cache/wan/txgrouping/WanTxGroupingConfigurationJUnitTest.java b/geode-wan-txgrouping/src/integrationTest/java/org/apache/geode/internal/cache/wan/txgrouping/WanTxGroupingConfigurationJUnitTest.java new file mode 100644 index 000000000000..f6f67b414bb2 --- /dev/null +++ b/geode-wan-txgrouping/src/integrationTest/java/org/apache/geode/internal/cache/wan/txgrouping/WanTxGroupingConfigurationJUnitTest.java @@ -0,0 +1,93 @@ +/* + * 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.wan.txgrouping; + +import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; + +import java.util.Set; + +import org.junit.After; +import org.junit.Test; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.RegionFactory; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.GatewaySenderFactory; +import org.apache.geode.cache.wan.internal.txgrouping.serial.TxGroupingSerialGatewaySenderImpl; +import org.apache.geode.internal.cache.wan.GatewaySenderException; + +public class WanTxGroupingConfigurationJUnitTest { + + private Cache cache; + + /** + * Test to validate that serial gateway sender group transaction events can + * be correctly set to true + */ + @Test + public void test_ValidateSerialGatewaySenderGroupTransactionEventsAttributeSetToTrue() { + cache = new CacheFactory().set(MCAST_PORT, "0").create(); + GatewaySenderFactory fact = cache.createGatewaySenderFactory(); + fact.setParallel(true); + fact.setBatchConflationEnabled(false); + boolean groupTransactionEvents = true; + fact.setManualStart(true); + fact.setGroupTransactionEvents(groupTransactionEvents); + GatewaySender sender1 = fact.create("TKSender", 2); + RegionFactory factory = cache.createRegionFactory(RegionShortcut.PARTITION); + factory.addGatewaySenderId(sender1.getId()); + Set senders = cache.getGatewaySenders(); + assertEquals(senders.size(), 1); + GatewaySender gatewaySender = senders.iterator().next(); + assertThat(sender1.mustGroupTransactionEvents()) + .isEqualTo(gatewaySender.mustGroupTransactionEvents()); + } + + @Test + public void test_create_SerialGatewaySender_ThrowsException_when_GroupTransactionEvents_isTrue_and_DispatcherThreads_is_greaterThanOne() { + cache = new CacheFactory().set(MCAST_PORT, "0").create(); + GatewaySenderFactory fact = cache.createGatewaySenderFactory(); + fact.setDispatcherThreads(2); + fact.setType(TxGroupingSerialGatewaySenderImpl.TYPE); + assertThatThrownBy(() -> fact.create("NYSender", 2)) + .isInstanceOf(GatewaySenderException.class) + .hasMessageContaining( + "SerialGatewaySender NYSender cannot be created with group transaction events set to true when dispatcher threads is greater than 1"); + } + + @Test + public void test_create_GatewaySender_ThrowsException_when_GroupTransactionEvents_isTrue_and_BatchConflation_is_enabled() { + cache = new CacheFactory().set(MCAST_PORT, "0").create(); + GatewaySenderFactory fact = cache.createGatewaySenderFactory(); + fact.setBatchConflationEnabled(true); + fact.setType(TxGroupingSerialGatewaySenderImpl.TYPE); + assertThatThrownBy(() -> fact.create("NYSender", 2)) + .isInstanceOf(GatewaySenderException.class) + .hasMessageContaining( + "GatewaySender NYSender cannot be created with both group transaction events set to true and batch conflation enabled"); + } + + @After + public void tearDown() { + if (this.cache != null) { + this.cache.close(); + } + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/CommonTxGroupingGatewaySenderFactory.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/CommonTxGroupingGatewaySenderFactory.java new file mode 100644 index 000000000000..3d94408e3dec --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/CommonTxGroupingGatewaySenderFactory.java @@ -0,0 +1,36 @@ +/* + * 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.cache.wan.internal.txgrouping; + +import static java.lang.String.format; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory; +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; + +public interface CommonTxGroupingGatewaySenderFactory { + static void validate(final @NotNull GatewaySenderTypeFactory factory, + final @NotNull MutableGatewaySenderAttributes attributes) { + if (attributes.isBatchConflationEnabled()) { + throw new GatewaySenderException( + format( + "%s %s cannot be created with both group transaction events set to true and batch conflation enabled", + factory.getType(), attributes.getId())); + } + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySender.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySender.java new file mode 100644 index 000000000000..a5a456c1ba10 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySender.java @@ -0,0 +1,26 @@ +/* + * 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.cache.wan.internal.txgrouping; + +public interface TxGroupingGatewaySender { + void setRetriesToGetTransactionEventsFromQueue(int retries); + + int getRetriesToGetTransactionEventsFromQueue(); + + void setTransactionEventsFromQueueWaitMs(int millisecs); + + int getTransactionEventsFromQueueWaitMs(); +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySenderProperties.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySenderProperties.java new file mode 100644 index 000000000000..155650cb306c --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/TxGroupingGatewaySenderProperties.java @@ -0,0 +1,85 @@ +/* + * 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.cache.wan.internal.txgrouping; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.geode.internal.lang.SystemProperty; +import org.apache.geode.util.internal.GeodeGlossary; + +public class TxGroupingGatewaySenderProperties implements TxGroupingGatewaySender { + + /** + * Milliseconds to wait before retrying to get events for a transaction from the + * gateway sender queue when group-transaction-events is true. + */ + public static final String GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS_PROPERTY = + "get-transaction-events-from-queue-wait-time-ms"; + + /** + * Number of times to retry to get events for a transaction from the gateway sender queue when + * group-transaction-events is set to true. + * When group-transaction-events is set to true and a batch ready to be sent does not contain + * all the events for all the transactions to which the events belong, the gateway sender will try + * to get the missing events of the transactions from the queue to add them to the batch + * before sending it. + * If the missing events are not in the queue when the gateway sender tries to get them + * it will retry for a maximum of times equal to the value set in this parameter before + * delivering the batch without the missing events and logging an error. + * Setting this parameter to a very low value could cause that under heavy load and + * group-transaction-events set to true, batches are sent with incomplete transactions. Setting it + * to a high value could cause that under heavy load and group-transaction-events set to true, + * batches are held for some time before being sent. + */ + static final int GET_TRANSACTION_EVENTS_FROM_QUEUE_RETRIES = + Integer.getInteger(GeodeGlossary.GEMFIRE_PREFIX + "get-transaction-events-from-queue-retries", + 10); + /** + * Milliseconds to wait before retrying to get events for a transaction from the + * gateway sender queue when group-transaction-events is true. + */ + public static final int GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS = + SystemProperty.getProductIntegerProperty( + GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS_PROPERTY).orElse(1); + + private AtomicInteger retriesToGetTransactionEventsFromQueue = + new AtomicInteger(GET_TRANSACTION_EVENTS_FROM_QUEUE_RETRIES); + + private AtomicInteger transactionEventsFromQueueWaitMs = + new AtomicInteger(GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); + + @Override + public void setRetriesToGetTransactionEventsFromQueue(int retries) { + retriesToGetTransactionEventsFromQueue.set(retries); + } + + @Override + public int getRetriesToGetTransactionEventsFromQueue() { + return retriesToGetTransactionEventsFromQueue.get(); + } + + @Override + public void setTransactionEventsFromQueueWaitMs(int millisecs) { + transactionEventsFromQueueWaitMs.set(millisecs); + + } + + @Override + public int getTransactionEventsFromQueueWaitMs() { + return retriesToGetTransactionEventsFromQueue.get(); + } + +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderCreation.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderCreation.java new file mode 100644 index 000000000000..330146f22f5a --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderCreation.java @@ -0,0 +1,41 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderCreation; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; + +public class TxGroupingParallelGatewaySenderCreation extends ParallelGatewaySenderCreation { + + public TxGroupingParallelGatewaySenderCreation(final @NotNull InternalCache cache, + final @NotNull GatewaySenderAttributes attributes) { + super(cache, attributes); + } + + @Override + public boolean mustGroupTransactionEvents() { + return false; + } + + @Override + public String getType() { + return TxGroupingParallelGatewaySenderImpl.TYPE; + } + +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderImpl.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderImpl.java new file mode 100644 index 000000000000..f44367f07691 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderImpl.java @@ -0,0 +1,85 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderImpl; +import org.apache.geode.cache.wan.internal.parallel.RemoteConcurrentParallelGatewaySenderEventProcessor; +import org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySender; +import org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySenderProperties; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.monitoring.ThreadsMonitoring; +import org.apache.geode.internal.statistics.StatisticsClock; + +public class TxGroupingParallelGatewaySenderImpl extends ParallelGatewaySenderImpl + implements TxGroupingGatewaySender { + + public static final String TYPE = "TxGroupingParallelGatewaySender"; + + private final TxGroupingGatewaySenderProperties properties = + new TxGroupingGatewaySenderProperties(); + + public TxGroupingParallelGatewaySenderImpl(final @NotNull InternalCache cache, + final @NotNull StatisticsClock clock, + final @NotNull GatewaySenderAttributes attributes) { + super(cache, clock, attributes); + } + + @Override + public boolean mustGroupTransactionEvents() { + return true; + } + + @Override + protected RemoteConcurrentParallelGatewaySenderEventProcessor createEventProcessor( + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + return new TxGroupingRemoteConcurrentParallelGatewaySenderEventProcessor(this, + threadsMonitoring, cleanQueues); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public int getRetriesToGetTransactionEventsFromQueue() { + return properties.getRetriesToGetTransactionEventsFromQueue(); + } + + @Override + public void setTransactionEventsFromQueueWaitMs(int millisecs) { + properties.setTransactionEventsFromQueueWaitMs(millisecs); + } + + @Override + public int getTransactionEventsFromQueueWaitMs() { + return properties.getTransactionEventsFromQueueWaitMs(); + } + + @Override + public void setRetriesToGetTransactionEventsFromQueue(int retries) { + properties.setRetriesToGetTransactionEventsFromQueue(retries); + } + + @Override + public boolean isParallel() { + return true; + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueue.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueue.java new file mode 100644 index 000000000000..4fefd06b2332 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueue.java @@ -0,0 +1,191 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import static org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySenderProperties.GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.CacheException; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.TransactionId; +import org.apache.geode.internal.cache.BucketRegionQueue; +import org.apache.geode.internal.cache.PartitionedRegion; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.GatewaySenderEventImpl; +import org.apache.geode.internal.cache.wan.parallel.BucketRegionQueueUnavailableException; +import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderQueue; + +public class TxGroupingParallelGatewaySenderQueue extends ParallelGatewaySenderQueue { + + public TxGroupingParallelGatewaySenderQueue( + final @NotNull AbstractGatewaySender sender, + final @NotNull Set> userRegions, + final int idx, final int nDispatcher, final boolean cleanQueues) { + super(sender, userRegions, idx, nDispatcher, cleanQueues); + } + + @Override + protected void postProcessBatch(final @NotNull PartitionedRegion partitionedRegion, + final @NotNull List batch) { + if (batch.isEmpty()) { + return; + } + + Map incompleteTransactionIdsInBatch = + getIncompleteTransactionsInBatch(batch); + if (incompleteTransactionIdsInBatch.isEmpty()) { + return; + } + + int retries = 0; + while (true) { + peekAndAddEventsToBatchToCompleteTransactions( + partitionedRegion, batch, incompleteTransactionIdsInBatch); + if (incompleteTransactionIdsInBatch.size() == 0 || + retries >= ((TxGroupingParallelGatewaySenderImpl) sender) + .getRetriesToGetTransactionEventsFromQueue()) { + break; + } + retries++; + try { + Thread.sleep(GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (incompleteTransactionIdsInBatch.size() > 0) { + logger.warn("Not able to retrieve all events for transactions: {} after {} retries of {}ms", + incompleteTransactionIdsInBatch, retries, GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); + stats.incBatchesWithIncompleteTransactions(); + } + } + + private void peekAndAddEventsToBatchToCompleteTransactions( + @NotNull PartitionedRegion partitionedRegion, @NotNull List batch, + Map incompleteTransactionIdsInBatch) { + for (Iterator> incompleteTransactionsIter = + incompleteTransactionIdsInBatch.entrySet().iterator(); incompleteTransactionsIter + .hasNext();) { + Map.Entry pendingTransaction = incompleteTransactionsIter.next(); + TransactionId transactionId = pendingTransaction.getKey(); + int bucketId = pendingTransaction.getValue(); + + List events = + peekEventsWithTransactionId(partitionedRegion, bucketId, transactionId); + + addEventsToBatch(batch, bucketId, events); + + for (Object event : events) { + if (((GatewaySenderEventImpl) event).isLastEventInTransaction()) { + incompleteTransactionsIter.remove(); + } + } + } + } + + private void addEventsToBatch( + @NotNull List batch, + int bucketId, List events) { + for (Object object : events) { + GatewaySenderEventImpl event = (GatewaySenderEventImpl) object; + batch.add(event); + peekedEvents.add(event); + if (logger.isDebugEnabled()) { + logger.debug( + "Peeking extra event: {}, bucketId: {}, isLastEventInTransaction: {}, batch size: {}", + event.getKey(), bucketId, event.isLastEventInTransaction(), batch.size()); + } + } + } + + protected List peekEventsWithTransactionId(PartitionedRegion prQ, int bucketId, + TransactionId transactionId) throws CacheException { + List objects; + BucketRegionQueue brq = getBucketRegionQueueByBucketId(prQ, bucketId); + + try { + Predicate hasTransactionIdPredicate = + getHasTransactionIdPredicate(transactionId); + Predicate isLastEventInTransactionPredicate = + getIsLastEventInTransactionPredicate(); + objects = + brq.getElementsMatching(hasTransactionIdPredicate, isLastEventInTransactionPredicate); + } catch (BucketRegionQueueUnavailableException e) { + // BucketRegionQueue unavailable. Can be due to the BucketRegionQueue being destroyed. + return Collections.emptyList(); + } + + return objects; // OFFHEAP: ok since callers are careful to do destroys on region queue after + // finished with peeked objects. + } + + private static Predicate getIsLastEventInTransactionPredicate() { + return x -> x.isLastEventInTransaction(); + } + + private static Predicate getHasTransactionIdPredicate( + TransactionId transactionId) { + return x -> transactionId.equals(x.getTransactionId()); + } + + private Map getIncompleteTransactionsInBatch( + List batch) { + Map incompleteTransactionsInBatch = new HashMap<>(); + for (GatewaySenderEventImpl event : batch) { + if (event.getTransactionId() != null) { + if (event.isLastEventInTransaction()) { + incompleteTransactionsInBatch.remove(event.getTransactionId()); + } else { + incompleteTransactionsInBatch.put(event.getTransactionId(), event.getBucketId()); + } + } + } + return incompleteTransactionsInBatch; + } + + @Override + protected void addPreviouslyPeekedEvents(final @NotNull List batch, + final int batchSize) { + Set incompleteTransactionsInBatch = new HashSet<>(); + for (int i = 0; i < batchSize || !incompleteTransactionsInBatch.isEmpty(); i++) { + GatewaySenderEventImpl event = peekedEventsProcessing.remove(); + batch.add(event); + if (event.getTransactionId() != null) { + if (event.isLastEventInTransaction()) { + incompleteTransactionsInBatch.remove(event.getTransactionId()); + } else { + incompleteTransactionsInBatch.add(event.getTransactionId()); + } + } + if (peekedEventsProcessing.isEmpty()) { + resetLastPeeked = false; + peekedEventsProcessingInProgress = false; + break; + } + } + } + +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactory.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactory.java new file mode 100644 index 000000000000..901ef67da83b --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactory.java @@ -0,0 +1,56 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderTypeFactory; +import org.apache.geode.cache.wan.internal.txgrouping.CommonTxGroupingGatewaySenderFactory; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; +import org.apache.geode.internal.statistics.StatisticsClock; + +public class TxGroupingParallelGatewaySenderTypeFactory extends ParallelGatewaySenderTypeFactory { + + @Override + public @NotNull String getType() { + return TxGroupingParallelGatewaySenderImpl.TYPE; + } + + @Override + public void validate(final @NotNull MutableGatewaySenderAttributes attributes) + throws GatewaySenderException { + super.validate(attributes); + + CommonTxGroupingGatewaySenderFactory.validate(this, attributes); + } + + @Override + public GatewaySender create(final @NotNull InternalCache cache, + final @NotNull StatisticsClock clock, + final @NotNull GatewaySenderAttributes attributes) { + return new TxGroupingParallelGatewaySenderImpl(cache, clock, attributes); + } + + @Override + public GatewaySender createCreation(final @NotNull InternalCache cache, + final @NotNull GatewaySenderAttributes attributes) { + return new TxGroupingParallelGatewaySenderCreation(cache, attributes); + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteConcurrentParallelGatewaySenderEventProcessor.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteConcurrentParallelGatewaySenderEventProcessor.java new file mode 100644 index 000000000000..68d994181672 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteConcurrentParallelGatewaySenderEventProcessor.java @@ -0,0 +1,42 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.wan.internal.parallel.RemoteConcurrentParallelGatewaySenderEventProcessor; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderEventProcessor; +import org.apache.geode.internal.monitoring.ThreadsMonitoring; + +public class TxGroupingRemoteConcurrentParallelGatewaySenderEventProcessor extends + RemoteConcurrentParallelGatewaySenderEventProcessor { + + public TxGroupingRemoteConcurrentParallelGatewaySenderEventProcessor( + final @NotNull AbstractGatewaySender sender, + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + super(sender, threadsMonitoring, cleanQueues); + } + + @Override + protected ParallelGatewaySenderEventProcessor createRemoteParallelGatewaySenderEventProcessor( + final @NotNull AbstractGatewaySender sender, final int id, final int dispatcherThreads, + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + return new TxGroupingRemoteParallelGatewaySenderEventProcessor(sender, id, dispatcherThreads, + threadsMonitoring, cleanQueues); + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteParallelGatewaySenderEventProcessor.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteParallelGatewaySenderEventProcessor.java new file mode 100644 index 000000000000..2ef8853a99cd --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingRemoteParallelGatewaySenderEventProcessor.java @@ -0,0 +1,46 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import java.util.Set; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.Region; +import org.apache.geode.cache.wan.internal.parallel.RemoteParallelGatewaySenderEventProcessor; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.parallel.ParallelGatewaySenderQueue; +import org.apache.geode.internal.monitoring.ThreadsMonitoring; + +public class TxGroupingRemoteParallelGatewaySenderEventProcessor extends + RemoteParallelGatewaySenderEventProcessor { + + protected TxGroupingRemoteParallelGatewaySenderEventProcessor( + final @NotNull AbstractGatewaySender sender, final int id, final int nDispatcher, + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + super(sender, id, nDispatcher, threadsMonitoring, cleanQueues); + } + + + @Override + protected @NotNull ParallelGatewaySenderQueue createParallelGatewaySenderQueue( + final @NotNull AbstractGatewaySender sender, final @NotNull Set> targetRegions, + final int index, final int dispatcherThreads, final boolean cleanQueues) { + return new TxGroupingParallelGatewaySenderQueue(sender, targetRegions, index, dispatcherThreads, + cleanQueues); + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteConcurrentSerialGatewaySenderEventProcessor.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteConcurrentSerialGatewaySenderEventProcessor.java new file mode 100644 index 000000000000..3f90465aecf5 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteConcurrentSerialGatewaySenderEventProcessor.java @@ -0,0 +1,46 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.wan.internal.serial.RemoteConcurrentSerialGatewaySenderEventProcessor; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.monitoring.ThreadsMonitoring; + +public class TxGroupingRemoteConcurrentSerialGatewaySenderEventProcessor + extends RemoteConcurrentSerialGatewaySenderEventProcessor { + public TxGroupingRemoteConcurrentSerialGatewaySenderEventProcessor( + final @NotNull AbstractGatewaySender sender, + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + super(sender, threadsMonitoring, cleanQueues); + } + + @Override + protected void initializeMessageQueue(String id, boolean cleanQueues) { + for (int i = 0; i < sender.getDispatcherThreads(); i++) { + final ThreadsMonitoring threadsMonitoring = getThreadMonitorObj(); + processors.add(new TxGroupingRemoteSerialGatewaySenderEventProcessor(sender, id + "." + i, + threadsMonitoring, cleanQueues)); + if (logger.isDebugEnabled()) { + logger.debug("Created the TxGroupingRemoteSerialGatewaySenderEventProcessor_{}->{}", i, + processors.get(i)); + } + } + } + +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteSerialGatewaySenderEventProcessor.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteSerialGatewaySenderEventProcessor.java new file mode 100644 index 000000000000..20334208569f --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingRemoteSerialGatewaySenderEventProcessor.java @@ -0,0 +1,43 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.CacheListener; +import org.apache.geode.cache.asyncqueue.AsyncEvent; +import org.apache.geode.cache.wan.internal.serial.RemoteSerialGatewaySenderEventProcessor; +import org.apache.geode.internal.cache.RegionQueue; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.monitoring.ThreadsMonitoring; + +public class TxGroupingRemoteSerialGatewaySenderEventProcessor extends + RemoteSerialGatewaySenderEventProcessor { + + public TxGroupingRemoteSerialGatewaySenderEventProcessor( + final @NotNull AbstractGatewaySender sender, final @NotNull String id, + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + super(sender, id, threadsMonitoring, cleanQueues); + } + + @Override + protected @NotNull RegionQueue createRegionQueue( + final @NotNull AbstractGatewaySender sender, final @NotNull String regionName, + final @NotNull CacheListener> listener, final boolean cleanQueues) { + return new TxGroupingSerialGatewaySenderQueue(sender, regionName, listener, cleanQueues); + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderCreation.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderCreation.java new file mode 100644 index 000000000000..ef9dd4a6d808 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderCreation.java @@ -0,0 +1,41 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.internal.serial.SerialGatewaySenderCreation; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; + +public class TxGroupingSerialGatewaySenderCreation extends SerialGatewaySenderCreation { + + public TxGroupingSerialGatewaySenderCreation(final @NotNull InternalCache cache, + final @NotNull GatewaySenderAttributes attributes) { + super(cache, attributes); + } + + @Override + public boolean mustGroupTransactionEvents() { + return true; + } + + @Override + public String getType() { + return TxGroupingSerialGatewaySenderImpl.TYPE; + } + +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderImpl.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderImpl.java new file mode 100644 index 000000000000..4cafad833c8d --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderImpl.java @@ -0,0 +1,91 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.apache.geode.cache.wan.internal.serial.SerialGatewaySenderImpl; +import org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySender; +import org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySenderProperties; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.AbstractGatewaySenderEventProcessor; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.monitoring.ThreadsMonitoring; +import org.apache.geode.internal.statistics.StatisticsClock; + +public class TxGroupingSerialGatewaySenderImpl extends SerialGatewaySenderImpl + implements TxGroupingGatewaySender { + + public static final String TYPE = "TxGroupingSerialGatewaySender"; + + private final TxGroupingGatewaySenderProperties properties = + new TxGroupingGatewaySenderProperties(); + + public TxGroupingSerialGatewaySenderImpl(final @NotNull InternalCache cache, + final @NotNull StatisticsClock clock, + final @NotNull GatewaySenderAttributes attributes) { + super(cache, clock, attributes); + } + + @Override + public boolean mustGroupTransactionEvents() { + return true; + } + + @Override + protected AbstractGatewaySenderEventProcessor createEventProcessor( + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + if (getDispatcherThreads() > 1) { + return new TxGroupingRemoteConcurrentSerialGatewaySenderEventProcessor(this, + threadsMonitoring, cleanQueues); + } else { + return new TxGroupingRemoteSerialGatewaySenderEventProcessor(this, getId(), + threadsMonitoring, cleanQueues); + } + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public void setRetriesToGetTransactionEventsFromQueue(int retries) { + properties.setRetriesToGetTransactionEventsFromQueue(retries); + } + + @Override + public int getRetriesToGetTransactionEventsFromQueue() { + return properties.getRetriesToGetTransactionEventsFromQueue(); + } + + @Override + public void setTransactionEventsFromQueueWaitMs(int millisecs) { + properties.setTransactionEventsFromQueueWaitMs(millisecs); + } + + @Override + public int getTransactionEventsFromQueueWaitMs() { + return properties.getTransactionEventsFromQueueWaitMs(); + } + + @Override + public boolean isParallel() { + return false; + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueue.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueue.java new file mode 100644 index 000000000000..073704479704 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueue.java @@ -0,0 +1,240 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; + +import org.apache.geode.annotations.VisibleForTesting; +import org.apache.geode.cache.CacheListener; +import org.apache.geode.cache.TransactionId; +import org.apache.geode.cache.asyncqueue.AsyncEvent; +import org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySender; +import org.apache.geode.cache.wan.internal.txgrouping.TxGroupingGatewaySenderProperties; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.GatewaySenderEventImpl; +import org.apache.geode.internal.cache.wan.serial.SerialGatewaySenderQueue; + +public class TxGroupingSerialGatewaySenderQueue extends SerialGatewaySenderQueue { + + /** + * Contains the set of peekedIds that were peeked to complete a transaction + * inside a batch when groupTransactionEvents is set. + */ + protected final Set extraPeekedIds = ConcurrentHashMap.newKeySet(); + + /** + * Contains the set of peekedIds that were peeked to complete a transaction + * inside a batch when groupTransactionEvents is set and whose event has been + * removed from the queue because an ack has been received from the receiver. + * Elements from this set are deleted when the event with the previous id + * is removed. + */ + private final Set extraPeekedIdsRemovedButPreviousIdNotRemoved = + ConcurrentHashMap.newKeySet(); + + public TxGroupingSerialGatewaySenderQueue( + final AbstractGatewaySender abstractSender, + final String regionName, final CacheListener listener, final boolean cleanQueues) { + super(abstractSender, regionName, listener, cleanQueues); + } + + @Override + protected void incrementEventsNotQueueConflated() { + // When mustGroupTransactionEvents is true, conflation cannot be enabled. + // Therefore, if we reach here, it would not be due to a conflated event + // but rather to an extra peeked event already sent. + } + + @Override + protected void postProcessBatch(final List> batch, final long lastKey) { + if (batch.isEmpty()) { + return; + } + + Set incompleteTransactionIdsInBatch = getIncompleteTransactionsInBatch(batch); + if (incompleteTransactionIdsInBatch.size() == 0) { + return; + } + + int retries = 0; + while (true) { + peekAndAddEventsToBatchToCompleteTransactions(batch, lastKey, + incompleteTransactionIdsInBatch); + if (incompleteTransactionIdsInBatch.size() == 0 || + retries >= ((TxGroupingGatewaySender) sender) + .getRetriesToGetTransactionEventsFromQueue()) { + break; + } + retries++; + try { + Thread.sleep( + TxGroupingGatewaySenderProperties.GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (incompleteTransactionIdsInBatch.size() > 0) { + logger.warn("Not able to retrieve all events for transactions: {} after {} retries of {}ms", + incompleteTransactionIdsInBatch, retries, + TxGroupingGatewaySenderProperties.GET_TRANSACTION_EVENTS_FROM_QUEUE_WAIT_TIME_MS); + stats.incBatchesWithIncompleteTransactions(); + } + } + + private void peekAndAddEventsToBatchToCompleteTransactions(List> batch, + long lastKey, Set incompleteTransactionIdsInBatch) { + for (Iterator incompleteTransactionsIter = + incompleteTransactionIdsInBatch.iterator(); incompleteTransactionsIter.hasNext();) { + TransactionId transactionId = incompleteTransactionsIter.next(); + List keyAndEventPairs = + peekEventsWithTransactionId(transactionId, lastKey); + if (lastEventInTransactionPresent(keyAndEventPairs)) { + addEventsToBatch(batch, keyAndEventPairs); + incompleteTransactionsIter.remove(); + } + } + } + + private boolean lastEventInTransactionPresent(List keyAndEventPairs) { + return keyAndEventPairs.size() > 0 + && ((GatewaySenderEventImpl) (keyAndEventPairs.get(keyAndEventPairs.size() - 1)).event) + .isLastEventInTransaction(); + } + + private void addEventsToBatch(List> batch, + List keyAndEventPairs) { + for (KeyAndEventPair object : keyAndEventPairs) { + GatewaySenderEventImpl event = (GatewaySenderEventImpl) object.event; + batch.add(event); + peekedIds.add(object.key); + extraPeekedIds.add(object.key); + if (logger.isDebugEnabled()) { + logger.debug( + "Peeking extra event: {}, isLastEventInTransaction: {}, batch size: {}", + event.getKey(), event.isLastEventInTransaction(), batch.size()); + } + } + } + + private Set getIncompleteTransactionsInBatch(List> batch) { + Set incompleteTransactionsInBatch = new HashSet<>(); + for (Object object : batch) { + if (object instanceof GatewaySenderEventImpl) { + GatewaySenderEventImpl event = (GatewaySenderEventImpl) object; + if (event.getTransactionId() != null) { + if (event.isLastEventInTransaction()) { + incompleteTransactionsInBatch.remove(event.getTransactionId()); + } else { + incompleteTransactionsInBatch.add(event.getTransactionId()); + } + } + } + } + return incompleteTransactionsInBatch; + } + + private List peekEventsWithTransactionId(TransactionId transactionId, + long lastKey) { + Predicate hasTransactionIdPredicate = + x -> transactionId.equals(x.getTransactionId()); + Predicate isLastEventInTransactionPredicate = + x -> x.isLastEventInTransaction(); + + return getElementsMatching(hasTransactionIdPredicate, isLastEventInTransactionPredicate, + lastKey); + } + + /** + * This method returns a list of objects that fulfill the matchingPredicate + * If a matching object also fulfills the endPredicate then the method + * stops looking for more matching objects. + */ + protected List getElementsMatching(Predicate condition, + Predicate stopCondition, + long lastKey) { + GatewaySenderEventImpl event; + List elementsMatching = new ArrayList<>(); + + long currentKey = lastKey; + + while ((currentKey = inc(currentKey)) != getTailKey()) { + if (extraPeekedIds.contains(currentKey)) { + continue; + } + event = (GatewaySenderEventImpl) optimalGet(currentKey); + if (event == null) { + continue; + } + + if (condition.test(event)) { + elementsMatching.add(new KeyAndEventPair(currentKey, event)); + + if (stopCondition.test(event)) { + break; + } + } + } + + return elementsMatching; + } + + @Override + protected void preProcessRemovedKey(Long key) { + boolean isExtraPeekedId = extraPeekedIds.contains(key); + if (!isExtraPeekedId) { + super.preProcessRemovedKey(key); + } else { + extraPeekedIdsRemovedButPreviousIdNotRemoved.add(key); + } + } + + @Override + protected void postProcessRemovedKey() { + // For those extraPeekedIds removed that are consecutive to lastDispatchedKey: + // - Update lastDispatchedKey with them so that they are removed + // by the batch removal thread. + // - Update the head key with them. + // - Remove them from extraPeekedIds. + long tmpKey = lastDispatchedKey; + while (extraPeekedIdsRemovedButPreviousIdNotRemoved.contains(tmpKey = inc(tmpKey))) { + extraPeekedIdsRemovedButPreviousIdNotRemoved.remove(tmpKey); + extraPeekedIds.remove(tmpKey); + super.preProcessRemovedKey(tmpKey); + } + } + + public void resetLastPeeked() { + super.resetLastPeeked(); + extraPeekedIds.clear(); + } + + @Override + protected boolean skipPeekedKey(Long key) { + return extraPeekedIds.contains(key); + } + + @VisibleForTesting + Set getExtraPeekedIds() { + return Collections.unmodifiableSet(extraPeekedIds); + } +} diff --git a/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactory.java b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactory.java new file mode 100644 index 000000000000..20b84d5e5ea6 --- /dev/null +++ b/geode-wan-txgrouping/src/main/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactory.java @@ -0,0 +1,68 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + +import static java.lang.String.format; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.internal.serial.SerialGatewaySenderTypeFactory; +import org.apache.geode.cache.wan.internal.txgrouping.CommonTxGroupingGatewaySenderFactory; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; +import org.apache.geode.internal.statistics.StatisticsClock; + +public class TxGroupingSerialGatewaySenderTypeFactory extends SerialGatewaySenderTypeFactory { + + @Override + public @NotNull String getType() { + return TxGroupingSerialGatewaySenderImpl.TYPE; + } + + @Override + public void validate(final @NotNull MutableGatewaySenderAttributes attributes) + throws GatewaySenderException { + + super.validate(attributes); + + CommonTxGroupingGatewaySenderFactory.validate(this, attributes); + + if (attributes.getDispatcherThreads() > 1) { + throw new GatewaySenderException( + format( + "%s %s cannot be created with group transaction events set to true when dispatcher threads is greater than 1", + getType(), attributes.getId())); + } + + } + + @Override + public GatewaySender create(final @NotNull InternalCache cache, + final @NotNull StatisticsClock clock, + final @NotNull GatewaySenderAttributes attributes) { + return new TxGroupingSerialGatewaySenderImpl(cache, clock, attributes); + } + + @Override + public GatewaySender createCreation(final @NotNull InternalCache cache, + final @NotNull GatewaySenderAttributes attributes) { + return new TxGroupingSerialGatewaySenderCreation(cache, attributes); + } + +} diff --git a/geode-wan-txgrouping/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory b/geode-wan-txgrouping/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory new file mode 100644 index 000000000000..1af795416931 --- /dev/null +++ b/geode-wan-txgrouping/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory @@ -0,0 +1,17 @@ +# +# 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. +# + +org.apache.geode.cache.wan.internal.txgrouping.serial.TxGroupingSerialGatewaySenderTypeFactory +org.apache.geode.cache.wan.internal.txgrouping.parallel.TxGroupingParallelGatewaySenderTypeFactory diff --git a/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueueJUnitTest.java b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueueJUnitTest.java new file mode 100644 index 000000000000..72821a7696e4 --- /dev/null +++ b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderQueueJUnitTest.java @@ -0,0 +1,242 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.junit.Before; +import org.junit.Test; + +import org.apache.geode.CancelCriterion; +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.PartitionAttributesFactory; +import org.apache.geode.cache.Region; +import org.apache.geode.internal.cache.BucketRegionQueue; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.internal.cache.PartitionedRegion; +import org.apache.geode.internal.cache.TXId; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.GatewaySenderEventImpl; +import org.apache.geode.internal.cache.wan.GatewaySenderStats; + +public class TxGroupingParallelGatewaySenderQueueJUnitTest { + + private AbstractGatewaySender sender; + + @Before + public void createParallelGatewaySenderQueue() { + GemFireCacheImpl cache = mock(GemFireCacheImpl.class); + sender = mock(AbstractGatewaySender.class); + CancelCriterion cancelCriterion = mock(CancelCriterion.class); + when(sender.getCancelCriterion()).thenReturn(cancelCriterion); + when(sender.getCache()).thenReturn(cache); + when(sender.getMaximumQueueMemory()).thenReturn(100); + when(sender.getLifeCycleLock()).thenReturn(new ReentrantReadWriteLock()); + when(sender.getId()).thenReturn(""); + } + + private void mockGatewaySenderStats() { + GatewaySenderStats stats = mock(GatewaySenderStats.class); + when(sender.getStatistics()).thenReturn(stats); + } + + @Test + public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInMaxSizeBatch() + throws Exception { + + GatewaySenderEventImpl event1 = createGatewaySenderEventImpl(1, false); + GatewaySenderEventImpl event2 = createGatewaySenderEventImpl(2, false); + GatewaySenderEventImpl event3 = createGatewaySenderEventImpl(1, true); + GatewaySenderEventImpl event4 = createGatewaySenderEventImpl(2, true); + GatewaySenderEventImpl event5 = createGatewaySenderEventImpl(3, false); + GatewaySenderEventImpl event6 = createGatewaySenderEventImpl(3, true); + + Queue backingList = new LinkedList<>(); + backingList.add(event1); + backingList.add(event2); + backingList.add(event3); + backingList.add(event4); + backingList.add(event5); + backingList.add(event6); + + BucketRegionQueue bucketRegionQueue = mockBucketRegionQueue(backingList); + + TestableParallelGatewaySenderQueue queue = new TestableParallelGatewaySenderQueue(sender, + Collections.emptySet(), 0, 1); + queue.setMockedAbstractBucketRegionQueue(bucketRegionQueue); + + List peeked = queue.peek(3, 100); + assertEquals(4, peeked.size()); + List peekedAfter = queue.peek(3, 100); + assertEquals(2, peekedAfter.size()); + } + + @Test + public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInBatchByTime() + throws Exception { + + GatewaySenderEventImpl event1 = createGatewaySenderEventImpl(1, false); + GatewaySenderEventImpl event2 = createGatewaySenderEventImpl(2, false); + GatewaySenderEventImpl event3 = createGatewaySenderEventImpl(1, true); + GatewaySenderEventImpl event4 = createGatewaySenderEventImpl(2, true); + GatewaySenderEventImpl event5 = createGatewaySenderEventImpl(3, false); + GatewaySenderEventImpl event6 = createGatewaySenderEventImpl(3, true); + + Queue backingList = new LinkedList<>(); + backingList.add(event1); + backingList.add(event2); + backingList.add(event3); + backingList.add(null); + backingList.add(event4); + backingList.add(event5); + backingList.add(event6); + + BucketRegionQueue bucketRegionQueue = mockBucketRegionQueue(backingList); + + TestableParallelGatewaySenderQueue queue = new TestableParallelGatewaySenderQueue(sender, + Collections.emptySet(), 0, 1); + queue.setMockedAbstractBucketRegionQueue(bucketRegionQueue); + + List peeked = queue.peek(-1, 1); + assertEquals(4, peeked.size()); + List peekedAfter = queue.peek(-1, 100); + assertEquals(2, peekedAfter.size()); + } + + @Test + public void peekEventsFromIncompleteTransactionsDoesNotThrowConcurrentModificationExceptionWhenCompletingTwoTransactions() { + mockGatewaySenderStats(); + GatewaySenderEventImpl event1 = createGatewaySenderEventImpl(1, false); + GatewaySenderEventImpl event2 = createGatewaySenderEventImpl(2, false); + GatewaySenderEventImpl event3 = createGatewaySenderEventImpl(1, true); + GatewaySenderEventImpl event4 = createGatewaySenderEventImpl(2, true); + + Queue backingList = new LinkedList<>(); + backingList.add(event3); + backingList.add(event4); + BucketRegionQueue bucketRegionQueue = mockBucketRegionQueue(backingList); + + TestableParallelGatewaySenderQueue queue = new TestableParallelGatewaySenderQueue(sender, + Collections.emptySet(), 0, 1); + queue.setMockedAbstractBucketRegionQueue(bucketRegionQueue); + + List batch = new ArrayList<>(Arrays.asList(event1, event2)); + PartitionedRegion mockBucketRegion = mockPR("bucketRegion"); + queue.postProcessBatch(mockBucketRegion, batch); + } + + + private GatewaySenderEventImpl createGatewaySenderEventImpl(int transactionId, + boolean isLastEventInTransaction) { + GatewaySenderEventImpl event = mock(GatewaySenderEventImpl.class); + when(event.getTransactionId()).thenReturn(new TXId(null, transactionId)); + when(event.makeHeapCopyIfOffHeap()).thenReturn(event); + when(event.isLastEventInTransaction()).thenReturn(isLastEventInTransaction); + return event; + } + + private PartitionedRegion mockPR(String name) { + PartitionedRegion region = mock(PartitionedRegion.class); + when(region.getFullPath()).thenReturn(name); + when(region.getPartitionAttributes()).thenReturn(new PartitionAttributesFactory<>().create()); + when(region.getTotalNumberOfBuckets()).thenReturn(113); + when(region.getDataPolicy()).thenReturn(DataPolicy.PARTITION); + return region; + } + + private BucketRegionQueue mockBucketRegionQueue(final Queue backingList) { + PartitionedRegion mockBucketRegion = mockPR("bucketRegion"); + // These next mocked return calls are for when peek is called. It ends up checking these on the + // mocked pr region + when(mockBucketRegion.getLocalMaxMemory()).thenReturn(100); + when(mockBucketRegion.size()).thenReturn(backingList.size()); + BucketRegionQueue bucketRegionQueue = mock(BucketRegionQueue.class); + when(bucketRegionQueue.getPartitionedRegion()).thenReturn(mockBucketRegion); + when(bucketRegionQueue.peek()).thenAnswer(invocation -> pollAndWaitIfNull(backingList)); + when(bucketRegionQueue.getElementsMatching(any(), any())) + .thenAnswer(invocation -> singletonList(getFirstNotNull(backingList))); + return bucketRegionQueue; + } + + private Object pollAndWaitIfNull(Queue queue) { + Object object = queue.poll(); + if (object == null) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return object; + } + + private Object getFirstNotNull(Queue queue) { + Object object = queue.poll(); + while (object == null) { + object = queue.poll(); + } + return object; + } + + private static class TestableParallelGatewaySenderQueue + extends TxGroupingParallelGatewaySenderQueue { + + private BucketRegionQueue mockedAbstractBucketRegionQueue; + + public TestableParallelGatewaySenderQueue(final AbstractGatewaySender sender, + final Set> userRegions, final int idx, final int nDispatcher) { + super(sender, userRegions, idx, nDispatcher, false); + } + + public void setMockedAbstractBucketRegionQueue(BucketRegionQueue mocked) { + mockedAbstractBucketRegionQueue = mocked; + } + + @Override + public boolean areLocalBucketQueueRegionsPresent() { + return true; + } + + @Override + protected PartitionedRegion getRandomShadowPR() { + return mockedAbstractBucketRegionQueue.getPartitionedRegion(); + } + + @Override + protected int getRandomPrimaryBucket(PartitionedRegion pr) { + return 0; + } + + @Override + protected BucketRegionQueue getBucketRegionQueueByBucketId(PartitionedRegion prQ, + int bucketId) { + return mockedAbstractBucketRegionQueue; + } + } + +} diff --git a/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactoryTest.java b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactoryTest.java new file mode 100644 index 000000000000..cf5b96d15f14 --- /dev/null +++ b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/parallel/TxGroupingParallelGatewaySenderTypeFactoryTest.java @@ -0,0 +1,52 @@ +/* + * 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.cache.wan.internal.txgrouping.parallel; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; + +public class TxGroupingParallelGatewaySenderTypeFactoryTest { + + final TxGroupingParallelGatewaySenderTypeFactory factory = + new TxGroupingParallelGatewaySenderTypeFactory(); + + @Test + public void validateThrowsIfBatchConflationEnabled() { + final MutableGatewaySenderAttributes attributes = mock(MutableGatewaySenderAttributes.class); + when(attributes.isBatchConflationEnabled()).thenReturn(true); + + assertThatThrownBy(() -> factory.validate(attributes)) + .isInstanceOf(GatewaySenderException.class) + .hasMessageContaining( + "both group transaction events set to true and batch conflation enabled"); + } + + @Test + public void validateDoesNotThrowsIfBatchConflationDisabled() { + final MutableGatewaySenderAttributes attributes = mock(MutableGatewaySenderAttributes.class); + when(attributes.isBatchConflationEnabled()).thenReturn(false); + + assertThatNoException().isThrownBy(() -> factory.validate(attributes)); + } + +} diff --git a/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueueJUnitTest.java b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueueJUnitTest.java new file mode 100644 index 000000000000..187ae204912a --- /dev/null +++ b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderQueueJUnitTest.java @@ -0,0 +1,223 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.junit.Before; +import org.junit.Test; + +import org.apache.geode.CancelCriterion; +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.asyncqueue.AsyncEvent; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.internal.cache.LocalRegion; +import org.apache.geode.internal.cache.TXId; +import org.apache.geode.internal.cache.wan.AbstractGatewaySender; +import org.apache.geode.internal.cache.wan.GatewaySenderEventImpl; +import org.apache.geode.internal.cache.wan.GatewaySenderStats; +import org.apache.geode.internal.cache.wan.serial.SerialGatewaySenderQueue; +import org.apache.geode.internal.statistics.DummyStatisticsRegistry; +import org.apache.geode.metrics.internal.NoopMeterRegistry; + +public class TxGroupingSerialGatewaySenderQueueJUnitTest { + + private static final String QUEUE_REGION = "queueRegion"; + + private AbstractGatewaySender sender; + Region region; + + @Before + public void setup() { + InternalDistributedSystem mockInternalDistributedSystem = mock(InternalDistributedSystem.class); + when(mockInternalDistributedSystem.getStatisticsManager()) + .thenReturn(new DummyStatisticsRegistry("", 0)); + + GemFireCacheImpl cache = mock(GemFireCacheImpl.class); + when(cache.getInternalDistributedSystem()).thenReturn(mockInternalDistributedSystem); + when(cache.getMeterRegistry()).thenReturn(new NoopMeterRegistry()); + + region = createLocalRegionMock(); + + CancelCriterion cancelCriterion = mock(CancelCriterion.class); + when(cache.getCancelCriterion()).thenReturn(cancelCriterion); + + sender = mock(TxGroupingSerialGatewaySenderImpl.class); + + when(sender.getCancelCriterion()).thenReturn(cancelCriterion); + when(sender.getCache()).thenReturn(cache); + when(cache.getRegion(any())).thenReturn(region); + when(sender.getMaximumQueueMemory()).thenReturn(100); + when(sender.getLifeCycleLock()).thenReturn(new ReentrantReadWriteLock()); + when(sender.getId()).thenReturn(""); + when(sender.getStatistics()).thenReturn(mock(GatewaySenderStats.class)); + } + + @Test + public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInMaxSizeBatch() { + TestableTxGroupingSerialGatewaySenderQueue queue = + new TestableTxGroupingSerialGatewaySenderQueue(sender, + QUEUE_REGION); + + List> peeked = queue.peek(3, 100); + assertEquals(4, peeked.size()); + List> peekedAfter = queue.peek(3, 100); + assertEquals(3, peekedAfter.size()); + } + + @Test + public void peekGetsExtraEventsWhenMustGroupTransactionEventsAndNotAllEventsForTransactionsInBatchByTime() { + GatewaySenderEventImpl event1 = createMockGatewaySenderEventImpl(1, false, region); + GatewaySenderEventImpl event2 = createMockGatewaySenderEventImpl(2, false, region); + GatewaySenderEventImpl event3 = createMockGatewaySenderEventImpl(1, true, region); + GatewaySenderEventImpl event4 = createMockGatewaySenderEventImpl(2, true, region); + TxGroupingSerialGatewaySenderQueue.KeyAndEventPair eventPair1 = + new SerialGatewaySenderQueue.KeyAndEventPair(0L, event1); + SerialGatewaySenderQueue.KeyAndEventPair eventPair2 = + new SerialGatewaySenderQueue.KeyAndEventPair(1L, event2); + SerialGatewaySenderQueue.KeyAndEventPair eventPair3 = + new SerialGatewaySenderQueue.KeyAndEventPair(2L, event3); + + TestableTxGroupingSerialGatewaySenderQueue realQueue = + new TestableTxGroupingSerialGatewaySenderQueue(sender, + QUEUE_REGION); + + TestableTxGroupingSerialGatewaySenderQueue queue = spy(realQueue); + + doAnswer(invocation -> eventPair1) + .doAnswer(invocation -> eventPair2) + .doAnswer(invocation -> eventPair3) + .doAnswer(invocation -> null) + .when(queue).peekAhead(); + + doAnswer(invocation -> Collections + .singletonList(new TxGroupingSerialGatewaySenderQueue.KeyAndEventPair(1L, event4))) + .when(queue).getElementsMatching(any(), any(), anyLong()); + + List> peeked = queue.peek(-1, 1); + assertEquals(4, peeked.size()); + } + + @Test + public void peekEventsFromIncompleteTransactionsDoesNotThrowConcurrentModificationExceptionWhenCompletingTwoTransactions() { + GatewaySenderEventImpl event1 = createMockGatewaySenderEventImpl(1, false, region); + GatewaySenderEventImpl event2 = createMockGatewaySenderEventImpl(2, false, region); + + TestableTxGroupingSerialGatewaySenderQueue queue = + new TestableTxGroupingSerialGatewaySenderQueue(sender, + QUEUE_REGION); + + @SuppressWarnings("unchecked") + List> batch = new ArrayList(Arrays.asList(event1, event2)); + queue.postProcessBatch(batch, 0); + } + + @Test + public void removeExtraPeekedEventDoesNotRemoveFromExtraPeekedIdsUntilPreviousEventIsRemoved() { + TestableTxGroupingSerialGatewaySenderQueue queue = + new TestableTxGroupingSerialGatewaySenderQueue(sender, + QUEUE_REGION); + List> peeked = queue.peek(3, -1); + assertEquals(4, peeked.size()); + assertThat(queue.getLastPeekedId()).isEqualTo(2); + assertThat(queue.getExtraPeekedIds().contains(5L)).isTrue(); + + + for (Object ignored : peeked) { + queue.remove(); + } + assertThat(queue.getExtraPeekedIds().contains(5L)).isTrue(); + + peeked = queue.peek(3, -1); + assertEquals(3, peeked.size()); + assertThat(queue.getExtraPeekedIds().contains(5L)).isTrue(); + + for (Object ignored : peeked) { + queue.remove(); + } + assertThat(queue.getExtraPeekedIds().contains(5L)).isFalse(); + } + + private GatewaySenderEventImpl createMockGatewaySenderEventImpl(int transactionId, + boolean isLastEventInTransaction, Region region) { + GatewaySenderEventImpl event = mock(GatewaySenderEventImpl.class); + when(event.getTransactionId()).thenReturn(new TXId(null, transactionId)); + when(event.makeHeapCopyIfOffHeap()).thenReturn(event); + when(event.isLastEventInTransaction()).thenReturn(isLastEventInTransaction); + when(event.getRegion()).thenReturn(region); + return event; + } + + private LocalRegion createLocalRegionMock() { + GatewaySenderEventImpl event1 = createMockGatewaySenderEventImpl(1, false, region); + GatewaySenderEventImpl event2 = createMockGatewaySenderEventImpl(2, false, region); + GatewaySenderEventImpl event3 = createMockGatewaySenderEventImpl(1, true, region); + GatewaySenderEventImpl event4 = createMockGatewaySenderEventImpl(3, true, region); + GatewaySenderEventImpl event5 = createMockGatewaySenderEventImpl(4, true, region); + GatewaySenderEventImpl event6 = createMockGatewaySenderEventImpl(2, true, region); + GatewaySenderEventImpl event7 = createMockGatewaySenderEventImpl(5, false, region); + + LocalRegion region = mock(LocalRegion.class); + + when(region.getValueInVMOrDiskWithoutFaultIn(0L)).thenReturn(event1); + when(region.getValueInVMOrDiskWithoutFaultIn(1L)).thenReturn(event2); + when(region.getValueInVMOrDiskWithoutFaultIn(2L)).thenReturn(event3); + when(region.getValueInVMOrDiskWithoutFaultIn(3L)).thenReturn(event4); + when(region.getValueInVMOrDiskWithoutFaultIn(4L)).thenReturn(event5); + when(region.getValueInVMOrDiskWithoutFaultIn(5L)).thenReturn(event6); + when(region.getValueInVMOrDiskWithoutFaultIn(6L)).thenReturn(event7); + + Map> map = new HashMap<>(); + map.put(0L, event1); + map.put(1L, event2); + map.put(2L, event3); + map.put(3L, event4); + map.put(4L, event5); + map.put(5L, event6); + map.put(6L, event7); + + when(region.keySet()).thenReturn(map.keySet()); + return region; + } + + private static class TestableTxGroupingSerialGatewaySenderQueue + extends TxGroupingSerialGatewaySenderQueue { + public TestableTxGroupingSerialGatewaySenderQueue(final AbstractGatewaySender sender, + String regionName) { + super(sender, regionName, null, false); + } + + @Override + protected void addOverflowStatisticsToMBean(Cache cache, AbstractGatewaySender sender) {} + + } +} diff --git a/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactoryTest.java b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactoryTest.java new file mode 100644 index 000000000000..81f91a4c2ae8 --- /dev/null +++ b/geode-wan-txgrouping/src/test/java/org/apache/geode/cache/wan/internal/txgrouping/serial/TxGroupingSerialGatewaySenderTypeFactoryTest.java @@ -0,0 +1,69 @@ +/* + * 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.cache.wan.internal.txgrouping.serial; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; + +public class TxGroupingSerialGatewaySenderTypeFactoryTest { + + final TxGroupingSerialGatewaySenderTypeFactory factory = + new TxGroupingSerialGatewaySenderTypeFactory(); + + final MutableGatewaySenderAttributes attributes = mock(MutableGatewaySenderAttributes.class); + + @Test + public void validateThrowsIfBatchConflationEnabled() { + when(attributes.isBatchConflationEnabled()).thenReturn(true); + + assertThatThrownBy(() -> factory.validate(attributes)) + .isInstanceOf(GatewaySenderException.class) + .hasMessageContaining( + "both group transaction events set to true and batch conflation enabled"); + } + + @Test + public void validateDoesNotThrowsIfBatchConflationDisabled() { + when(attributes.isBatchConflationEnabled()).thenReturn(false); + + assertThatNoException().isThrownBy(() -> factory.validate(attributes)); + } + + @Test + public void validateThrowsIfDispatcherThreadsGreaterThan1() { + when(attributes.getDispatcherThreads()).thenReturn(2); + + assertThatThrownBy(() -> factory.validate(attributes)) + .isInstanceOf(GatewaySenderException.class).hasMessageContaining( + "cannot be created with group transaction events set to true when dispatcher threads is greater than 1"); + } + + @Test + public void validateDoesNotThrow() { + when(attributes.getDispatcherThreads()).thenReturn(1); + + assertThatNoException().isThrownBy(() -> factory.validate(attributes)); + } + + +} diff --git a/geode-wan-txgrouping/src/test/resources/expected-pom.xml b/geode-wan-txgrouping/src/test/resources/expected-pom.xml new file mode 100644 index 000000000000..0f8d1279a2bc --- /dev/null +++ b/geode-wan-txgrouping/src/test/resources/expected-pom.xml @@ -0,0 +1,80 @@ + + + + 4.0.0 + org.apache.geode + geode-wan-txgrouping + ${version} + Apache Geode + Apache Geode provides a database-like consistency model, reliable transaction processing and a shared-nothing architecture to maintain very low latency performance with high concurrency processing + http://geode.apache.org + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + scm:git:https://github.com:apache/geode.git + scm:git:https://github.com:apache/geode.git + https://github.com/apache/geode + + + + + org.apache.geode + geode-all-bom + ${version} + pom + import + + + + + + org.apache.geode + geode-logging + runtime + + + org.apache.geode + geode-membership + runtime + + + org.apache.geode + geode-serialization + runtime + + + org.apache.geode + geode-tcp-server + runtime + + + org.apache.geode + geode-core + runtime + + + org.apache.geode + geode-wan + runtime + + + diff --git a/geode-wan/build.gradle b/geode-wan/build.gradle index 4e500ddcac4f..5f5dd617dafa 100644 --- a/geode-wan/build.gradle +++ b/geode-wan/build.gradle @@ -37,7 +37,6 @@ dependencies { compileOnly('org.apache.logging.log4j:log4j-api') compileOnly('org.jetbrains:annotations') - testImplementation(project(':geode-junit')) testImplementation('org.assertj:assertj-core') testImplementation('junit:junit') diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/cache/CacheXml70GatewayDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/cache/CacheXml70GatewayDUnitTest.java index 0489224a391c..2192e1b3baaf 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/cache/CacheXml70GatewayDUnitTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/cache/CacheXml70GatewayDUnitTest.java @@ -34,6 +34,8 @@ import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.cache.wan.GatewaySenderFactory; import org.apache.geode.cache.wan.GatewayTransportFilter; +import org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderCreation; +import org.apache.geode.cache.wan.internal.serial.SerialGatewaySenderCreation; import org.apache.geode.cache30.CacheXml70DUnitTestHelper; import org.apache.geode.cache30.CacheXmlTestCase; import org.apache.geode.cache30.MyGatewayEventFilter1; @@ -41,9 +43,7 @@ import org.apache.geode.cache30.MyGatewayTransportFilter2; import org.apache.geode.internal.cache.xmlcache.CacheCreation; import org.apache.geode.internal.cache.xmlcache.CacheXml; -import org.apache.geode.internal.cache.xmlcache.ParallelGatewaySenderCreation; import org.apache.geode.internal.cache.xmlcache.RegionAttributesCreation; -import org.apache.geode.internal.cache.xmlcache.SerialGatewaySenderCreation; import org.apache.geode.test.junit.categories.WanTest; @Category({WanTest.class}) diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/WANTestBase.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/WANTestBase.java index 7461bffe3d64..27f379cf5d1d 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/WANTestBase.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/WANTestBase.java @@ -97,7 +97,6 @@ import org.apache.geode.cache.RegionFactory; import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.Scope; -import org.apache.geode.cache.TransactionException; import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.asyncqueue.AsyncEventQueue; import org.apache.geode.cache.asyncqueue.AsyncEventQueueFactory; @@ -1731,14 +1730,7 @@ public static GatewaySenderFactory configureGateway(DiskStoreFactory dsf, File[] public static void createSender(String dsName, int remoteDsId, boolean isParallel, Integer maxMemory, Integer batchSize, boolean isConflation, boolean isPersistent, GatewayEventFilter filter, boolean isManualStart) { - createSender(dsName, remoteDsId, isParallel, maxMemory, batchSize, isConflation, isPersistent, - filter, isManualStart, false); - } - - public static void createSender(String dsName, int remoteDsId, boolean isParallel, - Integer maxMemory, Integer batchSize, boolean isConflation, boolean isPersistent, - GatewayEventFilter filter, boolean isManualStart, boolean groupTransactionEvents) { - final IgnoredException exln = addIgnoredException("Could not connect"); + final IgnoredException exln = IgnoredException.addIgnoredException("Could not connect"); try { File persistentDirectory = new File(dsName + "_disk_" + System.currentTimeMillis() + "_" + VM.getCurrentVMNum()); @@ -1749,11 +1741,6 @@ public static void createSender(String dsName, int remoteDsId, boolean isParalle batchSize, isConflation, isPersistent, filter, isManualStart, numDispatcherThreadsForTheRun, GatewaySender.DEFAULT_ORDER_POLICY, GatewaySender.DEFAULT_SOCKET_BUFFER_SIZE); - gateway.setGroupTransactionEvents(groupTransactionEvents); - if (groupTransactionEvents && gateway instanceof InternalGatewaySenderFactory) { - // Set a very high value to avoid flakiness in test cases - ((InternalGatewaySenderFactory) gateway).setRetriesToGetTransactionEventsFromQueue(1000); - } gateway.create(dsName, remoteDsId); } finally { exln.remove(); @@ -1979,68 +1966,6 @@ public static String createSenderWithDiskStore(String dsName, int remoteDsId, bo return persistentDirectory.getName(); } - - public static void createSenderWithListener(String dsName, int remoteDsName, boolean isParallel, - Integer maxMemory, Integer batchSize, boolean isConflation, boolean isPersistent, - GatewayEventFilter filter, boolean attachTwoListeners, boolean isManualStart) { - File persistentDirectory = - new File(dsName + "_disk_" + System.currentTimeMillis() + "_" + VM.getCurrentVMNum()); - persistentDirectory.mkdir(); - DiskStoreFactory dsf = cache.createDiskStoreFactory(); - File[] dirs1 = new File[] {persistentDirectory}; - - if (isParallel) { - GatewaySenderFactory gateway = cache.createGatewaySenderFactory(); - gateway.setParallel(true); - gateway.setMaximumQueueMemory(maxMemory); - gateway.setBatchSize(batchSize); - gateway.setManualStart(isManualStart); - // set dispatcher threads - gateway.setDispatcherThreads(numDispatcherThreadsForTheRun); - ((InternalGatewaySenderFactory) gateway).setLocatorDiscoveryCallback(new MyLocatorCallback()); - if (filter != null) { - gateway.addGatewayEventFilter(filter); - } - if (isPersistent) { - gateway.setPersistenceEnabled(true); - gateway.setDiskStoreName(dsf.setDiskDirs(dirs1).create(dsName).getName()); - } else { - DiskStore store = dsf.setDiskDirs(dirs1).create(dsName); - gateway.setDiskStoreName(store.getName()); - } - gateway.setBatchConflationEnabled(isConflation); - gateway.create(dsName, remoteDsName); - - } else { - GatewaySenderFactory gateway = cache.createGatewaySenderFactory(); - gateway.setMaximumQueueMemory(maxMemory); - gateway.setBatchSize(batchSize); - gateway.setManualStart(isManualStart); - // set dispatcher threads - gateway.setDispatcherThreads(numDispatcherThreadsForTheRun); - ((InternalGatewaySenderFactory) gateway).setLocatorDiscoveryCallback(new MyLocatorCallback()); - if (filter != null) { - gateway.addGatewayEventFilter(filter); - } - gateway.setBatchConflationEnabled(isConflation); - if (isPersistent) { - gateway.setPersistenceEnabled(true); - gateway.setDiskStoreName(dsf.setDiskDirs(dirs1).create(dsName).getName()); - } else { - DiskStore store = dsf.setDiskDirs(dirs1).create(dsName); - gateway.setDiskStoreName(store.getName()); - } - - eventListener1 = new MyGatewaySenderEventListener(); - ((InternalGatewaySenderFactory) gateway).addAsyncEventListener(eventListener1); - if (attachTwoListeners) { - eventListener2 = new MyGatewaySenderEventListener2(); - ((InternalGatewaySenderFactory) gateway).addAsyncEventListener(eventListener2); - } - ((InternalGatewaySenderFactory) gateway).create(dsName); - } - } - public static void createReceiverInVMs(int maximumTimeBetweenPings, VM... vms) { for (VM vm : vms) { vm.invoke(() -> createReceiverWithMaximumTimeBetweenPings(maximumTimeBetweenPings)); @@ -2384,53 +2309,6 @@ public static void putGivenKeyValue(String regionName, Map keyValue } } - public static void doOrderAndShipmentPutsInsideTransactions(Map keyValues, - int eventsPerTransaction) { - Region orderRegion = cache.getRegion(orderRegionName); - Region shipmentRegion = cache.getRegion(shipmentRegionName); - int eventInTransaction = 0; - CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager(); - for (Object key : keyValues.keySet()) { - if (eventInTransaction == 0) { - cacheTransactionManager.begin(); - } - Region r; - if (key instanceof OrderId) { - r = orderRegion; - } else { - r = shipmentRegion; - } - r.put(key, keyValues.get(key)); - if (++eventInTransaction == eventsPerTransaction) { - cacheTransactionManager.commit(); - eventInTransaction = 0; - } - } - if (eventInTransaction != 0) { - cacheTransactionManager.commit(); - } - } - - public static void doPutsInsideTransactions(String regionName, Map keyValues, - int eventsPerTransaction) { - Region r = cache.getRegion(Region.SEPARATOR + regionName); - int eventInTransaction = 0; - CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager(); - for (K key : keyValues.keySet()) { - if (eventInTransaction == 0) { - cacheTransactionManager.begin(); - } - r.put(key, keyValues.get(key)); - if (++eventInTransaction == eventsPerTransaction) { - cacheTransactionManager.commit(); - eventInTransaction = 0; - } - } - if (eventInTransaction != 0) { - cacheTransactionManager.commit(); - } - } - public static void destroyRegion(String regionName) { destroyRegion(regionName, -1); } @@ -2701,48 +2579,6 @@ public static void doTxPuts(String regionName) { mgr.commit(); } - public static void doTxPutsWithRetryIfError(String regionName, final long putsPerTransaction, - final long transactions, long offset) { - Region r = cache.getRegion(Region.SEPARATOR + regionName); - - long keyOffset = offset * ((putsPerTransaction + (10 * transactions)) * 100); - long j = 0; - CacheTransactionManager mgr = cache.getCacheTransactionManager(); - for (int i = 0; i < transactions; i++) { - boolean done = false; - do { - try { - mgr.begin(); - for (j = 0; j < putsPerTransaction; j++) { - long key = keyOffset + ((j + (10L * i)) * 100); - String value = "Value_" + key; - r.put(key, value); - } - mgr.commit(); - done = true; - } catch (TransactionException e) { - logger.info("Something went wrong with transaction [{},{}]. Retrying. Error: {}", i, j, - e.getMessage()); - e.printStackTrace(); - } catch (IllegalStateException e1) { - logger.info("Something went wrong with transaction [{},{}]. Retrying. Error: {}", i, j, - e1.getMessage()); - e1.printStackTrace(); - try { - mgr.rollback(); - logger.info("Rolled back transaction [{},{}]. Retrying. Error: {}", i, j, - e1.getMessage()); - } catch (Exception e2) { - logger.info( - "Something went wrong when rolling back transaction [{},{}]. Retrying transaction. Error: {}", - i, j, e2.getMessage()); - e2.printStackTrace(); - } - } - } while (!done); - } - } - public static void doNextPuts(String regionName, int start, int numPuts) { IgnoredException exp = addIgnoredException(CacheClosedException.class.getName()); diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderOperationsDistributedTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderOperationsDistributedTest.java index bc7ea22b21b1..e781299cbfcc 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderOperationsDistributedTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelGatewaySenderOperationsDistributedTest.java @@ -1075,12 +1075,10 @@ public void testParallelGWSenderUpdateAttrWhilePaused() { vm4.invoke(() -> doPuts(getUniqueName() + "_PR", 5000)); - updateGroupTransactionEvents(true); updateBatchTimeInterval(200); validateRegionSizes(getUniqueName() + "_PR", 0, vm2, vm3); - checkGroupTransactionEvents(true); checkBatchTimeInterval(200); vm4.invoke(() -> resumeSender("ln")); @@ -1411,58 +1409,6 @@ private void updateBatchTimeInterval(int batchTimeInterval) { }); } - private void updateGroupTransactionEvents(boolean groupTransactionEvents) { - vm4.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - boolean paused = false; - if (sender.isRunning() && !sender.isPaused()) { - sender.pause(); - paused = true; - } - sender.setGroupTransactionEvents(groupTransactionEvents); - if (paused) { - sender.resume(); - } - }); - vm5.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - boolean paused = false; - if (sender.isRunning() && !sender.isPaused()) { - sender.pause(); - paused = true; - } - sender.setGroupTransactionEvents(groupTransactionEvents); - if (paused) { - sender.resume(); - } - }); - vm6.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - boolean paused = false; - if (sender.isRunning() && !sender.isPaused()) { - sender.pause(); - paused = true; - } - sender.setGroupTransactionEvents(groupTransactionEvents); - if (paused) { - sender.resume(); - } - }); - vm7.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - boolean paused = false; - if (sender.isRunning() && !sender.isPaused()) { - sender.pause(); - paused = true; - } - sender.setGroupTransactionEvents(groupTransactionEvents); - if (paused) { - sender.resume(); - } - }); - - } - private void updateGatewayEventFilters(List filters) { vm4.invoke(() -> { AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); @@ -1552,25 +1498,6 @@ private void checkBatchTimeInterval(int batchTimeInterval) { }); } - private void checkGroupTransactionEvents(boolean groupTransactionEvents) { - vm4.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - assertThat(sender.mustGroupTransactionEvents()).isEqualTo(groupTransactionEvents); - }); - vm5.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - assertThat(sender.mustGroupTransactionEvents()).isEqualTo(groupTransactionEvents); - }); - vm6.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - assertThat(sender.mustGroupTransactionEvents()).isEqualTo(groupTransactionEvents); - }); - vm7.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - assertThat(sender.mustGroupTransactionEvents()).isEqualTo(groupTransactionEvents); - }); - } - private void stopSenders() { vm4.invoke(() -> stopSender("ln")); vm5.invoke(() -> stopSender("ln")); diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANPropagationDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANPropagationDUnitTest.java index fe3a0e6615e3..9d808eefb70c 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANPropagationDUnitTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANPropagationDUnitTest.java @@ -17,8 +17,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import java.util.HashMap; -import java.util.Map; import java.util.Set; import junitparams.Parameters; @@ -34,11 +32,6 @@ import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.RegionQueue; -import org.apache.geode.internal.cache.execute.data.CustId; -import org.apache.geode.internal.cache.execute.data.Order; -import org.apache.geode.internal.cache.execute.data.OrderId; -import org.apache.geode.internal.cache.execute.data.Shipment; -import org.apache.geode.internal.cache.execute.data.ShipmentId; import org.apache.geode.internal.cache.wan.AbstractGatewaySender; import org.apache.geode.internal.cache.wan.BatchException70; import org.apache.geode.internal.cache.wan.WANTestBase; @@ -1242,113 +1235,6 @@ public void testParallelPropagationTxNotificationsNotSentToAllRegionMembersWhenA vm5.invoke(() -> WANTestBase.validateEmptyBucketToTempQueueMap("ln")); } - @Test - public void testPartitionedParallelPropagationWithGroupTransactionEventsAndMixOfEventsInAndNotInTransactions() - throws Exception { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2, vm3); - createReceiverInVMs(vm2, vm3); - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - vm4.invoke(() -> setNumDispatcherThreadsForTheRun(2)); - vm5.invoke(() -> setNumDispatcherThreadsForTheRun(2)); - vm6.invoke(() -> setNumDispatcherThreadsForTheRun(2)); - vm7.invoke(() -> setNumDispatcherThreadsForTheRun(2)); - - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, true)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, true)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, true)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, true)); - - vm4.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - vm5.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - vm6.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - vm7.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - vm2.invoke(() -> createCustomerOrderShipmentPartitionedRegion(null, 1, 8, isOffHeap())); - vm3.invoke(() -> createCustomerOrderShipmentPartitionedRegion(null, 1, 8, isOffHeap())); - - int customers = 4; - - int transactionsPerCustomer = 1000; - final Map keyValuesInTransactions = new HashMap<>(); - for (int custId = 0; custId < customers; custId++) { - for (int i = 0; i < transactionsPerCustomer; i++) { - CustId custIdObject = new CustId(custId); - OrderId orderId = new OrderId(i, custIdObject); - ShipmentId shipmentId1 = new ShipmentId(i, orderId); - ShipmentId shipmentId2 = new ShipmentId(i + 1, orderId); - ShipmentId shipmentId3 = new ShipmentId(i + 2, orderId); - keyValuesInTransactions.put(orderId, new Order()); - keyValuesInTransactions.put(shipmentId1, new Shipment()); - keyValuesInTransactions.put(shipmentId2, new Shipment()); - keyValuesInTransactions.put(shipmentId3, new Shipment()); - } - } - - int ordersPerCustomerNotInTransactions = 1000; - - final Map keyValuesNotInTransactions = new HashMap<>(); - for (int custId = 0; custId < customers; custId++) { - for (int i = 0; i < ordersPerCustomerNotInTransactions; i++) { - CustId custIdObject = new CustId(custId); - OrderId orderId = new OrderId(i + transactionsPerCustomer * customers, custIdObject); - keyValuesNotInTransactions.put(orderId, new Order()); - } - } - - // eventsPerTransaction is 1 (orders) + 3 (shipments) - int eventsPerTransaction = 4; - AsyncInvocation inv1 = - vm7.invokeAsync( - () -> WANTestBase.doOrderAndShipmentPutsInsideTransactions(keyValuesInTransactions, - eventsPerTransaction)); - - AsyncInvocation inv2 = - vm6.invokeAsync( - () -> WANTestBase.putGivenKeyValue(orderRegionName, keyValuesNotInTransactions)); - - inv1.await(); - inv2.await(); - - int entries = - ordersPerCustomerNotInTransactions * customers + transactionsPerCustomer * customers; - - vm4.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm5.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm6.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm7.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - - vm2.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm3.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - - vm4.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - vm5.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - vm6.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - vm7.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - - vm7.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm6.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm5.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm4.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - } - private static RegionShortcut[] getRegionShortcuts() { return new RegionShortcut[] {RegionShortcut.PARTITION, RegionShortcut.PARTITION_PERSISTENT}; } diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANStatsDistributedTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANStatsDistributedTest.java index 2d48a2b828fe..0940c2c9eb41 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANStatsDistributedTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/parallel/ParallelWANStatsDistributedTest.java @@ -19,7 +19,6 @@ import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException; import static org.assertj.core.api.Assertions.assertThat; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -32,12 +31,6 @@ import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.client.internal.PoolImpl; -import org.apache.geode.internal.cache.execute.data.CustId; -import org.apache.geode.internal.cache.execute.data.Customer; -import org.apache.geode.internal.cache.execute.data.Order; -import org.apache.geode.internal.cache.execute.data.OrderId; -import org.apache.geode.internal.cache.execute.data.Shipment; -import org.apache.geode.internal.cache.execute.data.ShipmentId; import org.apache.geode.internal.cache.wan.WANTestBase; import org.apache.geode.test.dunit.AsyncInvocation; import org.apache.geode.test.dunit.VM; @@ -325,494 +318,6 @@ public void testPartitionedRegionParallelPropagation_AfterDispatch_NoRedundancy( vm2.invoke(() -> WANTestBase.checkGatewayReceiverStats(10, NUM_PUTS, NUM_PUTS)); } - @Test - public void testPRParallelPropagationWithoutGroupTransactionEventsSendsBatchesWithIncompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - createReceiverInVMs(vm2); - - createSenders(lnPort, false); - - createReceiverCustomerOrderShipmentPR(vm2); - - createSenderCustomerOrderShipmentPRs(vm4); - createSenderCustomerOrderShipmentPRs(vm5); - createSenderCustomerOrderShipmentPRs(vm6); - createSenderCustomerOrderShipmentPRs(vm7); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - final Map custKeyValue = new HashMap<>(); - int intCustId = 1; - CustId custId = new CustId(intCustId); - custKeyValue.put(custId, new Customer()); - vm4.invoke(() -> WANTestBase.putGivenKeyValue(customerRegionName, custKeyValue)); - - int transactions = 3; - final Map keyValues = new HashMap<>(); - for (int i = 0; i < transactions; i++) { - OrderId orderId = new OrderId(i, custId); - ShipmentId shipmentId1 = new ShipmentId(i, orderId); - ShipmentId shipmentId2 = new ShipmentId(i + 1, orderId); - ShipmentId shipmentId3 = new ShipmentId(i + 2, orderId); - keyValues.put(orderId, new Order()); - keyValues.put(shipmentId1, new Shipment()); - keyValues.put(shipmentId2, new Shipment()); - keyValues.put(shipmentId3, new Shipment()); - } - int eventsPerTransaction = 4; - vm4.invoke(() -> WANTestBase.doOrderAndShipmentPutsInsideTransactions(keyValues, - eventsPerTransaction)); - - int entries = (transactions * eventsPerTransaction) + 1; - - vm4.invoke(() -> WANTestBase.validateRegionSize(customerRegionName, 1)); - vm4.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, transactions)); - vm4.invoke(() -> WANTestBase.validateRegionSize(shipmentRegionName, transactions * 3)); - - await().untilAsserted(() -> { - List v4List = vm4.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v5List = vm5.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v6List = vm6.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v7List = vm7.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - // queue size: - assertThat(v4List.get(0) + v5List.get(0) + v6List.get(0) + v7List.get(0)).isEqualTo(0); - // eventsReceived: - assertThat(v4List.get(1) + v5List.get(1) + v6List.get(1) + v7List.get(1)).isEqualTo(entries); - // events queued: - assertThat(v4List.get(2) + v5List.get(2) + v6List.get(2) + v7List.get(2)).isEqualTo(entries); - // events distributed: - assertThat(v4List.get(3) + v5List.get(3) + v6List.get(3) + v7List.get(3)).isEqualTo(entries); - // batches distributed: - assertThat(v4List.get(4) + v5List.get(4) + v6List.get(4) + v7List.get(4)).isEqualTo(2); - // batches redistributed: - assertThat(v4List.get(5) + v5List.get(5) + v6List.get(5) + v7List.get(5)).isEqualTo(0); - }); - } - - @Test - public void testPRParallelPropagationWithGroupTransactionEventsWithoutBatchRedistributionSendsBatchesWithCompleteTransactions_SeveralClients() { - testPRParallelPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( - false); - } - - @Test - public void testPRParallelPropagationWithGroupTransactionEventsWithBatchRedistributionSendsBatchesWithCompleteTransactions_SeveralClients() { - testPRParallelPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( - true); - } - - public void testPRParallelPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( - boolean isBatchesRedistributed) { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - - if (!isBatchesRedistributed) { - createReceiverInVMs(vm2); - } - - createSenders(lnPort, true); - - createReceiverCustomerOrderShipmentPR(vm2); - - createSenderCustomerOrderShipmentPRs(vm4); - createSenderCustomerOrderShipmentPRs(vm5); - createSenderCustomerOrderShipmentPRs(vm6); - createSenderCustomerOrderShipmentPRs(vm7); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - int clients = 4; - int transactions = 300; - // batchSize is 10. Each transaction will contain 1 order + 3 shipments = 4 events. - // As a result, all batches will contain extra events to complete the - // transactions it will deliver. - int shipmentsPerTransaction = 3; - - final List> customerData = new ArrayList<>(clients); - for (int intCustId = 0; intCustId < clients; intCustId++) { - final Map custKeyValue = new HashMap<>(); - CustId custId = new CustId(intCustId); - custKeyValue.put(custId, new Customer()); - customerData.add(new HashMap<>()); - vm4.invoke(() -> WANTestBase.putGivenKeyValue(customerRegionName, custKeyValue)); - - for (int i = 0; i < transactions; i++) { - OrderId orderId = new OrderId(i, custId); - customerData.get(intCustId).put(orderId, new Order()); - for (int j = 0; j < shipmentsPerTransaction; j++) { - customerData.get(intCustId).put(new ShipmentId(i + j, orderId), new Shipment()); - } - } - } - - List> asyncInvocations = new ArrayList<>(clients); - - int eventsPerTransaction = shipmentsPerTransaction + 1; - for (int i = 0; i < clients; i++) { - final int intCustId = i; - AsyncInvocation asyncInvocation = - vm4.invokeAsync(() -> WANTestBase.doOrderAndShipmentPutsInsideTransactions( - customerData.get(intCustId), - eventsPerTransaction)); - asyncInvocations.add(asyncInvocation); - } - - try { - for (AsyncInvocation asyncInvocation : asyncInvocations) { - asyncInvocation.await(); - } - } catch (InterruptedException e) { - fail("Interrupted"); - } - - vm4.invoke(() -> WANTestBase.validateRegionSize(customerRegionName, clients)); - vm4.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, transactions * clients)); - vm4.invoke(() -> WANTestBase.validateRegionSize(shipmentRegionName, - transactions * shipmentsPerTransaction * clients)); - - if (isBatchesRedistributed) { - // wait for batches to be redistributed and then start the receiver - vm4.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(5) > 0)); - createReceiverInVMs(vm2); - } - - // Check that all entries have been written in the receiver - vm2.invoke( - () -> WANTestBase.validateRegionSize(customerRegionName, clients)); - vm2.invoke( - () -> WANTestBase.validateRegionSize(orderRegionName, transactions * clients)); - vm2.invoke( - () -> WANTestBase.validateRegionSize(shipmentRegionName, - shipmentsPerTransaction * transactions * clients)); - - checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated(isBatchesRedistributed); - } - - private void checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated( - boolean isBatchesRedistributed) { - await().untilAsserted(() -> { - List v4List = vm4.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v5List = vm5.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v6List = vm6.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v7List = vm7.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - // queue size: - assertThat(v4List.get(0) + v5List.get(0) + v6List.get(0) + v7List.get(0)).isEqualTo(0); - // batches redistributed: - int batchesRedistributed = v4List.get(5) + v5List.get(5) + v6List.get(5) + v7List.get(5); - if (isBatchesRedistributed) { - assertThat(batchesRedistributed).isGreaterThan(0); - } else { - assertThat(batchesRedistributed).isEqualTo(0); - } - // batches with incomplete transactions - assertThat(v4List.get(13) + v5List.get(13) + v6List.get(13) + v7List.get(7)).isEqualTo(0); - }); - - vm4.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm5.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm6.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm7.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - } - - @Test - public void testPRParallelPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - createReceiverInVMs(vm2); - - createSenders(lnPort, true); - - createReceiverCustomerOrderShipmentPR(vm2); - - createSenderCustomerOrderShipmentPRs(vm4); - createSenderCustomerOrderShipmentPRs(vm5); - createSenderCustomerOrderShipmentPRs(vm6); - createSenderCustomerOrderShipmentPRs(vm7); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - final Map custKeyValue = new HashMap<>(); - int intCustId = 1; - CustId custId = new CustId(intCustId); - custKeyValue.put(custId, new Customer()); - vm4.invoke(() -> WANTestBase.putGivenKeyValue(customerRegionName, custKeyValue)); - - int transactions = 3; - final Map keyValues = new HashMap<>(); - for (int i = 0; i < transactions; i++) { - OrderId orderId = new OrderId(i, custId); - ShipmentId shipmentId1 = new ShipmentId(i, orderId); - ShipmentId shipmentId2 = new ShipmentId(i + 1, orderId); - ShipmentId shipmentId3 = new ShipmentId(i + 2, orderId); - keyValues.put(orderId, new Order()); - keyValues.put(shipmentId1, new Shipment()); - keyValues.put(shipmentId2, new Shipment()); - keyValues.put(shipmentId3, new Shipment()); - } - - // 3 transactions of 4 events each are sent so that the batch would - // initially contain the first 2 transactions complete and the first - // 2 events of the last transaction (10 entries). - // As --group-transaction-events is configured in the senders, the remaining - // 2 events of the last transaction are added to the batch which makes - // that only one batch of 12 events is sent. - int eventsPerTransaction = 4; - vm4.invoke(() -> WANTestBase.doOrderAndShipmentPutsInsideTransactions(keyValues, - eventsPerTransaction)); - - int entries = (transactions * eventsPerTransaction) + 1; - - vm4.invoke(() -> WANTestBase.validateRegionSize(customerRegionName, 1)); - vm4.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, transactions)); - vm4.invoke(() -> WANTestBase.validateRegionSize(shipmentRegionName, transactions * 3)); - - await().untilAsserted(() -> { - List v4List = vm4.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v5List = vm5.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v6List = vm6.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v7List = vm7.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - // queue size: - assertThat(v4List.get(0) + v5List.get(0) + v6List.get(0) + v7List.get(0)).isEqualTo(0); - // eventsReceived: - assertThat(v4List.get(1) + v5List.get(1) + v6List.get(1) + v7List.get(1)).isEqualTo(entries); - // events queued: - assertThat(v4List.get(2) + v5List.get(2) + v6List.get(2) + v7List.get(2)).isEqualTo(entries); - // events distributed: - assertThat(v4List.get(3) + v5List.get(3) + v6List.get(3) + v7List.get(3)).isEqualTo(entries); - // batches distributed: - assertThat(v4List.get(4) + v5List.get(4) + v6List.get(4) + v7List.get(4)).isEqualTo(1); - // batches redistributed: - assertThat(v4List.get(5) + v5List.get(5) + v6List.get(5) + v7List.get(5)).isEqualTo(0); - // events not queued conflated: - assertThat(v4List.get(7) + v5List.get(7) + v6List.get(7) + v7List.get(7)).isEqualTo(0); - // batches with incomplete transactions - assertThat((int) v4List.get(13)).isEqualTo(0); - }); - - } - - @Test - public void testPRParallelPropagationWithGroupTransactionEventsWithIncompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - createReceiverInVMs(vm2); - - int dispThreads = 2; - createSenderInVm(lnPort, vm4, dispThreads); - - createReceiverPR(vm2, 0); - - createSenderPRInVM(0, vm4); - - startSenderInVMs("ln", vm4); - - // Adding events in transactions - // Transactions will contain objects assigned to different buckets but given that there is only - // one server, there will be no TransactionDataNotCollocatedException. - // With this and by using more than one dispatcher thread, we will provoke that - // it will be impossible for the batches to have complete transactions as some - // events for a transaction will be handled by one dispatcher thread and some other events by - // another thread. - final Map keyValue = new HashMap<>(); - int entries = 30; - for (int i = 0; i < entries; i++) { - keyValue.put(i, i); - } - - int entriesPerTransaction = 3; - vm4.invoke( - () -> WANTestBase.doPutsInsideTransactions(testName, keyValue, entriesPerTransaction)); - - vm4.invoke(() -> WANTestBase.validateRegionSize(testName, entries)); - - // The number of batches will be 4 because each - // dispatcher thread (there are 2) will send half the number of entries, - // each on 2 batches. - final int batches = 4; - - await().untilAsserted(() -> { - List v4List = vm4.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - // queue size: - assertThat((int) v4List.get(0)).isEqualTo(0); - // eventsReceived: - assertThat((int) v4List.get(1)).isEqualTo(entries); - // events queued: - assertThat((int) v4List.get(2)).isEqualTo(entries); - // events distributed: - assertThat((int) v4List.get(3)).isEqualTo(entries); - // batches distributed: - assertThat((int) v4List.get(4)).isEqualTo(batches); - // batches redistributed: - assertThat((int) v4List.get(5)).isEqualTo(0); - // events not queued conflated: - assertThat((int) v4List.get(7)).isEqualTo(0); - // batches with incomplete transactions - assertThat((int) v4List.get(13)).isEqualTo(batches); - }); - - vm2.invoke(() -> WANTestBase.checkGatewayReceiverStats(batches, entries, entries)); - } - - - @Test - public void testPRParallelPropagationWithBatchRedistWithoutGroupTransactionEventsSendsBatchesWithIncompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - - createSenders(lnPort, false); - - createSenderCustomerOrderShipmentPRs(vm4); - - startSenderInVMs("ln", vm4); - - final Map custKeyValue = new HashMap<>(); - int intCustId = 1; - CustId custId = new CustId(intCustId); - custKeyValue.put(custId, new Customer()); - vm4.invoke(() -> WANTestBase.putGivenKeyValue(customerRegionName, custKeyValue)); - - int transactions = 6; - final Map keyValues = new HashMap<>(); - for (int i = 0; i < transactions; i++) { - OrderId orderId = new OrderId(i, custId); - ShipmentId shipmentId1 = new ShipmentId(i, orderId); - ShipmentId shipmentId2 = new ShipmentId(i + 1, orderId); - ShipmentId shipmentId3 = new ShipmentId(i + 2, orderId); - keyValues.put(orderId, new Order()); - keyValues.put(shipmentId1, new Shipment()); - keyValues.put(shipmentId2, new Shipment()); - keyValues.put(shipmentId3, new Shipment()); - } - int eventsPerTransaction = 4; - vm4.invoke(() -> WANTestBase.doOrderAndShipmentPutsInsideTransactions(keyValues, - eventsPerTransaction)); - - int entries = (transactions * eventsPerTransaction) + 1; - - createReceiverCustomerOrderShipmentPR(vm2); - - vm4.invoke(() -> WANTestBase.validateRegionSize(customerRegionName, 1)); - vm4.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, transactions)); - vm4.invoke(() -> WANTestBase.validateRegionSize(shipmentRegionName, transactions * 3)); - - // wait for batches to be redistributed and then start the receiver - vm4.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(5) > 0)); - - createReceiverInVMs(vm2); - - await().untilAsserted(() -> { - List v4List = vm4.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - // queue size: - assertThat((int) v4List.get(0)).isEqualTo(0); - // events received: - assertThat((int) v4List.get(1)).isEqualTo(entries); - // events queued: - assertThat((int) v4List.get(2)).isEqualTo(entries); - // events distributed: - assertThat((int) v4List.get(3)).isEqualTo(entries); - // batches distributed: - assertThat((int) v4List.get(4)).isEqualTo(3); - // batches redistributed: - assertThat(v4List.get(5)).as("Batch was not redistributed").isGreaterThan(0); - }); - } - - @Test - public void testPRParallelPropagationWithBatchRedistWithGroupTransactionEventsSendsBatchesWithCompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - - createSenders(lnPort, true); - - createReceiverCustomerOrderShipmentPR(vm2); - - createSenderCustomerOrderShipmentPRs(vm4); - - startSenderInVMs("ln", vm4); - - - final Map custKeyValue = new HashMap<>(); - int intCustId = 1; - CustId custId = new CustId(intCustId); - custKeyValue.put(custId, new Customer()); - vm4.invoke(() -> WANTestBase.putGivenKeyValue(customerRegionName, custKeyValue)); - - int transactions = 6; - final Map keyValues = new HashMap<>(); - for (int i = 0; i < transactions; i++) { - OrderId orderId = new OrderId(i, custId); - ShipmentId shipmentId1 = new ShipmentId(i, orderId); - ShipmentId shipmentId2 = new ShipmentId(i + 1, orderId); - ShipmentId shipmentId3 = new ShipmentId(i + 2, orderId); - keyValues.put(orderId, new Order()); - keyValues.put(shipmentId1, new Shipment()); - keyValues.put(shipmentId2, new Shipment()); - keyValues.put(shipmentId3, new Shipment()); - } - - // 6 transactions of 4 events each are sent so that the first batch - // would initially contain the first 2 transactions complete and the first - // 2 events of the next transaction (10 entries). - // As --group-transaction-events is configured in the senders, the remaining - // 2 events of the second transaction are added to the batch which makes - // that the first batch is sent with 12 events. The same happens with the - // second batch which will contain 12 events too. - int eventsPerTransaction = 4; - vm4.invoke(() -> WANTestBase.doOrderAndShipmentPutsInsideTransactions(keyValues, - eventsPerTransaction)); - - int entries = (transactions * eventsPerTransaction) + 1; - - vm4.invoke(() -> WANTestBase.validateRegionSize(customerRegionName, 1)); - vm4.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, transactions)); - vm4.invoke(() -> WANTestBase.validateRegionSize(shipmentRegionName, transactions * 3)); - - // wait for batches to be redistributed and then start the receiver - vm4.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(5) > 0)); - - createReceiverInVMs(vm2); - - await().untilAsserted(() -> { - List v4List = vm4.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - // queue size: - assertThat((int) v4List.get(0)).isEqualTo(0); - // events received: - assertThat((int) v4List.get(1)).isEqualTo(entries); - // events queued: - assertThat((int) v4List.get(2)).isEqualTo(entries); - // events distributed: - assertThat((int) v4List.get(3)).isEqualTo(entries); - // batches distributed: - assertThat((int) v4List.get(4)).isEqualTo(2); - // batches redistributed: - assertThat(v4List.get(5)).as("Batch was not redistributed").isGreaterThan(0); - // events not queued conflated: - assertThat((int) v4List.get(7)).isEqualTo(0); - }); - } - @Test public void testPartitionedRegionParallelPropagation_AfterDispatch_Redundancy_3() { Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); @@ -967,77 +472,6 @@ public void testParallelPropagationHA() throws Exception { vm2.invoke(() -> WANTestBase.checkGatewayReceiverStatsHA(NUM_PUTS, 1000, 1000)); } - @Category({WanTest.class}) - @Test - public void testParallelPropagationHAWithGroupTransactionEvents() throws Exception { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - - createReceiverPR(vm2, 0); - - createReceiverInVMs(vm2); - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - createSenderPRs(3); - - int batchSize = 9; - boolean groupTransactionEvents = true; - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, true, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - AsyncInvocation inv1 = - vm5.invokeAsync(() -> WANTestBase.doTxPutsWithRetryIfError(testName, 2, 1000, 0)); - - vm2.invoke(() -> await() - .untilAsserted(() -> assertThat(getRegionSize(testName)).as( - "Waiting for some batches to be received").isGreaterThan(40))); - AsyncInvocation inv3 = vm4.invokeAsync(() -> WANTestBase.killSender()); - inv1.await(); - inv3.await(); - - vm2.invoke(() -> WANTestBase.validateRegionSize(testName, 2000)); - - await().untilAsserted(() -> { - List v5List = vm5.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v6List = vm6.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v7List = vm7.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - assertThat(v5List.get(0) + v6List.get(0) + v7List.get(0)).isEqualTo(0); // queue size - int receivedEvents = v5List.get(1) + v6List.get(1) + v7List.get(1); - // We may see two retried events (as transactions are made of 2 events) on all members due to - // the kill - assertThat(receivedEvents).isBetween(6000, 6006); - int queuedEvents = v5List.get(2) + v6List.get(2) + v7List.get(2); - assertThat(queuedEvents).isBetween(6000, 6006); - // batches redistributed - assertThat(v5List.get(5)).isZero(); - assertThat(v6List.get(5)).isZero(); - assertThat(v7List.get(5)).isZero(); - }); - - // batchesReceived is equal to numberOfEntries/(batchSize+1) - // As transactions are 2 events long, for each batch it will always be necessary to - // add one more entry to the 9 events batch in order to have complete transactions in the batch. - int batchesReceived = (1000 + 1000) / (batchSize + 1); - vm2.invoke(() -> WANTestBase.checkGatewayReceiverStatsHA(batchesReceived, 2000, 2000)); - } - - /** * 1 region and sender configured on local site and 1 region and a receiver configured on remote * site. Puts to the local region are in progress. Remote region is destroyed in the middle. @@ -1367,18 +801,6 @@ protected void createReceiverPR(VM vm, int redundancy) { () -> WANTestBase.createPartitionedRegion(testName, null, redundancy, 10, isOffHeap())); } - protected void createReceiverCustomerOrderShipmentPR(VM vm) { - vm.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion(null, 0, 10, - isOffHeap())); - } - - protected void createSenderCustomerOrderShipmentPRs(VM vm) { - vm.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 0, 10, - isOffHeap())); - } - protected void createSenderPRs(int redundancy) { vm4.invoke( () -> WANTestBase.createPartitionedRegion(testName, "ln", redundancy, 10, isOffHeap())); @@ -1404,6 +826,15 @@ protected void startPausedSenders() { vm7.invoke(() -> pauseSender("ln")); } + protected void createSenders(Integer lnPort) { + createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); + + vm4.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true)); + vm5.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true)); + vm6.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true)); + vm7.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true)); + } + protected void createSendersWithConflation(Integer lnPort) { createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); @@ -1413,36 +844,11 @@ protected void createSendersWithConflation(Integer lnPort) { vm7.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, true, false, null, true)); } - protected void createSenderInVm(Integer lnPort, VM vm, - int dispatcherThreads) { - createCacheInVMs(lnPort, vm); - vm.invoke(() -> WANTestBase.setNumDispatcherThreadsForTheRun(dispatcherThreads)); - vm.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, - true)); - } - protected void createSenderInVm(Integer lnPort, VM vm) { createCacheInVMs(lnPort, vm); vm.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true)); } - protected void createSenders(Integer lnPort, boolean groupTransactionEvents) { - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - vm4.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm5.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm6.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm7.invoke(() -> WANTestBase.createSender("ln", 2, true, 100, 10, false, false, null, true, - groupTransactionEvents)); - } - - protected void createSenders(Integer lnPort) { - createSenders(lnPort, false); - } - private void verifyConflationIndexesSize(String senderId, int expectedSize, VM... vms) { await().untilAsserted(() -> { int actualSize = 0; diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderAlterOperationsDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderAlterOperationsDUnitTest.java index c74d65c5797e..204f0269e6b8 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderAlterOperationsDUnitTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderAlterOperationsDUnitTest.java @@ -643,33 +643,6 @@ private void updateBatchTimeInterval(int batchTimeInterval) { }); } - private void updateGroupTransactionEvents(boolean groupTransactionEvents) { - vm4.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - boolean paused = false; - if (sender.isRunning() && !sender.isPaused()) { - sender.pause(); - paused = true; - } - sender.setGroupTransactionEvents(groupTransactionEvents); - if (paused) { - sender.resume(); - } - }); - vm5.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - boolean paused = false; - if (sender.isRunning() && !sender.isPaused()) { - sender.pause(); - paused = true; - } - sender.setGroupTransactionEvents(groupTransactionEvents); - if (paused) { - sender.resume(); - } - }); - } - private void updateGatewayEventFilters(List filters) { vm4.invoke(() -> { AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); @@ -719,19 +692,6 @@ private void checkBatchTimeInterval(int batchTimeInterval) { }); } - private void checkGroupTransactionEvents(boolean groupTransactionEvents) { - vm4.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - assertThat(sender.mustGroupTransactionEvents()).isEqualTo(groupTransactionEvents); - }); - vm5.invoke(() -> { - AbstractGatewaySender sender = (AbstractGatewaySender) cache.getGatewaySender("ln"); - assertThat(sender.mustGroupTransactionEvents()).isEqualTo(groupTransactionEvents); - }); - - } - - public static class MyGatewayEventFilter implements GatewayEventFilter, Serializable { String Id = "MyGatewayEventFilter"; diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventListenerDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventListenerDUnitTest.java deleted file mode 100644 index 767215be3c6d..000000000000 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialGatewaySenderEventListenerDUnitTest.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * 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.wan.serial; - -import static org.apache.geode.test.awaitility.GeodeAwaitility.await; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.junit.Ignore; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.cache.asyncqueue.AsyncEventListener; -import org.apache.geode.cache.wan.GatewaySender; -import org.apache.geode.internal.AvailablePortHelper; -import org.apache.geode.internal.cache.wan.AbstractGatewaySender; -import org.apache.geode.internal.cache.wan.MyGatewaySenderEventListener; -import org.apache.geode.internal.cache.wan.MyGatewaySenderEventListener2; -import org.apache.geode.internal.cache.wan.WANTestBase; -import org.apache.geode.test.awaitility.GeodeAwaitility; -import org.apache.geode.test.dunit.WaitCriterion; -import org.apache.geode.test.junit.categories.WanTest; - -@Category({WanTest.class}) -public class SerialGatewaySenderEventListenerDUnitTest extends WANTestBase { - - private static final long serialVersionUID = 1L; - - public SerialGatewaySenderEventListenerDUnitTest() { - super(); - } - - /** - * Test validates whether the listener attached receives all the events. this test hangs after the - * Darrel's checkin 36685. Need to work with Darrel.Commenting it out so that test suit will not - * hang - */ - @Ignore - @Test - public void testGatewaySenderEventListenerInvocationWithoutLocator() { - int mPort = AvailablePortHelper.getRandomAvailableTCPPort(); - vm4.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - vm5.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - vm6.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - vm7.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - - vm4.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, false, true)); - vm5.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, false, true)); - - startSenderInVMs("ln", vm4, vm5); - - vm4.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm5.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm6.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm7.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - - final Map keyValues = new HashMap(); - for (int i = 0; i < 1000; i++) { - keyValues.put(i, i); - } - - vm4.invoke(() -> WANTestBase.putGivenKeyValue(getTestMethodName() + "_RR", keyValues)); - - vm4.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", keyValues.size())); - - vm5.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", keyValues.size())); - - vm4.invoke(WANTestBase::printEventListenerMap); - vm5.invoke(WANTestBase::printEventListenerMap); - - fail("tried to invoke missing method"); - // vm4.invoke(() -> - // SerialGatewaySenderEventListenerDUnitTest.validateReceivedEventsMapSizeListener1("ln", - // keyValues )); - } - - /** - * Test validates whether the listener attached receives all the events. - */ - @Test - public void testGatewaySenderEventListenerInvocation() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - - createCacheInVMs(nyPort, vm2, vm3); - createReceiverInVMs(vm2, vm3); - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - vm4.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, false, true)); - vm5.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, false, true)); - - vm2.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", null, isOffHeap())); - vm3.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", null, isOffHeap())); - - startSenderInVMs("ln", vm4, vm5); - - vm4.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm5.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm6.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm7.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - - final Map keyValues = new HashMap(); - for (int i = 0; i < 1000; i++) { - keyValues.put(i, i); - } - - vm4.invoke(() -> WANTestBase.putGivenKeyValue(getTestMethodName() + "_RR", keyValues)); - - vm4.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", keyValues.size())); - - vm5.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", keyValues.size())); - - vm2.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", 0)); - vm3.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", 0)); - - vm4.invoke(() -> SerialGatewaySenderEventListenerDUnitTest - .validateReceivedEventsMapSizeListener1("ln", keyValues)); - } - - /** - * Test validates whether the listener attached receives all the events. When there are 2 - * listeners attached to the GatewaySender. - */ - @Test - public void testGatewaySender2EventListenerInvocation() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2, vm3); - - vm2.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", null, isOffHeap())); - vm3.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", null, isOffHeap())); - - createReceiverInVMs(vm2, vm3); - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - vm4.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, true, true)); - vm5.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, true, true)); - - startSenderInVMs("ln", vm4, vm5); - - vm4.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm5.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - - final Map keyValues = new HashMap(); - for (int i = 0; i < 1000; i++) { - keyValues.put(i, i); - } - - - vm4.invoke(() -> WANTestBase.putGivenKeyValue(getTestMethodName() + "_RR", keyValues)); - - vm2.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", 0)); - vm3.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_RR", 0)); - - // TODO: move validateReceivedEventsMapSizeListener2 to a shared util class - vm4.invoke(() -> SerialGatewaySenderEventListenerDUnitTest - .validateReceivedEventsMapSizeListener2("ln", keyValues)); - } - - /** - * Test validates whether the PoolImpl is created. Ideally when a listener is attached pool should - * not be created. - */ - @Test - public void testGatewaySenderEventListenerPoolImpl() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2, vm3); - createReceiverInVMs(vm2, vm3); - - createCacheInVMs(lnPort, vm4); - - vm4.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, false, false)); - - vm4.invoke(() -> SerialGatewaySenderEventListenerDUnitTest.validateNoPoolCreation("ln")); - } - - // Test start/stop/resume on listener invocation - // this test hangs after the Darrel's checkin 36685. Need to work with Darrel.Commenting it out so - // that test suit will not hang - @Ignore - @Test - public void testGatewaySenderEventListener_GatewayOperations() { - - int mPort = AvailablePortHelper.getRandomAvailableTCPPort(); - vm4.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - vm5.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - vm6.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - vm7.invoke(() -> WANTestBase.createCacheWithoutLocator(mPort)); - - vm4.invoke(() -> WANTestBase.createSenderWithListener("ln", 2, false, 100, 10, false, false, - null, false, true)); - - vm4.invoke(() -> WANTestBase.startSender("ln")); - - vm4.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm5.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm6.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - vm7.invoke( - () -> WANTestBase.createReplicatedRegion(getTestMethodName() + "_RR", "ln", isOffHeap())); - - final Map initialKeyValues = new HashMap(); - for (int i = 0; i < 1000; i++) { - initialKeyValues.put(i, i); - } - - vm4.invoke(() -> WANTestBase.putGivenKeyValue(getTestMethodName() + "_RR", initialKeyValues)); - - fail("tried to invoke missing method"); - // vm4.invoke(() -> - // SerialGatewaySenderEventListenerDUnitTest.validateReceivedEventsMapSizeListener1("ln", - // initialKeyValues )); - - vm4.invoke(() -> WANTestBase.stopSender("ln")); - - final Map keyValues = new HashMap(); - for (int i = 1000; i < 2000; i++) { - keyValues.put(i, i); - } - - vm4.invoke(() -> WANTestBase.putGivenKeyValue(getTestMethodName() + "_RR", keyValues)); - - fail("tried to invoke missing method"); - // vm4.invoke(() -> - // SerialGatewaySenderEventListenerDUnitTest.validateReceivedEventsMapSizeListener1("ln", - // initialKeyValues )); - - vm4.invoke(() -> WANTestBase.startSender("ln")); - - final Map finalKeyValues = new HashMap(); - for (int i = 2000; i < 3000; i++) { - finalKeyValues.put(i, i); - } - - vm4.invoke(() -> WANTestBase.putGivenKeyValue(getTestMethodName() + "_RR", finalKeyValues)); - - finalKeyValues.putAll(initialKeyValues); - fail("tried to invoke missing method"); - // vm4.invoke(() -> - // SerialGatewaySenderEventListenerDUnitTest.validateReceivedEventsMapSizeListener1("ln", - // finalKeyValues )); - - } - - public static void validateNoPoolCreation(final String siteId) { - Set senders = cache.getGatewaySenders(); - for (GatewaySender sender : senders) { - if (sender.getId().equals(siteId)) { - AbstractGatewaySender sImpl = (AbstractGatewaySender) sender; - assertNull(sImpl.getProxy()); - } - } - } - - public static void validateReceivedEventsMapSizeListener1(final String senderId, final Map map) { - - Set senders = cache.getGatewaySenders(); - GatewaySender sender = null; - for (GatewaySender s : senders) { - if (s.getId().equals(senderId)) { - sender = s; - break; - } - } - - final List listeners = - ((AbstractGatewaySender) sender).getAsyncEventListeners(); - if (listeners.size() == 1) { - final AsyncEventListener l = listeners.get(0); - - WaitCriterion wc = new WaitCriterion() { - Map listenerMap; - - @Override - public boolean done() { - listenerMap = ((MyGatewaySenderEventListener) l).getEventsMap(); - boolean sizeCorrect = map.size() == listenerMap.size(); - boolean keySetCorrect = listenerMap.keySet().containsAll(map.keySet()); - boolean valuesCorrect = listenerMap.values().containsAll(map.values()); - return sizeCorrect && keySetCorrect && valuesCorrect; - } - - @Override - public String description() { - return "Waiting for all sites to get updated, the sizes are " + listenerMap.size() - + " and " + map.size(); - } - }; - GeodeAwaitility.await().untilAsserted(wc); - } - } - - public static void validateReceivedEventsMapSizeListener2(final String senderId, final Map map) { - - Set senders = cache.getGatewaySenders(); - GatewaySender sender = null; - for (GatewaySender s : senders) { - if (s.getId().equals(senderId)) { - sender = s; - break; - } - } - - final List listeners = - ((AbstractGatewaySender) sender).getAsyncEventListeners(); - if (listeners.size() == 2) { - final AsyncEventListener l1 = listeners.get(0); - final AsyncEventListener l2 = listeners.get(1); - await().untilAsserted(() -> { - Map listenerMap1 = ((MyGatewaySenderEventListener) l1).getEventsMap(); - - Map listenerMap2 = ((MyGatewaySenderEventListener2) l2).getEventsMap(); - int listener1MapSize = listenerMap1.size(); - int listener2MapSize = listenerMap1.size(); - int expectedMapSize = map.size(); - boolean sizeCorrect = expectedMapSize == listener1MapSize; - boolean keySetCorrect = listenerMap1.keySet().containsAll(map.keySet()); - boolean valuesCorrect = listenerMap1.values().containsAll(map.values()); - - boolean sizeCorrect2 = expectedMapSize == listener2MapSize; - boolean keySetCorrect2 = listenerMap2.keySet().containsAll(map.keySet()); - boolean valuesCorrect2 = listenerMap2.values().containsAll(map.values()); - - assertEquals( - "Failed while waiting for all sites to get updated with the correct events. \nThe " - + "size of listener 1's map = " + listener1MapSize - + "\n The size of listener 2's map = " + "" + listener2MapSize - + "\n The expected map size =" + expectedMapSize, - true, sizeCorrect && keySetCorrect && valuesCorrect && sizeCorrect2 && keySetCorrect2 - && valuesCorrect2); - }); - } - } -} diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANPropagation_PartitionedRegionDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANPropagation_PartitionedRegionDUnitTest.java index 199076e110e2..8415a79fc096 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANPropagation_PartitionedRegionDUnitTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANPropagation_PartitionedRegionDUnitTest.java @@ -14,8 +14,6 @@ */ package org.apache.geode.internal.cache.wan.serial; -import java.util.HashMap; -import java.util.Map; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -23,11 +21,6 @@ import org.apache.geode.CancelException; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.internal.cache.ForceReattemptException; -import org.apache.geode.internal.cache.execute.data.CustId; -import org.apache.geode.internal.cache.execute.data.Order; -import org.apache.geode.internal.cache.execute.data.OrderId; -import org.apache.geode.internal.cache.execute.data.Shipment; -import org.apache.geode.internal.cache.execute.data.ShipmentId; import org.apache.geode.internal.cache.wan.WANTestBase; import org.apache.geode.test.dunit.AsyncInvocation; import org.apache.geode.test.dunit.IgnoredException; @@ -413,112 +406,4 @@ public void testPartitionedSerialPropagationWithParallelThreads() { vm2.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_PR", 1000)); vm3.invoke(() -> WANTestBase.validateRegionSize(getTestMethodName() + "_PR", 1000)); } - - @Test - public void testPartitionedSerialPropagationWithGroupTransactionEventsAndMixOfEventsInAndNotInTransactions() - throws Exception { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2, vm3); - createReceiverInVMs(vm2, vm3); - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - vm4.invoke(() -> setNumDispatcherThreadsForTheRun(1)); - vm5.invoke(() -> setNumDispatcherThreadsForTheRun(1)); - vm6.invoke(() -> setNumDispatcherThreadsForTheRun(1)); - vm7.invoke(() -> setNumDispatcherThreadsForTheRun(1)); - - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, true)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, true)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, true)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, true)); - - - vm4.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - vm5.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - vm6.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - vm7.invoke( - () -> WANTestBase.createCustomerOrderShipmentPartitionedRegion("ln", 2, 10, - isOffHeap())); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - vm2.invoke(() -> createCustomerOrderShipmentPartitionedRegion(null, 1, 8, isOffHeap())); - vm3.invoke(() -> createCustomerOrderShipmentPartitionedRegion(null, 1, 8, isOffHeap())); - - int customers = 4; - - int transactionsPerCustomer = 1000; - final Map keyValuesInTransactions = new HashMap<>(); - for (int custId = 0; custId < customers; custId++) { - for (int i = 0; i < transactionsPerCustomer; i++) { - CustId custIdObject = new CustId(custId); - OrderId orderId = new OrderId(i, custIdObject); - ShipmentId shipmentId1 = new ShipmentId(i, orderId); - ShipmentId shipmentId2 = new ShipmentId(i + 1, orderId); - ShipmentId shipmentId3 = new ShipmentId(i + 2, orderId); - keyValuesInTransactions.put(orderId, new Order()); - keyValuesInTransactions.put(shipmentId1, new Shipment()); - keyValuesInTransactions.put(shipmentId2, new Shipment()); - keyValuesInTransactions.put(shipmentId3, new Shipment()); - } - } - - int ordersPerCustomerNotInTransactions = 1000; - - final Map keyValuesNotInTransactions = new HashMap<>(); - for (int custId = 0; custId < customers; custId++) { - for (int i = 0; i < ordersPerCustomerNotInTransactions; i++) { - CustId custIdObject = new CustId(custId); - OrderId orderId = new OrderId(i + transactionsPerCustomer * customers, custIdObject); - keyValuesNotInTransactions.put(orderId, new Order()); - } - } - - // eventsPerTransaction is 1 (orders) + 3 (shipments) - int eventsPerTransaction = 4; - AsyncInvocation inv1 = - vm7.invokeAsync( - () -> WANTestBase.doOrderAndShipmentPutsInsideTransactions(keyValuesInTransactions, - eventsPerTransaction)); - - AsyncInvocation inv2 = - vm6.invokeAsync( - () -> WANTestBase.putGivenKeyValue(orderRegionName, keyValuesNotInTransactions)); - - inv1.await(); - inv2.await(); - - int entries = - ordersPerCustomerNotInTransactions * customers + transactionsPerCustomer * customers; - - vm4.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm5.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm6.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm7.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - - vm2.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - vm3.invoke(() -> WANTestBase.validateRegionSize(orderRegionName, entries)); - - vm4.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - vm5.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - vm6.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - vm7.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - - vm7.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm6.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm5.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - vm4.invoke(() -> WANTestBase.validateParallelSenderQueueAllBucketsDrained("ln")); - } } diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANStatsDistributedTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANStatsDistributedTest.java index 467c10c1e4d2..e9f389aa5a0b 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANStatsDistributedTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/serial/SerialWANStatsDistributedTest.java @@ -17,12 +17,9 @@ import static org.apache.geode.test.awaitility.GeodeAwaitility.await; import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException; import static org.apache.geode.test.dunit.Wait.pause; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.junit.Test; @@ -90,360 +87,6 @@ public void testReplicatedSerialPropagation() { } - @Test - public void testReplicatedSerialPropagationWithoutGroupTransactionEventsSendsBatchesWithIncompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - vm2.invoke(WANTestBase::createReceiver); - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - boolean groupTransactionEvents = false; - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - - vm2.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", null, isOffHeap())); - - startSenderInVMs("ln", vm4, vm5); - - vm4.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm5.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm6.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm7.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - - final Map keyValues = new HashMap<>(); - int entries = 12; - for (int i = 0; i < entries; i++) { - keyValues.put(i, i + "_Value"); - } - int eventsPerTransaction = 3; - vm5.invoke(() -> WANTestBase.doPutsInsideTransactions(testName + "_RR", keyValues, - eventsPerTransaction)); - - vm2.invoke(() -> WANTestBase.validateRegionSize(testName + "_RR", entries)); - - vm2.invoke(() -> WANTestBase.checkGatewayReceiverStats(2, entries, entries, true)); - - vm4.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, entries, entries)); - vm4.invoke(() -> WANTestBase.checkBatchStats("ln", 2, true, false)); - - // wait until queue is empty - vm5.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(0) == 0)); - - vm5.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, 0, 0)); - vm5.invoke(() -> WANTestBase.checkBatchStats("ln", 0)); - } - - @Test - public void testReplicatedSerialPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - vm2.invoke(WANTestBase::createReceiver); - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - boolean groupTransactionEvents = true; - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - - vm2.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", null, isOffHeap())); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - vm4.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm5.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm6.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm7.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - - final Map keyValues = new HashMap<>(); - int entries = 12; - for (int i = 0; i < entries; i++) { - keyValues.put(i, i + "_Value"); - } - - // 4 transactions of 3 events each are sent so that the first batch - // would initially contain the first 3 transactions complete and the first - // event of the next transaction (10 entries). - // As --group-transaction-events is configured in the senders, the remaining - // events of the third transaction are added to the batch which makes - // that the batch is sent with 12 events. - int eventsPerTransaction = 3; - vm5.invoke(() -> WANTestBase.doPutsInsideTransactions(testName + "_RR", keyValues, - eventsPerTransaction)); - - vm2.invoke(() -> WANTestBase.validateRegionSize(testName + "_RR", entries)); - - vm2.invoke(() -> WANTestBase.checkGatewayReceiverStats(1, entries, entries, true)); - - vm4.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, entries, entries)); - vm4.invoke(() -> WANTestBase.checkBatchStats("ln", 1, true)); - vm4.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - - // wait until queue is empty - vm5.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(0) == 0)); - - vm5.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, 0, 0)); - vm5.invoke(() -> WANTestBase.checkBatchStats("ln", 0, true)); - vm5.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - } - - @Test - public void testReplicatedSerialPropagationWithGroupTransactionEventsWithoutBatchRedistributionSendsBatchesWithCompleteTransactions_SeveralClients() { - testReplicatedSerialPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( - false); - } - - @Test - public void testReplicatedSerialPropagationWithGroupTransactionEventsWithBatchRedistributionSendsBatchesWithCompleteTransactions_SeveralClients() { - testReplicatedSerialPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( - true); - } - - public void testReplicatedSerialPropagationWithGroupTransactionEventsSendsBatchesWithCompleteTransactions_SeveralClients( - boolean isBatchRedistribution) { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - if (!isBatchRedistribution) { - vm2.invoke(WANTestBase::createReceiver); - } - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - final int batchSize = 10; - - boolean groupTransactionEvents = true; - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - - final String regionName = testName + "_RR"; - - vm2.invoke(() -> WANTestBase.createReplicatedRegion(regionName, null, isOffHeap())); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - vm4.invoke(() -> WANTestBase.createReplicatedRegion(regionName, "ln", isOffHeap())); - vm5.invoke(() -> WANTestBase.createReplicatedRegion(regionName, "ln", isOffHeap())); - vm6.invoke(() -> WANTestBase.createReplicatedRegion(regionName, "ln", isOffHeap())); - vm7.invoke(() -> WANTestBase.createReplicatedRegion(regionName, "ln", isOffHeap())); - - int clients = 2; - int eventsPerTransaction = batchSize + 1; - int entriesPerInvocation = eventsPerTransaction * 200; - - final List> data = new ArrayList<>(clients); - for (int clientId = 0; clientId < clients; clientId++) { - final Map keyValues = new HashMap<>(); - for (int i = entriesPerInvocation * clientId; i < entriesPerInvocation - * (clientId + 1); i++) { - keyValues.put(i, i + "_Value"); - } - data.add(keyValues); - } - - int entries = entriesPerInvocation * clients; - - List> invocations = new ArrayList<>(clients); - for (int i = 0; i < clients; i++) { - final int index = i; - AsyncInvocation asyncInvocation = - vm4.invokeAsync(() -> WANTestBase.doPutsInsideTransactions(regionName, data.get(index), - eventsPerTransaction)); - invocations.add(asyncInvocation); - } - - try { - for (AsyncInvocation invocation : invocations) { - invocation.await(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - - if (isBatchRedistribution) { - // wait for batches to be redistributed and then start the receiver - vm4.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(5) > 0)); - vm2.invoke(WANTestBase::createReceiver); - } - - vm2.invoke(() -> WANTestBase.validateRegionSize(regionName, entries)); - - checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated(isBatchRedistribution); - } - - @Test - public void testReplicatedSerialPropagationWithBatchRedistWithoutGroupTransactionEventsSendsBatchesWithIncompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - boolean groupTransactionEvents = false; - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, 10, false, false, null, true, - groupTransactionEvents)); - - vm2.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", null, isOffHeap())); - - startSenderInVMs("ln", vm4, vm5); - - vm4.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm5.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm6.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm7.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - - final Map keyValues = new HashMap<>(); - int entries = 24; - for (int i = 0; i < entries; i++) { - keyValues.put(i, i + "_Value"); - } - int eventsPerTransaction = 3; - vm5.invoke(() -> WANTestBase.doPutsInsideTransactions(testName + "_RR", keyValues, - eventsPerTransaction)); - - // wait for batches to be redistributed and then start the receiver - vm4.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(5) > 0)); - - vm2.invoke(WANTestBase::createReceiver); - - vm2.invoke(() -> WANTestBase.validateRegionSize(testName + "_RR", entries)); - - vm2.invoke(() -> WANTestBase.checkGatewayReceiverStats(3, entries, entries, true)); - - vm4.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, entries, entries)); - vm4.invoke(() -> WANTestBase.checkBatchStats("ln", 3, true, true)); - - // wait until queue is empty - vm5.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(0) == 0)); - - vm5.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, 0, 0)); - vm5.invoke(() -> WANTestBase.checkBatchStats("ln", 0)); - } - - @Test - public void testReplicatedSerialPropagationWithBatchRedistWithGroupTransactionEventsSendsBatchesWithCompleteTransactions() { - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - createCacheInVMs(nyPort, vm2); - - createCacheInVMs(lnPort, vm4, vm5, vm6, vm7); - - boolean groupTransactionEvents = true; - int batchSize = 10; - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - - vm2.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", null, isOffHeap())); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - vm4.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm5.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm6.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm7.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - - final Map keyValues = new HashMap<>(); - int entries = 24; - for (int i = 0; i < entries; i++) { - keyValues.put(i, i + "_Value"); - } - - // 8 transactions of 3 events each are sent so that the first batch - // events would initially contain the first 3 transactions complete and the first - // event of the next transaction (10 entries). - // As --group-transaction-events is configured in the senders, the remaining - // event of the third transaction is added to the batch which makes - // that the first batch is sent with 12 events. The same happens with the - // second batch which will contain 12 events too. - int eventsPerTransaction = 3; - vm5.invoke(() -> WANTestBase.doPutsInsideTransactions(testName + "_RR", keyValues, - eventsPerTransaction)); - - // wait for batches to be redistributed and then start the receiver - vm4.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(5) > 0)); - - vm2.invoke(WANTestBase::createReceiver); - - vm2.invoke(() -> WANTestBase.validateRegionSize(testName + "_RR", entries)); - - vm2.invoke(() -> WANTestBase.checkGatewayReceiverStats(2, entries, entries, true)); - - vm4.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, entries, entries)); - vm4.invoke(() -> WANTestBase.checkBatchStats("ln", 2, true, true)); - vm4.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - - // wait until queue is empty - vm5.invoke(() -> await() - .until(() -> WANTestBase.getSenderStats("ln", -1).get(0) == 0)); - - vm5.invoke(() -> WANTestBase.checkQueueStats("ln", 0, entries, 0, 0)); - vm5.invoke(() -> WANTestBase.checkBatchStats("ln", 0, true)); - vm5.invoke(() -> WANTestBase.checkConflatedStats("ln", 0)); - } - @Test public void testReplicatedSerialPropagationWithMultipleDispatchers() { Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); @@ -591,80 +234,6 @@ public void testReplicatedSerialPropagationHA() throws Exception { vm5.invoke(() -> WANTestBase.checkStats_Failover("ln", 10000)); } - @Test - public void testReplicatedSerialPropagationHAWithGroupTransactionEvents() throws Exception { - - Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); - Integer nyPort = vm1.invoke(() -> WANTestBase.createFirstRemoteLocator(2, lnPort)); - - vm2.invoke(() -> WANTestBase.createCache(nyPort)); - vm2.invoke(WANTestBase::createReceiver); - - vm4.invoke(() -> WANTestBase.createCache(lnPort)); - vm5.invoke(() -> WANTestBase.createCache(lnPort)); - vm6.invoke(() -> WANTestBase.createCache(lnPort)); - vm7.invoke(() -> WANTestBase.createCache(lnPort)); - - int batchSize = 9; - boolean groupTransactionEvents = true; - vm4.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm5.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm6.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - vm7.invoke( - () -> WANTestBase.createSender("ln", 2, false, 100, batchSize, false, false, null, true, - groupTransactionEvents)); - - vm2.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", null, isOffHeap())); - - startSenderInVMs("ln", vm4, vm5, vm6, vm7); - - vm4.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm5.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm6.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - vm7.invoke(() -> WANTestBase.createReplicatedRegion(testName + "_RR", "ln", isOffHeap())); - - AsyncInvocation inv1 = - vm6.invokeAsync(() -> WANTestBase.doTxPutsWithRetryIfError(testName + "_RR", 2, 5000, 0)); - AsyncInvocation inv2 = - vm7.invokeAsync(() -> WANTestBase.doTxPutsWithRetryIfError(testName + "_RR", 2, 5000, 1)); - - vm2.invoke(() -> await() - .untilAsserted(() -> assertThat(getRegionSize(testName + "_RR") > 40).as( - "Waiting for some batches to be received").isEqualTo(true))); - - AsyncInvocation inv3 = vm4.invokeAsync(() -> WANTestBase.killSender("ln")); - boolean isKilled = false; - try { - isKilled = inv3.getResult(); - } catch (Throwable e) { - fail("Unexpected exception while killing a sender"); - } - if (!isKilled) { - AsyncInvocation inv4 = vm5.invokeAsync(() -> WANTestBase.killSender("ln")); - inv4.join(); - } - inv1.join(); - inv2.join(); - inv3.join(); - - vm5.invoke(() -> WANTestBase.validateRegionSize(testName + "_RR", 20000)); - vm2.invoke(() -> WANTestBase.validateRegionSize(testName + "_RR", 20000)); - - // batchesReceived is equal to numberOfEntries/(batchSize+1) - // As transactions are 2 events long, for each batch it will always be necessary to - // add one more entry to the 9 events batch in order to have complete transactions in the batch. - int batchesReceived = (10000 + 10000) / (batchSize + 1); - vm2.invoke(() -> WANTestBase.checkGatewayReceiverStatsHA(batchesReceived, 20000, 20000)); - - vm5.invoke(() -> WANTestBase.checkStats_Failover("ln", 20000)); - } - @Test public void testReplicatedSerialPropagationUnprocessedEvents() throws Exception { Integer lnPort = vm0.invoke(() -> WANTestBase.createFirstLocatorWithDSId(1)); @@ -918,29 +487,4 @@ public void testSerialPropagationConflation() { vm4.invoke(() -> WANTestBase.checkQueueStats("ln", 0, 2000, 2000, 1500)); vm4.invoke(() -> WANTestBase.checkConflatedStats("ln", 500)); } - - private void checkQueuesAreEmptyAndOnlyCompleteTransactionsAreReplicated( - boolean isBatchesRedistributed) { - await().untilAsserted(() -> { - // Wait for sender queues to be empty - List v4List = vm4.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v5List = vm5.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v6List = vm6.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - List v7List = vm7.invoke(() -> WANTestBase.getSenderStats("ln", 0)); - - // queue size must be 0 - assertThat(v4List.get(0) + v5List.get(0) + v6List.get(0) + v7List.get(0)).isEqualTo(0); - - // batches redistributed: - int batchesRedistributed = v4List.get(5) + v5List.get(5) + v6List.get(5) + v7List.get(5); - if (isBatchesRedistributed) { - assertThat(batchesRedistributed).isGreaterThan(0); - } else { - assertThat(batchesRedistributed).isEqualTo(0); - } - - // batches with incomplete transactions must be 0 - assertThat(v4List.get(13) + v5List.get(13) + v6List.get(13) + v7List.get(13)).isEqualTo(0); - }); - } } diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/AlterGatewaySenderCommandDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/AlterGatewaySenderCommandDUnitTest.java index 14cc30bec75a..9cd106b140c7 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/AlterGatewaySenderCommandDUnitTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/AlterGatewaySenderCommandDUnitTest.java @@ -460,14 +460,8 @@ public void testCreateParallelGatewaySenderAndChangeGroupTransaction() throws Ex .containsOutput("sender1P"); gfsh.executeAndAssertThat("alter gateway-sender --id=sender1P --group-transaction-events=true") - .statusIsSuccess(); - - // verify that server1's event queue has the default value - server1.invoke(() -> { - InternalCache cache = ClusterStartupRule.getCache(); - GatewaySender sender = cache.getGatewaySender("sender1P"); - assertThat(sender.mustGroupTransactionEvents()).isTrue(); - }); + .statusIsError() + .containsOutput("alter-gateway-sender cannot be performed for --group-transaction-events"); } public static class MyGatewayEventFilter implements GatewayEventFilter { diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/CreateDestroyGatewaySenderCommandDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/CreateDestroyGatewaySenderCommandDUnitTest.java index 49fbea480a96..20f823d54ef4 100644 --- a/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/CreateDestroyGatewaySenderCommandDUnitTest.java +++ b/geode-wan/src/distributedTest/java/org/apache/geode/internal/cache/wan/wancommand/CreateDestroyGatewaySenderCommandDUnitTest.java @@ -194,8 +194,7 @@ public void testCreateDestroyGatewaySenderWithSingleDispatcherThread() { + "=ln" + " --" + CliStrings.CREATE_GATEWAYSENDER__REMOTEDISTRIBUTEDSYSTEMID + "=2" + " --" + CliStrings.CREATE_GATEWAYSENDER__MANUALSTART + "=true" + " --" + CliStrings.CREATE_GATEWAYSENDER__SOCKETBUFFERSIZE + "=1000" + " --" - + CliStrings.CREATE_GATEWAYSENDER__DISPATCHERTHREADS + "=1" + " --" - + CliStrings.CREATE_GATEWAYSENDER__GROUPTRANSACTIONEVENTS + "=true"; + + CliStrings.CREATE_GATEWAYSENDER__DISPATCHERTHREADS + "=1" + " --"; gfsh.executeAndAssertThat(command).statusIsSuccess() .doesNotContainOutput("Did not complete waiting") @@ -207,7 +206,7 @@ public void testCreateDestroyGatewaySenderWithSingleDispatcherThread() { VMProvider.invokeInEveryMember(() -> { verifySenderState("ln", false, false); verifySenderAttributes("ln", 2, false, true, 1000, 0, false, 100, 1000, false, - true, 100, 0, 1, null, null, null, true); + true, 100, 0, 1, null, null, null, false); }, server1, server2, server3); // destroy gateway sender and verify AEQs cleaned up diff --git a/geode-wan/src/integrationTest/java/org/apache/geode/internal/cache/wan/misc/WANConfigurationJUnitTest.java b/geode-wan/src/integrationTest/java/org/apache/geode/internal/cache/wan/misc/WANConfigurationJUnitTest.java index 533caf7af05e..b11d96448add 100644 --- a/geode-wan/src/integrationTest/java/org/apache/geode/internal/cache/wan/misc/WANConfigurationJUnitTest.java +++ b/geode-wan/src/integrationTest/java/org/apache/geode/internal/cache/wan/misc/WANConfigurationJUnitTest.java @@ -41,6 +41,7 @@ import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.cache.wan.GatewaySenderFactory; import org.apache.geode.cache.wan.GatewayTransportFilter; +import org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderImpl; import org.apache.geode.cache30.MyGatewayEventFilter1; import org.apache.geode.cache30.MyGatewayTransportFilter1; import org.apache.geode.cache30.MyGatewayTransportFilter2; @@ -69,7 +70,7 @@ public void test_GatewaySender_without_Locator() { cache = new CacheFactory().set(MCAST_PORT, "0").create(); GatewaySenderFactory fact = cache.createGatewaySenderFactory(); - fact.setParallel(true); + fact.setType(ParallelGatewaySenderImpl.TYPE); GatewaySender sender1 = fact.create("NYSender", 2); sender1.start(); fail("Expected IllegalStateException but not thrown"); @@ -82,31 +83,6 @@ public void test_GatewaySender_without_Locator() { } } - @Test - public void test_create_SerialGatewaySender_ThrowsException_when_GroupTransactionEvents_isTrue_and_DispatcherThreads_is_greaterThanOne() { - cache = new CacheFactory().set(MCAST_PORT, "0").create(); - GatewaySenderFactory fact = cache.createGatewaySenderFactory(); - fact.setParallel(false); - fact.setDispatcherThreads(2); - fact.setGroupTransactionEvents(true); - assertThatThrownBy(() -> fact.create("NYSender", 2)) - .isInstanceOf(GatewaySenderException.class) - .hasMessageContaining( - "SerialGatewaySender NYSender cannot be created with group transaction events set to true when dispatcher threads is greater than 1"); - } - - @Test - public void test_create_GatewaySender_ThrowsException_when_GroupTransactionEvents_isTrue_and_BatchConflation_is_enabled() { - cache = new CacheFactory().set(MCAST_PORT, "0").create(); - GatewaySenderFactory fact = cache.createGatewaySenderFactory(); - fact.setBatchConflationEnabled(true); - fact.setGroupTransactionEvents(true); - assertThatThrownBy(() -> fact.create("NYSender", 2)) - .isInstanceOf(GatewaySenderException.class) - .hasMessageContaining( - "GatewaySender NYSender cannot be created with both group transaction events set to true and batch conflation enabled"); - } - /** * Test to validate that sender with same Id can not be added to cache. */ @@ -437,19 +413,6 @@ public void test_GatewaySenderWithGatewaySenderEventListener1() { } } - @Test - public void test_GatewaySenderWithGatewaySenderEventListener2() { - cache = new CacheFactory().set(MCAST_PORT, "0").create(); - GatewaySenderFactory fact = cache.createGatewaySenderFactory(); - AsyncEventListener listener = new MyGatewaySenderEventListener(); - ((InternalGatewaySenderFactory) fact).addAsyncEventListener(listener); - try { - ((InternalGatewaySenderFactory) fact).create("ln"); - } catch (Exception e) { - fail("Received Exception :" + e); - } - } - @Test public void test_ValidateGatewayReceiverAttributes_2() { cache = new CacheFactory().set(MCAST_PORT, "0").create(); diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImpl.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImpl.java index 42e522c2b228..7d3d95f9fbae 100644 --- a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImpl.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImpl.java @@ -14,9 +14,14 @@ */ package org.apache.geode.cache.wan.internal; +import static java.lang.String.format; +import static java.util.ServiceLoader.load; +import static java.util.stream.StreamSupport.stream; + import java.util.concurrent.atomic.AtomicBoolean; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.client.internal.LocatorDiscoveryCallback; @@ -31,13 +36,11 @@ import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.InternalCache; -import org.apache.geode.internal.cache.wan.AsyncEventQueueConfigurationException; import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributesImpl; import org.apache.geode.internal.cache.wan.GatewaySenderException; import org.apache.geode.internal.cache.wan.InternalGatewaySenderFactory; import org.apache.geode.internal.cache.xmlcache.CacheCreation; -import org.apache.geode.internal.cache.xmlcache.ParallelGatewaySenderCreation; -import org.apache.geode.internal.cache.xmlcache.SerialGatewaySenderCreation; import org.apache.geode.internal.statistics.StatisticsClock; import org.apache.geode.logging.internal.log4j.api.LogService; @@ -55,7 +58,7 @@ public class GatewaySenderFactoryImpl implements InternalGatewaySenderFactory { * Used internally to pass the attributes from this factory to the real GatewaySender it is * creating. */ - private final GatewaySenderAttributes attrs = new GatewaySenderAttributes(); + private final GatewaySenderAttributesImpl attrs = new GatewaySenderAttributesImpl(); private final InternalCache cache; @@ -79,8 +82,8 @@ public GatewaySenderFactory setGroupTransactionEvents(boolean groupTransactionEv } @Override - public GatewaySenderFactory setRetriesToGetTransactionEventsFromQueue(int retries) { - attrs.setRetriesToGetTransactionEventsFromQueue(retries); + public GatewaySenderFactory setType(String type) { + attrs.setType(type); return this; } @@ -216,48 +219,88 @@ public GatewaySenderFactory setEnforceThreadsConnectSameReceiver( } @Override - public GatewaySender create(String id, int remoteDSId) { - int myDSId = InternalDistributedSystem.getAnyInstance().getDistributionManager() - .getDistributedSystemId(); + public @NotNull GatewaySender create(final @NotNull String id, final int remoteDSId) { + attrs.setId(id); + attrs.setRemoteDs(remoteDSId); + if (attrs.getType() == null) { + if (attrs.isParallel()) { + attrs.setType(ParallelGatewaySenderImpl.TYPE); + } else { + attrs.setType(SerialGatewaySenderImpl.TYPE); + } + } + + validate(cache, attrs); + + final GatewaySenderTypeFactory factory = getGatewaySenderTypeFactory(attrs); + factory.validate(attrs); + + return createGatewaySender(factory, cache, statisticsClock, attrs); + } + + static @NotNull GatewaySenderTypeFactory getGatewaySenderTypeFactory( + final @NotNull GatewaySenderAttributes attributes) { + return (findGatewaySenderTypeFactory(attributes.getType())); + } + + private static @NotNull GatewaySenderTypeFactory findGatewaySenderTypeFactory( + final @NotNull String name) { + return stream(load(GatewaySenderTypeFactory.class).spliterator(), false) + .filter(factory -> factory.getType().equals(name) + || factory.getClass().getName().startsWith(name)) + .findFirst() + .orElseThrow(() -> new GatewaySenderException("No factory found for " + name)); + } + + static void validate(final @NotNull InternalCache cache, + final @NotNull GatewaySenderAttributesImpl attributes) { + int myDSId; + if (cache instanceof CacheCreation) { + myDSId = InternalDistributedSystem.getAnyInstance().getDistributionManager() + .getDistributedSystemId(); + } else { + myDSId = cache.getDistributionManager().getDistributedSystemId(); + } + final int remoteDSId = attributes.getRemoteDSId(); + if (remoteDSId == myDSId) { throw new GatewaySenderException( - String.format( + format( "GatewaySender %s cannot be created with remote DS Id equal to this DS Id. ", - id)); + attributes.getId())); } if (remoteDSId < 0) { throw new GatewaySenderException( - String.format("GatewaySender %s cannot be created with remote DS Id less than 0. ", - id)); + format("GatewaySender %s cannot be created with remote DS Id less than 0. ", + attributes.getId())); } - attrs.setId(id); - attrs.setRemoteDs(remoteDSId); - GatewaySender sender = null; - if (attrs.getDispatcherThreads() <= 0) { + if (attributes.getDispatcherThreads() <= 0) { throw new GatewaySenderException( - String.format("GatewaySender %s can not be created with dispatcher threads less than 1", - id)); + format("GatewaySender %s can not be created with dispatcher threads less than 1", + attributes.getId())); } + + // TODO jbarrett why only check these for a real cache. // Verify socket read timeout if a proper logger is available if (cache instanceof GemFireCacheImpl) { // If socket read timeout is less than the minimum, log a warning. // Ideally, this should throw a GatewaySenderException, but wan dunit tests // were failing, and we were running out of time to change them. - if (attrs.getSocketReadTimeout() != 0 - && attrs.getSocketReadTimeout() < GatewaySender.MINIMUM_SOCKET_READ_TIMEOUT) { + if (attributes.getSocketReadTimeout() != 0 + && attributes.getSocketReadTimeout() < GatewaySender.MINIMUM_SOCKET_READ_TIMEOUT) { logger.warn( "{} cannot configure socket read timeout of {} milliseconds because it is less than the minimum of {} milliseconds. The default will be used instead.", - new Object[] {"GatewaySender " + id, attrs.getSocketReadTimeout(), - GatewaySender.MINIMUM_SOCKET_READ_TIMEOUT}); - attrs.setSocketReadTimeout(GatewaySender.MINIMUM_SOCKET_READ_TIMEOUT); + "GatewaySender " + attributes.getId(), attributes.getSocketReadTimeout(), + GatewaySender.MINIMUM_SOCKET_READ_TIMEOUT); + attributes.setSocketReadTimeout(GatewaySender.MINIMUM_SOCKET_READ_TIMEOUT); } - if (attrs.getDiskStoreName() != null - && cache.findDiskStore(attrs.getDiskStoreName()) == null) { + if (attributes.getDiskStoreName() != null + && cache.findDiskStore(attributes.getDiskStoreName()) == null) { throw new IllegalStateException( String.format("Disk store %s not found", - attrs.getDiskStoreName())); + attributes.getDiskStoreName())); } // Log a warning if the old system property is set. @@ -265,110 +308,30 @@ public GatewaySender create(String id, int remoteDSId) { if (System.getProperty(GatewaySender.GATEWAY_CONNECTION_READ_TIMEOUT_PROPERTY) != null) { logger.warn( "Obsolete java system property named {} was set to control {}. This property is no longer supported. Please use the GemFire API instead.", - new Object[] {GatewaySender.GATEWAY_CONNECTION_READ_TIMEOUT_PROPERTY, - "GatewaySender socket read timeout"}); + GatewaySender.GATEWAY_CONNECTION_READ_TIMEOUT_PROPERTY, + "GatewaySender socket read timeout"); } } } - if (attrs.mustGroupTransactionEvents() && attrs.isBatchConflationEnabled()) { - throw new GatewaySenderException( - String.format( - "GatewaySender %s cannot be created with both group transaction events set to true and batch conflation enabled", - id)); - } - - if (attrs.isParallel()) { - if ((attrs.getOrderPolicy() != null) - && attrs.getOrderPolicy().equals(OrderPolicy.THREAD)) { - throw new GatewaySenderException( - String.format("Parallel Gateway Sender %s can not be created with OrderPolicy %s", - id, attrs.getOrderPolicy())); - } - if (cache instanceof GemFireCacheImpl) { - sender = new ParallelGatewaySenderImpl(cache, statisticsClock, attrs); - cache.addGatewaySender(sender); - - if (!attrs.isManualStart()) { - sender.start(); - } - } else if (cache instanceof CacheCreation) { - sender = new ParallelGatewaySenderCreation(cache, attrs); - cache.addGatewaySender(sender); - } - } else { - if (attrs.getAsyncEventListeners().size() > 0) { - throw new GatewaySenderException( - String.format( - "SerialGatewaySender %s cannot define a remote site because at least AsyncEventListener is already added. Both listeners and remote site cannot be defined for the same gateway sender.", - id)); - } - if (attrs.mustGroupTransactionEvents() && attrs.getDispatcherThreads() > 1) { - throw new GatewaySenderException( - String.format( - "SerialGatewaySender %s cannot be created with group transaction events set to true when dispatcher threads is greater than 1", - id)); - } - if (attrs.getOrderPolicy() == null && attrs.getDispatcherThreads() > 1) { - attrs.setOrderPolicy(GatewaySender.DEFAULT_ORDER_POLICY); - } - if (cache instanceof GemFireCacheImpl) { - sender = new SerialGatewaySenderImpl(cache, statisticsClock, attrs); - cache.addGatewaySender(sender); - if (!attrs.isManualStart()) { - sender.start(); - } - } else if (cache instanceof CacheCreation) { - sender = new SerialGatewaySenderCreation(cache, attrs); - cache.addGatewaySender(sender); - } - } - return sender; } - @Override - public GatewaySender create(String id) { - attrs.setId(id); - GatewaySender sender = null; - - if (attrs.getDispatcherThreads() <= 0) { - throw new AsyncEventQueueConfigurationException( - String.format("AsyncEventQueue %s can not be created with dispatcher threads less than 1", - id)); - } - - if (attrs.isParallel()) { - if ((attrs.getOrderPolicy() != null) - && attrs.getOrderPolicy().equals(OrderPolicy.THREAD)) { - throw new AsyncEventQueueConfigurationException( - String.format( - "AsyncEventQueue %s can not be created with OrderPolicy %s when it is set parallel", - id, attrs.getOrderPolicy())); - } - - if (cache instanceof GemFireCacheImpl) { - sender = new ParallelGatewaySenderImpl(cache, statisticsClock, attrs); - cache.addGatewaySender(sender); - if (!attrs.isManualStart()) { - sender.start(); - } - } else if (cache instanceof CacheCreation) { - sender = new ParallelGatewaySenderCreation(cache, attrs); - cache.addGatewaySender(sender); + @NotNull + private static GatewaySender createGatewaySender(final @NotNull GatewaySenderTypeFactory factory, + final @NotNull InternalCache cache, + final @NotNull StatisticsClock clock, + final @NotNull GatewaySenderAttributesImpl attributes) { + final GatewaySender sender; + if (cache instanceof GemFireCacheImpl) { + sender = factory.create(cache, clock, attributes); + cache.addGatewaySender(sender); + if (!attributes.isManualStart()) { + sender.start(); } + } else if (cache instanceof CacheCreation) { + sender = factory.createCreation(cache, attributes); + cache.addGatewaySender(sender); } else { - if (attrs.getOrderPolicy() == null && attrs.getDispatcherThreads() > 1) { - attrs.setOrderPolicy(GatewaySender.DEFAULT_ORDER_POLICY); - } - if (cache instanceof GemFireCacheImpl) { - sender = new SerialGatewaySenderImpl(cache, statisticsClock, attrs); - cache.addGatewaySender(sender); - if (!attrs.isManualStart()) { - sender.start(); - } - } else if (cache instanceof CacheCreation) { - sender = new SerialGatewaySenderCreation(cache, attrs); - cache.addGatewaySender(sender); - } + throw new IllegalStateException(); } return sender; } @@ -387,7 +350,7 @@ public GatewaySenderFactory removeGatewayTransportFilter(GatewayTransportFilter @Override public GatewaySenderFactory setGatewayEventSubstitutionFilter( - GatewayEventSubstitutionFilter filter) { + GatewayEventSubstitutionFilter filter) { attrs.setEventSubstitutionFilter(filter); return this; } diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderTypeFactory.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderTypeFactory.java new file mode 100644 index 000000000000..d408b4355f97 --- /dev/null +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/GatewaySenderTypeFactory.java @@ -0,0 +1,40 @@ +/* + * 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.cache.wan.internal; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; +import org.apache.geode.internal.statistics.StatisticsClock; + +public interface GatewaySenderTypeFactory { + + @NotNull + String getType(); + + void validate(@NotNull MutableGatewaySenderAttributes attributes) throws GatewaySenderException; + + GatewaySender create(@NotNull InternalCache cache, @NotNull StatisticsClock clock, + @NotNull GatewaySenderAttributes attributes); + + GatewaySender createCreation(@NotNull InternalCache cache, + @NotNull GatewaySenderAttributes attributes); + +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ParallelGatewaySenderCreation.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderCreation.java similarity index 92% rename from geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ParallelGatewaySenderCreation.java rename to geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderCreation.java index 82adbee5dd6d..cb8b84b0c8cc 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/ParallelGatewaySenderCreation.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderCreation.java @@ -12,12 +12,10 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package org.apache.geode.internal.cache.xmlcache; +package org.apache.geode.cache.wan.internal.parallel; import static org.apache.geode.internal.statistics.StatisticsClockFactory.disabledClock; -import java.util.List; - import org.apache.geode.CancelCriterion; import org.apache.geode.cache.wan.GatewayQueueEvent; import org.apache.geode.cache.wan.GatewaySender; @@ -27,7 +25,6 @@ import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.cache.EntryEventImpl; -import org.apache.geode.internal.cache.EnumListenerEvent; import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.internal.cache.wan.AbstractGatewaySender; import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; @@ -38,10 +35,6 @@ public ParallelGatewaySenderCreation(InternalCache cache, GatewaySenderAttribute super(cache, disabledClock(), attrs); } - @Override - public void distribute(EnumListenerEvent operation, EntryEventImpl event, - List remoteDSIds) {} - @Override public void start() {} @@ -56,6 +49,11 @@ public void rebalance() { throw new UnsupportedOperationException(); } + @Override + public String getType() { + return ParallelGatewaySenderImpl.TYPE; + } + @Override public void destroy() {} diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImpl.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImpl.java index a0edf12f68b8..26b80ef60227 100644 --- a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImpl.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImpl.java @@ -15,6 +15,7 @@ package org.apache.geode.cache.wan.internal.parallel; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.wan.GatewayEventFilter; @@ -43,6 +44,8 @@ */ public class ParallelGatewaySenderImpl extends AbstractRemoteGatewaySender { + public static final String TYPE = "ParallelGatewaySender"; + private static final Logger logger = LogService.getLogger(); public ParallelGatewaySenderImpl(InternalCache cache, StatisticsClock statisticsClock, @@ -81,9 +84,7 @@ private void start(boolean cleanQueues) { * "ParallelGatewaySenderEventProcessor" and "ParallelGatewaySenderQueue" as a utility classes * of Concurrent version of processor and queue. */ - eventProcessor = - new RemoteConcurrentParallelGatewaySenderEventProcessor(this, getThreadMonitorObj(), - cleanQueues); + eventProcessor = createEventProcessor(getThreadMonitorObj(), cleanQueues); if (isStartEventProcessorInPausedState()) { pauseEvenIfProcessorStopped(); } @@ -107,6 +108,12 @@ private void start(boolean cleanQueues) { } } + protected RemoteConcurrentParallelGatewaySenderEventProcessor createEventProcessor( + final @Nullable ThreadsMonitoring threadsMonitoring, final boolean cleanQueues) { + return new RemoteConcurrentParallelGatewaySenderEventProcessor(this, threadsMonitoring, + cleanQueues); + } + @Override public void stop() { getLifeCycleLock().writeLock().lock(); @@ -142,6 +149,11 @@ public void stop() { } } + @Override + public String getType() { + return ParallelGatewaySenderImpl.TYPE; + } + @Override public String toString() { return "ParallelGatewaySender{" diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderTypeFactory.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderTypeFactory.java new file mode 100644 index 000000000000..e08d3bd5230c --- /dev/null +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderTypeFactory.java @@ -0,0 +1,61 @@ +/* + * 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.cache.wan.internal.parallel; + +import static java.lang.String.format; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; +import org.apache.geode.internal.statistics.StatisticsClock; + +public class ParallelGatewaySenderTypeFactory implements GatewaySenderTypeFactory { + + @Override + public @NotNull String getType() { + return ParallelGatewaySenderImpl.TYPE; + } + + @Override + public void validate(final @NotNull MutableGatewaySenderAttributes attributes) + throws GatewaySenderException { + if ((attributes.getOrderPolicy() != null) + && attributes.getOrderPolicy().equals(GatewaySender.OrderPolicy.THREAD)) { + throw new GatewaySenderException( + format("%s %s can not be created with OrderPolicy %s", + getType(), attributes.getId(), attributes.getOrderPolicy())); + } + } + + @Override + public GatewaySender create(final @NotNull InternalCache cache, + final @NotNull StatisticsClock clock, + final @NotNull GatewaySenderAttributes attributes) { + return new ParallelGatewaySenderImpl(cache, clock, attributes); + } + + @Override + public GatewaySender createCreation(final @NotNull InternalCache cache, + final @NotNull GatewaySenderAttributes attributes) { + return new ParallelGatewaySenderCreation(cache, attributes); + } + +} diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteConcurrentParallelGatewaySenderEventProcessor.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteConcurrentParallelGatewaySenderEventProcessor.java index 1da39c36c281..147c983b67ab 100644 --- a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteConcurrentParallelGatewaySenderEventProcessor.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteConcurrentParallelGatewaySenderEventProcessor.java @@ -17,6 +17,9 @@ import java.util.Set; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import org.apache.geode.cache.Region; import org.apache.geode.cache.wan.internal.GatewaySenderEventRemoteDispatcher; import org.apache.geode.distributed.internal.DistributionManager; @@ -46,11 +49,20 @@ protected void createProcessors(int dispatcherThreads, Set> targetR logger.debug("Creating GatewaySenderEventProcessor"); } for (int i = 0; i < sender.getDispatcherThreads(); i++) { - processors[i] = new RemoteParallelGatewaySenderEventProcessor(sender, targetRs, i, + processors[i] = createRemoteParallelGatewaySenderEventProcessor(sender, i, sender.getDispatcherThreads(), getThreadMonitorObj(), cleanQueues); } } + protected ParallelGatewaySenderEventProcessor createRemoteParallelGatewaySenderEventProcessor( + final @NotNull AbstractGatewaySender sender, final int id, + final int dispatcherThreads, final @Nullable ThreadsMonitoring threadsMonitoring, + final boolean cleanQueues) { + return new RemoteParallelGatewaySenderEventProcessor(sender, id, dispatcherThreads, + threadsMonitoring, cleanQueues); + } + + @Override protected void rebalance() { GatewaySenderStats statistics = sender.getStatistics(); diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteParallelGatewaySenderEventProcessor.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteParallelGatewaySenderEventProcessor.java index 03166275ed8f..774acdb9b70a 100644 --- a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteParallelGatewaySenderEventProcessor.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/parallel/RemoteParallelGatewaySenderEventProcessor.java @@ -14,11 +14,11 @@ */ package org.apache.geode.cache.wan.internal.parallel; -import java.util.Set; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import org.apache.geode.cache.Region; import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.cache.wan.internal.GatewaySenderEventRemoteDispatcher; import org.apache.geode.internal.cache.wan.AbstractGatewaySender; @@ -33,9 +33,9 @@ public class RemoteParallelGatewaySenderEventProcessor extends ParallelGatewaySe /** * use in concurrent scenario where queue is to be shared among all the processors. */ - protected RemoteParallelGatewaySenderEventProcessor(AbstractGatewaySender sender, - Set> userRegions, int id, int nDispatcher, ThreadsMonitoring tMonitoring, - boolean cleanQueues) { + protected RemoteParallelGatewaySenderEventProcessor(final @NotNull AbstractGatewaySender sender, + final int id, final int nDispatcher, + final @Nullable ThreadsMonitoring tMonitoring, final boolean cleanQueues) { super(sender, id, nDispatcher, tMonitoring, cleanQueues); } diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/RemoteConcurrentSerialGatewaySenderEventProcessor.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/RemoteConcurrentSerialGatewaySenderEventProcessor.java index 45967538f26a..4eecbeab035e 100644 --- a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/RemoteConcurrentSerialGatewaySenderEventProcessor.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/RemoteConcurrentSerialGatewaySenderEventProcessor.java @@ -24,7 +24,7 @@ public class RemoteConcurrentSerialGatewaySenderEventProcessor extends ConcurrentSerialGatewaySenderEventProcessor { - private static final Logger logger = LogService.getLogger(); + protected static final Logger logger = LogService.getLogger(); public RemoteConcurrentSerialGatewaySenderEventProcessor(AbstractGatewaySender sender, ThreadsMonitoring tMonitoring, boolean cleanQueues) { diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/SerialGatewaySenderCreation.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderCreation.java similarity index 94% rename from geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/SerialGatewaySenderCreation.java rename to geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderCreation.java index b0f02ceb91a8..ddaeb55520fe 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/SerialGatewaySenderCreation.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderCreation.java @@ -12,7 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package org.apache.geode.internal.cache.xmlcache; +package org.apache.geode.cache.wan.internal.serial; import static org.apache.geode.internal.statistics.StatisticsClockFactory.disabledClock; @@ -40,7 +40,7 @@ public SerialGatewaySenderCreation(InternalCache cache, GatewaySenderAttributes @Override public void distribute(EnumListenerEvent operation, EntryEventImpl event, - List remoteDSIds) {} + List remoteDSIds, boolean isLastEventInTransaction) {} @Override public void start() {} @@ -56,6 +56,11 @@ public void rebalance() { throw new UnsupportedOperationException(); } + @Override + public String getType() { + return SerialGatewaySenderImpl.TYPE; + } + @Override public void fillInProfile(Profile profile) {} diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImpl.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImpl.java index a639d3366d4a..df8b71cdf9b6 100644 --- a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImpl.java +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImpl.java @@ -17,7 +17,9 @@ import java.util.Set; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; +import org.apache.geode.annotations.VisibleForTesting; import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.wan.GatewayTransportFilter; import org.apache.geode.cache.wan.internal.AbstractRemoteGatewaySender; @@ -46,6 +48,8 @@ */ public class SerialGatewaySenderImpl extends AbstractRemoteGatewaySender { + public static final String TYPE = "SerialGatewaySender"; + private static final Logger logger = LogService.getLogger(); public SerialGatewaySenderImpl(InternalCache cache, StatisticsClock statisticsClock, @@ -117,16 +121,21 @@ private void start(boolean cleanQueues) { } } + @VisibleForTesting protected AbstractGatewaySenderEventProcessor createEventProcessor(boolean cleanQueues) { - AbstractGatewaySenderEventProcessor eventProcessor; + return createEventProcessor(getThreadMonitorObj(), cleanQueues); + } + + protected AbstractGatewaySenderEventProcessor createEventProcessor( + final @Nullable ThreadsMonitoring threadsMonitoring, + final boolean cleanQueues) { if (getDispatcherThreads() > 1) { - eventProcessor = new RemoteConcurrentSerialGatewaySenderEventProcessor( - this, getThreadMonitorObj(), cleanQueues); + return new RemoteConcurrentSerialGatewaySenderEventProcessor(this, + threadsMonitoring, cleanQueues); } else { - eventProcessor = new RemoteSerialGatewaySenderEventProcessor(this, - getId(), getThreadMonitorObj(), cleanQueues); + return new RemoteSerialGatewaySenderEventProcessor(this, getId(), + threadsMonitoring, cleanQueues); } - return eventProcessor; } @Override @@ -190,6 +199,11 @@ public void stop() { eventProcessor = null; } + @Override + public String getType() { + return TYPE; + } + @Override public String toString() { return "SerialGatewaySender{" diff --git a/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactory.java b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactory.java new file mode 100644 index 000000000000..6410644f66f1 --- /dev/null +++ b/geode-wan/src/main/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactory.java @@ -0,0 +1,66 @@ +/* + * 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.cache.wan.internal.serial; + +import static java.lang.String.format; + +import org.jetbrains.annotations.NotNull; + +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; +import org.apache.geode.internal.statistics.StatisticsClock; + +public class SerialGatewaySenderTypeFactory implements GatewaySenderTypeFactory { + + @Override + public @NotNull String getType() { + return SerialGatewaySenderImpl.TYPE; + } + + @Override + public void validate(final @NotNull MutableGatewaySenderAttributes attributes) + throws GatewaySenderException { + + if (!attributes.getAsyncEventListeners().isEmpty()) { + throw new GatewaySenderException( + format( + "%s %s cannot define a remote site because at least AsyncEventListener is already added. Both listeners and remote site cannot be defined for the same gateway sender.", + getType(), attributes.getId())); + } + + if (attributes.getOrderPolicy() == null && attributes.getDispatcherThreads() > 1) { + attributes.setOrderPolicy(GatewaySender.DEFAULT_ORDER_POLICY); + } + + } + + @Override + public GatewaySender create(final @NotNull InternalCache cache, + final @NotNull StatisticsClock clock, + final @NotNull GatewaySenderAttributes attributes) { + return new SerialGatewaySenderImpl(cache, clock, attributes); + } + + @Override + public GatewaySender createCreation(final @NotNull InternalCache cache, + final @NotNull GatewaySenderAttributes attributes) { + return new SerialGatewaySenderCreation(cache, attributes); + } +} diff --git a/geode-wan/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory b/geode-wan/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory new file mode 100644 index 000000000000..bab0e4a23096 --- /dev/null +++ b/geode-wan/src/main/resources/META-INF/services/org.apache.geode.cache.wan.internal.GatewaySenderTypeFactory @@ -0,0 +1,17 @@ +# +# 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. +# + +org.apache.geode.cache.wan.internal.serial.SerialGatewaySenderTypeFactory +org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderTypeFactory diff --git a/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImplTest.java b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImplTest.java new file mode 100644 index 000000000000..97b51b44506b --- /dev/null +++ b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/GatewaySenderFactoryImplTest.java @@ -0,0 +1,104 @@ +/* + * 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.cache.wan.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import org.apache.geode.cache.wan.internal.parallel.ParallelGatewaySenderTypeFactory; +import org.apache.geode.cache.wan.internal.serial.SerialGatewaySenderTypeFactory; +import org.apache.geode.distributed.internal.DistributionManager; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributes; +import org.apache.geode.internal.cache.wan.GatewaySenderAttributesImpl; +import org.apache.geode.internal.cache.wan.GatewaySenderException; + +public class GatewaySenderFactoryImplTest { + + @Test + public void getGatewaySenderTypeFactoryWithIsParallelTrueReturnsAParallelGatewaySenderTypeFactory() { + final GatewaySenderAttributes attributes = mock(GatewaySenderAttributes.class); + when(attributes.getType()).thenReturn("ParallelGatewaySender"); + assertThat(GatewaySenderFactoryImpl.getGatewaySenderTypeFactory(attributes)).isInstanceOf( + ParallelGatewaySenderTypeFactory.class); + } + + @Test + public void getGatewaySenderTypeFactoryWithIsParallelFalseReturnsASerialGatewaySenderTypeFactory() { + final GatewaySenderAttributes attributes = mock(GatewaySenderAttributes.class); + when(attributes.getType()).thenReturn("SerialGatewaySender"); + assertThat(GatewaySenderFactoryImpl.getGatewaySenderTypeFactory(attributes)).isInstanceOf( + SerialGatewaySenderTypeFactory.class); + } + + @Test + public void validateThrowsIfRemoteSystemIdEqualsLocalSystemId() { + final InternalCache cache = mock(InternalCache.class); + final DistributionManager distributionManager = mock(DistributionManager.class); + when(distributionManager.getDistributedSystemId()).thenReturn(42); + when(cache.getDistributionManager()).thenReturn(distributionManager); + final GatewaySenderAttributesImpl attributes = mock(GatewaySenderAttributesImpl.class); + when(attributes.getRemoteDSId()).thenReturn(42); + + assertThatThrownBy(() -> GatewaySenderFactoryImpl.validate(cache, attributes)).isInstanceOf( + GatewaySenderException.class).hasMessageContaining("remote DS Id equal to this DS Id"); + } + + @Test + public void validateThrowsIfRemoteSystemIdLessThan0() { + final InternalCache cache = mock(InternalCache.class); + final DistributionManager distributionManager = mock(DistributionManager.class); + when(distributionManager.getDistributedSystemId()).thenReturn(42); + when(cache.getDistributionManager()).thenReturn(distributionManager); + final GatewaySenderAttributesImpl attributes = mock(GatewaySenderAttributesImpl.class); + when(attributes.getRemoteDSId()).thenReturn(-1); + + assertThatThrownBy(() -> GatewaySenderFactoryImpl.validate(cache, attributes)).isInstanceOf( + GatewaySenderException.class).hasMessageContaining("remote DS Id less than 0"); + } + + @Test + public void validateThrowsIfDispatcherThreadsLessThan1() { + final InternalCache cache = mock(InternalCache.class); + final DistributionManager distributionManager = mock(DistributionManager.class); + when(cache.getDistributionManager()).thenReturn(distributionManager); + final GatewaySenderAttributesImpl attributes = mock(GatewaySenderAttributesImpl.class); + when(attributes.getRemoteDSId()).thenReturn(42); + when(attributes.getDispatcherThreads()).thenReturn(0); + + assertThatThrownBy(() -> GatewaySenderFactoryImpl.validate(cache, attributes)).isInstanceOf( + GatewaySenderException.class).hasMessageContaining("dispatcher threads less than 1"); + } + + @Test + public void validateDoesNotThrow() { + final InternalCache cache = mock(InternalCache.class); + final DistributionManager distributionManager = mock(DistributionManager.class); + when(cache.getDistributionManager()).thenReturn(distributionManager); + final GatewaySenderAttributesImpl attributes = mock(GatewaySenderAttributesImpl.class); + when(attributes.getRemoteDSId()).thenReturn(42); + when(attributes.getDispatcherThreads()).thenReturn(1); + when(attributes.isBatchConflationEnabled()).thenReturn(false); + + assertThatNoException().isThrownBy(() -> GatewaySenderFactoryImpl.validate(cache, attributes)); + } + +} diff --git a/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImplTest.java b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImplTest.java index aef02f135221..94f50a1f90fc 100644 --- a/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImplTest.java +++ b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/parallel/ParallelGatewaySenderImplTest.java @@ -14,6 +14,8 @@ */ package org.apache.geode.cache.wan.internal.parallel; +import static org.apache.geode.cache.wan.GatewaySender.DEFAULT_DISTRIBUTED_SYSTEM_ID; +import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -41,18 +43,17 @@ @Category(WanTest.class) public class ParallelGatewaySenderImplTest { - private InternalCache cache; - private StatisticsClock statisticsClock; - private GatewaySenderAttributes attrs; - private ParallelGatewaySenderImpl gatewaysender; + private ParallelGatewaySenderImpl gatewaySender; @Before public void setUp() { - cache = mock(InternalCache.class, RETURNS_DEEP_STUBS); - statisticsClock = mock(StatisticsClock.class); - attrs = new GatewaySenderAttributes(); - attrs.setParallel(true); - attrs.setId("sender"); + InternalCache cache = mock(InternalCache.class, RETURNS_DEEP_STUBS); + StatisticsClock statisticsClock = mock(StatisticsClock.class); + GatewaySenderAttributes attrs = mock(GatewaySenderAttributes.class); + when(attrs.isParallel()).thenReturn(true); + when(attrs.getId()).thenReturn("sender"); + when(attrs.getDispatcherThreads()).thenReturn(1); + when(attrs.getRemoteDSId()).thenReturn(DEFAULT_DISTRIBUTED_SYSTEM_ID); InternalDistributedSystem system = mock(InternalDistributedSystem.class); when(cache.getInternalDistributedSystem()).thenReturn(system); when(cache.getDistributedSystem()).thenReturn(system); @@ -67,27 +68,27 @@ public void setUp() { when(cache.getGatewaySenderLockService()).thenReturn(distributedLockService); LocalRegion region = mock(LocalRegion.class); - when(cache.getRegion(any())).thenReturn(region); + when(cache.getRegion(any())).thenReturn(uncheckedCast(region)); when(region.containsKey(any())).thenReturn(true); when(region.get(any())).thenReturn(1); TypeRegistry pdxRegistryMock = mock(TypeRegistry.class); when(cache.getPdxRegistry()).thenReturn(pdxRegistryMock); - gatewaysender = new ParallelGatewaySenderImpl(cache, statisticsClock, attrs); + gatewaySender = new ParallelGatewaySenderImpl(cache, statisticsClock, attrs); } @Test public void testStart() { - gatewaysender.start(); - RegionQueue queue = gatewaysender.getQueue(); + gatewaySender.start(); + RegionQueue queue = gatewaySender.getQueue(); assertFalse(((ConcurrentParallelGatewaySenderQueue) queue).getCleanQueues()); } @Test public void testStartWithCleanQueue() { - gatewaysender.startWithCleanQueue(); - RegionQueue queue = gatewaysender.getQueue(); + gatewaySender.startWithCleanQueue(); + RegionQueue queue = gatewaySender.getQueue(); assertTrue(((ConcurrentParallelGatewaySenderQueue) queue).getCleanQueues()); } } diff --git a/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImplTest.java b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImplTest.java index d0e85a8242c0..059b1000ba1f 100644 --- a/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImplTest.java +++ b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderImplTest.java @@ -15,6 +15,7 @@ package org.apache.geode.cache.wan.internal.serial; import static org.apache.geode.cache.wan.GatewaySender.DEFAULT_DISTRIBUTED_SYSTEM_ID; +import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; @@ -46,24 +47,22 @@ public class SerialGatewaySenderImplTest { private InternalCache cache; private SerialGatewaySenderImpl serialGatewaySender; - private StatisticsFactory statisticsFactory; private GatewaySenderAttributes gatewaySenderAttributes; private StatisticsClock statisticsClock; - private InternalRegionFactory regionFactory; AbstractGatewaySenderEventProcessor eventProcessor1; AbstractGatewaySenderEventProcessor eventProcessor2; @Before - public void setUp() throws Exception { + public void setUp() { cache = Fakes.cache(); when(cache.getRegion(any())).thenReturn(null); - regionFactory = mock(InternalRegionFactory.class); - when(regionFactory.create(any())).thenReturn(mock(LocalRegion.class)); - when(cache.createInternalRegionFactory(any())).thenReturn(regionFactory); + InternalRegionFactory regionFactory = mock(InternalRegionFactory.class); + when(regionFactory.create(any())).thenReturn(uncheckedCast(mock(LocalRegion.class))); + when(cache.createInternalRegionFactory(any())).thenReturn(uncheckedCast(regionFactory)); - statisticsFactory = mock(StatisticsFactory.class); + StatisticsFactory statisticsFactory = mock(StatisticsFactory.class); when(statisticsFactory.createAtomicStatistics(any(), any())).thenReturn(mock(Statistics.class)); gatewaySenderAttributes = mock(GatewaySenderAttributes.class); @@ -115,7 +114,7 @@ public void whenStartedShouldCreateEventProcessor() { } @Test - public void whenStartedwithCleanShouldCreateEventProcessor() { + public void whenStartedWithCleanShouldCreateEventProcessor() { serialGatewaySender = createSerialGatewaySenderImplSpy(); serialGatewaySender.startWithCleanQueue(); diff --git a/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactoryTest.java b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactoryTest.java new file mode 100644 index 000000000000..61264d3d6711 --- /dev/null +++ b/geode-wan/src/test/java/org/apache/geode/cache/wan/internal/serial/SerialGatewaySenderTypeFactoryTest.java @@ -0,0 +1,84 @@ +/* + * 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.cache.wan.internal.serial; + +import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; + +import org.junit.Test; + +import org.apache.geode.cache.asyncqueue.AsyncEventListener; +import org.apache.geode.cache.wan.GatewaySender; +import org.apache.geode.internal.cache.wan.GatewaySenderException; +import org.apache.geode.internal.cache.wan.MutableGatewaySenderAttributes; + +public class SerialGatewaySenderTypeFactoryTest { + + private final MutableGatewaySenderAttributes attributes = + mock(MutableGatewaySenderAttributes.class); + + private final SerialGatewaySenderTypeFactory factory = new SerialGatewaySenderTypeFactory(); + + @Test + public void validateThrowsIfAsyncEventListenersAdded() { + final List asyncEventListeners = uncheckedCast(mock(List.class)); + when(asyncEventListeners.isEmpty()).thenReturn(false); + when(attributes.getAsyncEventListeners()).thenReturn(asyncEventListeners); + + assertThatThrownBy(() -> factory.validate(attributes)) + .isInstanceOf(GatewaySenderException.class).hasMessageContaining( + "cannot define a remote site because at least AsyncEventListener is already added"); + } + + @Test + public void validateMutatesOrderPolicyIfNullAndDispatcherThreadsGreaterThan1() { + when(attributes.getOrderPolicy()).thenReturn(null); + when(attributes.getDispatcherThreads()).thenReturn(2); + + assertThatNoException().isThrownBy(() -> factory.validate(attributes)); + + verify(attributes).setOrderPolicy(GatewaySender.DEFAULT_ORDER_POLICY); + } + + @Test + public void validateDoesNotMutateOrderPolicyIfNullAndDispatcherThreadsIs1() { + when(attributes.getOrderPolicy()).thenReturn(null); + when(attributes.getDispatcherThreads()).thenReturn(1); + + assertThatNoException().isThrownBy(() -> factory.validate(attributes)); + + verify(attributes, never()).setOrderPolicy(any()); + } + + @Test + public void validateDoesNotMutateOrderPolicyIfSet() { + when(attributes.getOrderPolicy()).thenReturn(GatewaySender.OrderPolicy.KEY); + when(attributes.getDispatcherThreads()).thenReturn(2); + + assertThatNoException().isThrownBy(() -> factory.validate(attributes)); + + verify(attributes, never()).setOrderPolicy(any()); + } + +} diff --git a/settings.gradle b/settings.gradle index 74b2578816ef..63259aa45c43 100644 --- a/settings.gradle +++ b/settings.gradle @@ -68,6 +68,7 @@ include 'geode-lucene' include 'geode-lucene:geode-lucene-test' include 'geode-old-client-support' include 'geode-wan' +include 'geode-wan-txgrouping' include 'geode-cq' include 'geode-memcached' include 'geode-connectors'