Package com.atomikos.icatch.imp

Source Code of com.atomikos.icatch.imp.CoordinatorStateHandler

//$Id: CoordinatorStateHandler.java,v 1.2 2006/09/19 08:03:51 guy Exp $
//$Log: CoordinatorStateHandler.java,v $
//Revision 1.2  2006/09/19 08:03:51  guy
//FIXED 10050
//
//Revision 1.1.1.1  2006/08/29 10:01:05  guy
//Import of 3.0 essentials edition.
//
//Revision 1.1.1.1  2006/04/29 08:55:37  guy
//Initial import.
//
//Revision 1.1.1.1  2006/03/29 13:21:28  guy
//Imported.
//
//Revision 1.1.1.1  2006/03/23 16:25:27  guy
//Imported.
//
//Revision 1.1.1.1  2006/03/22 13:46:53  guy
//Import.
//
//Revision 1.2  2006/03/15 10:31:39  guy
//Formatted code.
//
//Revision 1.1.1.1  2006/03/09 14:59:08  guy
//Imported 3.0 development into CVS repository.
//
//Revision 1.9  2005/08/15 12:55:54  guy
//Corrected BUG: deadlock on immediate shutdown with interleaving
//terminating coordinator (statehandler). The entered() callback
//in the TS deadlocked with the shutdown (trying to synch in turn
//on the blocked statehandler.
//
//Revision 1.8  2005/08/15 10:43:27  guy
//Discovered (but not fixed) BUG: deadlock in state handler of
//immediate shutdown interleaves with entered() notification of TS.
//
//Revision 1.7  2004/11/24 10:20:15  guy
//Updated error messages.
//
//Revision 1.6  2004/10/12 13:03:25  guy
//Updated docs (changed Atomikos to Atomikos in many places).
//
//Revision 1.5  2004/09/06 09:26:37  guy
//Redesigned recovery: can now be done at any time.
//Resources can now be added after init() and will be
//recovered immediately rather than on the next restart.
//
//Revision 1.4  2004/09/03 10:00:18  guy
//Added check in replayCompletion: to make it idempotent.
//
//Revision 1.3  2004/09/01 13:39:02  guy
//Merged changes from TransactionsRMI 1.22.
//Corrected bug in SysException.printStackTrace.
//Added log method to Configuration.
//
//Revision 1.2  2004/03/22 15:36:53  guy
//Merged-in changes from branch redesign-4-2003.
//
//Revision 1.1.2.5  2004/01/14 10:38:25  guy
//Corrected forget to not block.
//
//Revision 1.1.2.4  2003/11/17 19:02:16  guy
//Corrected BUG: CoordinatorStateHandler blocked on forget() with readonly
//participant. Extended test for UserTransactionService.
//
//Revision 1.1.2.3  2003/06/20 16:31:32  guy
//*** empty log message ***
//
//Revision 1.1.2.2  2003/05/12 07:00:07  guy
//Redesigned Coordinator with STATE PATTERN.
//


             
/*
* Copyright 2000-2008, Atomikos (http://www.atomikos.com)
*
* This code ("Atomikos TransactionsEssentials"), by itself,
* is being distributed under the
* Apache License, Version 2.0 ("License"), a copy of which may be found at
* http://www.atomikos.com/licenses/apache-license-2.0.txt .
* You may not use this file except in compliance with the License.
*            
* While the License grants certain patent license rights,
* those patent license rights only extend to the use of
* Atomikos TransactionsEssentials by itself.
*            
* This code (Atomikos TransactionsEssentials) contains certain interfaces
* in package (namespace) com.atomikos.icatch
* (including com.atomikos.icatch.Participant) which, if implemented, may
* infringe one or more patents held by Atomikos. 
* It should be appreciated that you may NOT implement such interfaces;
* licensing to implement these interfaces must be obtained separately from Atomikos.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
package com.atomikos.icatch.imp;

import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;

import com.atomikos.diagnostics.Console;
import com.atomikos.icatch.HeurCommitException;
import com.atomikos.icatch.HeurHazardException;
import com.atomikos.icatch.HeurMixedException;
import com.atomikos.icatch.HeurRollbackException;
import com.atomikos.icatch.HeuristicMessage;
import com.atomikos.icatch.Participant;
import com.atomikos.icatch.RollbackException;
import com.atomikos.icatch.SysException;
import com.atomikos.icatch.TxState;
import com.atomikos.icatch.system.Configuration;

/**
*
*
* Application of the state pattern to the transaction coordinator: each
* important state has a handler and this class is the superclass that holds
* common logic.
*
* <b>Note: this class and it subclasses should not use synchronized blocks;
* the coordinator (owner) class is responsible for synchronizing access to
* this class.</b>
*/

abstract class CoordinatorStateHandler implements Serializable, Cloneable
{
    private static final int THREADS = 1;
    // how many propagator threads do we need?

    private transient CoordinatorImp coordinator_;
    // the coordinator instance whose state we represent

    private Hashtable readOnlyTable_;
    // a hash table that keeps track of which participants are readonly
    // needed on prepare, commit and rollback

    private transient Propagator propagator_;
    // The propagator for propagation of messages

    private transient Stack replayStack_;
    // where replay requests are queued

    private Boolean committed_;
    // True iff commit, False iff rollback, otherwise null

    private transient Dictionary cascadeList_;
    // The participants to cascade prepare to

    private Hashtable heuristicMap_;

    // Where heuristic states are mapped to participants in that state

    /**
     * Creates a new instance.
     *
     * @param coordinator
     *            The coordinator to represent.
     *
     */

    protected CoordinatorStateHandler ( CoordinatorImp coordinator )
    {
        coordinator_ = coordinator;
        replayStack_ = new Stack ();
        readOnlyTable_ = new Hashtable ();
        committed_ = null;

        heuristicMap_ = new Hashtable ();
        heuristicMap_.put ( TxState.HEUR_HAZARD, new Stack () );
        heuristicMap_.put ( TxState.HEUR_MIXED, new Stack () );
        heuristicMap_.put ( TxState.HEUR_ABORTED, new Stack () );
        heuristicMap_.put ( TxState.HEUR_COMMITTED, new Stack () );
        heuristicMap_.put ( TxState.TERMINATED, new Stack () );
    }

    /**
     * For use in this class or subclasses only. This constructor creates a new
     * instance based on a previous state handler's attributes. In this case,
     * activate or recover should NOT be called!
     *
     * @param other
     *            The previous instance whose attributes should be used.
     */

    protected CoordinatorStateHandler ( CoordinatorStateHandler other )
    {
        coordinator_ = other.coordinator_;
        propagator_ = other.propagator_;
        replayStack_ = other.replayStack_;
        readOnlyTable_ = other.readOnlyTable_;
        committed_ = other.committed_;
        cascadeList_ = other.cascadeList_;

        heuristicMap_ = other.heuristicMap_;

    }

    /**
     * For testing only.
     */

    void setCommitted ()
    {
        committed_ = new Boolean ( true );
    }

    /**
     * Performs a deep clone of the state handler, needed for logging the state
     * information in this handler.
     *
     * @return Object The deep clone.
     */

    public Object clone ()
    {

        CoordinatorStateHandler clone = null;
        try {
            clone = (CoordinatorStateHandler) super.clone ();
            clone.readOnlyTable_ = (Hashtable) readOnlyTable_.clone ();

            clone.heuristicMap_ = new Hashtable ();

            Stack hazStack = (Stack) heuristicMap_.get ( TxState.HEUR_HAZARD );
            Stack mixStack = (Stack) heuristicMap_.get ( TxState.HEUR_MIXED );
            Stack comStack = (Stack) heuristicMap_
                    .get ( TxState.HEUR_COMMITTED );
            Stack abStack = (Stack) heuristicMap_.get ( TxState.HEUR_ABORTED );
            Stack termStack = (Stack) heuristicMap_.get ( TxState.TERMINATED );

            clone.heuristicMap_.put ( TxState.HEUR_HAZARD, hazStack.clone () );
            clone.heuristicMap_.put ( TxState.HEUR_MIXED, mixStack.clone () );
            clone.heuristicMap_
                    .put ( TxState.HEUR_COMMITTED, comStack.clone () );
            clone.heuristicMap_.put ( TxState.HEUR_ABORTED, abStack.clone () );
            clone.heuristicMap_.put ( TxState.TERMINATED, termStack.clone () );
        } catch ( CloneNotSupportedException e ) {
            throw new RuntimeException (
                    "CoordinatorStateHandler: clone failure :"
                            + e.getMessage () );
        }

        return clone;
    }

    /**
     * Adds a participant with a given heuristic state to the map.
     *
     * @param p
     *            The participant.
     * @param state
     *            The (heuristic) state. Should be one of the four heuristic
     *            states, or the terminated state.
     */

    protected void addToHeuristicMap ( Participant p , Object state )
    {
        Stack stack = (Stack) heuristicMap_.get ( state );
        // returns non-null since stack is always created at construction time,
        // and restored from log image as well
        stack.push ( p );

    }

    /**
     * Adds a map of participants -> heuristic states to the map of heuristic
     * states -> participants. This method is called after heuristics on
     * commit/rollback, and allows to retrieve the exact state of each single
     * participant in case of heuristic terminations.
     *
     * @param participants
     *            The participant to heuristic state map.
     */

    protected void addToHeuristicMap ( Hashtable participants )
    {
        Enumeration parts = participants.keys ();
        while ( parts.hasMoreElements () ) {
            Participant next = (Participant) parts.nextElement ();
            Object state = participants.get ( next );
            addToHeuristicMap ( next, state );
            // System.err.println ( "Adding to heuristic map: state " + state );
        }
    }

    /**
     * Gets the heuristic messages for all participants that are in the given
     * heuristic state
     *
     * @param heuristicState
     *            The heuristic state, or the terminated state.
     * @return HeuristicMessage[] The heuristic messages of all participants in
     *         the given state, or an empty array if none.
     */

    protected HeuristicMessage[] getHeuristicMessages (
            Object heuristicState )
    {
        Vector msgs = new Vector ();

        Stack parts = (Stack) heuristicMap_.get ( heuristicState );
        if ( parts == null ) {
            throw new RuntimeException ( "Error: getHeuristicMessages "
                    + "for non-mapped heuristic state: " + heuristicState );
        }
        Enumeration enumm = parts.elements ();
        while ( enumm.hasMoreElements () ) {
            Participant p = (Participant) enumm.nextElement ();
            HeuristicMessage[] errs = p.getHeuristicMessages ();
            if ( errs != null ) {
                for ( int i = 0; i < errs.length; i++ ) {
                    msgs.addElement ( errs[i] );
                }
            }
        }
        HeuristicMessage[] template = new HeuristicMessage[0];
        return (HeuristicMessage[]) msgs.toArray ( template );
    }

    /**
     * Get the heuristic info for the message round.
     *
     * @return HeuristicMessages[] The heuristic messages, or an empty array if
     *         none.
     */

    protected HeuristicMessage[] getHeuristicMessages ()
    {
        // this method should NOT be synchronized to make rollback
        // recursion-safe.
        Vector msgs = new Vector ();
        Enumeration enumm = coordinator_.getParticipants ().elements ();
        while ( enumm.hasMoreElements () ) {
            Participant p = (Participant) enumm.nextElement ();
            HeuristicMessage[] errs = p.getHeuristicMessages ();
            if ( errs != null ) {
                for ( int i = 0; i < errs.length; i++ ) {
                    msgs.addElement ( errs[i] );
                }
            }
        }

        HeuristicMessage[] template = new HeuristicMessage[0];
        return (HeuristicMessage[]) msgs.toArray ( template );
    }

    /**
     * Get the coordinator whose state we handle.
     *
     * @return CoordinatorImp The coordinator.
     */

    protected CoordinatorImp getCoordinator ()
    {
        return coordinator_;
    }

    protected long getRollbackTicks ()
    {
        // return 0 by default
        return 0;
    }

    /**
     * Get the replay stack for replay completion requests.
     *
     * @return Stack The stack with replay requests, or an empty stack if none
     *         are present.
     */

    protected Stack getReplayStack ()
    {
        return replayStack_;
    }

    /**
     * Get the readonly table.
     *
     * @return The table.
     */

    protected Hashtable getReadOnlyTable ()
    {
        return readOnlyTable_;
    }

    /**
     * Get the cascade list.
     *
     * @return Dictionary The cascade list.
     */

    protected Dictionary getCascadeList ()
    {
        return cascadeList_;
    }

    /**
     * Get the propagator for sending messages in the subclasses.
     *
     * @return Propagator The propagator.
     */

    protected Propagator getPropagator ()
    {
        return propagator_;
    }

    /**
     * Test if the result was commit.
     *
     * @return Boolean Null if not known yet, True if commit, False if rollback.
     */

    protected Boolean getCommitted ()
    {
        return committed_;
    }

    /**
     * Tests if commit has happened.
     *
     * @return boolean True iff commit happened.
     */

    protected boolean isCommitted ()
    {
        if ( committed_ == null )
            return false;
        else
            return committed_.booleanValue ();
    }

    /**
     * Print a message to the console.
     *
     * @param message
     *            The message to print.
     */

    protected void printMsg ( String message )
    {
        try {
            Console console = coordinator_.getConsole ();
            if ( console != null )
                console.println ( message );
        } catch ( IOException io ) {
        }
    }

    protected void printMsg ( String msg , int level )
    {
        Console console = coordinator_.getConsole ();
        if ( console != null ) {
            try {
                console.println ( msg, level );
            } catch ( IOException ioerr ) {

            }
        }
    }

    /**
     * Sets the table of readonly participants.
     *
     * @param table
     *            The table.
     */

    protected void setReadOnlyTable ( Hashtable table )
    {
        readOnlyTable_ = table;
    }

    /**
     * Start the threads. This method should be called when the state handler
     * should start being active, as the first method for recovered instances or
     * when the constructor without a propagator argument is called.
     */

    protected void activate ()
    {
        // stopThreads removed to make activate idempotent
        // required for new recovery!
        // if ( propagator_ != null ) propagator_.stopThreads();
          boolean threaded = !coordinator_.prefersSingleThreaded2PC();
        if ( propagator_ == null )
            propagator_ = new Propagator ( threaded );
    }

    /**
     * Recover the state handler after restart. For safety, this method should
     * be called AFTER activate has been called, or recovery may not work fine!
     *
     * @param coordinator
     *            The (transient) coordinator to use.
     */

    protected void recover ( CoordinatorImp coordinator )
    {
        coordinator_ = coordinator;
        replayStack_ = new Stack ();
    }

    /**
     * Notification of shutdown; this method triggers the stopping of all active
     * threads for propagation.
     */

    protected void dispose ()
    {
          //notifying threads is no longer required since 3.2
        propagator_ = null;
    }

    /**
     * Handle a replay request for a participant. This method makes the
     * participant eligible for replay on the next timer event, but does nothing
     * else. Subclasses should take care of checking preconditions!
     *
     * @return Boolean Indication of the termination decision, null if not known yet.
     */

    protected Boolean replayCompletion ( Participant participant )
            throws IllegalStateException
    {
        // check added to make recovery idempotent
        // as from the official 2.0 release
        if ( !replayStack_.contains ( participant ) )
            replayStack_.push ( participant );

        return committed_;
    }

    /**
     * Utility method for subclasses.
     *
     * @param participants
     */
    protected void addAllForReplay ( Collection participants )
    {
      Iterator it = participants.iterator();
      while ( it.hasNext() ) {
        Participant p = ( Participant ) it.next();
        replayCompletion ( p );
      }
    }
   
    /**
     * The corresponding 2PC method is delegated hereto.
     */

    protected void setCascadeList ( Dictionary allParticipants )
    {
        cascadeList_ = allParticipants;
    }

    /**
     * Callback method on timeout event of the coordinator. The interpretation
     * of timeout will typically be different for each state handler; some may
     * rollback while others need to inquire about completion. This method
     * should also check any replay requests.
     */

    protected abstract void onTimeout ();

    /**
     * Get the (non-pseudo) coordinator state to which this handler belongs.
     *
     * @return Object The object that represents the corresponsding coordinator
     *         state.
     */

    abstract Object getState ();

    /**
     * The corresponding 2PC method is delegated hereto.
     */

    abstract void setGlobalSiblingCount ( int count );

    /**
     * The corresponding 2PC method is delegated hereto.
     */

    protected abstract int prepare () throws RollbackException,
            java.lang.IllegalStateException, HeurHazardException,
            HeurMixedException, SysException;

    /**
     * The corresponding 2PC method is delegated hereto. Subclasses should
     * override this, and may use the auxiliary commit method provided by this
     * class (in addition to their state-specific preconditions).
     *
     */

    protected abstract HeuristicMessage[] commit ( boolean onePhase )
            throws HeurRollbackException, HeurMixedException,
            HeurHazardException, java.lang.IllegalStateException,
            RollbackException, SysException;

    /*
     * The corresponding 2PC method is delegated hereto. Subclasses should
     * override this, and may use the auxiliary rollback method provided by this
     * class (in addition to their state-specific preconditions).
     */

    protected abstract HeuristicMessage[] rollback ()
            throws HeurCommitException, HeurMixedException, SysException,
            HeurHazardException, java.lang.IllegalStateException;

    /**
     * Auxiliary method for committing. This method can be reused in subclasses
     * in order to process commit.
     *
     * @param heuristic
     *            True iff a heuristic commit should be done.
     * @param onePhase
     *            True iff one-phase commit.
     */

    protected HeuristicMessage[] commit ( boolean heuristic ,
            boolean onePhase ) throws HeurRollbackException,
            HeurMixedException, HeurHazardException,
            java.lang.IllegalStateException, RollbackException, SysException
    {
        Stack errors = new Stack ();
        CoordinatorStateHandler nextStateHandler = null;

        try {

            Vector participants = coordinator_.getParticipants ();
            int count = (participants.size () - readOnlyTable_.size ());
            TerminationResult commitresult = new TerminationResult ( count );

            try {
              coordinator_.setState ( TxState.COMMITTING );
            } catch ( RuntimeException error ) {
            //See case 23334
            String msg = "Error in committing: " + error.getMessage() + " - rolling back instead";
            Configuration.logWarning ( msg , error );
            try {
          rollback ( getCoordinator().isRecoverableWhileActive().booleanValue() , false );
          throw new RollbackException ( msg );
            } catch ( HeurCommitException e ) {
          Configuration.logWarning ( "Illegal heuristic commit during rollback:" + e );
          throw new HeurMixedException ( e.getHeuristicMessages() );
        }
          }
            committed_ = new Boolean ( true );
            // for replaying completion: commit decision was reached
            // otherwise, replay requests might only see TERMINATED!

            // start messages
            Enumeration enumm = participants.elements ();
            while ( enumm.hasMoreElements () ) {
                Participant p = (Participant) enumm.nextElement ();
                if ( !readOnlyTable_.containsKey ( p ) ) {
                    CommitMessage cm = new CommitMessage ( p, commitresult,
                            onePhase );

                    // if onephase: set cascadelist anyway, because if the
                    // participant is a REMOTE one, then it might have
                    // multiple participants that are not visible here!

                    if ( onePhase && cascadeList_ != null ) { // null for OTS
                                                                // case?
                        Integer sibnum = (Integer) cascadeList_.get ( p );
                        if ( sibnum != null ) // null for local participant!
                            p.setGlobalSiblingCount ( sibnum.intValue () );
                        p.setCascadeList ( cascadeList_ );
                    }
                    propagator_.submitPropagationMessage ( cm );
                    // this will trigger sending the message
                }
            } // while

            commitresult.waitForReplies ();
            int res = commitresult.getResult ();

            if ( res != TerminationResult.ALL_OK ) {

                if ( res == TerminationResult.HEUR_MIXED ) {
                    Hashtable hazards = commitresult.getPossiblyIndoubts ();
                    Hashtable heuristics = commitresult
                            .getHeuristicParticipants ();
                    addToHeuristicMap ( heuristics );
                    enumm = participants.elements ();
                    while ( enumm.hasMoreElements () ) {
                        Participant p = (Participant) enumm.nextElement ();
                        if ( !heuristics.containsKey ( p ) )
                            addToHeuristicMap ( p, TxState.TERMINATED );
                    }
                    nextStateHandler = new HeurMixedStateHandler ( this,
                            hazards );

                    coordinator_.setStateHandler ( nextStateHandler );
                    throw new HeurMixedException ( getHeuristicMessages () );
                }

                else if ( res == TerminationResult.ROLLBACK ) {
                    // 1PC and rolled back before commit arrived.
                    nextStateHandler = new TerminatedStateHandler ( this );
                    coordinator_.setStateHandler ( nextStateHandler );
                    throw new RollbackException ( "Rolled back already." );
                } else if ( res == TerminationResult.HEUR_ROLLBACK ) {
                    nextStateHandler = new HeurAbortedStateHandler ( this );
                    coordinator_.setStateHandler ( nextStateHandler );
                    // Here, we do NOT need to add extra information, since ALL
                    // participants
                    // agreed to rollback. Therefore, we need not worry about
                    // who aborted
                    // and who committed.
                    throw new HeurRollbackException ( getHeuristicMessages () );

                }

                else if ( res == TerminationResult.HEUR_HAZARD ) {
                    Hashtable hazards = commitresult.getPossiblyIndoubts ();
                    Hashtable heuristics = commitresult
                            .getHeuristicParticipants ();
                    addToHeuristicMap ( heuristics );
                    enumm = participants.elements ();
                    while ( enumm.hasMoreElements () ) {
                        Participant p = (Participant) enumm.nextElement ();
                        if ( !heuristics.containsKey ( p ) )
                            addToHeuristicMap ( p, TxState.TERMINATED );
                    }
                    nextStateHandler = new HeurHazardStateHandler ( this,
                            hazards );
                    coordinator_.setStateHandler ( nextStateHandler );
                    throw new HeurHazardException ( getHeuristicMessages () );
                }

            } else {
                // all OK
                if ( heuristic ) {
                    nextStateHandler = new HeurCommittedStateHandler ( this );
                    // again, here we do NOT need to preserve extra
                    // per-participant
                    // state mappings, since ALL participants were heur.
                    // committed.
                } else
                    nextStateHandler = new TerminatedStateHandler ( this );

                coordinator_.setStateHandler ( nextStateHandler );
            }
        } catch ( RuntimeException runerr ) {
            errors.push ( runerr );
            throw new SysException (
                    "Error in commit: " + runerr.getMessage (), errors );
        }

        catch ( InterruptedException intr ) {
            errors.push ( intr );
            throw new SysException ( "Error in commit" + intr.getMessage (),
                    errors );
        }

        return getHeuristicMessages ();

    }

    /**
     * Auxiliary method for rollback. This method can be reused in subclasses in
     * order to process rollback.
     *
     * @param indoubt
     *            True iff some participants may already have voted YES.
     * @param heuristic
     *            True iff a heuristic commit should be done.
     */

    protected HeuristicMessage[] rollback ( boolean indoubt ,
            boolean heuristic ) throws HeurCommitException, HeurMixedException,
            SysException, HeurHazardException, java.lang.IllegalStateException
    {
        // propagate ONLY IF participants are NOT readonly!

        Stack errors = new Stack ();
        CoordinatorStateHandler nextStateHandler = null;
        try {

            coordinator_.setState ( TxState.ABORTING );

            // mark decision for replay requests; since these might only
            // see TERMINATED state!
            committed_ = new Boolean ( false );

            Vector participants = coordinator_.getParticipants ();
            int count = (participants.size () - readOnlyTable_.size ());

            TerminationResult rollbackresult = new TerminationResult ( count );

            // start messages

            Enumeration enumm = participants.elements ();
            while ( enumm.hasMoreElements () ) {
                Participant p = (Participant) enumm.nextElement ();
                if ( !readOnlyTable_.containsKey ( p ) ) {
                    RollbackMessage rm = new RollbackMessage ( p,
                            rollbackresult, indoubt );
                    propagator_.submitPropagationMessage ( rm );
                    // this will trigger sending the message
                }
            } // while

            rollbackresult.waitForReplies ();
            int res = rollbackresult.getResult ();

            // check results, but we only care if we are indoubt.
            // otherwise, we don't mind any remaining indoubts.

            if ( indoubt && res != TerminationResult.ALL_OK ) {

                if ( res == TerminationResult.HEUR_MIXED ) {
                    Hashtable hazards = rollbackresult.getPossiblyIndoubts ();
                    Hashtable heuristics = rollbackresult
                            .getHeuristicParticipants ();
                    addToHeuristicMap ( heuristics );
                    enumm = participants.elements ();
                    while ( enumm.hasMoreElements () ) {
                        Participant p = (Participant) enumm.nextElement ();
                        if ( !heuristics.containsKey ( p ) )
                            addToHeuristicMap ( p, TxState.TERMINATED );
                    }
                    nextStateHandler = new HeurMixedStateHandler ( this,
                            hazards );
                    coordinator_.setStateHandler ( nextStateHandler );
                    throw new HeurMixedException ( getHeuristicMessages () );
                }

                else if ( res == TerminationResult.HEUR_COMMIT ) {
                    nextStateHandler = new HeurCommittedStateHandler ( this );
                    coordinator_.setStateHandler ( nextStateHandler );
                    // NO extra per-participant state mappings, since ALL
                    // participants
                    // are heuristically committed.
                    throw new HeurCommitException ( getHeuristicMessages () );

                }

                else if ( res == TerminationResult.HEUR_HAZARD ) {
                    Hashtable hazards = rollbackresult.getPossiblyIndoubts ();
                    Hashtable heuristics = rollbackresult
                            .getHeuristicParticipants ();
                    // will trigger logging of indoubts and messages
                    addToHeuristicMap ( heuristics );
                    enumm = participants.elements ();
                    while ( enumm.hasMoreElements () ) {
                        Participant p = (Participant) enumm.nextElement ();
                        if ( !heuristics.containsKey ( p ) ) {
                            addToHeuristicMap ( p, TxState.TERMINATED );
                        }
                    }
                    nextStateHandler = new HeurHazardStateHandler ( this,
                            hazards );
                    coordinator_.setStateHandler ( nextStateHandler );
                    throw new HeurHazardException ( getHeuristicMessages () );
                }
            }

            else {
                // all answers OK
                if ( heuristic ) {
                    nextStateHandler = new HeurAbortedStateHandler ( this );
                    // NO per-participant state mapping needed, since ALL agree
                    // on same
                    // heuristic outcome.
                } else
                    nextStateHandler = new TerminatedStateHandler ( this );

                coordinator_.setStateHandler ( nextStateHandler );
            }

        }

        catch ( RuntimeException runerr ) {
            errors.push ( runerr );
            throw new SysException ( "Error in rollback: "
                    + runerr.getMessage (), errors );
        }

        catch ( InterruptedException e ) {
            errors.push ( e );
            throw new SysException ( "Error in rollback: " + e.getMessage (),
                    errors );
        } finally {
            // System.err.println ( "Exiting CoordinatorStateHandler.rollback"
            // );
        }

        return getHeuristicMessages ();

    }

    protected void forget ()
    {
        // NOTE: no need to add synchronized -> don't
        // do it, you never know if recursion happens here

        // start messages
        // NOTE: this is of secondary importance; failures are not
        // problematic since forget is mainly for log efficiency.
        // Therefore, this does not affect the final TERMINATED state
        // NOTE: remote participants are notified as well, but they
        // are themselves responsible for deciding whether or not
        // to react to the forget notification.

        CoordinatorStateHandler nextStateHandler = null;

        Vector participants = coordinator_.getParticipants ();
        // @todo CHECK IN TRMI RELEASE BRANCH if forget might block!
        int count = (participants.size () - readOnlyTable_.size ());
        Enumeration enumm = participants.elements ();
        ForgetResult result = new ForgetResult ( count );
        while ( enumm.hasMoreElements () ) {
            Participant p = (Participant) enumm.nextElement ();
            if ( !readOnlyTable_.containsKey ( p ) ) {
                ForgetMessage fm = new ForgetMessage ( p, result );
                propagator_.submitPropagationMessage ( fm );
                // this will trigger sending the message
            }

        }
        try {
            // System.out.println ( "Coordinator state handler: waiting for
            // replies...");
            result.waitForReplies ();
            // System.out.println ( "Coordinator state handler: replies
            // gotten");
        } catch ( InterruptedException inter ) {
            // some might be left in heuristic state -- that's OK.
        }
        nextStateHandler = new TerminatedStateHandler ( this );
        coordinator_.setStateHandler ( nextStateHandler );
    }
}
TOP

Related Classes of com.atomikos.icatch.imp.CoordinatorStateHandler

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.