GEODE-3027: add a simple PartitionResolver The new PartitionResolver is: org.apache.geode.cache.util.StringPrefixPartitionResolver It has a default no-arg constructor and can be configured on a partitioned region as its PartitionResolver. It requires that the region it is on to use String keys and that the key contains at least one "|" delimiter. The portion of the key that precedes the delimiter, called the prefix, will be returned from getRoutingObject and used to partition the data on the region. For example if the key is "customer#36|item#45" then it would be partitioned uisng "customer#36". This resolver does not allow the prefix string to contain a delimiter.
Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/c8c24dd4 Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/c8c24dd4 Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/c8c24dd4 Branch: refs/heads/feature/GEODE-3023 Commit: c8c24dd49e3e87808d43f0b0df796e2c307999eb Parents: c756d31 Author: Darrel Schneider <[email protected]> Authored: Mon Jun 5 17:07:46 2017 -0700 Committer: Udo Kohlmeyer <[email protected]> Committed: Fri Jun 9 13:12:03 2017 -0700 ---------------------------------------------------------------------- .../util/StringPrefixPartitionResolver.java | 86 ++++++++++++++++++ .../StringPrefixPartitionResolverJUnitTest.java | 96 ++++++++++++++++++++ 2 files changed, 182 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/c8c24dd4/geode-core/src/main/java/org/apache/geode/cache/util/StringPrefixPartitionResolver.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/cache/util/StringPrefixPartitionResolver.java b/geode-core/src/main/java/org/apache/geode/cache/util/StringPrefixPartitionResolver.java new file mode 100644 index 0000000..6a2d037 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/cache/util/StringPrefixPartitionResolver.java @@ -0,0 +1,86 @@ +/* + * 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.util; + +import org.apache.geode.cache.EntryOperation; +import org.apache.geode.cache.PartitionResolver; + +/** + * This partition resolver requires every key of the partitioned region to be an instance of String + * and to contain at least one "|" delimiter. The prefix, the substring of the key that precedes the + * first delimiter, is returned by getRoutingObject. + * + * @since Geode 1.2.0 + */ +public class StringPrefixPartitionResolver implements PartitionResolver<String, Object> { + + /** + * The default delimiter is "|". Currently this class only uses the default delimiter but in a + * future release configuring the delimiter may be supported. + */ + public static final String DEFAULT_DELIMITER = "|"; + + /** + * Creates a prefix resolver with the default delimiter. + */ + public StringPrefixPartitionResolver() {} + + /** + * Returns the prefix of the String key that precedes the first "|" in the key. + * + * @throws ClassCastException if the key is not an instance of String + * @throws IllegalArgumentException if the key does not contain at least one "|". + */ + @Override + public Object getRoutingObject(EntryOperation<String, Object> opDetails) { + String key = opDetails.getKey(); + String delimiter = getDelimiter(); + int idx = key.indexOf(delimiter); + if (idx == -1) { + throw new IllegalArgumentException( + "The key \"" + key + "\" does not contains the \"" + delimiter + "\" delimiter."); + } + return key.substring(0, idx); + } + + @Override + public java.lang.String getName() { + return getClass().getName(); + } + + private java.lang.String getDelimiter() { + return DEFAULT_DELIMITER; + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof StringPrefixPartitionResolver)) { + return false; + } + StringPrefixPartitionResolver other = (StringPrefixPartitionResolver) o; + return other.getName().equals(getName()) && other.getDelimiter().equals(getDelimiter()); + } + + @Override + public void close() {} +} http://git-wip-us.apache.org/repos/asf/geode/blob/c8c24dd4/geode-core/src/test/java/org/apache/geode/cache/util/StringPrefixPartitionResolverJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/cache/util/StringPrefixPartitionResolverJUnitTest.java b/geode-core/src/test/java/org/apache/geode/cache/util/StringPrefixPartitionResolverJUnitTest.java new file mode 100644 index 0000000..be67f1b --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/cache/util/StringPrefixPartitionResolverJUnitTest.java @@ -0,0 +1,96 @@ +/* + * 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.util; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.*; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.cache.EntryOperation; +import org.apache.geode.cache.util.StringPrefixPartitionResolver; +import org.apache.geode.internal.cache.EntryOperationImpl; +import org.apache.geode.test.junit.categories.UnitTest; + +@Category(UnitTest.class) +public class StringPrefixPartitionResolverJUnitTest { + static final String DELIMITER = StringPrefixPartitionResolver.DEFAULT_DELIMITER; + + @Test + public void testGetName() { + assertEquals("org.apache.geode.cache.util.StringPrefixPartitionResolver", + (new StringPrefixPartitionResolver()).getName()); + } + + @Test + public void testEquals() { + StringPrefixPartitionResolver pr1 = new StringPrefixPartitionResolver(); + assertEquals(true, pr1.equals(pr1)); + StringPrefixPartitionResolver pr2 = new StringPrefixPartitionResolver(); + assertEquals(true, pr1.equals(pr2)); + assertEquals(false, pr1.equals(new Object())); + } + + @Test + public void testNonStringKey() { + Object key = new Object(); + StringPrefixPartitionResolver pr = new StringPrefixPartitionResolver(); + assertThatThrownBy(() -> pr.getRoutingObject(createEntryOperation(key))) + .isInstanceOf(ClassCastException.class); + } + + @Test + public void testNoDelimiterKey() { + String key = "foobar"; + StringPrefixPartitionResolver pr = new StringPrefixPartitionResolver(); + assertThatThrownBy(() -> pr.getRoutingObject(createEntryOperation(key))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("The key \"foobar\" does not contains the \"" + DELIMITER + "\" delimiter."); + } + + @Test + public void testEmptyPrefix() { + String key = DELIMITER + "foobar"; + StringPrefixPartitionResolver pr = new StringPrefixPartitionResolver(); + assertEquals("", pr.getRoutingObject(createEntryOperation(key))); + } + + @Test + public void testAllPrefix() { + String key = "foobar" + DELIMITER; + StringPrefixPartitionResolver pr = new StringPrefixPartitionResolver(); + assertEquals("foobar", pr.getRoutingObject(createEntryOperation(key))); + } + + @Test + public void testSimpleKey() { + String key = "1" + DELIMITER + "2"; + StringPrefixPartitionResolver pr = new StringPrefixPartitionResolver(); + assertEquals("1", pr.getRoutingObject(createEntryOperation(key))); + } + + @Test + public void testMulitPrefix() { + String key = "one" + DELIMITER + "two" + DELIMITER + "three"; + StringPrefixPartitionResolver pr = new StringPrefixPartitionResolver(); + assertEquals("one", pr.getRoutingObject(createEntryOperation(key))); + } + + @SuppressWarnings("unchecked") + private EntryOperation<String, Object> createEntryOperation(Object key) { + return new EntryOperationImpl(null, null, key, null, null); + } +}
