Repository: ignite Updated Branches: refs/heads/master 9d9c237d0 -> 1382df19f
IGNITE-9365 - Attribute based affinity backup filter implementation - Fixes #4719 Signed-off-by: Valentin Kulichenko <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/1382df19 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/1382df19 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/1382df19 Branch: refs/heads/master Commit: 1382df19fa49a89714c707b04ec4920802a6064d Parents: 9d9c237 Author: Dave Harvey <[email protected]> Authored: Fri Sep 21 15:53:00 2018 -0700 Committer: Valentin Kulichenko <[email protected]> Committed: Fri Sep 21 15:53:00 2018 -0700 ---------------------------------------------------------------------- ...lusterNodeAttributeAffinityBackupFilter.java | 141 +++++++++---------- ...ityFunctionBackupFilterAbstractSelfTest.java | 8 +- ...deAttributeAffinityBackupFilterSelfTest.java | 15 +- 3 files changed, 78 insertions(+), 86 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/1382df19/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilter.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilter.java b/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilter.java index 7b75dbe..3949a28 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilter.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilter.java @@ -17,16 +17,15 @@ package org.apache.ignite.cache.affinity.rendezvous; -import java.io.Serializable; import java.util.List; import java.util.Objects; - import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.lang.IgniteBiPredicate; /** - * This class can be used as a {@link RendezvousAffinityFunction#affinityBackupFilter } to create - * cache templates in Spring that force each partition's primary and backup to different hardware which + * This class can be used as a {@link RendezvousAffinityFunction#affinityBackupFilter } to create + * cache templates in Spring that force each partition's primary and backup to different hardware which * is not expected to fail simultaneously, e.g., in AWS, to different "availability zones". This * is a per-partition selection, and different partitions may choose different primaries. * <p> @@ -35,8 +34,8 @@ import org.apache.ignite.lang.IgniteBiPredicate; * <p> * A list of node attributes to compare is provided on construction. Note: "All cluster nodes, * on startup, automatically register all the environment and system properties as node attributes." - * <p> - * This class is constructed with a array of node attribute names, and a candidate node will be rejected if *any* of the + * <p> + * This class is constructed with a array of node attribute names, and a candidate node will be rejected if *any* of the * previously selected nodes for a partition have the identical values for *all* of those attributes on the candidate node. * Another way to understand this is the set of attribute values defines the key of a group into which a node is placed, * an the primaries and backups for a partition cannot share nodes in the same group. A null attribute is treated as @@ -48,87 +47,85 @@ import org.apache.ignite.lang.IgniteBiPredicate; * </pre> * <h2 class="header">Spring Example</h2> * Create a partitioned cache template plate with 1 backup, where the backup will not be placed in the same availability zone - * as the primary. Note: This example requires that the environment variable "AVAILABILTY_ZONE" be set appropriately on - * each node via some means external to Ignite. On AWS, some nodes might have AVAILABILTY_ZONE=us-east-1a and others - * AVAILABILTY_ZONE=us-east-1b. + * as the primary. Note: This example requires that the environment variable "AVAILABILTY_ZONE" be set appropriately on + * each node via some means external to Ignite. On AWS, some nodes might have AVAILABILTY_ZONE=us-east-1a and others + * AVAILABILTY_ZONE=us-east-1b. * <pre name="code" class="xml"> - * - * <property name="cacheConfiguration"> - * <list> - * <bean id="cache-template-bean" abstract="true" class="org.apache.ignite.configuration.CacheConfiguration"> - * <property name="name" value="JobcaseDefaultCacheConfig*"/> - * <property name="cacheMode" value="PARTITIONED" /> - * <property name="backups" value="1" /> + * <property name="cacheConfiguration"> + * <list> + * <bean id="cache-template-bean" abstract="true" class="org.apache.ignite.configuration.CacheConfiguration"> + * <property name="name" value="JobcaseDefaultCacheConfig*"/> + * <property name="cacheMode" value="PARTITIONED" /> + * <property name="backups" value="1" /> * <property name="affinity"> * <bean class="org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction"> * <property name="affinityBackupFilter"> * <bean class="org.apache.ignite.cache.affinity.rendezvous.ClusterNodeAttributeAffinityBackupFilter"> - * <constructor-arg> - * <array value-type="java.lang.String"> + * <constructor-arg> + * <array value-type="java.lang.String"> * <!-- Backups must go to different AZs --> * <value>AVAILABILITY_ZONE</value> - * </array> - * </constructor-arg> + * </array> + * </constructor-arg> * </bean> * </property> - * </bean> + * </bean> * </property> - * </bean> - * </list> - * </property> + * </bean> + * </list> + * </property> * </pre> - * - * With more backups, multiple properties, e.g., SITE, ZONE, could be used to force backups to different subgroups. + * <p> + * With more backups, multiple properties, e.g., SITE, ZONE, could be used to force backups to different subgroups. */ -public class ClusterNodeAttributeAffinityBackupFilter implements IgniteBiPredicate<ClusterNode, List<ClusterNode>>, Serializable { - /** - * - */ - private static final long serialVersionUID = 1L; +public class ClusterNodeAttributeAffinityBackupFilter implements IgniteBiPredicate<ClusterNode, List<ClusterNode>> { + /** */ + private static final long serialVersionUID = 1L; + + /** Attribute names. */ + private final String[] attributeNames; + + /** + * @param attributeNames The list of attribute names for the set of attributes to compare. Must be at least one. + */ + ClusterNodeAttributeAffinityBackupFilter(String... attributeNames) { + A.ensure(attributeNames.length > 0, "attributeNames.length > 0"); + + this.attributeNames = attributeNames; + } + + /** + * Defines a predicate which returns {@code true} if a node is acceptable for a backup + * or {@code false} otherwise. An acceptable node is one where its set of attribute values + * is not exact match with any of the previously selected nodes. If an attribute does not + * exist on exactly one node of a pair, then the attribute does not match. If the attribute + * does not exist both nodes of a pair, then the attribute matches. + * <p> + * Warning: if an attribute is specified that does not exist on any node, then no backups + * will be created, because all nodes will match. + * <p> + * + * @param candidate A node that is a candidate for becoming a backup node for a partition. + * @param previouslySelected A list of primary/backup nodes already chosen for a partition. + * The primary is first. + */ + @Override public boolean apply(ClusterNode candidate, List<ClusterNode> previouslySelected) { + for (ClusterNode node : previouslySelected) { + boolean match = true; - - final String [] attributeNames; + for (String attribute : attributeNames) { + if (!Objects.equals(candidate.attribute(attribute), node.attribute(attribute))) { + match = false; - /* - * @param attributeNames - the list of attribute names for the set of attributes to compare. Must be at least one. - */ - ClusterNodeAttributeAffinityBackupFilter(String[] attributeNames) - { - assert attributeNames.length > 0; - - this.attributeNames = attributeNames; - } + break; + } + } - /** - * Defines a predicate which returns {@code true} if a node is acceptable for a backup - * or {@code false} otherwise. An acceptable node is one where its set of attribute values - * is not exact match with any of the previously selected nodes. If an attribute does not - * exist on exactly one node of a pair, then the attribute does not match. If the attribute - * does not exist both nodes of a pair, then the attribute matches. - * <p> - * Warning: if an attribute is specified that does not exist on any node, then no backups - * will be created, because all nodes will match. - * <p> - * @param candidate A node that is a candidate for becoming a backup node for a partition. - * @param previouslySelected A list of primary/backup nodes already chosen for a partition. - * The primary is first. - */ - @Override - public boolean apply(ClusterNode candidate, List<ClusterNode> previouslySelected) { + if (match) + return false; + } - for (ClusterNode node : previouslySelected) { - boolean match = true; - - for (String attribute : attributeNames) { - if (!Objects.equals(candidate.attribute(attribute), node.attribute(attribute)) ) { - match = false; - break; - } - } - if (match) - return false; - } - return true; - } + return true; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1382df19/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityFunctionBackupFilterAbstractSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityFunctionBackupFilterAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityFunctionBackupFilterAbstractSelfTest.java index 9e04dbb..74add0c 100644 --- a/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityFunctionBackupFilterAbstractSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/cache/affinity/AffinityFunctionBackupFilterAbstractSelfTest.java @@ -87,7 +87,7 @@ public abstract class AffinityFunctionBackupFilterAbstractSelfTest extends GridC return backupAssignedAttribute.get(nodeAttributeVal).equals(0); } }; - + /** * @param nodes List of cluster nodes. * @return Statistic. @@ -233,7 +233,7 @@ public abstract class AffinityFunctionBackupFilterAbstractSelfTest extends GridC stopAllGrids(); } } - + /* Different affinityBackupFilters have different goals */ protected int expectedNodesForEachPartition() { return backups + 1; @@ -249,7 +249,7 @@ public abstract class AffinityFunctionBackupFilterAbstractSelfTest extends GridC int partCnt = aff.partitions(); IgniteCache<Object, Object> cache = grid(0).cache(DEFAULT_CACHE_NAME); - + for (int i = 0; i < partCnt; i++) { Collection<ClusterNode> nodes = affinity(cache).mapKeyToPrimaryAndBackups(i); @@ -264,4 +264,4 @@ public abstract class AffinityFunctionBackupFilterAbstractSelfTest extends GridC assertEquals(stat.get("C"), new Integer(1)); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/1382df19/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilterSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilterSelfTest.java b/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilterSelfTest.java index f0e8720..2c1ddbf 100644 --- a/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilterSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/ClusterNodeAttributeAffinityBackupFilterSelfTest.java @@ -17,10 +17,6 @@ package org.apache.ignite.cache.affinity.rendezvous; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.apache.ignite.cache.affinity.AffinityFunction; import org.apache.ignite.cache.affinity.AffinityFunctionBackupFilterAbstractSelfTest; @@ -40,19 +36,18 @@ public class ClusterNodeAttributeAffinityBackupFilterSelfTest extends AffinityFu /** {@inheritDoc} */ @Override protected AffinityFunction affinityFunctionWithAffinityBackupFilter(String attributeName) { RendezvousAffinityFunction aff = new RendezvousAffinityFunction(false); - + String[] stringArray = new String[1]; - + stringArray[0] = attributeName; - + aff.setAffinityBackupFilter(new ClusterNodeAttributeAffinityBackupFilter(stringArray)); return aff; } - + /** {@inheritDoc} */ - @Override - protected int expectedNodesForEachPartition() { + @Override protected int expectedNodesForEachPartition() { return 3; } }
