Extents

Managed Objects automatically maintain an extent. The extent makes it possible to find all instances of a Managed Object at any time. Applications should not rely on any ordering of objects in an extent.

Example 5.8. Managed object extents

//     $Revision: 1.1.2.1 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.ManagedObject;
import com.kabira.platform.Transaction;
import com.kabira.platform.annotation.Managed;

/**
 *  Using a managed object extent
 * <p>
 * <h2> Target Nodes</h2>
 * <ul>
 * <li> <b>domainnode</b> = A
 * </ul>
 */
public class Extent
{
    /**
     * A managed object
     */
    @Managed
    public static class MyObject
    {
        MyObject (int number)
        {
            super();
            this.number = number;
        }
        int    number;
    }
    
    /**
     * Main entry point
     * @param args  Not used
     */
    public static void main(String [] args)
    {
        new Transaction("Extent")
        {
            @Override
            protected void run() throws Rollback
            {
                int    j;

                //
                //    Create objects in shared memory
                //
                for (j = 0; j < 10; j++)
                {
                    new MyObject(j);
                }

                //
                //    Iterate the extent deleting all of the created objects
                //
                for (MyObject myObject : ManagedObject.extent(MyObject.class))
                {
                    System.out.println(myObject.number);
                    ManagedObject.delete(myObject);
                }
           }
        }.execute();
    }
}

Locking and isolation

Extents support a transaction isolation of READ COMMITTED. This means that a write lock is not taken on an extent when an object is created or destroyed. This does imply that two extent iterations of the same extent in a transaction may return different results if other transactions have committed between the two iterations.

The specific extent isolation supported is:

  • creates are always visible in the transaction in which they occur

  • deletes are visible in the transaction in which they occur on objects that were created in the same transaction

  • deletes are visible after the transaction commits on objects that were created in a separate transaction

Example 5.9, “Extent locking” demonstrates these rules.

Example 5.9. Extent locking

//     $Revision: 1.1.2.1 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.ManagedObject;
import com.kabira.platform.Transaction;
import com.kabira.platform.Transaction.Rollback;
import com.kabira.platform.annotation.Managed;

/**
 *  Extent locking
 * <p>
 * <h2> Target Nodes</h2>
 * <ul>
 * <li> <b>domainnode</b> = A
 * </ul>
 */
public class Locking extends Transaction
{
    /**
     * A managed object
     */
    @Managed
    public static class MyObject { }
    
    /**
     * Control program execution
     */
    public enum Action
    {
        /**
         * Create objects in a separate transaction
         */
        CREATE,
        /**
         * Create and delete objects in the same transaction
         */
        BOTH,
        /**
         * Delete objects in a separate transaction
         */
        DELETE
    }

    private Action    m_action;
    private String    m_message;
    
    /**
     * Main entry point
     * @param args  Not used
     */
    public static void main(String [] args)
    {
        Locking    locking = new Locking();
        
        locking.m_action = Action.BOTH;
        locking.m_message = "Same Transaction";
        locking.execute();
        
        locking.m_action = Action.CREATE;
        locking.m_message = "Separate Transactions";
        locking.execute();

        locking.m_action = Action.DELETE;
        locking.m_message = "Separate Transactions";
        locking.execute();
    }
    
    /**
     * Transaction run method
     * 
     * @throws com.kabira.platform.Transaction.Rollback
     */
    @Override
    protected void run() throws Rollback
    {
        int    i;
        
        if ((m_action == Action.BOTH) || (m_action == Action.CREATE))
        {        
            for (i = 0; i < 10; i++)
            {
                new MyObject();
            }
        }
                
        if ((m_action == Action.BOTH) || (m_action == Action.CREATE))
        {        
            System.out.println(m_message);
            System.out.println(ManagedObject.cardinality(MyObject.class)
                + " objects in extent after create");
        }
        
        if (m_action == Action.BOTH || m_action == Action.DELETE)
        {
            for (MyObject j1 : ManagedObject.extent(MyObject.class))
            {
                ManagedObject.delete(j1);
            }
        
            System.out.println(ManagedObject.cardinality(MyObject.class)
                + " objects in extent after delete");
        }
    }
}

When Example 5.9, “Extent locking” is run it outputs (annotation added):

Example 5.10. Extent locking output

#
#     Both creates and deletes are reflected because both are done
#     in the same transaction
#
[A] Same Transaction
[A] 10 objects in extent after create
[A] 0 objects in extent after delete

#
#     Deletes are not reflected until the tranasction commits because
#     creates occurred in a separate transction
#
[A] Separate Transactions
[A] 10 objects in extent after create
[A] 10 objects in extent after delete

There are two extent methods supported for Managed Objects - one that explicitly takes a transaction lock on returned objects and one that does not take a transaction lock on returned objects. If no transaction lock is taken on objects returned from extent iteration, a transaction lock is taken when a field in the object is accessed or the object is explicitly locked (see the section called “Explicit locking”).

As discussed above, there is no lock taken on an extent when objects are created or deleted. The combination of no extent locking, and locks optionally not being taken on objects returned from extent iteration, may cause deleted object references being returned from an extent. This is shown in Example 5.11, “Extent object locking”.

Example 5.11. Extent object locking

//     $Revision: 1.1.2.1 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.Transaction;
import com.kabira.platform.ManagedObject;
import com.kabira.platform.annotation.Managed;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *  Demonstrate extent iteration with object deletion.
 * <p>
 * <h2> Target Nodes</h2>
 * <ul>
 * <li> <b>domainnode</b> = A
 * </ul>
 */
public class ObjectLocking
{
    /**
     * A managed object
     */
    @Managed
    public static class MyObject { };

    /**
     * Life cycle thread
     * <p>
     * This thread creates and deletes Managed Objects in shared memory.
     * Sleep to introduce some variability
     */
    public static class LifeCycleThread extends Thread
    {
        private static final int    NUMBERITERATIONS = 10;
        @Override
        public void run()
        {
            int        i;
            for (i = 0; i < NUMBERITERATIONS; i++)
            {
                try
                {
                    new LifeCycleTransaction(
						LifeCycleTransaction.Action.CREATE).execute();
                    Thread.sleep(1000);
                    new LifeCycleTransaction(
						LifeCycleTransaction.Action.DELETE).execute();
                }
                catch (InterruptedException ex)
                {
                    Logger.getLogger(
						LifeCycleThread.class.getName()).log(
						Level.SEVERE, null, ex);
                }
            }
        }
    }

    /**
     * Life cycle transaction
     * <p>
     *  Transaction to create and delete Managed Objects
     */
    public static class LifeCycleTransaction extends Transaction
    {
        private static final int    COUNT = 100;

        /**
         * Control transaction behavior
         */
        public enum Action
        {
            /**
             * Create managed objects
             */
            CREATE,
            /**
             * Delete managed objects
             */
            DELETE
        }

        LifeCycleTransaction (Action action)
        {
            m_action = action;
        }

        private Action    m_action;

        /**
         * Transaction run method
         * 
         * @throws com.kabira.platform.Transaction.Rollback
         */
        @Override
        protected void run() throws Rollback
        {
            //
            //    Create managed Managed Objects
            //
            if (m_action == Action.CREATE)
            {
                int    i;

                for (i = 0; i < COUNT; i++)
                {
                    new MyObject();
                }
            }
            else
            {
                assert ( m_action == Action.DELETE );

                //
                //    Iterate extent - test for deleted objects, delete 
                //    ones that are not already deleted by another thread
                //
                for (MyObject k : ManagedObject.extent(MyObject.class))
                {
                    if (ManagedObject.isEmpty(k) == false)
                    {
                        ManagedObject.delete(k);
                    }
                }
            }
        }

    }
    private static final int    NUMBERTHREADS = 15;
    
    /**
     * Main entry point
     * @param args  Not used
     * @throws java.lang.InterruptedException
     */
    public static void main(String [] args) throws InterruptedException
    {
        int        i;
        LifeCycleThread        threads[] = new LifeCycleThread[NUMBERTHREADS];
        
        for (i = 0; i < NUMBERTHREADS; i++)
        {
            threads[i] = new LifeCycleThread();
            threads[i].start();
        }
        
        //
        //    Wait for all of the threads to exit
        //
        for (i = 0; i < NUMBERTHREADS; i++)
        {
            threads[i].join();
        }
    }
}