view src/org/dancres/blitz/disk/DiskTxn.java @ 35:6f68e94c1fb8 default tip

Add CondensedStats monitoring utility, equivalent to vmstat
author Dominic Cleal <dominic-cleal@cdo2.com>
date Thu, 05 Aug 2010 11:07:25 +0100
parents 3dc0c5604566
children
line wrap: on
line source

package org.dancres.blitz.disk;

import java.io.IOException;

import java.util.Stack;
import java.util.logging.Level;

import com.sleepycat.je.Transaction;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Database;

import EDU.oswego.cs.dl.util.concurrent.LockReleaser;

/**
   Disk operations are encapsulated in transactions for the purposes of
   recovery etc.  DiskTxn represents such transactions.  No DiskTxn means
   no disk update.
 */
public class DiskTxn {
    private static ThreadLocal ACTIVE_TXN = new ThreadLocal();

    private Transaction theTxn;

    private boolean amStandalone = false;

    private DiskTxn(Transaction aTxn) {
        theTxn = aTxn;
    }

    private DiskTxn(Transaction aTxn, boolean isStandalone) {
        theTxn = aTxn;
        amStandalone = isStandalone;
    }

    /**
       Create a new txn and make it part of the current thread's context.
       <B>Warning</B> if there's another Txn already associated with this
       thread (i.e. a non-standalone txn) then it will be overwritten by
       this one with the resultant loss of the old transaction which will
       remain open forever - this would be bad!  Under circumstances where
       it's necessary to nest txns, use newStandlone().
     */
    public static DiskTxn newTxn() throws IOException {
        Transaction myDbTxn;

        try {
            myDbTxn = Disk.newTxn();
        } catch (DatabaseException aDbe) {
            Disk.theLogger.log(Level.SEVERE, "Got DatabaseException", aDbe);
            throw new IOException("DatabaseException");
        }

        DiskTxn myTxn = new DiskTxn(myDbTxn);

        ACTIVE_TXN.set(myTxn);

        return myTxn;
    }

    /**
       Create a new txn but don't make it a part of the current thread's
       context.
     */
    public static DiskTxn newStandalone() throws IOException {
        Transaction myDbTxn;
        
        try {
            myDbTxn = Disk.newTxn();
        } catch (DatabaseException aDbe) {
            Disk.theLogger.log(Level.SEVERE, "Got DatabaseException", aDbe);
            throw new IOException("DatabaseException");
        }

        DiskTxn myTxn = new DiskTxn(myDbTxn, true);

        return myTxn;
    }

    /**
       If you choose to use a non-blocking transaction, you must be prepared
       to handle (for Db) <code>DatabaseException</code> with an errno of
       <code>Db.DB_LOCK_NOTGRANTED</code> during any operations performed under
       that transaction.  This breaks encapsulation of Db a little.
       Note that Db documentation for 4.1.25 would lead a programmer to
       believe they need to handle DbLockNotGrantedException - unfortunately,
       that never seems to be thrown - sigh.

       @todo Fix API leakage.
     */
    public static DiskTxn newNonBlockingStandalone() throws IOException {
        Transaction myDbTxn;
        
        try {
            myDbTxn = Disk.newNonBlockingTxn();
        } catch (DatabaseException aDbe) {
            Disk.theLogger.log(Level.SEVERE, "Got DatabaseException", aDbe);
            throw new IOException("DatabaseException");
        }

        DiskTxn myTxn = new DiskTxn(myDbTxn, true);

        return myTxn;
    }

    public static DiskTxn getActiveTxn() {
        return (DiskTxn) ACTIVE_TXN.get();
    }

    public static Transaction getActiveDbTxn() {
        return getActiveTxn().getDbTxn();
    }

    public Transaction getDbTxn() {
        return theTxn;
    }

    /**
       Commit the transaction with no forced logging.  If you want forced
       logging invoke <code>commit(true)</code>.
     */
    public void commit() throws IOException {
        commit(false);
    }

    public void commit(boolean shouldSync) throws IOException {
        try {
            if (shouldSync)
                theTxn.commitSync();
            else 
                theTxn.commitNoSync();
        } catch (DatabaseException aDbe) {
            Disk.theLogger.log(Level.SEVERE, "Got DatabaseException", aDbe);
            throw new IOException("DatabaseException");
        }
            
        release();

        if (!amStandalone)
            ACTIVE_TXN.set(null);
    }

    public void abort() throws IOException {
        try {
            theTxn.abort();
        } catch (DatabaseException aDbe) {
            Disk.theLogger.log(Level.SEVERE, "Got DatabaseException", aDbe);
            throw new IOException("DatabaseException");
        }
            
        release();

        if (!amStandalone)
            ACTIVE_TXN.set(null);
    }

    private void release() {
    }
}