Configuration c = new ConfigurationBuilder().clustering().hash().groups().enabled().build();
In some cases you may wish to co-locate a group of entries onto a particular node. In this, the group API will be useful for you.
Infinispan allocates each node a portion of the total hash space. Normally, when you store an entry, Infinispan will take a hash of the key, and store the entry on the node which owns that portion of the hash space. Infinispan always uses an algorithm to locate a key in the hash space, never allowing the node on which the entry is stored to be specified manually. This scheme allows any node to know which nodes owns a key, without having to distribute such ownership information. This reduces the overhead of Infinispan, but more importantly improves redundancy as there is no need to replicate the ownership information in case of node failure.
If you use the grouping API , then Infinispan will ignore the hash of the key when deciding which node to store the entry on, and instead use a hash of the group. Infinispan still uses the hash of the key to store the entry on a node. When the group API is in use, it is important that every node can still compute, using an algorithm, the owner of every key. For this reason, the group cannot be specified manually. The group can either be intrinsic to the entry (generated by the key class) or extrinsic (generated by an external function).
First, you must enable groups. If you are configuring Infinispan programmatically, then call:
Configuration c = new ConfigurationBuilder().clustering().hash().groups().enabled().build();
Or, if you are using XML:
<clustering> <hash> <groups enabled="true" /> </hash> </clustering>
If you have control of the key class (you can alter the class definition, it's not part of an unmodifiable library), and the determination of the group is not an orthogonal concern to the key class, then we recommend you use an intrinsic group. The intrinsic group can be specified using the @Group annotation placed on the method. Let's take a look at an example:
class User { ... String office; ... int hashCode() { // Defines the hash for the key, normally used to determine location ... } // Override the location by specifying a group, all keys in the same // group end up with the same owner @Group String getOffice() { return office; } }
The group must be a String.
If you don't have control over the key class, or the determination of the group is an orthogonal concern to the key class, we recommend you use an extrinsic group. In extrinsic group is specified by implementing the Grouper interface, which has a single method computeGroup, which should return the group. Grouper acts as an interceptor, passing the previously computed value in. The group passed to the first Grouper will be that determined by @Group (if @Groupis defined). This allows you even greater control over the group when using an intrinsic group. For a grouper to be used when determining the group for a key, it's keyType must be assignable from the key being grouped.
Let's take a look at an example of a Grouper:
public class KXGrouper implements Grouper<String> { // A pattern that can extract from a "kX" (e.g. k1, k2) style key // The pattern requires a String key, of length 2, where the first character is // "k" and the second character is a digit. We take that digit, and perform // modular arithmetic on it to assign it to group "1" or group "2". private static Pattern kPattern = Pattern.compile("(^k)(<a>\\d</a>)$"); public String computeGroup(String key, String group) { Matcher matcher = kPattern.matcher(key); if (matcher.matches()) { String g = Integer.parseInt(matcher.group(2)) % 2 + ""; return g; } else return null; } public Class<String> getKeyType() { return String.class; } }
Here we determine a simple grouper that can take the key class and extract from the group from the key using a pattern. We ignore any group information specified on the key class.
You must register every grouper you wish to have used. If you are configuring Infinispan programmatically:
Configuration c = new ConfigurationBuilder().clustering().hash().groups().addGrouper(new KXGrouper()).build();
Or, if you are using XML:
<clustering> <hash> <groups enabled="true"> <grouper class="com.acme.KXGrouper" /> </groups> </hash> </clustering>