You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ds...@apache.org on 2018/11/16 21:01:16 UTC

[geode] 02/02: DestroyMappingFunction now cleans up the region and the async event queue. Verified with unit test

This is an automated email from the ASF dual-hosted git repository.

dschneider pushed a commit to branch feature/GEODE-6068
in repository https://gitbox.apache.org/repos/asf/geode.git

commit f7eabd153fded118344e52d5f1e36c7060009d0d
Author: Darrel Schneider <ds...@pivotal.io>
AuthorDate: Fri Nov 16 13:00:34 2018 -0800

    DestroyMappingFunction now cleans up the region and the async event queue. Verified with unit test
---
 .../jdbc/internal/cli/DestroyMappingCommand.java   |   2 -
 .../jdbc/internal/cli/DestroyMappingFunction.java  |  45 +++++++-
 .../cli/DestroyMappingCommandFunctionTest.java     | 116 ++++++++++++++++++++-
 3 files changed, 154 insertions(+), 9 deletions(-)

diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
index f85bf44..4bf12fb 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
@@ -39,8 +39,6 @@ public class DestroyMappingCommand extends SingleGfshCommand {
   static final String DESTROY_MAPPING__REGION_NAME = "region";
   static final String DESTROY_MAPPING__REGION_NAME__HELP = "Name of the region mapping to destroy.";
 
-  private static final String ERROR_PREFIX = "ERROR: ";
-
   @CliCommand(value = DESTROY_MAPPING, help = DESTROY_MAPPING__HELP)
   @CliMetaData(relatedTopic = CliStrings.DEFAULT_TOPIC_GEODE)
   @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingFunction.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingFunction.java
index 2204596..5a0a255 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingFunction.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingFunction.java
@@ -14,12 +14,22 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import java.util.Set;
+
 import org.apache.geode.annotations.Experimental;
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheLoader;
+import org.apache.geode.cache.CacheWriter;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.asyncqueue.internal.InternalAsyncEventQueue;
 import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.connectors.jdbc.JdbcLoader;
+import org.apache.geode.connectors.jdbc.JdbcWriter;
 import org.apache.geode.connectors.jdbc.internal.JdbcConnectorService;
 import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
 import org.apache.geode.management.cli.CliFunction;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult.StatusState;
 
 
 @Experimental
@@ -27,17 +37,48 @@ public class DestroyMappingFunction extends CliFunction<String> {
 
   @Override
   public CliFunctionResult executeFunction(FunctionContext<String> context) {
+    Cache cache = context.getCache();
     JdbcConnectorService service = FunctionContextArgumentProvider.getJdbcConnectorService(context);
     String regionName = context.getArguments();
     String member = context.getMemberName();
     RegionMapping mapping = service.getMappingForRegion(regionName);
     if (mapping != null) {
+      cleanupRegionAndQueue(cache, regionName);
       service.destroyRegionMapping(regionName);
       String message = "Destroyed region mapping for region " + regionName + " on " + member;
-      return new CliFunctionResult(member, true, message);
+      return new CliFunctionResult(member, StatusState.OK, message);
     } else {
       String message = "Region mapping for region \"" + regionName + "\" not found";
-      return new CliFunctionResult(member, false, message);
+      return new CliFunctionResult(member, StatusState.ERROR, message);
+    }
+  }
+
+  private void cleanupRegionAndQueue(Cache cache, String regionName) {
+    String queueName = CreateMappingCommand.createAsyncEventQueueName(regionName);
+    InternalAsyncEventQueue queue = (InternalAsyncEventQueue) cache.getAsyncEventQueue(queueName);
+
+    if (queue != null) {
+      queue.stop();
+    }
+
+    Region<?, ?> region = cache.getRegion(regionName);
+    if (region != null) {
+      CacheLoader<?, ?> loader = region.getAttributes().getCacheLoader();
+      if (loader instanceof JdbcLoader) {
+        region.getAttributesMutator().setCacheLoader(null);
+      }
+      CacheWriter<?, ?> writer = region.getAttributes().getCacheWriter();
+      if (writer instanceof JdbcWriter) {
+        region.getAttributesMutator().setCacheWriter(null);
+      }
+      Set<String> queueIds = region.getAttributes().getAsyncEventQueueIds();
+      if (queueIds.contains(queueName)) {
+        region.getAttributesMutator().removeAsyncEventQueueId(queueName);
+      }
+    }
+
+    if (queue != null) {
+      queue.destroy();
     }
   }
 }
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandFunctionTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandFunctionTest.java
index 8525280..4913eb8 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandFunctionTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandFunctionTest.java
@@ -16,20 +16,31 @@ package org.apache.geode.connectors.jdbc.internal.cli;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.io.Serializable;
+import java.util.Collections;
 
 import org.apache.commons.lang3.SerializationUtils;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
+import org.apache.geode.cache.AttributesMutator;
+import org.apache.geode.cache.CacheLoader;
+import org.apache.geode.cache.CacheWriter;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionAttributes;
+import org.apache.geode.cache.asyncqueue.internal.InternalAsyncEventQueue;
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.cache.execute.ResultSender;
+import org.apache.geode.connectors.jdbc.JdbcLoader;
+import org.apache.geode.connectors.jdbc.JdbcWriter;
 import org.apache.geode.connectors.jdbc.internal.JdbcConnectorService;
 import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
 import org.apache.geode.distributed.DistributedMember;
@@ -46,11 +57,23 @@ public class DestroyMappingCommandFunctionTest {
   private ResultSender<Object> resultSender;
   private RegionMapping mapping;
   private JdbcConnectorService service;
+  private InternalCache cache;
+  private Region region;
+  private RegionAttributes regionAttributes;
+  private AttributesMutator regionMutator;
 
   @Before
   public void setUp() {
-    InternalCache cache = mock(InternalCache.class);
+    cache = mock(InternalCache.class);
+    region = mock(Region.class);
+    when(region.getName()).thenReturn(regionName);
+    regionAttributes = mock(RegionAttributes.class);
+    regionMutator = mock(AttributesMutator.class);
+    when(region.getAttributes()).thenReturn(regionAttributes);
+    when(region.getAttributesMutator()).thenReturn(regionMutator);
+    when(cache.getRegion(regionName)).thenReturn(region);
     context = mock(FunctionContext.class);
+    when(context.getMemberName()).thenReturn("myMemberName");
     DistributedMember member = mock(DistributedMember.class);
     resultSender = mock(ResultSender.class);
     service = mock(JdbcConnectorService.class);
@@ -88,23 +111,106 @@ public class DestroyMappingCommandFunctionTest {
   }
 
   @Test
-  public void destroyRegionMappingReturnsTrueIfConnectionDestroyed() {
+  public void executeFunctionGivenExistingMappingReturnsTrue() {
     when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
     CliFunctionResult result = function.executeFunction(context);
+
     assertThat(result.isSuccessful()).isTrue();
+    assertThat(result.toString())
+        .contains("Destroyed region mapping for region " + regionName + " on myMemberName");
   }
 
   @Test
-  public void destroyRegionMappingReturnsFalseIfMappingDoesNotExist() {
+  public void executeFunctionGivenNoExistingMappingReturnsFalse() {
     CliFunctionResult result = function.executeFunction(context);
+
     assertThat(result.isSuccessful()).isFalse();
+    assertThat(result.toString())
+        .contains("Region mapping for region \"" + regionName + "\" not found");
   }
 
   @Test
-  public void executeDestroysIfMappingFound() {
+  public void executeFunctionGivenARegionWithJdbcLoaderRemovesTheLoader() {
+    when(regionAttributes.getCacheLoader()).thenReturn(mock(JdbcLoader.class));
     when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
 
-    function.execute(context);
+    function.executeFunction(context);
+
+    verify(regionMutator, times(1)).setCacheLoader(null);
+  }
+
+  @Test
+  public void executeFunctionGivenARegionWithNonJdbcLoaderDoesNotRemoveTheLoader() {
+    when(regionAttributes.getCacheLoader()).thenReturn(mock(CacheLoader.class));
+    when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
+    function.executeFunction(context);
+
+    verify(regionMutator, never()).setCacheLoader(null);
+  }
+
+  @Test
+  public void executeFunctionGivenARegionWithJdbcWriterRemovesTheWriter() {
+    when(regionAttributes.getCacheWriter()).thenReturn(mock(JdbcWriter.class));
+    when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
+    function.executeFunction(context);
+
+    verify(regionMutator, times(1)).setCacheWriter(null);
+  }
+
+  @Test
+  public void executeFunctionGivenARegionWithNonJdbcWriterDoesNotRemoveTheWriter() {
+    when(regionAttributes.getCacheWriter()).thenReturn(mock(CacheWriter.class));
+    when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
+    function.executeFunction(context);
+
+    verify(regionMutator, never()).setCacheWriter(null);
+  }
+
+  @Test
+  public void executeFunctionGivenARegionWithJdbcAsyncEventQueueRemovesTheQueueName() {
+    String queueName = CreateMappingCommand.createAsyncEventQueueName(regionName);
+    when(regionAttributes.getAsyncEventQueueIds()).thenReturn(Collections.singleton(queueName));
+    when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
+    function.executeFunction(context);
+
+    verify(regionMutator, times(1)).removeAsyncEventQueueId(queueName);
+  }
+
+  @Test
+  public void executeFunctionGivenARegionWithNonJdbcAsyncEventQueueDoesNotRemoveTheQueueName() {
+    when(regionAttributes.getAsyncEventQueueIds())
+        .thenReturn(Collections.singleton("nonJdbcQueue"));
+    when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
+    function.executeFunction(context);
+
+    verify(regionMutator, never()).removeAsyncEventQueueId(any());
+  }
+
+  @Test
+  public void executeFunctionGivenAJdbcAsyncWriterQueueRemovesTheQueue() {
+    String queueName = CreateMappingCommand.createAsyncEventQueueName(regionName);
+    InternalAsyncEventQueue myQueue = mock(InternalAsyncEventQueue.class);
+    when(cache.getAsyncEventQueue(queueName)).thenReturn(myQueue);
+
+    when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
+    function.executeFunction(context);
+
+    verify(myQueue, times(1)).stop();
+    verify(myQueue, times(1)).destroy();
+  }
+
+  @Test
+  public void executeFunctionGivenExistingMappingCallsDestroyRegionMapping() {
+    when(service.getMappingForRegion(eq(regionName))).thenReturn(mapping);
+
+    function.executeFunction(context);
 
     verify(service, times(1)).destroyRegionMapping(eq(regionName));
   }