All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arjuna.ats.internal.arjuna.abstractrecords.PersistenceRecord Maven / Gradle / Ivy

There is a newer version: 5.12.7.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 *
 * (C) 2005-2006,
 * @author JBoss Inc.
 */
/*
 * Copyright (C) 1998, 1999, 2000, 2001,
 *
 * Arjuna Solutions Limited,
 * Newcastle upon Tyne,
 * Tyne and Wear,
 * UK.
 *
 * $Id: PersistenceRecord.java 2342 2006-03-30 13:06:17Z  $
 */

package com.arjuna.ats.internal.arjuna.abstractrecords;

import java.io.IOException;
import java.io.PrintWriter;

import com.arjuna.ats.arjuna.ObjectType;
import com.arjuna.ats.arjuna.StateManager;
import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.arjuna.common.arjPropertyManager;
import com.arjuna.ats.arjuna.coordinator.RecordType;
import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome;
import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
import com.arjuna.ats.arjuna.logging.tsLogger;
import com.arjuna.ats.arjuna.objectstore.ParticipantStore;
import com.arjuna.ats.arjuna.state.InputObjectState;
import com.arjuna.ats.arjuna.state.OutputObjectState;

/**
 * A PersistenceRecord is created whenever a persistent object is
 * created/read/modified within the scope of a transaction. It is responsible
 * for ensuring that state changes are committed or rolled back on behalf of the
 * object depending upon the outcome of the transaction.
 *
 * @author Mark Little ([email protected])
 * @version $Id: PersistenceRecord.java 2342 2006-03-30 13:06:17Z  $
 * @since JTS 1.0.
 */

public class PersistenceRecord extends RecoveryRecord
{

	/**
	 * This constructor is used to create a new instance of PersistenceRecord.
	 */

	public PersistenceRecord (OutputObjectState os, ParticipantStore participantStore, StateManager sm)
	{
		super(os, sm);

		if (tsLogger.logger.isTraceEnabled()) {
            tsLogger.logger.trace("PersistenceRecord::PersistenceRecord("
                    + os + ", " + sm.get_uid() + ")");
        }

		shadowMade = false;
		this.targetParticipantStore = participantStore;
		topLevelState = null;
	}

	/**
	 * Redefintions of abstract functions inherited from RecoveryRecord.
	 */

	public int typeIs ()
	{
		return RecordType.PERSISTENCE;
	}

	/**
	 * topLevelAbort may have to remove the persistent state that was written
	 * into the object store during the processing of topLevelPrepare. It then
	 * does the standard abort processing.
	 */

	public int topLevelAbort ()
	{
	    if (tsLogger.logger.isTraceEnabled()) {
	        tsLogger.logger.trace("PersistenceRecord::topLevelAbort() for "
	                + order());
	    }

	    Uid uid = null;
	    String type = null;

	    if (shadowMade) // state written by StateManager instance
	    {
	        uid = order();
	        type = getTypeOfObject();
	    }
	    else
	    {
	        if (topLevelState == null) // hasn't been prepared, so no state
	        {
	            return nestedAbort();
	        }
	        else
	        {
	            uid = topLevelState.stateUid();
	            type = topLevelState.type();
	        }
	    }

	    try
	    {
	        if (!targetParticipantStore.remove_uncommitted(uid, type)) {
	            tsLogger.i18NLogger.warn_PersistenceRecord_19();

	            return TwoPhaseOutcome.FINISH_ERROR;
	        }
	    }
	    catch (ObjectStoreException e) {
	        tsLogger.i18NLogger.warn_PersistenceRecord_20(e);

	        return TwoPhaseOutcome.FINISH_ERROR;
	    }

	    return nestedAbort();
	}

	/**
	 * commit the state saved during the prepare phase.
	 */

	public int topLevelCommit ()
	{
		if (tsLogger.logger.isTraceEnabled()) {
            tsLogger.logger.trace("PersistenceRecord::topLevelCommit() : About to commit state, "+
                    "uid = "+order()+", ObjType = "+getTypeOfObject());
        }

		if (tsLogger.logger.isTraceEnabled())
		{
			if (targetParticipantStore != null) {
                tsLogger.logger.trace(", store = "
                        + targetParticipantStore + "(" + targetParticipantStore.getClass().getCanonicalName() + ")");
            }
			else {
                tsLogger.logger.trace("");
            }
		}

		boolean result = false;

		if (targetParticipantStore != null)
		{
			try
			{
				if (shadowMade)
				{
					result = targetParticipantStore.commit_state(order(), super.getTypeOfObject());

					if (!result) {
                        tsLogger.i18NLogger.warn_PersistenceRecord_2(order());
                    }
				}
				else
				{
					if (topLevelState != null)
					{
						result = targetParticipantStore.write_committed(order(), super.getTypeOfObject(), topLevelState);
					}
					else {
                        tsLogger.i18NLogger.warn_PersistenceRecord_3();
                    }
				}
			}
			catch (ObjectStoreException e) {
                tsLogger.i18NLogger.warn_PersistenceRecord_4(e);

                result = false;
            }
		}
		else {
            tsLogger.i18NLogger.warn_PersistenceRecord_5();
        }

		if (!result) {
            tsLogger.i18NLogger.warn_PersistenceRecord_6();
        }

		super.forgetAction(true);

		return ((result) ? TwoPhaseOutcome.FINISH_OK
				: TwoPhaseOutcome.FINISH_ERROR);
	}

	/**
	 * topLevelPrepare attempts to save the object. It will either do this in
	 * the action intention list or directly in the object store by using the
	 * 'deactivate' function of the object depending upon the size of the state.
	 * To ensure that objects are correctly hidden while they are in an
	 * uncommitted state if we use the abbreviated protocol then we write an
	 * EMPTY object state as the shadow state - THIS MUST NOT BE COMMITTED.
	 * Instead we write_committed the one saved in the intention list. If the
	 * store cannot cope with being given an empty state we revert to the old
	 * protocol.
	 */

	public int topLevelPrepare ()
	{
		if (tsLogger.logger.isTraceEnabled()) {
            tsLogger.logger.trace("PersistenceRecord::topLevelPrepare() for "
                    + order());
        }

		int result = TwoPhaseOutcome.PREPARE_NOTOK;
		StateManager sm = super.objectAddr;

		if ((sm != null) && (targetParticipantStore != null))
		{
		    /*
		     * Get ready to create our state to be saved. At this stage we're not
		     * sure if the state will go into its own log or be written into the
		     * transaction log for improved performance.
		     */
		    
			topLevelState = new OutputObjectState(sm.get_uid(), sm.type());

			if (writeOptimisation
					&& (!targetParticipantStore.fullCommitNeeded()
							&& (sm.save_state(topLevelState, ObjectType.ANDPERSISTENT)) && (topLevelState.size() <= PersistenceRecord.MAX_OBJECT_SIZE)))
			{
			    /*
			     * We assume that crash recovery will always run before
			     * the object can be reactivated!
			     */

				if (PersistenceRecord.classicPrepare)
				{
					OutputObjectState dummy = new OutputObjectState(
							Uid.nullUid(), null);

					/*
					 * Write an empty shadow state to the store to indicate one
					 * exists, and to prevent bogus activation in the case where
					 * crash recovery hasn't run yet.
					 */

					try
					{
						if (targetParticipantStore.write_uncommitted(sm.get_uid(), sm.type(), dummy))
						    result = TwoPhaseOutcome.PREPARE_OK;
						else
						{
						    result = TwoPhaseOutcome.PREPARE_NOTOK;
						}
					}
					catch (ObjectStoreException e) {
                        tsLogger.i18NLogger.warn_PersistenceRecord_21(e);
                    }

					dummy = null;
				}
				else
				{
				    /*
				     * Don't write anything as our state will go into the log.
				     */
				    
					result = TwoPhaseOutcome.PREPARE_OK;
				}
			}
			else
			{
			    if (sm.deactivate(targetParticipantStore.getStoreName(), false))
			    {
			        shadowMade = true;

			        result = TwoPhaseOutcome.PREPARE_OK;
			    }
			    else 
			    {
			        topLevelState = null;
			        
			        tsLogger.i18NLogger.warn_PersistenceRecord_7();
			    }
			}
		}
		else {
            tsLogger.i18NLogger.warn_PersistenceRecord_8();
        }

		return result;
	}

	/**
	 * topLevelCleanup must leave the persistent state that was written in the
	 * object store during the processing of topLevelPrepare intact. Crash
	 * recovery will take care of its resolution
	 */

	public int topLevelCleanup ()
	{
		if (tsLogger.logger.isTraceEnabled()) {
            tsLogger.logger.trace("PersistenceRecord::topLevelCleanup() for "
                    + order());
        }

		return TwoPhaseOutcome.FINISH_OK;
	}

	/**
	 * @return true
	 */

	public boolean doSave ()
	{
		return true;
	}

    public boolean restore_state (InputObjectState os, int ot)
	{
		if (tsLogger.logger.isTraceEnabled()) {
            tsLogger.logger.trace("PersistenceRecord::restore_state() for "
                    + order());
        }

		boolean res = false;
		topLevelState = null;

        try
        {
            shadowMade = os.unpackBoolean();

            // topLevelState = null;

            if (!shadowMade)
            {
                topLevelState = new OutputObjectState(os);
                res = topLevelState.valid();
            }
            else
                res = true;

            res = (res && super.restore_state(os, ot));

            // Note: we don't persist the targetParticipantStore, instead assuming the
            // default one present at recovery time will be equivalent. Changing the
            // objectstore config when records exist in the tx store is therefore a Bad Thing.
            targetParticipantStore = getStore();

            return res;
        }
        catch (final Exception e) {
            tsLogger.i18NLogger.warn_PersistenceRecord_10();
        }

		return res;
	}

	public boolean save_state (OutputObjectState os, int ot)
	{
		if (tsLogger.logger.isTraceEnabled()) {
            tsLogger.logger.trace("PersistenceRecord::save_state() for "
                    + order());
        }

		boolean res = true;

		if (targetParticipantStore != null)
		{
            // Note: we don't persist the targetParticipantStore, instead assuming the
            // default one present at recovery time will be equivalent. Changing the
            // objectstore config when records exist in the tx store is therefore a Bad Thing.

            try
            {
                os.packBoolean(shadowMade);

                /*
                         * If we haven't written a shadow state, then pack the state
                         * into the transaction log. There MUST be a state at this
                         * point.
                         */

                if (!shadowMade)
                {
                    res = (topLevelState != null);

                    if (res)
                        topLevelState.packInto(os);
                    else {
                        tsLogger.i18NLogger.warn_PersistenceRecord_14();
                    }
                }
            }
            catch (IOException e) {
                res = false;

                tsLogger.i18NLogger.warn_PersistenceRecord_15();
            }

		}
		else {
            tsLogger.i18NLogger.warn_PersistenceRecord_16();

            try {
                os.packString(null);
            }
            catch (IOException e) {
                res = false;
            }
        }

		return res && super.save_state(os, ot);
	}

	public void print (PrintWriter strm)
	{
		super.print(strm); /* bypass RecoveryRecord */

		strm.println("PersistenceRecord with state:\n" + super.state);
	}

	public String type ()
	{
		return "/StateManager/AbstractRecord/RecoveryRecord/PersistenceRecord";
	}

	/**
	 * Creates a 'blank' persistence record. This is used during crash recovery
	 * when recreating the prepared list of a server atomic action.
	 */

	public PersistenceRecord ()
	{
		super();

		if (tsLogger.logger.isTraceEnabled()) {
            tsLogger.logger.trace("PersistenceRecord::PersistenceRecord() - crash recovery constructor");
        }

		shadowMade = false;
		targetParticipantStore = null;
		topLevelState = null;
	}

	/**
	 * Cadaver records force write shadows. This operation supresses to
	 * abbreviated commit This should never return false
	 */

	protected boolean shadowForced ()
	{
		if (topLevelState == null)
		{
			shadowMade = true;

			return true;
		}

		/* I've already done the abbreviated protocol so its too late */

		return false;
	}

	// this value should really come from the object store implementation!

	public static final int MAX_OBJECT_SIZE = 4096; // block size

	protected boolean shadowMade;
	protected ParticipantStore targetParticipantStore;
	protected OutputObjectState topLevelState;
	protected static final boolean classicPrepare = arjPropertyManager.getCoordinatorEnvironmentBean().isClassicPrepare();
	
	private static final boolean writeOptimisation = arjPropertyManager.getCoordinatorEnvironmentBean().isWriteOptimisation();
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy