com.sun.jts.CosTransactions.TransactionState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
//----------------------------------------------------------------------------
//
// Module: TransactionState.java
//
// Description: Transaction state manager.
//
// Product: com.sun.jts.CosTransactions
//
// Author: Simon Holdsworth
//
// Date: March, 1997
//
// Copyright (c): 1995-1997 IBM Corp.
//
// The source code for this program is not published or otherwise divested
// of its trade secrets, irrespective of what has been deposited with the
// U.S. Copyright Office.
//
// This software contains confidential and proprietary information of
// IBM Corp.
//----------------------------------------------------------------------------
package com.sun.jts.CosTransactions;
import java.io.*;
import java.util.*;
import com.sun.jts.trace.*;
import org.omg.CosTransactions.*;
import com.sun.jts.utils.RecoveryHooks.FailureInducer;
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import com.sun.jts.utils.LogFormatter;
/**
* The TransactionState interface provides operations that maintain the
* relative commitment state of a Coordinator object, and is responsible for
* allocating new global and local transaction identifiers. This class is
* contained in the TopCoordinator and SubCoordinator classes.
*
* @version 0.7
*
* @author Simon Holdsworth, IBM Corporation
*
* @see
*/
//----------------------------------------------------------------------------
// CHANGE HISTORY
//
// Version By Change Description
// 0.1 SAJH Initial implementation.
// 0.2 SAJH GlobalTID interface changes.
// 0.3 SAJH Repository synchronization.
// 0.4 SAJH Conversion to new bindings.
// 0.5 SAJH Modified log record writing.
// 0.6 SAJH Allow preparing->rolled back for prepare heuristics.
// 0.7 SAJH Renamed repository.
// 0.8 GDH Added commit_one_phase related states
//----------------------------------------------------------------------------
class TransactionState {
/**
* A state value indicating that the transaction has not yet been started.
*/
final static int STATE_NONE = 0;
/**
* A state value indicating that the transaction has been started,
* and not yet completed.
*/
final static int STATE_ACTIVE = 1;
/**
* A state value indicating that the transaction is in the process of being
* prepared.
*/
final static int STATE_PREPARING = 2;
/**
* A state value indicating that the transaction has been
* successfully prepared, but commit or rollback has not yet started.
*/
final static int STATE_PREPARED_SUCCESS = 3;
/**
* A state value indicating that the transaction has failed to be prepared,
* but rollback has not yet started.
*/
final static int STATE_PREPARED_FAIL = 4;
/**
* A state value indicating that the transaction has been prepared
* and is read-only, but rollback has not yet started.
*/
final static int STATE_PREPARED_READONLY = 5;
/**
* A state value indicating that the transaction is in the process of being
* committed.
*/
final static int STATE_COMMITTING = 6;
/**
* A state value indicating that the transaction has been committed.
*/
final static int STATE_COMMITTED = 7;
/**
* A state value indicating that the transaction is in the process of being
* rolled back.
*/
final static int STATE_ROLLING_BACK = 8;
/**
* A state value indicating that the transaction has been rolled back.
*/
final static int STATE_ROLLED_BACK = 9;
// GDH: New COP States
/**
* A state value indicating that the transaction is being commited
* to a downstream resource using one phase commit
*/
final static int STATE_COMMITTING_ONE_PHASE = 10;
/**
* A state value indicating that the transaction has been successfully
* commited using commit one phase
*/
final static int STATE_COMMITTED_ONE_PHASE_OK = 11;
/**
* A state value indicating that the transaction has been rolled back
* after a commit one phase flow.
*/
final static int STATE_COMMIT_ONE_PHASE_ROLLED_BACK = 12;
/**
* A state value indicating that the transaction has heuristic
* hazard after a commit one phase flow.
*/
final static int STATE_COMMIT_ONE_PHASE_HEURISTIC_HAZARD = 13;
/**
* A state value indicating that the resources are heuristic mixed
* after a commit one phase flow.
*/
final static int STATE_COMMIT_ONE_PHASE_HEURISTIC_MIXED = 14;
/*
Logger to log transaction messages
*/
static Logger _logger = LogDomains.getLogger(TransactionState.class, LogDomains.TRANSACTION_LOGGER);
static RWLock freezeLock = new RWLock();
GlobalTID globalTID = null;
Long localTID = null;
int state = STATE_NONE;
boolean subordinate = false;
CoordinatorLog logRecord = null;
Object logSection = null;
//static long epochNumber = new Date().getTime();
static long sequenceNumber = 1;
static boolean inDoubt = false;
//get server name only once
//static String serverName = Configuration.getServerName();
//half built cached TID - used as template for any globalTIDs generations
static byte [] TIDTemplate=null;
// GDH State table added to for one phase commit of single resource
// could have extended further to split out:
// heuristic rollback
// rolling back huristic hazard
// rolling back heuristic mixed
// but these are factored into rolled back and rolling back respectively
// GDH: Added this column onwards
//
final static boolean[][] validStateChange = {
/* from to none actve ping pds pdf pdr cing cd ring rd c1p 1p_ok 1p_rb 1p_hh 1p_hm */
/* none */ { false, true, false, false, false, false, false, false, true, false, false, false, false, false, false },
/* active */ { false, false, true, false, false, false, false, false, true, false, true, false, false, false, false },
/* preparing */ { false, false, false, true, true, true, false, false, true, true, false, false, false, false, false },
/* prepared_success*/ { false, false, false, false, false, false, true, false, true, false, false, false, false, false, false },
/* prepared_fail */ { false, false, false, false, false, false, false, false, true, false, false, false, false, false, false },
/* prepared_ro */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false },
/* committing */ { false, false, false, false, false, false, true, true, false, false, false, false, false, false, false },
/* committed */ { true, false, false, false, false, false, false, false, false, false, false, false, false, false, false },
/* rolling back */ { false, false, false, false, false, false, false, false, true, true, false, false, false, false, false },
/* rolled back */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false },
// GDH: Added this row onwards
/* commit_one_phas */ { false, false, false, false , false, false, false, false, true, false, true, true, true, true, true },
/* cmt_one_phse_ok */ { false, false, false, false, false, false, false, true, false, false, false, false, false, false, false },
/* cmt_one_phse_rb */ { false, false, false, false, false, false, false, false, false, true, false, false, false, false, false },
/* cmt_one_phse_hh */ { false, false, false, false, false, false, false, true, false, false, false, false, false, false, false },
/* cmt_one_phse_hm */ { false, false, false, false, false, false, false, true, false, false, false, false, false, false, false }};
// XID format identifier.
final static int XID_FORMAT_ID = ('J'<<16) + ('T'<<8) + 'S';
private final static String LOG_SECTION_NAME = "TS"/*#Frozen*/;
/**
* Default TransactionState constructor.
*
* @param
*
* @return
*
* @see
*/
TransactionState() {}
/**
* This constructor is used for a root Coordinator.
* It allocates a global identifier for the transaction, and a local
* identifier for the local Transaction Service. The global ID is used to
* propagate to other processes to identify the transaction globally. The
* local ID is used for local comparisons. The CoordinatorLog object is
* used to recover the TransactionState at restart. Use of this operation
* indicates that the transaction is a top-level transaction. A section is
* created in the given CoordinatorLog object to maintain the transaction
* state persistently.
*
* @param log The CoordinatorLog object for the transaction.
*
* @return
*
* @see
*/
TransactionState(CoordinatorLog log) {
// Get the sequence number for the transaction identifier.
localTID = getSequenceNumber();
// Get the epoch number for this execution of the server.
//int epoch = getEpochNumber();
// Create a global identifier.
globalTID = new GlobalTID(XID_FORMAT_ID, 0,
generateTID(localTID.longValue()));
// Store the values in instance variables.
// This is a top-level transaction.
state = STATE_NONE;
subordinate = false;
// Set the CoordinatorLog id to the InternalTid.
if (log != null) {
logRecord = log;
logRecord.setLocalTID(localTID);
// Create a section in the CoordinatorLog for TransactionState
logSection = logRecord.createSection(LOG_SECTION_NAME);
}
}
/**
* This constructor is used for a subordinate Coordinator.
* It allocates a local identifier for a subordinate transaction that is
* represented by the given global identifier, and returns it.
* The presence of a CoordinatorLog object indicates
* whether the transaction is a top-level
* transaction. A section is created in the given CoordinatorLog object to
* maintain the transaction state persistently.
*
* @param globalTID The global identifier for the transaction.
* @param log The CoordinatorLog for a top-level transaction.
*
* @return
*
* @see
*/
TransactionState(GlobalTID globalTID, CoordinatorLog log) {
// Get the sequence number for the transaction identifier.
this.globalTID = globalTID;
localTID = getSequenceNumber();
// Store the values in instance variables.
state = STATE_NONE;
subordinate = true;
// Create a section in the CoordinatorLog.
if (log != null) {
logRecord = log;
// Set the CoordinatorLog id to the InternalTid.
logRecord.setLocalTID(localTID);
// Create a section in the CoordinatorLog for TransactionState
logSection = logRecord.createSection(LOG_SECTION_NAME);
}
}
/**
* This constructor is used for a root nested transaction.
* It allocates a global identifier and local identifier
* for a child transaction based on the local
* and global identifiers given for the parent, and returns
* them. The use of this operation indicates that the transaction is a
* subtransaction.
*
* @param parentLocalTID The parent's local identifier.
* @param parentGlobalTID The parent's global identifier.
*
* @return
*
* @see
*/
TransactionState(Long parentLocalTID, GlobalTID parentGlobalTID) {
// Get the sequence number for the transaction identifier.
localTID = getSequenceNumber();
// Get the epoch number for this execution of the server.
//int epoch = getEpochNumber();
// Create a global identifier.
globalTID = new GlobalTID(XID_FORMAT_ID, 0,
generateTID(localTID.longValue()));
// Store the values in instance variables. This is a subtransaction.
state = STATE_NONE;
subordinate = false;
}
/**
* Directs the TransactionState to recover its state
* after a failure, based on the given CoordinatorLog object.
* If the TransactionState has already been defined or
* recovered, the operation returns the current state of the transaction.
* If the state cannot be recovered, the operation returns none.
* If the CoordinatorLog records information prior to a log record being
* forced, this may result in recovery of an in-flight transaction. The
* TransactionState returns active in this case.
*
* @param log The CoordinatorLog for the transaction.
*
* @return The current state of the transaction.
*
* @see
*/
int reconstruct(CoordinatorLog log) {
int result = STATE_NONE;
// Get a section id in the CoordinatorLog for TransactionState
logSection = log.createSection(LOG_SECTION_NAME);
byte[][] logData = log.getData(logSection);
// Go through the sequence to get the overall status
int logState = 0;
for (int i = 0; i < logData.length; i++) {
if (logData[i].length > 1) {
logState |= (((logData[i][0] & 255) << 8) +
(logData[i][1] & 255));
} else {
// If the log record data is invalid, then exit immediately.
_logger.log(Level.SEVERE,"jts.invalid_log_record_data",
LOG_SECTION_NAME);
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.invalid_log_record_data",
new java.lang.Object[] { LOG_SECTION_NAME });
throw new org.omg.CORBA.INTERNAL(msg);
}
}
// Set the state value returned from the reconstruct method
if ((logState & (1 << STATE_ROLLED_BACK)) != 0)
result = STATE_ROLLED_BACK;
else if ((logState & (1 << STATE_COMMITTED)) != 0)
result = STATE_COMMITTED;
else if ((logState & (1 << STATE_COMMITTING)) != 0)
result = STATE_COMMITTING;
else if ((logState & (1 << STATE_ROLLING_BACK)) != 0)
result = STATE_ROLLING_BACK;
else if ((logState & (1 << STATE_PREPARED_READONLY)) != 0)
result = STATE_PREPARED_READONLY;
else if ((logState & (1 << STATE_PREPARED_FAIL)) != 0)
result = STATE_PREPARED_FAIL;
else if ((logState & (1 << STATE_PREPARED_SUCCESS)) != 0)
result = STATE_PREPARED_SUCCESS;
// GDH new states-->
else if ((logState & (1 << STATE_COMMITTING_ONE_PHASE)) != 0)
result = STATE_COMMITTING_ONE_PHASE;
else if ((logState & (1 << STATE_COMMITTED_ONE_PHASE_OK)) != 0)
result = STATE_COMMITTED_ONE_PHASE_OK;
else if ((logState & (1 << STATE_COMMIT_ONE_PHASE_ROLLED_BACK)) != 0)
result = STATE_COMMIT_ONE_PHASE_ROLLED_BACK;
else if ((logState &
(1 << STATE_COMMIT_ONE_PHASE_HEURISTIC_HAZARD)) != 0)
result = STATE_COMMIT_ONE_PHASE_HEURISTIC_HAZARD;
else if ((logState &
(1 << STATE_COMMIT_ONE_PHASE_HEURISTIC_MIXED)) != 0)
result = STATE_COMMIT_ONE_PHASE_HEURISTIC_MIXED;
state = result;
subordinate = false;
logRecord = log;
return result;
}
/**
* Sets the state to the given value and returns true.
* If the state change is invalid, the state is not
* changed and the operation returns false. When a top-level
* transaction has its state changed to prepared, the information
* is stored in the CoordinatorLog object. When prepared_success, the log
* record for the transaction is explicitly forced. Otherwise the
* transaction will be treated as in-flight upon
* recovery (i.e. will be rolled back). When
* a subordinate transaction has its state changed to committing or
* rolling_back, the state is added to the CoordinatorLog object, which is
* then forced.
*
* @param newState The new state of the transaction.
*
* @return Indicates if the state change is possible.
*
* @see
*/
boolean setState(int newState) {
boolean result = false;
// Check that the state change is valid
if (validStateChange[state][newState]) {
//Added code for counting and blocking.
if(AdminUtil.bSampling)
{
switch ( newState )
{
case STATE_PREPARED_SUCCESS :
AdminUtil.incrementPendingTransactionCount();
break ;
case STATE_PREPARED_READONLY :
AdminUtil.incrementPendingTransactionCount();
break ;
case STATE_COMMITTED :
AdminUtil.incrementCommitedTransactionCount();
break ;
case STATE_ROLLED_BACK :
AdminUtil.incrementAbortedTransactionCount();
break ;
/*
case STATE_COMMITTED_ONE_PHASE_OK :
AdminUtil.incrementCommitedTransactionCount();
break ;
case STATE_COMMIT_ONE_PHASE_ROLLED_BACK :
AdminUtil.incrementCommitedTransactionCount();
break ;
*/
case STATE_ROLLING_BACK :
AdminUtil.incrementUnpreparedAbortedTransactionCount();
break;
}
}
//release the readlocks.
switch ( state )
{
case STATE_PREPARING :
case STATE_COMMITTING :
case STATE_COMMITTING_ONE_PHASE :
if(_logger.isLoggable(Level.FINEST)){
String statestr=null;
switch(newState ) {
case STATE_PREPARING :
statestr="PREPARING";
break;
case STATE_COMMITTING :
statestr="COMMITTING";
break;
case STATE_COMMITTING_ONE_PHASE :
statestr="COMMITTING_ONE_PHASE";
break;
default :
statestr="Illegal state ";
break;
}
_logger.logp(Level.FINEST,"TransactionState","setState()",
"Releasing read lock on freeze : state "+statestr);
}
freezeLock.releaseReadLock();
if(_logger.isLoggable(Level.FINEST)){
String statestr=null;
_logger.logp(Level.FINEST,"TransactionState","setState()",
"Released read lock on freeze");
switch(newState ) {
case STATE_PREPARING :
statestr="PREPARING";
break;
case STATE_COMMITTING :
statestr="COMMITTING";
break;
case STATE_COMMITTING_ONE_PHASE :
statestr="COMMITTING_ONE_PHASE";
break;
default :
statestr="Illegal state ";
break;
}
_logger.logp(Level.FINEST,"TransactionState","setState()",
"Released read lock on freeze : state "+statestr);
}
break;
}
//acquire read locks
switch ( newState )
{
case STATE_PREPARING :
case STATE_COMMITTING :
//case STATE_ROLLING_BACK :
case STATE_COMMITTING_ONE_PHASE :
if(_logger.isLoggable(Level.FINEST)){
String statestr=null;
switch(newState ) {
case STATE_PREPARING :
statestr="PREPARING";
break;
case STATE_COMMITTING :
statestr="COMMITTING";
break;
case STATE_COMMITTING_ONE_PHASE :
statestr="COMMITTING_ONE_PHASE";
break;
default :
statestr="Illegal state ";
break;
}
_logger.logp(Level.FINEST,"TransactionState","setState()",
"Acquiring read lock on freeze : state "+statestr);
}
freezeLock.acquireReadLock();
if(_logger.isLoggable(Level.FINEST)){
String statestr=null;
switch(newState ) {
case STATE_PREPARING :
statestr="PREPARING";
break;
case STATE_COMMITTING :
statestr="COMMITTING";
break;
case STATE_COMMITTING_ONE_PHASE :
statestr="COMMITTING_ONE_PHASE";
break;
default :
statestr="Illegal state ";
break;
}
_logger.logp(Level.FINEST,"TransactionState","setState()",
"Acquired read lock on freeze : state "+statestr);
}
break;
}
// RecoveryHook (for induced crashes and waits) (Ram Jeyaraman)
if (FailureInducer.isFailureInducerActive() &&
(!(Thread.currentThread().getName().
equals("JTS Resync Thread"/*#Frozen*/)))) {
Integer failurePoint = null;
switch (newState) {
case STATE_PREPARING :
failurePoint = FailureInducer.ACTIVE; break;
case STATE_PREPARED_SUCCESS :
failurePoint = FailureInducer.PREPARING; break;
case STATE_PREPARED_FAIL :
failurePoint = FailureInducer.PREPARING; break;
case STATE_PREPARED_READONLY :
failurePoint = FailureInducer.PREPARING; break;
case STATE_COMMITTING_ONE_PHASE :
failurePoint = FailureInducer.ACTIVE; break;
case STATE_COMMITTED_ONE_PHASE_OK :
failurePoint = FailureInducer.COMPLETING; break;
case STATE_COMMIT_ONE_PHASE_ROLLED_BACK :
failurePoint = FailureInducer.COMPLETING; break;
case STATE_COMMITTING :
failurePoint = FailureInducer.PREPARED; break;
case STATE_COMMITTED :
failurePoint = FailureInducer.COMPLETING; break;
case STATE_ROLLING_BACK :
if (state == STATE_PREPARED_SUCCESS) {
failurePoint = FailureInducer.PREPARED;
} else if (state == STATE_PREPARED_FAIL) {
failurePoint = FailureInducer.PREPARED;
} else if (state == STATE_PREPARED_READONLY) {
failurePoint = FailureInducer.PREPARED;
} else if (state == STATE_ACTIVE) {
failurePoint = FailureInducer.ACTIVE;
}
break;
case STATE_ROLLED_BACK :
failurePoint = FailureInducer.COMPLETING;
}
FailureInducer.waitForFailure(this.globalTID, failurePoint);
}
// Change state. This is the point at which some
// log records may be written
state = newState;
result = true;
// Add state information to CoordinatorLog for various states.
if (logRecord != null &&
(newState == STATE_PREPARED_SUCCESS ||
newState == STATE_PREPARED_FAIL ||
(newState == STATE_COMMITTING && subordinate) ||
(newState == STATE_ROLLING_BACK && subordinate) ||
newState == STATE_COMMITTED ||
newState == STATE_ROLLED_BACK ||
// GDH
// newState == STATE_COMMITTING_ONE_PHASE ||
// newState == STATE_COMMITTED_ONE_PHASE_OK ||
// newState == STATE_COMMIT_ONE_PHASE_ROLLED_BACK ||
newState == STATE_COMMIT_ONE_PHASE_HEURISTIC_HAZARD ||
newState == STATE_COMMIT_ONE_PHASE_HEURISTIC_MIXED
// GDH
)) {
byte[] byteData = new byte[2];
byteData[0] = (byte)(((1 << state) & 0xff00) >> 8);
byteData[1] = (byte)( (1 << state) & 0x00ff);
result = logRecord.addData(logSection, byteData);
}
// If the new state represents successful preparation,
// and the transaction is a top-level transaction,
// or the new state indicates the beginning of commit or
// rollback and the Coordinator is a subordinate, we want to make
// sure that the log information is permanent.
if (logRecord != null &&
(newState == STATE_PREPARED_SUCCESS ||
// GDH: All the new states should be flushed to the log
// cop as it represents begining of commit and
// the others as they represent end of phase one
// (at least)
newState == STATE_COMMIT_ONE_PHASE_HEURISTIC_HAZARD ||
newState == STATE_COMMIT_ONE_PHASE_HEURISTIC_MIXED ||
// \GDH
(newState == STATE_COMMITTING && subordinate) ||
(newState == STATE_ROLLING_BACK && subordinate))) {
// If this is the first time a transaction has
// gone in-doubt in this process, then ensure
// that the restart required flag is set in the repository.
setInDoubt(true);
// Force the log record for the transaction.
// How much 'force' can we use in Java?
result = logRecord.write(true);
/**
if (!result) {
// empty
}
**/
} else {
if (newState == STATE_PREPARED_SUCCESS ||
newState == STATE_COMMIT_ONE_PHASE_HEURISTIC_HAZARD ||
newState == STATE_COMMIT_ONE_PHASE_HEURISTIC_MIXED ||
(newState == STATE_COMMITTING && subordinate) ||
(newState == STATE_ROLLING_BACK && subordinate)) {
setInDoubt(true);
// LogDBHelper.getInstance().addRecord(localTID.longValue(), globalTID.toTidBytes());
}
}
// If the new state represents completion of a
// top-level transaction, a top-level transaction,
// then write an unforced record to the log.
if (logRecord != null && (newState == STATE_COMMITTED ||
// newState == STATE_COMMITTING_ONE_PHASE ||
// newState == STATE_COMMITTED_ONE_PHASE_OK ||
// newState == STATE_COMMIT_ONE_PHASE_ROLLED_BACK ||
newState == STATE_ROLLED_BACK)) {
// Write the log record for the transaction (unforced).
result = logRecord.write(false);
/**
if (!result) {
// empty
}
**/
}
// RecoveryHook (for induced crashes and waits) (Ram Jeyaraman)
if (FailureInducer.isFailureInducerActive() &&
(!(Thread.currentThread().getName().
equals("JTS Resync Thread"/*#Frozen*/)))) {
Integer failurePoint = null;
switch (newState) {
case STATE_COMMITTED_ONE_PHASE_OK :
failurePoint = FailureInducer.COMPLETED; break;
case STATE_COMMITTED :
failurePoint = FailureInducer.COMPLETED; break;
case STATE_ROLLED_BACK :
failurePoint = FailureInducer.COMPLETED;
}
FailureInducer.waitForFailure(this.globalTID, failurePoint);
}
}
return result;
}
/**
* Returns the current transaction sequence number and increments it.
*
* @param
*
* @return The current transaction sequence number.
*
* @see
*/
private static synchronized long getSequenceNumber() {
return ++sequenceNumber;
}
/**
* Returns the current epoch number.
*
* @param
*
* @return The current epoch number.
*
* @see
*/
/*private static int getEpochNumber() {
int result = (int)epochNumber;
return result;
}*/
/**
* Returns a flag indicating whether any transactions may be in doubt.
*
* @param
*
* @return The in doubt indicator.
*
* @see
*/
static boolean inDoubt() {
return inDoubt;
}
/**
* Sets the in doubt indicator.
*
* @param value The new value of the indicator.
*
* @return
*
* @see
*/
static void setInDoubt(boolean value) {
inDoubt = value;
}
/**
* Generates the body of a transaction identifier.
*
* @param localTID The local transaction identifier.
* @param epoch The epoch number.
* @param serverName The server name.
*
* @return
*
* @see
*/
private static final byte[] generateTID(long localTID) {
if(TIDTemplate==null){
synchronized(TransactionState.class){
if(TIDTemplate==null){
String serverName = Configuration.getServerName();
int nameLength = (serverName == null ? 0 : serverName.length());
TIDTemplate = new byte[nameLength+8];
long epochNumber = new Date().getTime();
TIDTemplate[4] = (byte) epochNumber;
TIDTemplate[5] = (byte)(epochNumber >> 8);
TIDTemplate[6] = (byte)(epochNumber >> 16);
TIDTemplate[7] = (byte)(epochNumber >> 24);
for( int i = 0; i < nameLength; i++ )
TIDTemplate[i+8] = (byte) serverName.charAt(i);
}
}
}
byte[] result = new byte[TIDTemplate.length];
System.arraycopy(TIDTemplate, 4, result, 4, TIDTemplate.length-4);
result[0] = (byte) localTID;
result[1] = (byte)(localTID >> 8);
result[2] = (byte)(localTID >> 16);
result[3] = (byte)(localTID >> 24);
return result;
}
}