Package org.ozoneDB.core

Source Code of org.ozoneDB.core.Transaction

// You can redistribute this software and/or modify it under the terms of
// the Ozone Core License version 1 published by ozone-db.org.
//
// The original code and portions created by SMB are
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
//
// $Id: Transaction.java,v 1.4 2002/07/26 12:29:22 per_nyfelt Exp $

package org.ozoneDB.core;

import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import org.ozoneDB.DxLib.*;
import org.ozoneDB.*;
import org.ozoneDB.core.DbRemote.*;
import org.ozoneDB.core.dr.*;
import org.ozoneDB.util.*;

import org.ozoneDB.data.SimpleArrayList;

/**
* This class represents an internal transaction.<p>
*
* Most methods of this class are synchronized. In fact, this is not strictly
* needed because a transaction is invoked by one thread (associated with this
* transaction) only.<p>
*
* All public methods are wrapped into try/catch statements to convert thrown
* exception into OzoneInternalExc. So the client gets OzoneRemoteExc, if an
* object could not be found or something; OzoneInternalExc, if there was a
* critical internal error; any other exceptions were thrown by the user code.
*
*
* @author <a href="http://www.softwarebuero.de/">SMB</a>
* @author <A HREF="http://www.medium.net/">Medium.net</A>
* @version $Revision: 1.4 $Date: 2002/07/26 12:29:22 $
*/
public final class Transaction implements Locker {

    /** Status of a transaction: transaction is not active. */
    public final static int STATUS_NONE = 1;

    /** Status of a transaction: transaction has been started. */
    public final static int STATUS_STARTED = 2;

    /** Status of a transaction: transaction is about to prepare. */
    public final static int STATUS_PREPARING = 3;

    /** Status of a transaction: transaction has been successfully prepared. */
    public final static int STATUS_PREPARED = 4;

    /** Status of a transaction: transaction is about to commit.*/
    public final static int STATUS_COMMITING = 5;

    /** Status of a transaction: transaction has been successfully committed. */
    public final static int STATUS_COMMITED = 6;

    /** Status of a transaction: transaction is about to abort. */
    public final static int STATUS_ABORTING = 7;

    /** Status of a transaction: transaction has been aborted. */
    public final static int STATUS_ABORTED = 8;

    public final static int HASHTABLE_INIT_SIZE = 100;

    /**
     * The environment of this object.
     */
    protected transient Env  env;

    protected TransactionID  taID;

    protected String    ownerName;

    protected User    owner;

    protected int    status;

    protected boolean    rollbackOnly;

    protected int    maxLockLevel;

    /**
     * Data that the StoreManager implementation uses to hold data that is associated
     * with this transaction. Usually this is a table of all containers that are
     * currently joined to this transaction.
     */
    private     Object    data;

    protected int    commandCount;

    /**
     * The ID of the object (container) that blocks this transaction.
     */
    protected ObjectID    blocker;

    protected long    startTime;

    protected int    acquireCount;

    protected boolean    stopped;

    /**
        Are we deadlocked?
    */
    protected boolean           deadlocked;

    /**
        The minimum deadlockWaitTimeMaximum can have. (default: 1 second)
    */
    protected final static long deadlockWaitTimeMaximumMinimum  =   1*1000;

    /**
        The maximum deadlockWaitTimeMaximum can have. (default: 30 minutes)
    */
    protected final static long deadlockWaitTimeMaximumMaximum  =   30*60*1000;

    /**
        The maximum time (in milliseconds) to wait after a deadlock.
    */
    protected long              deadlockWaitTimeMaximum;

    /**
        Is this thread sleeping?
    */
    protected boolean           sleeping;

    /**
        The list of {@link ObjectContainer}s which are called by this transactions but where the call
        is not completed. The last object called is represented by the {@link ObjectContainer} with
        the greatest index in the list.
    */
    protected SimpleArrayList   callStack;


    /**
     * Construct a new transaction.
     *
     *
     * @param _env Environment of this transaction.
     * @param _command Command that will be performed by run().
     * @param _owner User that has started this transaction.
     */
    public Transaction( Env _env, User _owner ) {
        env = _env;
        taID = new TransactionID( env.keyGenerator.nextID() );
        owner = _owner;

        callStack       =       new SimpleArrayList(40);
        reset();
    }


    /**
     * Construct a new transaction. THIS TRANSACTION CAN BE USED FOR TESTING
     * ONLY!
     */
    public Transaction( TransactionID _taID ) {
        taID = _taID;
        reset();
    }


    public synchronized void stop() {
        stopped = true;
    }


    public void reset() {
        startTime = System.currentTimeMillis();
        status = STATUS_STARTED;
        commandCount = 0;
        callStack.clear();
        deadlocked = false;
        setData(env.storeManager.newTransactionData());
        if (deadlockWaitTimeMaximum==0) {
            deadlockWaitTimeMaximum =   deadlockWaitTimeMaximumMinimum;
        }
    }

    protected void setDeadlockWaitTimeMaximum(long to) {
        deadlockWaitTimeMaximum = to;
    }

    protected long getDeadlockWaitTimeMaximum() {
        return deadlockWaitTimeMaximum;
    }

    protected long increaseDeadlockWaitTimeMaximum() {
        long newDeadlockWaitTimeMaximum = (long) (getDeadlockWaitTimeMaximum()*1.5);

        if (newDeadlockWaitTimeMaximum>deadlockWaitTimeMaximumMaximum) {
            newDeadlockWaitTimeMaximum  = deadlockWaitTimeMaximumMaximum;
        }

        setDeadlockWaitTimeMaximum(newDeadlockWaitTimeMaximum);

        return newDeadlockWaitTimeMaximum;
    }

    public void setDeadlocked(boolean to) {
//      env.logWriter.newEntry(this,toString()+".setDeadlocked("+to+").", LogWriter.DEBUG2);
        deadlocked = to;
    }

    public boolean isDeadlocked() {
        return deadlocked;
    }

    public int status() {
        return status;
    }


    public User owner() {
        return owner;
    }


    public int maxLockLevel() {
        return maxLockLevel;
    }

    /**
        The corresponding method to {@link #acquireObjectAndPin}.
        <DIV>
            Currently, it just unpins the container.
        </DIV>
    */
    public void releaseObjectAndUnpin(ObjectContainer objectContainer) {
        objectContainer.unpin();
    }

    /**
     * Set a lock on the container specified by the given object ID and join
     * the container to this transaction.
     * If a container is returned, it is pinned. Thus, it has to be unpinned by the caller.
     *
     *
     * @param id ObjectID of the container which we try to join to this transaction.
     * @param lockLevel The lock level we need on this object (container).
     * @return The container for the specified id, if all was ok.
     * @throws ObjectNotFoundExc If there is no such object.
     */
    public ObjectContainer acquireObjectAndPin( ObjectID id, int lockLevel ) throws ObjectNotFoundExc,IOException,ClassNotFoundException,TransactionExc,TransactionError {

        // this is not good style but this method is a hotspot and we should
        // do all we can to make it fast
        if (env.transactionManager.exclusiveThread != null &&
                env.transactionManager.exclusiveThread != Thread.currentThread()) {
            env.transactionManager.checkExclusion();
        }

        ObjectContainer container = env.storeManager.containerForIDAndPin(this,id);

        if (container == null) {
            throw new ObjectNotFoundExc( "No such object ID: " + id );
        }

        boolean allright = false;

        try {
            container = acquireContainer(container,lockLevel);

            allright    =   true;

            return container;
        } finally {
            if (!allright) {
                container.unpin();
            }
        }
    }


    protected ObjectContainer acquireContainer( ObjectContainer container, int lockLevel ) throws PermissionError,TransactionExc,TransactionError,IOException,ObjectNotFoundExc,ClassNotFoundException {

        if (stopped == true) {
            throw new TransactionExc( "Stopped.", TransactionExc.STOPPED );
        }

        maxLockLevel = lockLevel > maxLockLevel ? lockLevel : maxLockLevel;

        acquireCount++;

        // this should help to let the following code execute without
        // interrupt and so ensure that the container that we retrieve from
        // the store is not deactivated while this method is running
        // Thread.currentThread().yield();

        // transaktion als blockiert markieren (kante in lock-graphen einfuegen);
        // vor deadlock-erkennung: es werden auch deadlocks mit
        // transaktionen erkannt, die selber erstmal auf deadlock checken
        // aber auf keinem fall zuwenige (race-cond. zwischen deadlock-pruefung
        // und lock setzen)
        blocker = container.id();

        // this may happen when the container was deactivated between
        // acquireObject() and this point; I'm not sure what to do here

        // But I (Xu�n Baldauf, Medium.net) am (partly):
        // If our caller is acquireContainer(), the container is pinned and thus may not be deactived inbetween.
        // If our caller is createObjectAndPin(), the container is pinned and thus may not be deactived inbetween.
        if (container.lock() == null) {
            throw new IllegalStateException( "Container was wrongly deactivated. Increasing heap memory of the JVM may help." );
        }

        // try to aquire the lock of the container; wait until the locks is
        // successfully aquired
        int prevLevel = container.lock().tryAcquire( this, lockLevel );

        if (prevLevel == Lock.NOT_ACQUIRED) {
            synchronized (this) {
                while (prevLevel == Lock.NOT_ACQUIRED) {
                    try {
                        if (false) {
                            env.logWriter.newEntry( this, toString() + " blocked by lock "+container.lock()+"...", LogWriter.DEBUG );
                        }

                        wait();

                        if (false) {
                            env.logWriter.newEntry( this, toString() + " checking lock again...", LogWriter.DEBUG );
                        }
                    } catch (Exception e) {
                        // do nothing; just proceed...
                    }

                    /*
                        We have two cases:
                        (1) We are called by acquireObjectAndPin()
                        (2) We are not called by acquireObjectAndPin()

                        In case (1), we do not need to reload, because the object is pinned.
                        In case (2), we never come to this code location, because in this case, the objects are freshly created and thus never locked.

                        Thus, we never need to reload.

                        Oh, the reasoning above does not work out. If a cluster is pinned,
                        it still may be aborted and thus need to reload. But maybe then the
                        "pinned" concept is mood. Maybe pinned clusters which are arborted
                        should be reloaded immediately.
                    */

                    // since the container was maybe deactivated while waiting we
                    // reload it here again
                    ObjectContainer newContainer = env.storeManager.containerForIDAndPin(this,blocker);

                    if (container == null) {
                        throw new ObjectNotFoundExc( "No such object." );
                    }

                    // HACK!!!
                    if (!((org.ozoneDB.core.wizardStore.WizardObjectContainer) newContainer).hasSameClusterAs((org.ozoneDB.core.wizardStore.WizardObjectContainer) container)) {
                        if (false) {
                            // Does this allow a pinning livelock?
                            while (container.isPinned()) {
                                newContainer.pin();
                                container.unpin();
                            }
                            newContainer.unpin();
                        } else {
                            int oldPinCount = ((org.ozoneDB.core.wizardStore.WizardObjectContainer) container).getCluster().clearPinCount();

                            ((org.ozoneDB.core.wizardStore.WizardObjectContainer) newContainer).getCluster().addPinCount(oldPinCount);
                            ((org.ozoneDB.core.wizardStore.WizardObjectContainer) newContainer).getCluster().unpin();
                        }

                        container = newContainer;
                    }

                    // throw an exception if we are forced to abort because of a deadlock
                    container.lock().checkDeadlock(this);

                    prevLevel = container.lock().tryAcquire( this, lockLevel );
                }
            }
        }

        if (false) {
            env.logWriter.newEntry(this,toString()+".acquireContainer("+blocker+"): successful.", LogWriter.DEBUG);
        }

                // transaction is no longer blocked
        blocker = null;


        // after acquiring the lock we update the lock level of the container
        if (prevLevel < lockLevel) {
            if (owner == null) {
                throw new PermissionError( "No such user." );
            }
            if (!env.userManager.checkPermission( owner, container, lockLevel )) {
                throw new PermissionError( "User does not have proper access rights." );
            }

            env.storeManager.updateLockLevel( this, container );
        }
        container.touch();

        return container;
    }


    public boolean performCommand(DbCommand command) {
        if (env.logWriter.hasTarget( LogWriter.DEBUG )) {
            env.logWriter.newEntry( this, "performCommand(): " + toString() + ", " + command.toString(), LogWriter.DEBUG );
        }

        commandCount++;

        boolean result = true;
        try {
            // result goes in command.result
            command.perform( this );
        } catch (TransactionError e) {
            throw e;
        } catch (Throwable e) {
            Throwable resultingException = e;

            if (e instanceof ExceptionInOzoneObjectException) {
                if (false) { // User exceptions do not need to be verbose. It's the responsibility of the user to print or not to print out the stack trace.
                    Throwable cause = ((ExceptionInOzoneObjectException) e).getCause();

                    env.logWriter.newEntry( this, toString() + ": exception in ozone object: (" + e + "): ", e, LogWriter.WARN );
                    env.logWriter.newEntry( this, toString() + ": cause:", cause, LogWriter.WARN );

//                  resultingException = cause;
                }
            } else {
                env.logWriter.newEntry( this, toString() + ": uncaught exception: (" + e + ")", e, LogWriter.WARN );
            }

            if (e instanceof PermissionError) {
                e = new PermissionDeniedExc( e.toString() );
            }

            rollbackOnly = true;
            command.result = resultingException;
            result = false;
        }
        return result;
    }


    public synchronized void prepareCommit() throws IOException,ClassNotFoundException {
        if (false&&env.logWriter.hasTarget( LogWriter.DEBUG )) {
            env.logWriter.newEntry( this, "==> PREPARECOMMIT() ", LogWriter.DEBUG );
        }
        status = STATUS_PREPARING;
        env.storeManager.prepareCommitTransaction( this );
        status = STATUS_PREPARED;
    }


    /**
     * Commit this transaction. The transaction has to be in PREPARED state.
     * Ones this method is called it MUST commit the entire transaction
     * stuff without any exception.
     */
    public synchronized void commit() throws IOException,ClassNotFoundException {
        if (false&&env.logWriter.hasTarget( LogWriter.DEBUG )) {
            env.logWriter.newEntry( this, "==> COMMIT() ", LogWriter.DEBUG );
        }

        status = STATUS_COMMITING;
        try {
            env.storeManager.commitTransaction( this );
            // don't delete data in case of an exception
            setData(null);
        } finally {
            blocker = null;
        }
        status = STATUS_COMMITED;
    }

    protected void setData(Object to) {
        data = to;
    }

    public Object getData() {
        return data;
    }


    /**
     * Once this method is called it MUST cleanup the entire transaction
     * stuff without exception. An exception signals an internal server error.
     * <p>
     * Note: This may be called after/from prepareCommit() !
     */
    public synchronized void abort(DbCommand command) throws IOException,ClassNotFoundException {
        if (false&&env.logWriter.hasTarget( LogWriter.DEBUG )) {
            env.logWriter.newEntry( this, "==> ABORT() ", LogWriter.DEBUG );
        }

        status = STATUS_ABORTING;
        try {
            env.storeManager.abortTransaction( this );
        } finally {
            // FIXME: We better do not delete the data now. Somewhere it is used again. (Maybe in case of deadlock retry?)
            setData(null);
            blocker = null;
        }
        status = STATUS_ABORTED;
    }


    /**
     * Helper method to implement the Locker interface to support deadlock
     * recognition via core.dr package
     */
    public Lockable blockedByAndPin() {
        try {
            return blocker != null ? (Lockable) env.storeManager.containerForIDAndPin(this,blocker) : null;
        } catch (NullPointerException e) {
            env.logWriter.newEntry( this, "blockedBy(): Our blocker is invalidated. We are not blocked anymore?",e, LogWriter.ERROR );

            blocker = null;

            return null;
        } catch (Exception e) {
            env.logWriter.newEntry( this, "blockedBy() ",e, LogWriter.ERROR );
            throw new RuntimeException( "blockedBy() FAILED!" );
        }
    }

    /**
        Returns wether this locker is blocked.
    */
    public boolean isBlocked() {
        return blocker!=null;
    }

    /**
     * Create a new database object. If the className is null, an empty container
     * is created.
     *
     * @param className
     * @param access
     * @param name
     * @param id The ID of the new container or null.
     * @exception PermissionDeniedExc If user in invalid, name is already in
     * use, target is not OzoneCompatible...
     */
    public ObjectContainer createObjectAndPin( String className, int access, String name, String sig, Object[] args, ObjectID id ) throws Exception,org.ozoneDB.ExceptionInOzoneObjectException {
        if (false&&env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "createObject() ", LogWriter.DEBUG3 );
        }

        // check (and wait) if a thread runs exclusively;
        env.transactionManager.checkExclusion();

        try {
            Class cl = null;
            if (className != null) {
                cl = env.classManager.classForName( className );
            }

            Permissions perms = new Permissions( owner, access );

            if (id == null) {
                id = new ObjectID( env.keyGenerator.nextID() );
            }

            ObjectContainer container = env.storeManager.newContainerAndPinAndLock(this,null,id,perms,Lock.LEVEL_WRITE);

            boolean alright = false;
            boolean containerAcquired = false;

            try {
                container = acquireContainer(container,Lock.LEVEL_WRITE);
                containerAcquired = true;

                if (cl != null) {
                    container.createTarget( env, cl, sig, args );
                    container.target().onCreate();
                }

                if (name != null) {
                    nameObject( container.id(), name );
                }

                alright = true;

                return container;
            } finally {
                if (!containerAcquired) {
                    /*
                        We have had acquired a lock but somehow did not manage to acquire the corresponding container.
                        Thus, the cluster would not be added to this transaction and thus it would not be unlocked
                        when the transaction is finished. Thus we have to unlock it now.
                    */
                    container./*getCluster().getLock().*/lock().release(this);
                    /*
                        But is this the right behaviour? What if acquireContainer() fails for some reason (e.g. PermissionError)
                        after it locked the cluster itself. Then we would unlock it while it should remain locked? Should it
                        if it fails with an exception?
                    */
                }
                if (!alright) {
                    container.unpin();
                }
            }
        } catch (InvocationTargetException e) {
            Throwable ee = e.getTargetException();

            if (ee instanceof org.ozoneDB.core.TransactionError) {
                throw (org.ozoneDB.core.TransactionError) ee;
            }

            if (ee instanceof ExceptionInOzoneObjectException)
                throw (ExceptionInOzoneObjectException) ee;

            throw new org.ozoneDB.ExceptionInOzoneObjectException("caught",ee);
            /*
            if (ee instanceof RuntimeException) {
                throw (RuntimeException)ee;
            } else if (ee instanceof Exception) {
                throw (Exception)ee;
            } else if (ee instanceof Error) {
                throw (Error)ee;
            } else {
                throw new Exception( "Unknown exception type " + ee.getClass().getName() );
            }
            */
        } catch (ExceptionInOzoneObjectException e) {
            throw e;
        } catch (OzoneRemoteExc e) {
            throw e;
        } catch (Exception e) {
            env.logWriter.newEntry( this, "createObject()", e, LogWriter.WARN );
            throw new OzoneInternalExc(e.toString(),e);
        }
    }


    public ObjectContainer copyObjectAndPin( ObjectID id ) throws Exception {
        if (env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "copyObject() ", LogWriter.DEBUG3 );
        }

        // check (and wait) if a thread runs exclusively;
        env.transactionManager.checkExclusion();

        try {
            if (env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
                env.logWriter.newEntry( this, "copyObject(): " + id.toString(), LogWriter.DEBUG3 );
            }

            ObjectContainer container = acquireObjectAndPin(id,Lock.LEVEL_WRITE);

            try {
                Object          target          = container.targetClone();
                Permissions     perms           = (Permissions)container.permissions().clone();
                ObjectContainer copyContainer   = env.storeManager.newContainerAndPinAndLock( this, (OzoneCompatible)target, new ObjectID( env.keyGenerator.nextID() ), perms,Lock.LEVEL_WRITE);
                boolean         alright         = false;

                try {
                    copyContainer = acquireContainer( copyContainer, Lock.LEVEL_WRITE );
                    alright = true;
                    return copyContainer;
                } finally {
                    if (!alright) {
                        copyContainer.unpin();
                    }
                }
            } finally {
                releaseObjectAndUnpin(container);
            }
        } catch (OzoneRemoteExc e) {
            throw e;
        } catch (Exception e) {
            env.logWriter.newEntry( this, "copyObject()", e, LogWriter.WARN );
            throw new OzoneInternalExc(e.toString(),e);
        }
    }


    public void deleteObject(ObjectID id) throws ObjectNotFoundExc,IOException,ClassNotFoundException,TransactionExc,TransactionError,OzoneRemoteExc,OzoneInternalExc,ExceptionInOzoneObjectException {
        if (false&&env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "deleteObject(): " + id.toString(), LogWriter.DEBUG3 );
        }

        try {
            ObjectContainer container = acquireObjectAndPin(id,Lock.LEVEL_WRITE);

            try {
                try {
                    container.target().onDelete();
                } catch (OzoneRemoteExc e) {
                    throw e;
                } catch (ExceptionInOzoneObjectException e) {
                    throw e;
                } catch (Throwable e) {
                    env.logWriter.newEntry( this, "deleteObject()", e, LogWriter.WARN );
//                  throw new OzoneInternalExc( e.toString() );
                    throw new ExceptionInOzoneObjectException("caught onDelete()",e);
                }
                container.deleteTarget();
            } finally {
                releaseObjectAndUnpin(container);
            }
        } catch (OzoneRemoteExc e) {
            throw e;
        } catch (Exception e) {
            env.logWriter.newEntry( this, "deleteObject()", e, LogWriter.WARN );
            throw new OzoneInternalExc( e.toString(),e);
        }
    }


    /**
     * @param id
     * @param methodName
     * @param sig
     * @param lockLevel
     * @return
     */
    public Object invokeObject(ObjectID id,String methodName,String sig,Object[] args,int lockLevel) throws Exception,org.ozoneDB.ExceptionInOzoneObjectException {
        if (false&&env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "invokeObject(): " + methodName, LogWriter.DEBUG3 );
        }

        try {
            ObjectContainer container = acquireObjectAndPin(id,lockLevel);

            try {
                env.getGarbageCollector().interceptInvocationPre(this,container,args);

                Object result = null;

                try {
                    result = container.invokeTarget( env, methodName, sig, args );
                } finally {
                    env.getGarbageCollector().interceptInvocationPost(this,container,result);
                }

                return result;
            } finally {
                releaseObjectAndUnpin(container);
            }
        // using the container after the invoke is dangerous because
        // it's possibly deactivated meanwhile
        } catch (InvocationTargetException e) {
            Throwable ee = e.getTargetException();

            if (ee instanceof org.ozoneDB.core.TransactionError) {
                throw (org.ozoneDB.core.TransactionError) ee;
            }

            if (ee instanceof ExceptionInOzoneObjectException)
                throw (ExceptionInOzoneObjectException) ee;

            throw new org.ozoneDB.ExceptionInOzoneObjectException("caught",ee);

            /*
            if (ee instanceof RuntimeException) {
                throw (RuntimeException)ee;
            } else if (ee instanceof Exception) {
                throw (Exception)ee;
            } else if (ee instanceof Error) {
                throw (Error)ee;
            } else {
                throw new Exception( "Unknown exception type " + ee.getClass().getName() );
            }
            */
        } catch (ExceptionInOzoneObjectException e) {
            throw e;
        } catch (OzoneRemoteExc e) {
            env.logWriter.newEntry( this, "invokeObject()", e, LogWriter.WARN );
            throw e;
        } catch (Exception e) {
            // since we throw away stack trace of the original exception we
            // create a new log message here
            env.logWriter.newEntry( this, "invokeObject()", e, LogWriter.WARN );
            throw new OzoneInternalExc( e.toString(),e);
        }
    }


    public Object invokeObject( ObjectID id, int methodIndex, Object[] args, int lockLevel ) throws Exception,org.ozoneDB.ExceptionInOzoneObjectException {
        if (env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "invokeObject(,"+methodIndex+"): start.", LogWriter.DEBUG3 );
        }

        try {
            try {
                ObjectContainer container = acquireObjectAndPin(id,lockLevel);

                if(container == null) {
                   System.out.println("***************** Null here!");
                }

                try {
                    env.getGarbageCollector().interceptInvocationPre(this,container,args);

                    Object result = null;

                    try {
                        result = container.invokeTarget( env, methodIndex, args );
                    } finally {
                        env.getGarbageCollector().interceptInvocationPost(this,container,result);
                    }

                    return result;
                } finally {
                    releaseObjectAndUnpin(container);
                }

                // using the container after the invoke is dangerous because
                // it's possibly deactivated meanwhile
            } catch (InvocationTargetException e) {
                Throwable ee = e.getTargetException();

                if (ee instanceof org.ozoneDB.core.TransactionError) {
                    throw (org.ozoneDB.core.TransactionError) ee;
                }

                if (ee instanceof ExceptionInOzoneObjectException)
                   throw (ExceptionInOzoneObjectException) ee;

                throw new ExceptionInOzoneObjectException("caught",ee);
                /*
                if (ee instanceof RuntimeException) {
                    throw (RuntimeException)ee;
                }
                else if (ee instanceof Exception) {
                    throw (Exception)ee;
                }
                else if (ee instanceof Error) {
                    throw (Error)ee;
                }
                else {
                    throw new Exception( "Unknown exception type " + ee.getClass().getName() );
                }
                */
            } catch (ExceptionInOzoneObjectException e) {
                throw e;
            } catch (OzoneRemoteExc e) {
                env.logWriter.newEntry( this, "invokeObject()", e, LogWriter.WARN );
                throw e;
            } catch (Exception e) {
                // since we throw away stack trace of the original exception we
                // create a new log message here
                env.logWriter.newEntry( this, "invokeObject()", e, LogWriter.WARN );
                throw new OzoneInternalExc( e.toString(),e);
            }
        } finally {
            if (env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
                env.logWriter.newEntry( this, "invokeObject(,"+methodIndex+"): end.", LogWriter.DEBUG3 );
            }
        }
    }


    public void nameObject( ObjectID id, String name ) throws Exception {
        if (false&&env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "nameObject()", LogWriter.DEBUG3 );
        }

        try {
            ObjectContainer container = acquireObjectAndPin( id, Lock.LEVEL_WRITE );

            try {
                ObjectContainer oldContainerWithThatName = env.storeManager.containerForNameAndPin(this,name);

                if (oldContainerWithThatName!=null) {
                    oldContainerWithThatName.unpin();
                    throw new PermissionDeniedExc( "Root object name '" + name + "' already exists." );
                }

                env.storeManager.nameContainer( this, container, name );
            } finally {
                releaseObjectAndUnpin(container);
            }
        } catch (OzoneRemoteExc e) {
            throw e;
        } catch (Exception e) {
            env.logWriter.newEntry( this, "nameObject()", e, LogWriter.WARN );
            throw new OzoneInternalExc( e.toString(),e);
        }
    }


    public OzoneProxy objectForName( String name ) throws Exception {
        if (env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "objectForName()", LogWriter.DEBUG3 );
        }

        // check (and wait) if a thread runs exclusively;
        env.transactionManager.checkExclusion();

        try {
            ObjectContainer container = env.storeManager.containerForNameAndPin(this,name);
            if (container != null) {
                try {
                    return container.ozoneProxy();
                } finally {
                    container.unpin();
                }
            } else {
                return null;
            }
        } catch (OzoneRemoteExc e) {
            throw e;
        } catch (Exception e) {
            env.logWriter.newEntry( this, "objectForName()", e, LogWriter.WARN );
            throw new OzoneInternalExc(e.toString(),e);
        }
    }

    public OzoneProxy objectForID( ObjectID id ) throws Exception {
        if (env.logWriter.hasTarget( LogWriter.DEBUG3 )) {
            env.logWriter.newEntry( this, "objectForID()", LogWriter.DEBUG3 );
        }

        // check (and wait) if a thread runs exclusively;
        env.transactionManager.checkExclusion();

        try {
            /*
            ObjectContainer container = env.storeManager.containerForID( this, id );
            if (container != null) {
                return container.ozoneProxy();
            } else {
                return null;
            }
            */
            ObjectContainer container = env.storeManager.containerForIDAndPin(this,id);
            if (container != null) {
                try {
                    return container.ozoneProxy();
                } finally {
                    container.unpin();
                }
            } else {
                return null;
            }
        } catch (OzoneRemoteExc e) {
            throw e;
        } catch (Exception e) {
            env.logWriter.newEntry( this, "objectForID()", e, LogWriter.WARN );
            throw new OzoneInternalExc( e.toString() );
        }
    }

    public void sleep(long millis) {
        try {
            sleeping = true;

            if (false) {
                Thread.currentThread().sleep(millis);
            } else {
                synchronized (this) {
                    this.wait(millis);
                }
            }
        } catch (Exception e) {
            env.logWriter.newEntry(this,"caught while sleeping",e,LogWriter.ERROR);
        } finally {
            sleeping = false;
        }
    }

    protected boolean isSleeping() {
        return sleeping;
    }


    public TransactionID taID() {
        return taID;
    }


    public boolean equals( Object obj ) {
        return hashCode() == obj.hashCode();
    }


    public String toString() {
//      return "ta[" + (byte)taID.value() + "]";
        return "ta[id="+taID+",blocker="+blocker+"]";
    }


    public void finalize() throws Throwable {
//      env.logWriter.newEntry( this, this+".finalize()", LogWriter.DEBUG );
    }

    public SimpleArrayList getCallStack() {
        return callStack;
    }

    public TransactionManager getManager() {
        return env.transactionManager;
    }
}
TOP

Related Classes of org.ozoneDB.core.Transaction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.