Monday, 20 June 2011

The Grouping API

Infinispan 5 CR4 (and above) includes a new Grouping API. You can read more in the documentation, but I'll introduce it quickly for you here.

In some cases you may wish to co-locate a group of entries onto a particular node. In this case, the group API will be useful for you.

How does it work?

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).

How can I use it?

If you can alter the key class, and the determination of the group is not an orthogonal concern to the key class, then you can simply annotate a method on the key class that will provide the group. For 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;
}

}



Of course, you need to make sure your algorithm for computing the key is consistent, and always returns the same group for a key!

Alternatively, if you can't modify the key class, or determination of the group is an orthogonal concern, you can externalise computation of the group to an "interceptor style" class, called a "Grouper". Let's take a look an example of a Grouper:




class KXGrouper implements Grouper {

// A pattern that can extract from a "kX" (e.g. k1, k2) style key
static Pattern kPattern = Pattern.compile("(^k)(\\d)$");

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;
}

Class getKeyType() {
return String.class;
}

}


Here, we've had to use a grouper, as we cannot modify the key class (String). Our group is still based upon the key, and established by extracting a part of the key.

Of course, you need to enable grouping support in Infinispan, and configure any groupers. The reference documentation will help you here.

1 comment:

  1. Would there be any way to achieve a locking/serialization based on group id?

    ReplyDelete