Defining partitions using configuration

Example 9.11, “Partition definition in configuration” shows an example of using configuration to define and enable highly available partitions (see the section called “Defining and enabling partitions”). In this snippet, if a partition in the configuration data defines the active node as the local node, the partition is defined and enabled.

The snippet loads and activates the configuration file from main. However, in general, an application would install a configuration notifier, and the configuration data would be automatically loaded as part of node startup, or by the operator during normal operation.

Example 9.11. Partition definition in configuration

//     $Revision: 1.1.2.3 $
package com.kabira.snippets.configuring;

import com.kabira.platform.highavailability.ReplicaNode;
import com.kabira.platform.annotation.Managed;
import com.kabira.platform.ManagedObject;
import com.kabira.platform.Transaction;
import com.kabira.platform.Transaction.Rollback;
import com.kabira.test.management.Client;
import com.kabira.test.management.CommandFailed;
import java.net.URL;
import com.kabira.platform.kcs.Configuration;
import com.kabira.platform.switchconfig.Config;
import com.kabira.platform.switchconfig.ConfigurationListener;
import com.kabira.platform.switchconfig.Version;
import com.kabira.platform.highavailability.PartitionManager;
import com.kabira.platform.highavailability.Partition.Properties;
import static com.kabira.platform.highavailability.PartitionManager.EnableAction.*;
import static com.kabira.platform.highavailability.ReplicaNode.ReplicationType;
import com.kabira.platform.property.Status;

/**
 *  Partition configuration object
 */

@Managed
class Replica
{
    String name;
    ReplicationType type;
}

/**
 * This snippet demonstrates the use of configuration for defining partitions.
 * 
 * NOTE: This snippet requires the classpath to include the
 * directory where the configuration files are located.  This
 * allows the get resource call to locate the configuration files
 *
 * <p>
 * <h2> Target Nodes</h2>
 * <ul>
 * <li> <b>domainname</b> = A
 * </ul>
 */
public class Partition extends Configuration
{
    String  name;
    String activeNode;
    String restoreFromNode = "";
    Boolean forceReplication = false;
    Replica [] replicas;
    
    /**
     * Set configuration type
     * @return Configuration type
     */
    @Override
    public String getType()
    {
        return CONFIGURATION_TYPE;
    }
    
    //
    //  Configuration notifier
    //
    private static class Notifier extends ConfigurationListener
    {
        static final String localNode = System.getProperty(Status.NODE_NAME);

        Notifier()
        {
            super(CONFIGURATION_TYPE);
        }
        
        @Override
        public void activated(Version version)
        {
            Boolean needEnable = false;

            for (Config config : version.getConfigs())
            {
                Partition   partition = (Partition)config;                
                //
                //  Skip partitions that are not active on this node
                //
                if (partition.activeNode.equals(localNode) == false)
                {
                    continue;
                }
                needEnable = true;
                
                //
                //  Define the partition properties
                //
                Properties  properties = new Properties();
                properties.forceReplication(partition.forceReplication);
                properties.restoreFromNode(partition.restoreFromNode);
               
                //
                //  Define the partition
                //
                ReplicaNode [] replicas = new ReplicaNode[partition.replicas.length];
                
                for (int i = 0; i < partition.replicas.length; i++)
                {
                    replicas[i] = new ReplicaNode(
                        partition.replicas[i].name,
                        partition.replicas[i].type);
                }
                PartitionManager.definePartition(
                    partition.name, properties, partition.activeNode, replicas);
            }
            
            //
            //  Enable the partitions
            //
            if (needEnable == true)
            {
                PartitionManager.enablePartitions(JOIN_CLUSTER);
            }
        }
    }
    

    public static void main(String[] args) throws CommandFailed, ClassNotFoundException
    {
        Client client = new Client("guest", "guest");

        URL url1 = client.getClass().getClassLoader().getResource("partitions.kcs");

        if (url1 == null)
        {
            throw new Error(
                "Configuration file partitions.kcs not located - "
                + "is it installed into the current class path?");
        }

        Client.Configuration version = client.new Configuration(url1);
        
        //
        //  Install the configuration notifier
        //
        new Transaction("Install configuration notifier")
        {
            @Override
            protected void run() throws Rollback
            {
                new Notifier();
            }
        }.execute();

        //
        //  Install configuration notifiers
        //
        NotifierLifeCycle   notifierLifeCycle = new NotifierLifeCycle();
        notifierLifeCycle.initialize();


        //
        //  Load, activate configuration file
        //
        version.load();
        version.activate();
        version.deactivate();
        version.remove();

        //
        //  Remove the configuration notifier
        //
        new Transaction("Remove configuration notifier")
        {
            @Override
            protected void run() throws Rollback
            {
                for (Object notifier : ManagedObject.extent(Notifier.class))
                {
                    ManagedObject.delete(notifier);
                }
            }
        }.execute();

    }
    private static final String CONFIGURATION_TYPE = "partition";
}

Example 9.12, “Partition configuration” shows the configuration data captured for each partition. Partition configuration includes:

Example 9.12. Partition configuration

//     $Revision: 1.1.2.1 $
configuration "partitions" version "1.0" type "partition"
{
    configure com.kabira.snippets.configuring
    {
        //
        //    Define partition A with an active node A
        //
        Partition
        {
               name = "A";
               activeNode = "A";
            restoreFromNode = "B";
            forceReplication = true;
            replicas = 
            {
                { 
                    name = "B";
                    type = SYNCHRONOUS;
                },
                {
                    name = "C";
                    type = ASYNCHRONOUS;
                }
            };
        };

        //
        //    Define partition B with an active node B
        //
        Partition
        {
               name = "B";
               activeNode = "B";
            replicas = 
            {
                {
                    name = "A";
                    type = SYNCHRONOUS;
                },
                {
                    name = "C";
                    type = ASYNCHRONOUS;
                }
            };
        };
    };
};

After this snippet has been run on node A and B, displaying the defined partitions in ActiveSpaces® Transactions shows the information in Figure 9.1, “Configured partitions”.

Configured partitions

Figure 9.1. Configured partitions