Partition mappers are defined by extending
com.kabira.platform.highavailability.PartitionMapper
and implementing the getPartition
method. Partition mappers are installed on a specific class using
the PartitionManager.setMapper()
method.
All child classes extending a parent class inherit the parent's partition mapper. The parent's partition mapper can be overridden in a child class by installing a partition mapper on the child. Only a child's partition mapper is called when the child is created.
The getPartition
method is called when objects
are created, or re-partitioning (the section called “Updating partition mapping”) is requested. The method is
passed an object of the type for which it was registered. The
getPartition
method must return a valid partition name
for the object. The object is assigned to the returned partition
name.
Partition mappers must be installed on each node in the cluster that has the managed object type installed. This includes all replica nodes for the managed object type. Failure to do so will cause inconsistent behavior in the cluster because the type will be partitioned on some nodes, but not on others. The partition mapper should be installed as part of application initialization before a node joins the cluster and before any objects of that type are created.
When a partition mapper is installed an audit is performed to validate the current state of partitioned objects on the node. The audit to perform can be one of:
IGNORE_PARTITIONING
- do not perform any
validation of previously created object instances for the type on
which the partition mapper is being installed. Any objects created
before the partition mapper is installed will not be
partitioned.
VERIFY_DEFER_INSTALL
- verify that
there are no previously created object instances for the type on which
the partition mapper is being installed. If there are object instances
a com.kabira.platform.ResourceUnavailableException
is thrown. If the type has not loaded, the installation of the
partition mapper is deferred until the type is loaded.
VERIFY_PARTIONING
- verify that there
are no previously created object instances for the type on which the
mapper is being installed. If there are object instances a
com.kabira.platform.ResourceUnavailableException
is
thrown.
The decision on which partition should be associated with an object
is based on an application specific criteria. For example all customers on
the west coast could be in a partition named westcoast
,
while all customers on the east coast could be in a partition named
eastcoast
. Partitions could also be assigned based on
load balancing, or other system resource criteria.
If an invalid partition name is returned from the
getPartition
method a
com.kabira.platform.ResourceUnavailableException
is
thrown.
Partition mappers can be cleared using the
PartitionManager.clearMapper()
method.
Example 7.1, “Defining , installing, and clearing a partition mapper” shows the definition and installation of a partition mapper.
Example 7.1. Defining , installing, and clearing a partition mapper
// $Revision: 1.1.2.4 $ package com.kabira.snippets.highavailability; import com.kabira.platform.Transaction; import com.kabira.platform.annotation.Managed; import com.kabira.platform.highavailability.PartitionManager; import com.kabira.platform.highavailability.PartitionMapper; /** * Defining and installing a partition mapper. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = A</li> * </ul> * </p> */ public class HighAvailability { @Managed private static class MyObject { }; // // Partition mapper that just returns a hard-coded partition name // private static class MyPartitionMapper extends PartitionMapper { @Override public String getPartition(Object obj) { return "Unknown Partition"; } } /** * Main entry point * * @param args Not used */ public static void main(String[] args) { new Transaction("High Availability") { @Override protected void run() throws Rollback { // // Define partition mapper properties to audit for any // unpartitioned objects // PartitionMapper.Properties properties = new PartitionMapper.Properties(); properties.setAudit(PartitionMapper.Properties.Audit.VERIFY_PARTIONING); // // Install the partition mapper // PartitionManager.setMapper( MyObject.class, new MyPartitionMapper(), properties); // // Create an instance of MyObject. // This will fail because partition mapper // is returning an unknown partition // try { new MyObject(); } finally { // // Clear the partition mapper // PartitionManager.clearMapper(MyPartitionMapper.class); } } }.execute(); } }
When Example 7.1, “Defining , installing, and clearing a partition mapper” is run it fails with the following output:
[A] Java main class com.kabira.snippets.highavailability.HighAvailability.main exited with an exception. [A] com.kabira.platform.ResourceUnavailableException: could not find partition 'Unknown Partition' for object 'com.kabira.snippets.highavailability.MyObject:1 (1352756:1794744:14616904711:1 offset 68152136)' [A] at com.kabira.platform.ManagedObject.createSMObject(Native Method) [A] at com.kabira.snippets.highavailability.MyObject.<init>(HighAvailability.java:11) [A] at com.kabira.snippets.highavailability.HighAvailability$1.run(HighAvailability.java:56) [A] at com.kabira.platform.Transaction.execute(Transaction.java:303) [A] at com.kabira.snippets.highavailability.HighAvailability.main(HighAvailability.java:43) [A] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [A] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [A] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [A] at java.lang.reflect.Method.invoke(Method.java:597) [A] at com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:49)
This is expected, because the partition name returned by
getPartition
was not defined. Defining partitions is
described in the section called “Defining and enabling partitions”.