📄 xact.java
字号:
/* Derby - Class org.apache.derby.impl.store.raw.xact.Xact Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 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. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.store.raw.xact;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.store.raw.ContainerKey;import org.apache.derby.iapi.services.context.ContextManager;import org.apache.derby.iapi.services.daemon.Serviceable;import org.apache.derby.iapi.services.locks.LockFactory;import org.apache.derby.iapi.services.locks.Limit;import org.apache.derby.iapi.store.raw.ContainerHandle;import org.apache.derby.iapi.store.raw.Compensation;import org.apache.derby.iapi.store.raw.GlobalTransactionId;import org.apache.derby.iapi.store.raw.LockingPolicy;import org.apache.derby.iapi.store.raw.Loggable;import org.apache.derby.iapi.store.raw.RecordHandle;import org.apache.derby.iapi.store.raw.StreamContainerHandle;import org.apache.derby.iapi.store.raw.Transaction;import org.apache.derby.iapi.store.raw.data.DataFactory;import org.apache.derby.iapi.store.raw.data.RawContainerHandle;import org.apache.derby.iapi.store.raw.xact.RawTransaction; import org.apache.derby.iapi.store.raw.xact.TransactionId;import org.apache.derby.iapi.store.raw.log.LogFactory;import org.apache.derby.iapi.store.raw.log.LogInstant;import org.apache.derby.iapi.store.raw.log.Logger;import org.apache.derby.iapi.store.access.FileResource;import org.apache.derby.iapi.store.access.RowSource;import org.apache.derby.iapi.store.access.TransactionController;import org.apache.derby.iapi.error.ExceptionSeverity;import org.apache.derby.iapi.services.property.PersistentSet;import org.apache.derby.catalog.UUID;import java.util.Stack;import java.util.Enumeration;import java.util.Properties;import java.util.ArrayList;import java.util.List;import java.util.Dictionary;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;import org.apache.derby.iapi.util.ByteArray;import org.apache.derby.iapi.services.property.PropertyUtil;import org.apache.derby.iapi.reference.Property;import org.apache.derby.impl.store.raw.log.LogToFile;import org.apache.derby.iapi.services.io.LimitObjectInput;import org.apache.derby.iapi.services.context.ContextService;/** A transaction has five states <OL> <LI> CLOSED - cannot be used <LI> IDLE - no reads have been performed by the transaction. <LI> ACTIVE - at least one read has been attempted by the transaction <LI> UPDATE - at least one update has been attempted by the transaction <LI> PREPARED - the transaction is ready to commit (FUTURE). </OL> <BR>Transaction identifiers are re-used for transactions that do not enter the UPDATE state during their lifetime. @see Transaction*/public class Xact extends RawTransaction implements Limit { /* ** Static Fields */ protected static final int CLOSED = 0; protected static final int IDLE = 1; protected static final int ACTIVE = 2; protected static final int UPDATE = 3; protected static final int PREPARED = 4; /* ** Transaction status stored in the beginXact and endXact */ public static final int END_ABORTED = 0x00000001; public static final int END_PREPARED = 0x00000002; public static final int END_COMMITTED = 0x00000004; public static final int RECOVERY_ROLLBACK_FIRST = 0x00000010; public static final int INTERNAL_TRANSACTION = 0x00000020; public static final int NESTED_TOP_TRANSACTION = 0x00000040; /** private static - make sure these bits don't overwrite bits in Transaction.commit commitflag */ private static final int COMMIT_SYNC = 0x00010000; private static final int COMMIT_NO_SYNC = 0x00020000; private static final int COMMIT_PREPARE = 0x00040000; /* ** Fields */ // // set during recovery if this is the recovery transaction. // private int savedEndStatus; // // if this transaction object was committed without syncing, then in a // subsequent commit with sync, the log must be flushed even if the last // transaction is read only private boolean needSync; // // When the xact is first created, it is in an IDLE state. Since the // transaction table needs an XactId, one will be made for it. When this // transaction commits, it goes back to the IDLE state. If we then create // a new XactId for it, we will waste one XactId per transaction object // because it must first go thru the IDLE state before it gets closed. // Therefore, the first XactId is assigned in the constructor and // subsequent XactId is assigned in the setActiveState. However, the first // time it goes into setActiveState, we don't want it to create a new // XactId when the one that was assigned to it in the constructore is good // enough, so we use this justCreate field to indicate to setActiveState // whether it needs to make a new XactId (for the next transaction) for // not. private boolean justCreated = true; protected XactContext xc; // my context - set by XactContext // these fields remain fixed for the lifetime of this object protected final XactFactory xactFactory; protected final DataFactory dataFactory; protected final LogFactory logFactory; protected final Object compatibilitySpace; // these fields remain fixedfor the lifetime private LockingPolicy defaultLocking; // Global id, unique among all rawstores and all eternity private GlobalTransactionId myGlobalId; // id that is valid locally in this raw store. private volatile TransactionId myId; protected Logger logger; // the object we use to access the log. protected volatile int state; // we access this without synchronization sometimes private Integer inComplete = null; // set between preComplete() and postComplete() private boolean seenUpdates; // true if this session has written a log // record to disk. Note this is per // session and not per transaction, namely // during recovery, a transaction may have // updates but it may not have any updates // during recovery. In that case, // seenUpdates is false even though state // is UPDATE. // This value is used to decide whether // the log needs to get flushed at commit // time. private boolean inPostCommitProcessing; // true if we are processing post // commit work in the same context the // work was queued. This is used to stop // recursion only. We don't want a post // commit task to queue other post commit // task, ad infinitum. PostCommitWork // requested while processing // postCommitWork will be processed // by the daemon, which may itself // recurse once. private LogInstant logStart; // If this is a read only transaction (has // never written a log record to disk), // then null. Otherwise, set to the log // instant of the first log record. private LogInstant logLast; // the last log record written by this // transaction private Stack savePoints; // stack of SavePoint objects. protected List postCommitWorks; // a list of post commit work protected List postTerminationWorks; // work to be done after // transaction terminates, // commit or abort private boolean recoveryTransaction; // this transaction is being // used by recovery DynamicByteArrayOutputStream logBuffer; private boolean postCompleteMode; // perform most preComplete work in postComplete // Use this flag to catch the case where a global transaction was closed. // Normally a closed transaction should not be aborted again, but we need // to allow abort of a closed global transaction for error handling. Use // this flag to make sure people are not abusing this loop hole. // RESOLVE: sku to remove before GA private boolean sanityCheck_xaclosed; // Indicates the name of the transaction, and if it is set, it is displayed // by the transactiontable VTI private String transName; // The transaction is only allowed read operations, no log writes. private boolean readOnly; /* ** Constructor */ protected Xact( XactFactory xactFactory, LogFactory logFactory, DataFactory dataFactory, boolean readOnly, Object compatibilitySpace) { super(); this.xactFactory = xactFactory; this.logFactory = logFactory; this.dataFactory = dataFactory; this.readOnly = readOnly; this.compatibilitySpace = (compatibilitySpace == null ? this : compatibilitySpace); if (SanityManager.DEBUG) { SanityManager.ASSERT(dataFactory != null, "datafactory is null"); SanityManager.ASSERT(xactFactory != null, "xactfactory is null"); SanityManager.ASSERT(logFactory != null, "logfactory is null"); } resetDefaultLocking(); // TransactionTable needs this xactFactory.setNewTransactionId((XactId)null, this); setIdleState(); /* System.out.println("Xact.constructor: readonly = " + this.readOnly + ";this = " + this); */ } /* ** Methods of RawTransaction */ /** */ public final LockFactory getLockFactory() { return xactFactory.getLockFactory(); } public final DataFactory getDataFactory() { return dataFactory; } /** Get cache statistics for the specified cache */ public long[] getCacheStats(String cacheName) { return getDataFactory().getCacheStats(cacheName); } /** Reset the cache statistics for the specified cache */ public void resetCacheStats(String cacheName) { getDataFactory().resetCacheStats(cacheName); } /** Return true if any transaction is currently blocked, even if not by this transaction. */ public boolean anyoneBlocked() { return getLockFactory().anyoneBlocked(); } public DynamicByteArrayOutputStream getLogBuffer() { if (logBuffer == null) { logBuffer = new DynamicByteArrayOutputStream(1024); } else { logBuffer.reset(); } return logBuffer; } /** Log and apply a compensation operation. Only need to write out the compensation op itself, the optional data has already been written by the rollforward operation this is attempting to undo. @see RawTransaction#logAndDo @exception StandardException Standard cloudscape exception policy */ public void logAndUndo(Compensation compensation, LogInstant undoInstant, LimitObjectInput in) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(logStart != null); } setActiveState(); if (state == ACTIVE) setUpdateState(); seenUpdates = true; LogInstant clrInstant = logger.logAndUndo(this, compensation, undoInstant, in); setLastLogInstant(clrInstant); // set the top savepoint to rollback to this record if it doesn't yet have a point saved if ((savePoints != null) && !savePoints.empty()) { SavePoint sp = (SavePoint) savePoints.peek(); if (sp.getSavePoint() == null) sp.setSavePoint(clrInstant); } } /** Add this to the xactFactory list of update transaction. */ public void addUpdateTransaction(int transactionStatus) { // during runtime, rollbackFirst == recoveryRolblackFirst(), but during // recovery redo, we only use a regular transaction, so we need to get // the rollbackFirst status from the log record // // If my Id is null, I have no identity, makes no sense to add it to a // transaction table where my identity will be saved and restored if (myId != null) xactFactory.addUpdateTransaction(myId, this, transactionStatus); } /** Remove this from the xactFactory list of update transaction. */ public void removeUpdateTransaction() { if (myId != null) xactFactory.removeUpdateTransaction(myId); // If my Id is null, I have no identity, makes no sense to remove it // from transaction table } /** Remove this from the xactFactory list of update transaction. */ public void prepareTransaction() { // RESOLVE - should I be changing the state to PREPARE? if (myId != null) { // If my Id is null, I have no identity, makes no sense to set // my state in the transaction table. xactFactory.prepareTransaction(myId); } } /** Set the log instant for the first log record written by this transaction. */ public void setFirstLogInstant(LogInstant instant) { if (SanityManager.DEBUG) { SanityManager.ASSERT(instant != null); SanityManager.ASSERT(logStart == null); } logStart = instant; } /** Get the log instant for the first log record written by this transaction. */ public LogInstant getFirstLogInstant() { return logStart; } /** Set the log instant for the last log record written by this transaction. */ public void setLastLogInstant(LogInstant instant) { if (SanityManager.DEBUG) { SanityManager.ASSERT(instant != null); } logLast = instant; } /** Get the log instant for the last log record written by this transaction. */ public LogInstant getLastLogInstant() { return logLast; } /** Set my transaction identifier. */ public void setTransactionId(GlobalTransactionId extid, TransactionId localid) { if (SanityManager.DEBUG) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -