Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 6B701200C40 for ; Thu, 23 Mar 2017 18:53:24 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 69798160B68; Thu, 23 Mar 2017 17:53:24 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 3F497160B83 for ; Thu, 23 Mar 2017 18:53:22 +0100 (CET) Received: (qmail 72358 invoked by uid 500); 23 Mar 2017 17:53:21 -0000 Mailing-List: contact commits-help@geode.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.apache.org Delivered-To: mailing list commits@geode.apache.org Received: (qmail 72341 invoked by uid 99); 23 Mar 2017 17:53:21 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 23 Mar 2017 17:53:21 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 0F311DFFF0; Thu, 23 Mar 2017 17:53:21 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: boglesby@apache.org To: commits@geode.apache.org Date: Thu, 23 Mar 2017 17:53:22 -0000 Message-Id: <4fe3373b37b44fccbb6f7f196fa3cd91@git.apache.org> In-Reply-To: <6a3ef519f25a4f57854f4b1669ed3476@git.apache.org> References: <6a3ef519f25a4f57854f4b1669ed3476@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [2/2] geode git commit: GEODE-2404: Added gfsh support for destroying a lucene index archived-at: Thu, 23 Mar 2017 17:53:24 -0000 GEODE-2404: Added gfsh support for destroying a lucene index Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/b89427fa Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/b89427fa Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/b89427fa Branch: refs/heads/develop Commit: b89427fad1363af7ae5ae1a329aba34345329b44 Parents: 5ed0b4d Author: Barry Oglesby Authored: Thu Mar 16 18:25:03 2017 -0700 Committer: Barry Oglesby Committed: Wed Mar 22 17:53:30 2017 -0700 ---------------------------------------------------------------------- .../java/org/apache/geode/internal/Version.java | 9 +- .../geode/internal/cache/GemFireCacheImpl.java | 4 + .../cache/tier/sockets/CommandInitializer.java | 7 +- .../geode/internal/i18n/LocalizedStrings.java | 8 +- .../configuration/domain/XmlEntity.java | 85 +++++++++- .../internal/configuration/utils/XmlUtils.java | 8 +- .../RollingUpgrade2DUnitTest.java | 119 +++++++++++++ .../sanctionedDataSerializables.txt | 8 +- .../internal/LuceneIndexCreationProfile.java | 7 +- .../lucene/internal/LuceneRegionListener.java | 110 ++++++++++++ .../lucene/internal/LuceneServiceImpl.java | 126 +++++++------- .../lucene/internal/cli/LuceneCliStrings.java | 11 +- .../internal/cli/LuceneDestroyIndexInfo.java | 38 +++++ .../internal/cli/LuceneIndexCommands.java | 158 ++++++++++++----- .../functions/LuceneCreateIndexFunction.java | 2 +- .../functions/LuceneDestroyIndexFunction.java | 33 +++- .../cli/LuceneIndexCommandsDUnitTest.java | 114 ++++++------- .../cli/LuceneIndexCommandsJUnitTest.java | 168 ++++++++++++++++--- .../LuceneDestroyIndexFunctionJUnitTest.java | 122 ++++++++++++-- .../LuceneClusterConfigurationDUnitTest.java | 149 ++-------------- 20 files changed, 906 insertions(+), 380 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/main/java/org/apache/geode/internal/Version.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/Version.java b/geode-core/src/main/java/org/apache/geode/internal/Version.java index 0f64e72..288d104 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/Version.java +++ b/geode-core/src/main/java/org/apache/geode/internal/Version.java @@ -59,7 +59,7 @@ public final class Version implements Comparable { /** byte used as ordinal to represent this Version */ private final short ordinal; - public static final int HIGHEST_VERSION = 50; + public static final int HIGHEST_VERSION = 55; private static final Version[] VALUES = new Version[HIGHEST_VERSION + 1]; @@ -180,7 +180,12 @@ public final class Version implements Comparable { public static final Version GFE_90 = new Version("GFE", "9.0", (byte) 9, (byte) 0, (byte) 0, (byte) 0, GFE_90_ORDINAL); - private static final byte GFE_91_ORDINAL = 50; + private static final byte GEODE_110_ORDINAL = 50; + + public static final Version GEODE_110 = + new Version("GEODE", "1.1.0", (byte) 9, (byte) 0, (byte) 1, (byte) 0, GEODE_110_ORDINAL); + + private static final byte GFE_91_ORDINAL = 55; public static final Version GFE_91 = new Version("GFE", "9.1", (byte) 9, (byte) 1, (byte) 0, (byte) 0, GFE_91_ORDINAL); http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java index fcf7a2a..1575517 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java @@ -3886,6 +3886,10 @@ public class GemFireCacheImpl this.regionListeners.remove(l); } + public Set getRegionListeners() { + return Collections.unmodifiableSet(this.regionListeners); + } + @SuppressWarnings("unchecked") public T getService(Class clazz) { return (T) services.get(clazz); http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java index 2f6b963..71586a0 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java @@ -331,8 +331,13 @@ public class CommandInitializer { gfe90Commands.put(MessageType.QUERY, QueryGeode10.getCommand()); } { + Map geode110Commands = new HashMap(); + geode110Commands.putAll(ALL_COMMANDS.get(Version.GFE_90)); + ALL_COMMANDS.put(Version.GEODE_110, geode110Commands); + } + { Map gfe91Commands = new HashMap(); - gfe91Commands.putAll(ALL_COMMANDS.get(Version.GFE_90)); + gfe91Commands.putAll(ALL_COMMANDS.get(Version.GEODE_110)); ALL_COMMANDS.put(Version.GFE_91, gfe91Commands); } http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java b/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java index 1d288ec..499bf8e 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java +++ b/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java @@ -7669,14 +7669,16 @@ public class LocalizedStrings { "Caught the following exception attempting waitUntilFlushed and will return:"); public static final StringId LuceneService_INDEX_0_NOT_FOUND_IN_REGION_1 = - new StringId(6651, "Lucene index {0} was not found in region {1}."); - public static final StringId LuceneService_DESTROYED_INDEX_0_FROM_REGION_1 = - new StringId(6652, "Destroyed Lucene index {0} from region {1}."); + new StringId(6651, "Lucene index {0} was not found in region {1}"); + public static final StringId LuceneService_DESTROYED_INDEX_0_FROM_1_REGION_2 = + new StringId(6652, "Destroyed Lucene index {1} from {0} region {2}"); public static final StringId PoolFactoryImpl_CAUGHT_EXCEPTION_ATTEMPTING_TO_ADD_REMOTE_LOCATOR_0 = new StringId(6653, "Caught the following exception attempting to add remote locator {0}. The locator will be ignored."); + public static final StringId LuceneService_NO_INDEXES_WERE_FOUND_IN_REGION_0 = + new StringId(6654, "No Lucene indexes were found in region {0}"); /** Testing strings, messageId 90000-99999 **/ /** http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java index a009fef..f740dde 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java @@ -31,13 +31,14 @@ import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.xpath.XPathExpressionException; import org.apache.geode.internal.Assert; +import org.apache.geode.internal.Version; +import org.apache.geode.internal.VersionedDataSerializable; import org.apache.logging.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import org.apache.geode.DataSerializable; import org.apache.geode.DataSerializer; import org.apache.geode.InternalGemFireError; import org.apache.geode.cache.Cache; @@ -54,7 +55,7 @@ import org.apache.geode.management.internal.configuration.utils.XmlUtils.XPathCo * * */ -public class XmlEntity implements DataSerializable { +public class XmlEntity implements VersionedDataSerializable { private static final long serialVersionUID = 1L; private static final Logger logger = LogService.getLogger(); @@ -69,6 +70,10 @@ public class XmlEntity implements DataSerializable { private String namespace = CacheXml.GEODE_NAMESPACE; + private String childPrefix; + + private String childNamespace; + /** * Default constructor for serialization only. * @@ -113,25 +118,56 @@ public class XmlEntity implements DataSerializable { // TODO consider parent as nested XmlEntity type. this.parentType = parentType; this.type = childType; + initializeSearchString(parentKey, parentValue, this.prefix, childKey, childValue); + + // no init(); + } + + /**** + * Construct a new XmlEntity while creating Xml from the cache using the element which has + * attributes matching those given + * + * @param parentType Parent type of the XML element to search for. Should be one of the constants + * from the {@link CacheXml} class. For example, CacheXml.REGION. + * + * @param parentKey Identifier for the parent elements such "name/id" + * @param parentValue Value of the identifier + * @param childPrefix Namespace prefix for the child element such as "lucene" + * @param childNamespace Namespace for the child element such as + * "http://geode.apache.org/schema/lucene" + * @param childType Child type of the XML element to search for within the parent . Should be one + * of the constants from the {@link CacheXml} class. For example, CacheXml.INDEX. + * @param childKey Identifier for the child element such as "name/id" + * @param childValue Value of the child element identifier + */ + public XmlEntity(final String parentType, final String parentKey, final String parentValue, + final String childPrefix, final String childNamespace, final String childType, + final String childKey, final String childValue) { + // Note: Do not invoke init + this.parentType = parentType; + this.type = childType; + this.childPrefix = childPrefix; + this.childNamespace = childNamespace; + initializeSearchString(parentKey, parentValue, childPrefix, childKey, childValue); + } + private void initializeSearchString(final String parentKey, final String parentValue, + final String childPrefix, final String childKey, final String childValue) { StringBuffer sb = new StringBuffer(); - sb.append("//").append(prefix).append(':').append(parentType); + sb.append("//").append(this.prefix).append(':').append(this.parentType); if (!StringUtils.isBlank(parentKey) && !StringUtils.isBlank(parentValue)) { sb.append("[@").append(parentKey).append("='").append(parentValue).append("']"); } - sb.append("/").append(prefix).append(':').append(childType); + sb.append("/").append(childPrefix).append(':').append(this.type); if (!StringUtils.isBlank(childKey) && !StringUtils.isBlank(childValue)) { sb.append("[@").append(childKey).append("='").append(childValue).append("']"); } this.searchString = sb.toString(); - - // no init(); } - /** * Initialize new instances. Called from {@link #XmlEntity(String, String, String)} and * {@link XmlEntityBuilder#build()}. @@ -312,6 +348,24 @@ public class XmlEntity implements DataSerializable { return prefix; } + /** + * Gets the prefix for the child element. + * + * @return XML element prefix for the child element + */ + public String getChildPrefix() { + return this.childPrefix; + } + + /** + * Gets the namespace for the child element. + * + * @return XML element namespace for the child element + */ + public String getChildNamespace() { + return this.childNamespace; + } + @Override public String toString() { return "XmlEntity [namespace=" + namespace + ", type=" + this.type + ", attributes=" @@ -356,6 +410,12 @@ public class XmlEntity implements DataSerializable { @Override public void toData(DataOutput out) throws IOException { + toDataPre_GFE_9_1_0_0(out); + DataSerializer.writeString(this.childPrefix, out); + DataSerializer.writeString(this.childNamespace, out); + } + + public void toDataPre_GFE_9_1_0_0(DataOutput out) throws IOException { DataSerializer.writeString(this.type, out); DataSerializer.writeObject(this.attributes, out); DataSerializer.writeString(this.xmlDefinition, out); @@ -366,6 +426,12 @@ public class XmlEntity implements DataSerializable { @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { + fromDataPre_GFE_9_1_0_0(in); + this.childPrefix = DataSerializer.readString(in); + this.childNamespace = DataSerializer.readString(in); + } + + public void fromDataPre_GFE_9_1_0_0(DataInput in) throws IOException, ClassNotFoundException { this.type = DataSerializer.readString(in); this.attributes = DataSerializer.readObject(in); this.xmlDefinition = DataSerializer.readString(in); @@ -384,6 +450,11 @@ public class XmlEntity implements DataSerializable { return new XmlEntityBuilder(); } + @Override + public Version[] getSerializationVersions() { + return new Version[] {Version.GFE_91}; + } + /** * Builder for {@link XmlEntity}. Default values are as described in {@link XmlEntity}. * http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/XmlUtils.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/XmlUtils.java b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/XmlUtils.java index 2471c83..a6fafaa 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/XmlUtils.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/XmlUtils.java @@ -355,8 +355,12 @@ public class XmlUtils { */ public static NodeList getNodes(Document doc, XmlEntity xmlEntity) throws XPathExpressionException { - return query(doc, xmlEntity.getSearchString(), - new XPathContext(xmlEntity.getPrefix(), xmlEntity.getNamespace())); + XPathContext context = new XPathContext(); + context.addNamespace(xmlEntity.getPrefix(), xmlEntity.getNamespace()); + if (xmlEntity.getChildPrefix() != null) { + context.addNamespace(xmlEntity.getChildPrefix(), xmlEntity.getChildNamespace()); + } + return query(doc, xmlEntity.getSearchString(), context); } /** http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgrade2DUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgrade2DUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgrade2DUnitTest.java index 54c6d94..beb3a9a 100755 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgrade2DUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgrade2DUnitTest.java @@ -35,6 +35,12 @@ import org.apache.geode.cache.client.ClientRegionFactory; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.control.RebalanceOperation; import org.apache.geode.cache.control.RebalanceResults; +import org.apache.geode.cache.execute.Execution; +import org.apache.geode.cache.execute.Function; +import org.apache.geode.cache.execute.FunctionContext; +import org.apache.geode.cache.execute.FunctionException; +import org.apache.geode.cache.execute.FunctionService; +import org.apache.geode.cache.execute.ResultCollector; import org.apache.geode.cache.query.Index; import org.apache.geode.cache.query.IndexCreationException; import org.apache.geode.cache.query.MultiIndexCreationException; @@ -43,6 +49,7 @@ import org.apache.geode.cache.query.QueryService; import org.apache.geode.cache.query.SelectResults; import org.apache.geode.cache.server.CacheServer; import org.apache.geode.cache30.CacheSerializableRunnable; +import org.apache.geode.distributed.DistributedMember; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.distributed.Locator; import org.apache.geode.distributed.internal.DistributionConfig; @@ -89,9 +96,12 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Properties; +import java.util.Set; /** * This test will not run properly in eclipse at this point due to having to bounce vms Currently, @@ -1006,6 +1016,63 @@ public class RollingUpgrade2DUnitTest extends JUnit4DistributedTestCase { + @Test + // This test verifies that an XmlEntity created in the current version serializes properly to + // previous versions and vice versa. + public void testVerifyXmlEntity() throws Exception { + doTestVerifyXmlEntity(oldVersion); + } + + private void doTestVerifyXmlEntity(String oldVersion) throws Exception { + final Host host = Host.getHost(0); + VM oldLocator = host.getVM(oldVersion, 0); + VM oldServer = host.getVM(oldVersion, 1); + VM currentServer1 = host.getVM(2); + VM currentServer2 = host.getVM(3); + + int[] locatorPorts = AvailablePortHelper.getRandomAvailableTCPPorts(1); + String hostName = NetworkUtils.getServerHostName(host); + String locatorsString = getLocatorString(locatorPorts); + DistributedTestUtils.deleteLocatorStateFile(locatorPorts); + + try { + // Start locator + oldLocator.invoke(invokeStartLocator(hostName, locatorPorts[0], getTestMethodName(), + getLocatorPropertiesPre91(locatorsString))); + + // Start servers + invokeRunnableInVMs(invokeCreateCache(getSystemProperties(locatorPorts)), oldServer, + currentServer1, currentServer2); + currentServer1.invoke(invokeAssertVersion(Version.CURRENT_ORDINAL)); + currentServer2.invoke(invokeAssertVersion(Version.CURRENT_ORDINAL)); + + // Get DistributedMembers of the servers + DistributedMember oldServerMember = oldServer.invoke(() -> getDistributedMember()); + DistributedMember currentServer1Member = currentServer1.invoke(() -> getDistributedMember()); + DistributedMember currentServer2Member = currentServer2.invoke(() -> getDistributedMember()); + + // Register function in all servers + Function function = new GetDataSerializableFunction(); + invokeRunnableInVMs(invokeRegisterFunction(function), oldServer, currentServer1, + currentServer2); + + // Execute the function in the old server against the other servers to verify the + // DataSerializable can be serialized from a newer server to an older one. + oldServer.invoke(() -> executeFunctionAndVerify(function.getId(), + "org.apache.geode.management.internal.configuration.domain.XmlEntity", + currentServer1Member, currentServer2Member)); + + // Execute the function in a new server against the other servers to verify the + // DataSerializable can be serialized from an older server to a newer one. + currentServer1.invoke(() -> executeFunctionAndVerify(function.getId(), + "org.apache.geode.management.internal.configuration.domain.XmlEntity", oldServerMember, + currentServer2Member)); + } finally { + invokeRunnableInVMs(true, invokeStopLocator(), oldLocator); + invokeRunnableInVMs(true, invokeCloseCache(), oldServer, currentServer1, currentServer2); + } + } + // ******** TEST HELPER METHODS ********/ private void putAndVerify(String objectType, VM putter, String regionName, int start, int end, VM check1, VM check2, VM check3) throws Exception { @@ -1090,6 +1157,19 @@ public class RollingUpgrade2DUnitTest extends JUnit4DistributedTestCase { } + private void executeFunctionAndVerify(String functionId, String dsClassName, + DistributedMember... members) { + Set membersSet = new HashSet<>(); + Collections.addAll(membersSet, members); + Execution execution = FunctionService.onMembers(membersSet).withArgs(dsClassName); + ResultCollector rc = execution.execute(functionId); + List result = (List) rc.getResult(); + assertEquals(membersSet.size(), result.size()); + for (Iterator i = result.iterator(); i.hasNext();) { + assertTrue(i.next().getClass().getName().equals(dsClassName)); + } + } + private void query(String queryString, int numExpectedResults, VM... vms) { for (VM vm : vms) { vm.invoke(invokeAssertQueryResults(queryString, numExpectedResults)); @@ -1525,6 +1605,18 @@ public class RollingUpgrade2DUnitTest extends JUnit4DistributedTestCase { }; } + private CacheSerializableRunnable invokeRegisterFunction(final Function function) { + return new CacheSerializableRunnable("invokeRegisterFunction") { + public void run2() { + try { + registerFunction(function, RollingUpgrade2DUnitTest.cache); + } catch (Exception e) { + fail("Error registering function ", e); + } + } + }; + } + public void deleteDiskStores() throws Exception { try { FileUtils.deleteDirectory(new File(diskDir).getAbsoluteFile()); @@ -1568,6 +1660,10 @@ public class RollingUpgrade2DUnitTest extends JUnit4DistributedTestCase { return cache.getRegion(regionName); } + public static DistributedMember getDistributedMember() { + return cache.getDistributedSystem().getDistributedMember(); + } + public static boolean assertEntriesCorrect(GemFireCache cache, String regionName, int start, int end) throws Exception { assertRegionExists(cache, regionName); @@ -1731,6 +1827,10 @@ public class RollingUpgrade2DUnitTest extends JUnit4DistributedTestCase { } } + public static void registerFunction(Function function, GemFireCache cache) { + FunctionService.registerFunction(function); + } + public static void stopCacheServers(GemFireCache cache) throws Exception { List servers = ((Cache) cache).getCacheServers(); for (CacheServer server : servers) { @@ -1813,5 +1913,24 @@ public class RollingUpgrade2DUnitTest extends JUnit4DistributedTestCase { return Host.getHost(0).getHostName(); } + public static class GetDataSerializableFunction implements Function { + + @Override + public void execute(FunctionContext context) { + String dsClassName = (String) context.getArguments(); + try { + Class aClass = Thread.currentThread().getContextClassLoader().loadClass(dsClassName); + Constructor constructor = aClass.getConstructor(new Class[0]); + context.getResultSender().lastResult(constructor.newInstance(new Object[0])); + } catch (Exception e) { + throw new FunctionException(e); + } + } + + @Override + public String getId() { + return GetDataSerializableFunction.class.getName(); + } + } } http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt ---------------------------------------------------------------------- diff --git a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt index 0a791c4..2f5a5cd 100644 --- a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt +++ b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt @@ -2078,9 +2078,11 @@ org/apache/geode/management/internal/configuration/domain/ConfigurationChangeRes fromData,31,2a2bb80019b6001ab500022a2bb8001bb500032a2bb8001cc0001db50004b1 toData,28,2ab40002b800152bb800162ab400032bb800172ab400042bb80018b1 -org/apache/geode/management/internal/configuration/domain/XmlEntity,2 -fromData,52,2a2bb80065b500072a2bb80066c00067b500042a2bb80065b500032a2bb80065b5001c2a2bb80065b500062a2bb80065b50005b1 -toData,49,2ab400072bb800632ab400042bb800642ab400032bb800632ab4001c2bb800632ab400062bb800632ab400052bb80063b1 +org/apache/geode/management/internal/configuration/domain/XmlEntity,4 +fromData,22,2a2bb600692a2bb8006ab500122a2bb8006ab50013b1 +fromDataPre_GFE_9_1_0_0,52,2a2bb8006ab500072a2bb8006bc0006cb500042a2bb8006ab500032a2bb8006ab5001f2a2bb8006ab500062a2bb8006ab50005b1 +toData,22,2a2bb600662ab400122bb800672ab400132bb80067b1 +toDataPre_GFE_9_1_0_0,49,2ab400072bb800672ab400042bb800682ab400032bb800672ab4001f2bb800672ab400062bb800672ab400052bb80067b1 org/apache/geode/management/internal/configuration/messages/ConfigurationRequest,2 fromData,73,2a2bb900130100b500052bb9001401003dbb000259b700034e1c9e001f03360415041ca200162d2bb900150100b90009020057840401a7ffea2a2db500042a2bb900140100b50007b1 http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexCreationProfile.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexCreationProfile.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexCreationProfile.java index 1c20209..0e28bab 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexCreationProfile.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneIndexCreationProfile.java @@ -158,9 +158,10 @@ public class LuceneIndexCreationProfile implements CacheServiceProfile, DataSeri public String toString() { return new StringBuilder().append(getClass().getSimpleName()).append("[").append("indexName=") - .append(this.indexName).append("; fieldNames=").append(Arrays.toString(this.fieldNames)) - .append("; analyzerClass=").append(this.analyzerClass).append("; fieldAnalyzers=") - .append(this.fieldAnalyzers).append("]").toString(); + .append(this.indexName).append("; regionPath=").append(this.regionPath) + .append("; fieldNames=").append(Arrays.toString(this.fieldNames)).append("; analyzerClass=") + .append(this.analyzerClass).append("; fieldAnalyzers=").append(this.fieldAnalyzers) + .append("]").toString(); } public String getRegionPath() { http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneRegionListener.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneRegionListener.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneRegionListener.java new file mode 100644 index 0000000..c2109e4 --- /dev/null +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneRegionListener.java @@ -0,0 +1,110 @@ +/* + * 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.lucene.internal; + +import org.apache.geode.cache.AttributesFactory; +import org.apache.geode.cache.EvictionAlgorithm; +import org.apache.geode.cache.EvictionAttributes; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionAttributes; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.internal.cache.InternalRegionArguments; +import org.apache.geode.internal.cache.RegionListener; +import org.apache.lucene.analysis.Analyzer; + +import java.util.Map; + +public class LuceneRegionListener implements RegionListener { + + private final LuceneServiceImpl service; + + private final GemFireCacheImpl cache; + + private final String indexName; + + private final String regionPath; + + private final Analyzer analyzer; + + private final Map fieldAnalyzers; + + private final String[] fields; + + public LuceneRegionListener(LuceneServiceImpl service, GemFireCacheImpl cache, String indexName, + String regionPath, String[] fields, Analyzer analyzer, Map fieldAnalyzers) { + this.service = service; + this.cache = cache; + this.indexName = indexName; + this.regionPath = regionPath; + this.fields = fields; + this.analyzer = analyzer; + this.fieldAnalyzers = fieldAnalyzers; + } + + public String getRegionPath() { + return this.regionPath; + } + + public String getIndexName() { + return this.indexName; + } + + @Override + public RegionAttributes beforeCreate(Region parent, String regionName, RegionAttributes attrs, + InternalRegionArguments internalRegionArgs) { + RegionAttributes updatedRA = attrs; + String path = parent == null ? "/" + regionName : parent.getFullPath() + "/" + regionName; + + if (path.equals(this.regionPath)) { + + if (!attrs.getDataPolicy().withPartitioning()) { + // replicated region + throw new UnsupportedOperationException( + "Lucene indexes on replicated regions are not supported"); + } + + // For now we cannot support eviction with local destroy. + // Eviction with overflow to disk still needs to be supported + EvictionAttributes evictionAttributes = attrs.getEvictionAttributes(); + EvictionAlgorithm evictionAlgorithm = evictionAttributes.getAlgorithm(); + if (evictionAlgorithm != EvictionAlgorithm.NONE + && evictionAttributes.getAction().isLocalDestroy()) { + throw new UnsupportedOperationException( + "Lucene indexes on regions with eviction and action local destroy are not supported"); + } + + String aeqId = LuceneServiceImpl.getUniqueIndexName(this.indexName, this.regionPath); + if (!attrs.getAsyncEventQueueIds().contains(aeqId)) { + AttributesFactory af = new AttributesFactory(attrs); + af.addAsyncEventQueueId(aeqId); + updatedRA = af.create(); + } + + // Add index creation profile + internalRegionArgs.addCacheServiceProfile(new LuceneIndexCreationProfile(this.indexName, + this.regionPath, this.fields, this.analyzer, this.fieldAnalyzers)); + } + return updatedRA; + } + + @Override + public void afterCreate(Region region) { + if (region.getFullPath().equals(this.regionPath)) { + this.service.afterDataRegionCreated(this.indexName, this.analyzer, this.regionPath, + this.fieldAnalyzers, this.fields); + this.cache.removeRegionListener(this); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java index 41d2991..dbe24ff 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/LuceneServiceImpl.java @@ -160,57 +160,10 @@ public class LuceneServiceImpl implements InternalLuceneService { throw new IllegalStateException("The lucene index must be created before region"); } - final String dataRegionPath = regionPath; - cache.addRegionListener(new RegionListener() { - @Override - public RegionAttributes beforeCreate(Region parent, String regionName, RegionAttributes attrs, - InternalRegionArguments internalRegionArgs) { - RegionAttributes updatedRA = attrs; - String path = parent == null ? "/" + regionName : parent.getFullPath() + "/" + regionName; - - if (path.equals(dataRegionPath)) { - - if (!attrs.getDataPolicy().withPartitioning()) { - // replicated region - throw new UnsupportedOperationException( - "Lucene indexes on replicated regions are not supported"); - } - - // For now we cannot support eviction with local destroy. - // Eviction with overflow to disk still needs to be supported - EvictionAttributes evictionAttributes = attrs.getEvictionAttributes(); - EvictionAlgorithm evictionAlgorithm = evictionAttributes.getAlgorithm(); - if (evictionAlgorithm != EvictionAlgorithm.NONE - && evictionAttributes.getAction().isLocalDestroy()) { - throw new UnsupportedOperationException( - "Lucene indexes on regions with eviction and action local destroy are not supported"); - } - - String aeqId = LuceneServiceImpl.getUniqueIndexName(indexName, dataRegionPath); - if (!attrs.getAsyncEventQueueIds().contains(aeqId)) { - AttributesFactory af = new AttributesFactory(attrs); - af.addAsyncEventQueueId(aeqId); - updatedRA = af.create(); - } - - // Add index creation profile - internalRegionArgs.addCacheServiceProfile(new LuceneIndexCreationProfile(indexName, - dataRegionPath, fields, analyzer, fieldAnalyzers)); - } - return updatedRA; - } - - @Override - public void afterCreate(Region region) { - if (region.getFullPath().equals(dataRegionPath)) { - afterDataRegionCreated(indexName, analyzer, dataRegionPath, fieldAnalyzers, fields); - cache.removeRegionListener(this); - } - } - }); + cache.addRegionListener(new LuceneRegionListener(this, cache, indexName, regionPath, fields, + analyzer, fieldAnalyzers)); } - /** * Finish creating the lucene index after the data region is created . * @@ -273,14 +226,38 @@ public class LuceneServiceImpl implements InternalLuceneService { } LuceneIndexImpl indexImpl = (LuceneIndexImpl) getIndex(indexName, regionPath); if (indexImpl == null) { - throw new IllegalArgumentException( - LocalizedStrings.LuceneService_INDEX_0_NOT_FOUND_IN_REGION_1.toLocalizedString(indexName, - regionPath)); + destroyDefinedIndex(indexName, regionPath); } else { indexImpl.destroy(initiator); removeFromIndexMap(indexImpl); - logger.info(LocalizedStrings.LuceneService_DESTROYED_INDEX_0_FROM_REGION_1 - .toLocalizedString(indexName, regionPath)); + logger.info(LocalizedStrings.LuceneService_DESTROYED_INDEX_0_FROM_1_REGION_2 + .toLocalizedString(indexName, "initialized", regionPath)); + } + } + + public void destroyDefinedIndex(String indexName, String regionPath) { + String uniqueIndexName = LuceneServiceImpl.getUniqueIndexName(indexName, regionPath); + if (definedIndexMap.containsKey(uniqueIndexName)) { + definedIndexMap.remove(uniqueIndexName); + RegionListener listenerToRemove = null; + for (RegionListener listener : cache.getRegionListeners()) { + if (listener instanceof LuceneRegionListener) { + LuceneRegionListener lrl = (LuceneRegionListener) listener; + if (lrl.getRegionPath().equals(regionPath) && lrl.getIndexName().equals(indexName)) { + listenerToRemove = lrl; + break; + } + } + } + if (listenerToRemove != null) { + cache.removeRegionListener(listenerToRemove); + } + logger.info(LocalizedStrings.LuceneService_DESTROYED_INDEX_0_FROM_1_REGION_2 + .toLocalizedString(indexName, "defined", regionPath)); + } else { + throw new IllegalArgumentException( + LocalizedStrings.LuceneService_INDEX_0_NOT_FOUND_IN_REGION_1.toLocalizedString(indexName, + regionPath)); } } @@ -301,10 +278,43 @@ public class LuceneServiceImpl implements InternalLuceneService { indexesToDestroy.add(indexImpl); } } - for (LuceneIndex index : indexesToDestroy) { - removeFromIndexMap(index); - logger.info(LocalizedStrings.LuceneService_DESTROYED_INDEX_0_FROM_REGION_1 - .toLocalizedString(index.getName(), regionPath)); + + // If list is empty throw an exception; otherwise iterate and destroy the defined index + if (indexesToDestroy.isEmpty()) { + throw new IllegalArgumentException( + LocalizedStrings.LuceneService_NO_INDEXES_WERE_FOUND_IN_REGION_0 + .toLocalizedString(regionPath)); + } else { + for (LuceneIndex index : indexesToDestroy) { + removeFromIndexMap(index); + logger.info(LocalizedStrings.LuceneService_DESTROYED_INDEX_0_FROM_1_REGION_2 + .toLocalizedString(index.getName(), "initialized", regionPath)); + } + } + } + + public void destroyDefinedIndexes(String regionPath) { + if (!regionPath.startsWith("/")) { + regionPath = "/" + regionPath; + } + + // Iterate the defined indexes to get the ones for the regionPath + List indexesToDestroy = new ArrayList<>(); + for (Map.Entry entry : definedIndexMap.entrySet()) { + if (entry.getValue().getRegionPath().equals(regionPath)) { + indexesToDestroy.add(entry.getValue()); + } + } + + // If list is empty throw an exception; otherwise iterate and destroy the defined index + if (indexesToDestroy.isEmpty()) { + throw new IllegalArgumentException( + LocalizedStrings.LuceneService_NO_INDEXES_WERE_FOUND_IN_REGION_0 + .toLocalizedString(regionPath)); + } else { + for (LuceneIndexCreationProfile profile : indexesToDestroy) { + destroyDefinedIndex(profile.getIndexName(), profile.getRegionPath()); + } } } http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneCliStrings.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneCliStrings.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneCliStrings.java index fbb70d2..d0a2999 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneCliStrings.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneCliStrings.java @@ -44,9 +44,6 @@ public class LuceneCliStrings { public static final String LUCENE_CREATE_INDEX__ANALYZER = "analyzer"; public static final String LUCENE_CREATE_INDEX__ANALYZER_HELP = "Type of the analyzer for each field."; - public static final String LUCENE_CREATE_INDEX__GROUP = "group"; - public static final String LUCENE_CREATE_INDEX__GROUP__HELP = - "Group of members in which the lucene index will be created."; public static final String CREATE_INDEX__SUCCESS__MSG = "Index successfully created with following details"; public static final String CREATE_INDEX__FAILURE__MSG = @@ -109,8 +106,8 @@ public class LuceneCliStrings { "Index cannot be empty."; public static final String LUCENE_DESTROY_INDEX__MSG__COULDNOT_FIND_MEMBERS_FOR_REGION_0 = "Could not find any members defining region {0}."; - public static final String LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FOR_REGION_0 = - "Successfully destroyed all lucene indexes for region {0}"; - public static final String LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FOR_REGION_1 = - "Successfully destroyed lucene index {0} for region {1}"; + public static final String LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FROM_REGION_0 = + "Successfully destroyed all lucene indexes from region {0}"; + public static final String LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FROM_REGION_1 = + "Successfully destroyed lucene index {0} from region {1}"; } http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneDestroyIndexInfo.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneDestroyIndexInfo.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneDestroyIndexInfo.java new file mode 100644 index 0000000..d839ce9 --- /dev/null +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneDestroyIndexInfo.java @@ -0,0 +1,38 @@ +/* + * 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.lucene.internal.cli; + +public class LuceneDestroyIndexInfo extends LuceneFunctionSerializable { + + private boolean definedDestroyOnly; + + public LuceneDestroyIndexInfo(final String indexName, final String regionPath) { + this(indexName, regionPath, false); + } + + public LuceneDestroyIndexInfo(final String indexName, final String regionPath, + boolean definedDestroyOnly) { + super(indexName, regionPath); + this.definedDestroyOnly = definedDestroyOnly; + } + + public void setDefinedDestroyOnly(boolean definedDestroyOnly) { + this.definedDestroyOnly = definedDestroyOnly; + } + + public boolean isDefinedDestroyOnly() { + return this.definedDestroyOnly; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommands.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommands.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommands.java index e2d85a6..3fa34e7 100755 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommands.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommands.java @@ -22,6 +22,7 @@ import org.apache.geode.cache.lucene.internal.cli.functions.*; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.internal.cache.execute.AbstractExecution; import org.apache.geode.internal.lang.StringUtils; +import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.security.IntegratedSecurityService; import org.apache.geode.internal.security.SecurityService; import org.apache.geode.management.cli.CliMetaData; @@ -44,6 +45,8 @@ import org.springframework.shell.core.annotation.CliAvailabilityIndicator; import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; +import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -173,13 +176,7 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER, mandatory = false, unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER_HELP) @CliMetaData( - valueSeparator = ",") final String[] analyzers, - - @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP, - optionContext = ConverterHint.MEMBERGROUP, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, - help = LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP__HELP) @CliMetaData( - valueSeparator = ",") final String[] groups) { + valueSeparator = ",") final String[] analyzers) { Result result = null; XmlEntity xmlEntity = null; @@ -189,7 +186,7 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { final Cache cache = getCache(); LuceneIndexInfo indexInfo = new LuceneIndexInfo(indexName, regionPath, fields, analyzers); final ResultCollector rc = - this.executeFunctionOnGroups(createIndexFunction, groups, indexInfo); + this.executeFunctionOnAllMembers(createIndexFunction, indexInfo); final List funcResults = (List) rc.getResult(); final TabularResultData tabularResult = ResultBuilder.createTabularResultData(); @@ -255,7 +252,7 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { protected List getIndexDetails(LuceneIndexInfo indexInfo) throws Exception { this.securityService.authorizeRegionManage(indexInfo.getRegionPath()); final ResultCollector rc = - this.executeFunctionOnGroups(describeIndexFunction, new String[] {}, indexInfo); + executeFunctionOnRegion(describeIndexFunction, indexInfo, true); final List funcResults = (List) rc.getResult(); return funcResults.stream().filter(indexDetails -> indexDetails != null) .collect(Collectors.toList()); @@ -318,7 +315,6 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { help = LuceneCliStrings.LUCENE_DESTROY_INDEX__HELP) @CliMetaData(shellOnly = false, relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA}) - @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ) public Result destroyIndex( @CliOption(key = LuceneCliStrings.LUCENE__INDEX_NAME, mandatory = false, help = LuceneCliStrings.LUCENE_DESTROY_INDEX__NAME__HELP) final String indexName, @@ -338,32 +334,16 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { this.securityService.authorizeRegionManage(regionPath); - Result result = null; + Result result; try { - LuceneIndexInfo indexInfo = new LuceneIndexInfo(indexName, regionPath); - ResultCollector rc = executeFunction(destroyIndexFunction, indexInfo, false); - List functionResults = (List) rc.getResult(); - CliFunctionResult cliFunctionResult = functionResults.get(0); - - final TabularResultData tabularResult = ResultBuilder.createTabularResultData(); - tabularResult.accumulate("Member", cliFunctionResult.getMemberIdOrName()); - if (cliFunctionResult.isSuccessful()) { - tabularResult.accumulate("Status", - indexName == null - ? CliStrings.format( - LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FOR_REGION_0, - new Object[] {regionPath}) - : CliStrings.format( - LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FOR_REGION_1, - new Object[] {indexName, regionPath})); - } else { - tabularResult.accumulate("Status", "Failed: " + cliFunctionResult.getMessage()); - } - result = ResultBuilder.buildResult(tabularResult); - if (cliFunctionResult.isSuccessful()) { + List accumulatedResults = new ArrayList<>(); + final XmlEntity xmlEntity = + executeDestroyIndexFunction(accumulatedResults, indexName, regionPath); + result = getDestroyIndexResult(accumulatedResults, indexName, regionPath); + if (xmlEntity != null) { persistClusterConfiguration(result, () -> { - // Update the xml entity (region entity) to remove the async event id(s) and index(es) - getSharedConfiguration().addXmlEntity((XmlEntity) cliFunctionResult.getXmlEntity(), null); + // Delete the xml entity to remove the index(es) in all groups + getSharedConfiguration().deleteXmlEntity(xmlEntity, null); }); } } catch (FunctionInvocationTargetException ignore) { @@ -375,6 +355,7 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { } catch (IllegalArgumentException e) { result = ResultBuilder.createInfoResult(e.getMessage()); } catch (Throwable t) { + t.printStackTrace(); SystemFailure.checkFailure(); getCache().getLogger().warning(LuceneCliStrings.LUCENE_DESTROY_INDEX__EXCEPTION_MESSAGE, t); result = ResultBuilder.createGemFireErrorResult(t.getMessage()); @@ -382,6 +363,91 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { return result; } + private XmlEntity executeDestroyIndexFunction(List accumulatedResults, + String indexName, String regionPath) { + // Destroy has three cases: + // + // - no members define the region + // In this case, send the request to all members to handle the case where the index has been + // created, but not the region + // + // - all members define the region + // In this case, send the request to one of the region members to destroy the index on all + // member + // + // - some members define the region; some don't + // In this case, send the request to one of the region members to destroy the index in all the + // region members. Then send the function to the remaining members to handle the case where + // the index has been created, but not the region + XmlEntity xmlEntity = null; + Cache cache = getCache(); + Set regionMembers = getRegionMembers(cache, regionPath); + Set normalMembers = getNormalMembers(cache); + LuceneDestroyIndexInfo indexInfo = new LuceneDestroyIndexInfo(indexName, regionPath); + ResultCollector rc; + if (regionMembers.isEmpty()) { + // Attempt to destroy the proxy index on all members + indexInfo.setDefinedDestroyOnly(true); + rc = executeFunction(destroyIndexFunction, indexInfo, normalMembers); + accumulatedResults.addAll((List) rc.getResult()); + } else { + // Attempt to destroy the index on a region member + indexInfo.setDefinedDestroyOnly(false); + Set singleMember = new HashSet<>(); + singleMember.add(regionMembers.iterator().next()); + rc = executeFunction(destroyIndexFunction, indexInfo, singleMember); + List cliFunctionResults = (List) rc.getResult(); + CliFunctionResult cliFunctionResult = cliFunctionResults.get(0); + xmlEntity = cliFunctionResult.getXmlEntity(); + for (DistributedMember regionMember : regionMembers) { + accumulatedResults.add(new CliFunctionResult(regionMember.getId(), + cliFunctionResult.isSuccessful(), cliFunctionResult.getMessage())); + } + // If that succeeds, destroy the proxy index(es) on all other members if necessary + if (cliFunctionResult.isSuccessful()) { + normalMembers.removeAll(regionMembers); + if (!normalMembers.isEmpty()) { + indexInfo.setDefinedDestroyOnly(true); + rc = executeFunction(destroyIndexFunction, indexInfo, normalMembers); + accumulatedResults.addAll((List) rc.getResult()); + } + } else { + // @todo Should dummy results be added to the accumulatedResults for the non-region + // members in the failed case + } + } + return xmlEntity; + } + + protected Set getRegionMembers(Cache cache, String regionPath) { + return CliUtil.getMembersForeRegionViaFunction(cache, regionPath, true); + } + + protected Set getNormalMembers(Cache cache) { + return CliUtil.getAllNormalMembers(cache); + } + + private Result getDestroyIndexResult(List cliFunctionResults, String indexName, + String regionPath) { + final TabularResultData tabularResult = ResultBuilder.createTabularResultData(); + for (CliFunctionResult cliFunctionResult : cliFunctionResults) { + tabularResult.accumulate("Member", cliFunctionResult.getMemberIdOrName()); + if (cliFunctionResult.isSuccessful()) { + tabularResult.accumulate("Status", + indexName == null + ? CliStrings.format( + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FROM_REGION_0, + new Object[] {regionPath}) + : CliStrings.format( + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FROM_REGION_1, + new Object[] {indexName, regionPath})); + } else { + tabularResult.accumulate("Status", cliFunctionResult.getMessage()); + } + } + return ResultBuilder.buildResult(tabularResult); + } + private Result displayResults(int pageSize, boolean keysOnly) throws Exception { if (searchResults.size() == 0) { return ResultBuilder @@ -492,23 +558,18 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { return ResultBuilder.buildResult(data); } - protected ResultCollector executeFunctionOnGroups(FunctionAdapter function, String[] groups, - final LuceneIndexInfo indexInfo) throws IllegalArgumentException, CommandResultException { - ResultCollector results = null; - if (function != createIndexFunction) { - results = executeFunction(function, indexInfo, true); - } else { - Set targetMembers = CliUtil.findMembersOrThrow(groups, null); - results = CliUtil.executeFunction(function, indexInfo, targetMembers); - } - return results; + protected ResultCollector executeFunctionOnAllMembers(Function function, + final LuceneFunctionSerializable functionArguments) + throws IllegalArgumentException, CommandResultException { + Set targetMembers = CliUtil.getAllNormalMembers(getCache()); + return executeFunction(function, functionArguments, targetMembers); } protected ResultCollector executeSearch(final LuceneQueryInfo queryInfo) throws Exception { - return executeFunction(searchIndexFunction, queryInfo, false); + return executeFunctionOnRegion(searchIndexFunction, queryInfo, false); } - protected ResultCollector executeFunction(Function function, + protected ResultCollector executeFunctionOnRegion(Function function, LuceneFunctionSerializable functionArguments, boolean returnAllMembers) { Set targetMembers = CliUtil.getMembersForeRegionViaFunction(getCache(), functionArguments.getRegionPath(), returnAllMembers); @@ -517,6 +578,11 @@ public class LuceneIndexCommands extends AbstractCommandsSupport { LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__COULDNOT_FIND_MEMBERS_FOR_REGION_0, new Object[] {functionArguments.getRegionPath()})); } + return executeFunction(function, functionArguments, targetMembers); + } + + protected ResultCollector executeFunction(Function function, + LuceneFunctionSerializable functionArguments, Set targetMembers) { return CliUtil.executeFunction(function, functionArguments, targetMembers); } http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java index f1b9c82..f7edd8f 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java @@ -55,7 +55,7 @@ public class LuceneCreateIndexFunction extends FunctionAdapter implements Intern } public String getId() { - return LuceneListIndexFunction.class.getName(); + return LuceneCreateIndexFunction.class.getName(); } public void execute(final FunctionContext context) { http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneDestroyIndexFunction.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneDestroyIndexFunction.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneDestroyIndexFunction.java index 1535637..e4e2277 100644 --- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneDestroyIndexFunction.java +++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneDestroyIndexFunction.java @@ -20,7 +20,9 @@ import org.apache.geode.cache.execute.Function; import org.apache.geode.cache.execute.FunctionContext; import org.apache.geode.cache.lucene.LuceneService; import org.apache.geode.cache.lucene.LuceneServiceProvider; -import org.apache.geode.cache.lucene.internal.cli.LuceneIndexInfo; +import org.apache.geode.cache.lucene.internal.LuceneServiceImpl; +import org.apache.geode.cache.lucene.internal.cli.LuceneDestroyIndexInfo; +import org.apache.geode.cache.lucene.internal.xml.LuceneXmlConstants; import org.apache.geode.internal.InternalEntity; import org.apache.geode.internal.cache.xmlcache.CacheXml; import org.apache.geode.management.internal.cli.functions.CliFunctionResult; @@ -29,26 +31,39 @@ import org.apache.geode.management.internal.configuration.domain.XmlEntity; public class LuceneDestroyIndexFunction implements Function, InternalEntity { public void execute(final FunctionContext context) { + CliFunctionResult result = null; String memberId = getCache().getDistributedSystem().getDistributedMember().getId(); try { - LuceneIndexInfo indexInfo = (LuceneIndexInfo) context.getArguments(); + LuceneDestroyIndexInfo indexInfo = (LuceneDestroyIndexInfo) context.getArguments(); String indexName = indexInfo.getIndexName(); String regionPath = indexInfo.getRegionPath(); LuceneService service = LuceneServiceProvider.get(getCache()); if (indexName == null) { - service.destroyIndexes(regionPath); + if (indexInfo.isDefinedDestroyOnly()) { + ((LuceneServiceImpl) service).destroyDefinedIndexes(regionPath); + result = new CliFunctionResult(memberId); + } else { + service.destroyIndexes(regionPath); + result = new CliFunctionResult(memberId, getXmlEntity(indexName, regionPath)); + } } else { - service.destroyIndex(indexName, regionPath); + if (indexInfo.isDefinedDestroyOnly()) { + ((LuceneServiceImpl) service).destroyDefinedIndex(indexName, regionPath); + result = new CliFunctionResult(memberId); + } else { + service.destroyIndex(indexName, regionPath); + result = new CliFunctionResult(memberId, getXmlEntity(indexName, regionPath)); + } } - context.getResultSender() - .lastResult(new CliFunctionResult(memberId, getXmlEntity(regionPath))); } catch (Exception e) { - context.getResultSender().lastResult(new CliFunctionResult(memberId, e, e.getMessage())); + result = new CliFunctionResult(memberId, e, e.getMessage()); } + context.getResultSender().lastResult(result); } - protected XmlEntity getXmlEntity(String regionPath) { - return new XmlEntity(CacheXml.REGION, "name", regionPath); + protected XmlEntity getXmlEntity(String indexName, String regionPath) { + return new XmlEntity(CacheXml.REGION, "name", regionPath, LuceneXmlConstants.PREFIX, + LuceneXmlConstants.NAMESPACE, LuceneXmlConstants.INDEX, "name", indexName); } protected Cache getCache() { http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java index a3e2a90..7f203ce 100755 --- a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java +++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java @@ -14,6 +14,7 @@ */ package org.apache.geode.cache.lucene.internal.cli; +import junitparams.Parameters; import org.apache.geode.cache.*; import org.apache.geode.cache.lucene.LuceneIndex; import org.apache.geode.cache.lucene.LuceneQuery; @@ -22,7 +23,7 @@ import org.apache.geode.cache.lucene.LuceneServiceProvider; import org.apache.geode.cache.lucene.internal.LuceneIndexCreationProfile; import org.apache.geode.cache.lucene.internal.LuceneIndexImpl; import org.apache.geode.cache.lucene.internal.LuceneServiceImpl; -import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.management.cli.Result.Status; import org.apache.geode.management.internal.cli.CommandManager; import org.apache.geode.management.internal.cli.commands.CliCommandTestBase; @@ -38,6 +39,7 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.core.KeywordAnalyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -51,7 +53,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.concurrent.TimeUnit; import junitparams.JUnitParamsRunner; @@ -203,47 +204,6 @@ public class LuceneIndexCommandsDUnitTest extends CliCommandTestBase { } @Test - public void createIndexOnGroupShouldCreateANewIndexOnGroup() throws Exception { - final VM vm1 = Host.getHost(0).getVM(1); - final VM vm2 = Host.getHost(0).getVM(2); - vm1.invoke(() -> { - getCache(); - }); - vm2.invoke(() -> { - Properties props = new Properties(); - props.setProperty(ConfigurationProperties.GROUPS, "group1"); - getSystem(props); - getCache(); - }); - - CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); - - CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_CREATE_INDEX); - csb.addOption(LuceneCliStrings.LUCENE__INDEX_NAME, INDEX_NAME); - csb.addOption(LuceneCliStrings.LUCENE__REGION_PATH, REGION_NAME); - csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD, "field1,field2,field3"); - csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP, "group1"); - String resultAsString = executeCommandAndLogResult(csb); - - vm2.invoke(() -> { - LuceneService luceneService = LuceneServiceProvider.get(getCache()); - createRegion(); - final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); - assertArrayEquals(new String[] {"field1", "field2", "field3"}, index.getFieldNames()); - }); - - vm1.invoke(() -> { - LuceneService luceneService = LuceneServiceProvider.get(getCache()); - try { - createRegion(); - fail("Should have thrown an exception due to the missing index"); - } catch (IllegalStateException expected) { - - } - }); - } - - @Test public void createIndexWithoutRegionShouldReturnCorrectResults() throws Exception { final VM vm1 = Host.getHost(0).getVM(1); vm1.invoke(() -> { @@ -543,42 +503,70 @@ public class LuceneIndexCommandsDUnitTest extends CliCommandTestBase { } @Test - public void destroySingleIndexOnRegion() throws Exception { + @Parameters({"true", "false"}) + public void testDestroySingleIndex(boolean createRegion) throws Exception { final VM vm1 = Host.getHost(0).getVM(1); - createIndex(vm1); - CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); - CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_DESTROY_INDEX); - csb.addOption(LuceneCliStrings.LUCENE__INDEX_NAME, INDEX_NAME); - csb.addOption(LuceneCliStrings.LUCENE__REGION_PATH, REGION_NAME); - String resultAsString = executeCommandAndLogResult(csb); + if (createRegion) { + createIndex(vm1); + } else { + createIndexWithoutRegion(vm1); + } + CommandResult result = createAndExecuteDestroyIndexCommand(INDEX_NAME, REGION_NAME); + String resultAsString = commandResultToString(result); String expectedStatus = CliStrings.format( - LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FOR_REGION_1, + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FROM_REGION_1, new Object[] {INDEX_NAME, REGION_NAME}); assertTrue(resultAsString.contains(expectedStatus)); } @Test - public void destroyAllIndexesOnRegion() throws Exception { + @Parameters({"true", "false"}) + public void testDestroyAllIndexes(boolean createRegion) throws Exception { final VM vm1 = Host.getHost(0).getVM(1); - createIndex(vm1); - CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); - CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_DESTROY_INDEX); - csb.addOption(LuceneCliStrings.LUCENE__REGION_PATH, REGION_NAME); - String resultAsString = executeCommandAndLogResult(csb); + if (createRegion) { + createIndex(vm1); + } else { + createIndexWithoutRegion(vm1); + } + CommandResult result = createAndExecuteDestroyIndexCommand(null, REGION_NAME); + String resultAsString = commandResultToString(result); String expectedStatus = CliStrings.format( - LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FOR_REGION_0, + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FROM_REGION_0, new Object[] {REGION_NAME}); assertTrue(resultAsString.contains(expectedStatus)); } @Test - public void destroyIndexWithoutRegionShouldReturnError() throws Exception { + public void testDestroyNonExistentSingleIndex() throws Exception { final VM vm1 = Host.getHost(0).getVM(1); - createIndexWithoutRegion(vm1); + vm1.invoke(() -> createRegion()); + CommandResult result = createAndExecuteDestroyIndexCommand(INDEX_NAME, REGION_NAME); + String resultAsString = commandResultToString(result); + String expectedStatus = LocalizedStrings.LuceneService_INDEX_0_NOT_FOUND_IN_REGION_1 + .toLocalizedString(new Object[] {INDEX_NAME, '/' + REGION_NAME}); + assertTrue(resultAsString.contains(expectedStatus)); + } + + @Test + public void testDestroyNonExistentIndexes() throws Exception { + final VM vm1 = Host.getHost(0).getVM(1); + vm1.invoke(() -> createRegion()); + CommandResult result = createAndExecuteDestroyIndexCommand(null, REGION_NAME); + String resultAsString = commandResultToString(result); + String expectedStatus = LocalizedStrings.LuceneService_NO_INDEXES_WERE_FOUND_IN_REGION_0 + .toLocalizedString(new Object[] {'/' + REGION_NAME}); + assertTrue(resultAsString.contains(expectedStatus)); + } + + private CommandResult createAndExecuteDestroyIndexCommand(String indexName, String regionPath) + throws Exception { + CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_DESTROY_INDEX); - csb.addOption(LuceneCliStrings.LUCENE__REGION_PATH, REGION_NAME); - String resultAsString = executeCommandAndLogResult(csb); - assertTrue(resultAsString.contains(getRegionNotFoundErrorMessage(REGION_NAME))); + if (indexName != null) { + csb.addOption(LuceneCliStrings.LUCENE__INDEX_NAME, indexName); + } + csb.addOption(LuceneCliStrings.LUCENE__REGION_PATH, regionPath); + return executeCommandAndGetResult(csb); } private void createRegion() { http://git-wip-us.apache.org/repos/asf/geode/blob/b89427fa/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java index 9e8d7a9..e4b4b4f 100644 --- a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java +++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java @@ -27,6 +27,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.core.KeywordAnalyzer; @@ -34,6 +36,7 @@ import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.apache.geode.cache.Cache; @@ -71,6 +74,7 @@ import org.apache.geode.test.junit.categories.UnitTest; * @since GemFire 7.0 */ @Category(UnitTest.class) +@RunWith(JUnitParamsRunner.class) public class LuceneIndexCommandsJUnitTest { @Test @@ -185,8 +189,8 @@ public class LuceneIndexCommandsJUnitTest { cliFunctionResults.add(new CliFunctionResult("member2", false, "Index creation failed")); cliFunctionResults.add(new CliFunctionResult("member3", true, "Index Created")); - doReturn(mockResultCollector).when(commands).executeFunctionOnGroups( - isA(LuceneCreateIndexFunction.class), any(), any(LuceneIndexInfo.class)); + doReturn(mockResultCollector).when(commands).executeFunctionOnAllMembers( + isA(LuceneCreateIndexFunction.class), any(LuceneIndexInfo.class)); doReturn(cliFunctionResults).when(mockResultCollector).getResult(); String indexName = "index"; @@ -196,7 +200,7 @@ public class LuceneIndexCommandsJUnitTest { KeywordAnalyzer.class.getCanonicalName(), StandardAnalyzer.class.getCanonicalName()}; CommandResult result = (CommandResult) commands.createIndex(indexName, regionPath, - searchableFields, fieldAnalyzers, null); + searchableFields, fieldAnalyzers); assertEquals(Status.OK, result.getStatus()); TabularResultData data = (TabularResultData) result.getResultData(); assertEquals(Arrays.asList("member1", "member2", "member3"), data.retrieveAllValues("Member")); @@ -223,8 +227,8 @@ public class LuceneIndexCommandsJUnitTest { indexDetails.add(createIndexDetails("memberFive", "/Employees", searchableFields, fieldAnalyzers, mockIndexStats, true, serverName)); - doReturn(mockResultCollector).when(commands).executeFunctionOnGroups( - isA(LuceneDescribeIndexFunction.class), any(), any(LuceneIndexInfo.class)); + doReturn(mockResultCollector).when(commands).executeFunctionOnRegion( + isA(LuceneDescribeIndexFunction.class), any(LuceneIndexInfo.class), eq(true)); doReturn(indexDetails).when(mockResultCollector).getResult(); CommandResult result = (CommandResult) commands.describeIndex("memberFive", "/Employees"); @@ -404,29 +408,141 @@ public class LuceneIndexCommandsJUnitTest { } @Test - public void testDestroySingleIndexOnRegion() throws Exception { + @Parameters({"true", "false"}) + public void testDestroySingleIndexNoRegionMembers(boolean expectedToSucceed) throws Exception { LuceneIndexCommands commands = createTestLuceneIndexCommandsForDestroyIndex(); String indexName = "index"; String regionPath = "regionPath"; + + final ResultCollector mockResultCollector = mock(ResultCollector.class); + final List cliFunctionResults = new ArrayList<>(); + String expectedStatus = null; + if (expectedToSucceed) { + expectedStatus = CliStrings.format( + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FROM_REGION_1, + new Object[] {indexName, regionPath}); + cliFunctionResults.add(new CliFunctionResult("member0")); + } else { + Exception e = new IllegalStateException("failed"); + expectedStatus = e.getMessage(); + cliFunctionResults.add(new CliFunctionResult("member0", e, e.getMessage())); + } + + doReturn(mockResultCollector).when(commands).executeFunction( + isA(LuceneDestroyIndexFunction.class), any(LuceneDestroyIndexInfo.class), any()); + doReturn(cliFunctionResults).when(mockResultCollector).getResult(); + + doReturn(Collections.emptySet()).when(commands).getNormalMembers(any()); + doReturn(Collections.emptySet()).when(commands).getRegionMembers(any(), any()); + + CommandResult result = (CommandResult) commands.destroyIndex(indexName, regionPath); + verifyDestroyIndexCommandResult(result, cliFunctionResults, expectedStatus); + } + + @Test + @Parameters({"true", "false"}) + public void testDestroySingleIndexWithRegionMembers(boolean expectedToSucceed) throws Exception { + LuceneIndexCommands commands = createTestLuceneIndexCommandsForDestroyIndex(); + String indexName = "index"; + String regionPath = "regionPath"; + + Set members = new HashSet<>(); + DistributedMember mockMember = mock(DistributedMember.class); + when(mockMember.getId()).thenReturn("member0"); + members.add(mockMember); + + final ResultCollector mockResultCollector = mock(ResultCollector.class); + final List cliFunctionResults = new ArrayList<>(); + String expectedStatus = null; + if (expectedToSucceed) { + expectedStatus = CliStrings.format( + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FROM_REGION_1, + new Object[] {indexName, regionPath}); + cliFunctionResults.add(new CliFunctionResult(mockMember.getId())); + } else { + Exception e = new IllegalStateException("failed"); + expectedStatus = e.getMessage(); + cliFunctionResults.add(new CliFunctionResult("member0", e, e.getMessage())); + } + + doReturn(mockResultCollector).when(commands).executeFunction( + isA(LuceneDestroyIndexFunction.class), any(LuceneDestroyIndexInfo.class), any()); + doReturn(cliFunctionResults).when(mockResultCollector).getResult(); + + doReturn(members).when(commands).getNormalMembers(any()); + doReturn(members).when(commands).getRegionMembers(any(), any()); + CommandResult result = (CommandResult) commands.destroyIndex(indexName, regionPath); - String expectedMember = "member"; - String expectedStatus = CliStrings.format( - LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEX_0_FOR_REGION_1, - new Object[] {indexName, regionPath}); - verifyDestroyIndexCommandResult(result, expectedMember, expectedStatus); + verifyDestroyIndexCommandResult(result, cliFunctionResults, expectedStatus); } @Test - public void testDestroyAllIndexesOnRegion() throws Exception { + @Parameters({"true", "false"}) + public void testDestroyAllIndexesNoRegionMembers(boolean expectedToSucceed) throws Exception { LuceneIndexCommands commands = createTestLuceneIndexCommandsForDestroyIndex(); String indexName = null; String regionPath = "regionPath"; + + final ResultCollector mockResultCollector = mock(ResultCollector.class); + final List cliFunctionResults = new ArrayList<>(); + String expectedStatus = null; + if (expectedToSucceed) { + expectedStatus = CliStrings.format( + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FROM_REGION_0, + new Object[] {regionPath}); + cliFunctionResults.add(new CliFunctionResult("member0")); + } else { + Exception e = new IllegalStateException("failed"); + expectedStatus = e.getMessage(); + cliFunctionResults.add(new CliFunctionResult("member0", e, e.getMessage())); + } + + doReturn(mockResultCollector).when(commands).executeFunction( + isA(LuceneDestroyIndexFunction.class), any(LuceneDestroyIndexInfo.class), any()); + doReturn(cliFunctionResults).when(mockResultCollector).getResult(); + + doReturn(Collections.emptySet()).when(commands).getNormalMembers(any()); + doReturn(Collections.emptySet()).when(commands).getRegionMembers(any(), any()); + CommandResult result = (CommandResult) commands.destroyIndex(indexName, regionPath); - String expectedMember = "member"; - String expectedStatus = CliStrings.format( - LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FOR_REGION_0, - new Object[] {regionPath}); - verifyDestroyIndexCommandResult(result, expectedMember, expectedStatus); + verifyDestroyIndexCommandResult(result, cliFunctionResults, expectedStatus); + } + + @Test + @Parameters({"true", "false"}) + public void testDestroyAllIndexesWithRegionMembers(boolean expectedToSucceed) throws Exception { + LuceneIndexCommands commands = createTestLuceneIndexCommandsForDestroyIndex(); + String indexName = null; + String regionPath = "regionPath"; + + Set members = new HashSet<>(); + DistributedMember mockMember = mock(DistributedMember.class); + when(mockMember.getId()).thenReturn("member0"); + members.add(mockMember); + + final ResultCollector mockResultCollector = mock(ResultCollector.class); + final List cliFunctionResults = new ArrayList<>(); + String expectedStatus = null; + if (expectedToSucceed) { + expectedStatus = CliStrings.format( + LuceneCliStrings.LUCENE_DESTROY_INDEX__MSG__SUCCESSFULLY_DESTROYED_INDEXES_FROM_REGION_0, + new Object[] {regionPath}); + cliFunctionResults.add(new CliFunctionResult(mockMember.getId())); + } else { + Exception e = new IllegalStateException("failed"); + expectedStatus = e.getMessage(); + cliFunctionResults.add(new CliFunctionResult("member0", e, e.getMessage())); + } + + doReturn(mockResultCollector).when(commands).executeFunction( + isA(LuceneDestroyIndexFunction.class), any(LuceneDestroyIndexInfo.class), any()); + doReturn(cliFunctionResults).when(mockResultCollector).getResult(); + + doReturn(Collections.emptySet()).when(commands).getNormalMembers(any()); + doReturn(Collections.emptySet()).when(commands).getRegionMembers(any(), any()); + + CommandResult result = (CommandResult) commands.destroyIndex(indexName, regionPath); + verifyDestroyIndexCommandResult(result, cliFunctionResults, expectedStatus); } private LuceneIndexCommands createTestLuceneIndexCommandsForDestroyIndex() { @@ -437,21 +553,27 @@ public class LuceneIndexCommandsJUnitTest { final List cliFunctionResults = new ArrayList<>(); cliFunctionResults.add(new CliFunctionResult("member", true, "Index Destroyed")); - doReturn(mockResultCollector).when(commands).executeFunction( + doReturn(mockResultCollector).when(commands).executeFunctionOnRegion( isA(LuceneDestroyIndexFunction.class), any(LuceneIndexInfo.class), eq(false)); doReturn(cliFunctionResults).when(mockResultCollector).getResult(); return commands; } - private void verifyDestroyIndexCommandResult(CommandResult result, String expectedMember, - String expectedStatus) { + private void verifyDestroyIndexCommandResult(CommandResult result, + List cliFunctionResults, String expectedStatus) { assertEquals(Status.OK, result.getStatus()); TabularResultData data = (TabularResultData) result.getResultData(); List members = data.retrieveAllValues("Member"); + assertEquals(cliFunctionResults.size(), members.size()); + // Verify each member + for (int i = 0; i < members.size(); i++) { + assertEquals("member" + i, members.get(i)); + } + // Verify each status List status = data.retrieveAllValues("Status"); - assertTrue(members.size() == 1); - assertEquals(expectedMember, members.get(0)); - assertEquals(expectedStatus, status.get(0)); + for (int i = 0; i < status.size(); i++) { + assertEquals(expectedStatus, status.get(i)); + } } private String getPage(final LuceneSearchResults[] expectedResults, int[] indexList) {