EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.impl.store.raw.xact]

COVERAGE SUMMARY FOR SOURCE FILE [Xact.java]

nameclass, %method, %block, %line, %
Xact.java100% (2/2)96%  (92/96)83%  (2076/2502)88%  (516.7/590)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class LockCount100% (1/1)100% (1/1)100% (3/3)100% (1/1)
LockCount (): void 100% (1/1)100% (3/3)100% (1/1)
     
class Xact100% (1/1)96%  (91/95)83%  (2073/2499)88%  (515.7/589)
Xact (XactFactory, LogFactory, DataFactory, boolean, Object): void 100% (1/1)95%  (55/58)98%  (14.7/15)
abort (): void 100% (1/1)87%  (88/101)81%  (22/27)
addAndLoadStreamContainer (long, Properties, RowSource): long 100% (1/1)100% (10/10)100% (2/2)
addContainer (long, long, int, Properties, int): long 100% (1/1)100% (12/12)100% (2/2)
addPostCommitWork (Serviceable): void 100% (1/1)95%  (18/19)83%  (5/6)
addPostTerminationWork (Serviceable): void 100% (1/1)95%  (18/19)83%  (5/6)
addUpdateTransaction (int): void 100% (1/1)100% (11/11)100% (3/3)
anyoneBlocked (): boolean 100% (1/1)100% (4/4)100% (1/1)
assumeGlobalXactIdentity (TransactionTableEntry): void 100% (1/1)81%  (91/113)89%  (20.6/23)
assumeIdentity (TransactionTableEntry): void 100% (1/1)74%  (70/94)91%  (19.2/21)
checkObserverException (): void 100% (1/1)33%  (4/12)40%  (2/5)
checkpointInRollForwardRecovery (LogInstant, long): void 100% (1/1)100% (8/8)100% (2/2)
close (): void 100% (1/1)79%  (72/91)90%  (18.8/21)
commit (): LogInstant 100% (1/1)100% (4/4)100% (1/1)
commit (int): LogInstant 100% (1/1)80%  (12/15)80%  (4/5)
commitNoSync (int): LogInstant 100% (1/1)95%  (53/56)97%  (7.8/8)
completeCommit (int): void 100% (1/1)96%  (24/25)99%  (6.9/7)
createXATransactionFromLocalTransaction (int, byte [], byte []): void 100% (1/1)97%  (29/30)99%  (5.9/6)
defaultLockingPolicy (): LockingPolicy 100% (1/1)100% (3/3)100% (1/1)
destroy (): void 100% (1/1)100% (8/8)100% (4/4)
doComplete (Integer): void 100% (1/1)48%  (15/31)75%  (6/8)
doPostCommitWorkInTran (): boolean 100% (1/1)100% (16/16)100% (1/1)
dropContainer (ContainerKey): void 100% (1/1)100% (8/8)100% (3/3)
dropStreamContainer (long, long): void 100% (1/1)100% (9/9)100% (3/3)
getActiveStateTxIdString (): String 100% (1/1)100% (19/19)100% (4/4)
getCacheStats (String): long [] 0%   (0/1)0%   (0/5)0%   (0/1)
getCompatibilitySpace (): Object 100% (1/1)91%  (10/11)95%  (1.9/2)
getContextId (): String 100% (1/1)78%  (7/9)77%  (0.8/1)
getContextManager (): ContextManager 100% (1/1)100% (4/4)100% (1/1)
getDataFactory (): DataFactory 100% (1/1)100% (3/3)100% (1/1)
getDefaultLockingPolicy (): LockingPolicy 0%   (0/1)0%   (0/3)0%   (0/1)
getFileHandler (): FileResource 100% (1/1)100% (4/4)100% (1/1)
getFirstLogInstant (): LogInstant 100% (1/1)100% (3/3)100% (1/1)
getGlobalId (): GlobalTransactionId 100% (1/1)100% (3/3)100% (1/1)
getId (): TransactionId 100% (1/1)91%  (10/11)95%  (1.9/2)
getIdNoCheck (): TransactionId 100% (1/1)100% (3/3)100% (1/1)
getLastLogInstant (): LogInstant 100% (1/1)100% (3/3)100% (1/1)
getLockFactory (): LockFactory 100% (1/1)100% (4/4)100% (1/1)
getLogBuffer (): DynamicByteArrayOutputStream 100% (1/1)100% (16/16)100% (4/4)
getLogger (): void 100% (1/1)100% (6/6)100% (2/2)
getSavePointPosition (String, Object, boolean): int 100% (1/1)100% (46/46)100% (10/10)
getState (): String 100% (1/1)73%  (11/15)71%  (5/7)
getTransName (): String 100% (1/1)100% (3/3)100% (1/1)
handlesPostTerminationWork (): boolean 100% (1/1)100% (7/7)100% (1/1)
inAbort (): boolean 100% (1/1)100% (5/5)100% (1/1)
inRollForwardRecovery (): boolean 100% (1/1)100% (4/4)100% (1/1)
isActive (): boolean 0%   (0/1)0%   (0/12)0%   (0/2)
isIdle (): boolean 100% (1/1)50%  (11/22)67%  (2/3)
isPrepared (): boolean 100% (1/1)100% (8/8)100% (1/1)
isPristine (): boolean 100% (1/1)100% (12/12)100% (1/1)
isUserTransaction (): boolean 100% (1/1)100% (14/14)100% (2/2)
logAndDo (Loggable): void 100% (1/1)91%  (77/85)86%  (19/22)
logAndUndo (Compensation, LogInstant, LimitObjectInput): void 100% (1/1)92%  (44/48)91%  (10.9/12)
newLockingPolicy (int, int, boolean): LockingPolicy 100% (1/1)100% (7/7)100% (1/1)
openContainer (ContainerKey, LockingPolicy, int): ContainerHandle 100% (1/1)100% (19/19)100% (4/4)
openContainer (ContainerKey, int): ContainerHandle 100% (1/1)100% (7/7)100% (1/1)
openDroppedContainer (ContainerKey, LockingPolicy): RawContainerHandle 100% (1/1)73%  (24/33)78%  (7/9)
openStreamContainer (long, long, boolean): StreamContainerHandle 100% (1/1)100% (10/10)100% (2/2)
popSavePoints (int, boolean): boolean 100% (1/1)84%  (57/68)81%  (17/21)
postComplete (int, Integer): void 100% (1/1)100% (24/24)100% (8/8)
postTermination (): void 100% (1/1)97%  (150/154)99%  (34.6/35)
preComplete (Integer): void 100% (1/1)79%  (23/29)88%  (7/8)
prepareCommit (int): LogInstant 100% (1/1)93%  (99/107)91%  (21.9/24)
prepareTransaction (): void 100% (1/1)100% (9/9)100% (3/3)
reCreateContainerForLoadTran (long, long, ByteArray): void 100% (1/1)100% (10/10)100% (3/3)
reached (Object, Object, int, Enumeration, int): void 100% (1/1)89%  (97/109)87%  (26/30)
recoveryTransaction (): void 100% (1/1)100% (10/10)100% (3/3)
releaseAllLocks (): void 100% (1/1)100% (7/7)100% (2/2)
releaseSavePoint (String, Object): int 100% (1/1)100% (31/31)100% (7/7)
removeUpdateTransaction (): void 100% (1/1)100% (9/9)100% (3/3)
reprepare (): void 100% (1/1)65%  (40/62)61%  (9.8/16)
resetCacheStats (String): void 0%   (0/1)0%   (0/5)0%   (0/2)
resetDefaultLocking (): void 100% (1/1)93%  (14/15)98%  (2.9/3)
rollbackToSavePoint (String, Object): int 100% (1/1)100% (34/34)100% (8/8)
setActiveState (): void 100% (1/1)59%  (53/90)74%  (12.6/17)
setDefaultLockingPolicy (LockingPolicy): void 100% (1/1)100% (13/13)100% (4/4)
setFirstLogInstant (LogInstant): void 100% (1/1)88%  (15/17)95%  (3.8/4)
setIdleState (): void 100% (1/1)45%  (26/58)72%  (7.9/11)
setLastLogInstant (LogInstant): void 100% (1/1)90%  (9/10)97%  (2.9/3)
setPostComplete (): void 100% (1/1)100% (4/4)100% (2/2)
setPrepareState (): void 100% (1/1)84%  (26/31)80%  (4.8/6)
setSavePoint (String, Object): int 100% (1/1)71%  (42/59)82%  (9/11)
setTransName (String): void 100% (1/1)100% (4/4)100% (2/2)
setTransactionId (GlobalTransactionId, TransactionId): void 100% (1/1)37%  (24/65)60%  (4.8/8)
setTransactionId (Loggable, TransactionId): void 100% (1/1)79%  (19/24)96%  (4.8/5)
setUpdateState (): void 100% (1/1)76%  (28/37)76%  (6.8/9)
setup (PersistentSet): void 100% (1/1)100% (15/15)100% (3/3)
startNestedTopTransaction (): RawTransaction 100% (1/1)100% (10/10)100% (1/1)
statusForBeginXactLog (): int 100% (1/1)100% (7/7)100% (1/1)
statusForEndXactLog (): int 100% (1/1)100% (3/3)100% (1/1)
throwExceptionIfSQLSavepointNotAllowed (Object): void 100% (1/1)95%  (35/37)98%  (9.8/10)
toString (): String 100% (1/1)100% (7/7)100% (3/3)
xa_commit (boolean): void 100% (1/1)90%  (35/39)90%  (9.9/11)
xa_prepare (): int 100% (1/1)53%  (29/55)82%  (9/11)
xa_rollback (): void 100% (1/1)90%  (9/10)97%  (2.9/3)

1/*
2 
3   Derby - Class org.apache.derby.impl.store.raw.xact.Xact
4 
5   Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21package org.apache.derby.impl.store.raw.xact;
22 
23import org.apache.derby.iapi.reference.SQLState;
24 
25import org.apache.derby.iapi.store.raw.ContainerKey;
26 
27import org.apache.derby.iapi.services.context.ContextManager;
28import org.apache.derby.iapi.services.daemon.Serviceable;
29import org.apache.derby.iapi.services.locks.LockFactory;
30import org.apache.derby.iapi.services.locks.Limit;
31 
32import org.apache.derby.iapi.store.raw.ContainerHandle;
33import org.apache.derby.iapi.store.raw.Compensation;
34import org.apache.derby.iapi.store.raw.GlobalTransactionId;
35import org.apache.derby.iapi.store.raw.LockingPolicy;
36import org.apache.derby.iapi.store.raw.Loggable;
37import org.apache.derby.iapi.store.raw.RecordHandle;
38import org.apache.derby.iapi.store.raw.StreamContainerHandle;
39import org.apache.derby.iapi.store.raw.Transaction;
40 
41import org.apache.derby.iapi.store.raw.data.DataFactory;
42import org.apache.derby.iapi.store.raw.data.RawContainerHandle;
43 
44import org.apache.derby.iapi.store.raw.xact.RawTransaction; 
45import org.apache.derby.iapi.store.raw.xact.TransactionId;
46 
47import org.apache.derby.iapi.store.raw.log.LogFactory;
48import org.apache.derby.iapi.store.raw.log.LogInstant;
49import org.apache.derby.iapi.store.raw.log.Logger;
50 
51import org.apache.derby.iapi.store.access.FileResource;
52import org.apache.derby.iapi.store.access.RowSource;
53import org.apache.derby.iapi.store.access.TransactionController;
54import org.apache.derby.iapi.error.ExceptionSeverity;
55 
56import org.apache.derby.iapi.services.property.PersistentSet;
57 
58import org.apache.derby.catalog.UUID;
59 
60import java.util.Stack;
61import java.util.Enumeration;
62import java.util.Properties;
63import java.util.ArrayList;
64import java.util.List;
65import java.util.Dictionary;
66 
67import org.apache.derby.iapi.error.StandardException;
68 
69import org.apache.derby.iapi.services.sanity.SanityManager;
70import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;
71import org.apache.derby.iapi.util.ByteArray;
72import org.apache.derby.iapi.services.property.PropertyUtil;
73import org.apache.derby.iapi.reference.Property;
74 
75import org.apache.derby.impl.store.raw.log.LogToFile;
76 
77import org.apache.derby.iapi.services.io.LimitObjectInput;
78 
79import org.apache.derby.iapi.services.context.ContextService;
80 
81/**
82 
83  A transaction has five states
84  <OL>
85  <LI> CLOSED - cannot be used
86  <LI> IDLE - no reads have been performed by the transaction.
87  <LI> ACTIVE - at least one read has been attempted by the transaction
88  <LI> UPDATE - at least one update has been attempted by the transaction
89  <LI> PREPARED - the transaction is ready to commit (FUTURE).
90  </OL>
91  <BR>Transaction identifiers are re-used for transactions that do not enter the
92  UPDATE state during their lifetime.
93 
94        @see Transaction
95 
96*/
97public class Xact extends RawTransaction implements Limit  {
98 
99        /*
100        ** Static Fields
101        */
102 
103        protected static final int        CLOSED                    = 0;
104        protected static final int        IDLE                    = 1;
105        protected static final int        ACTIVE                    = 2;
106        protected static final int        UPDATE                    = 3;
107        protected static final int        PREPARED            = 4;
108 
109 
110        /*
111        **        Transaction status stored in the beginXact and endXact
112        */
113 
114        public static final int END_ABORTED             = 0x00000001;
115        public static final int END_PREPARED            = 0x00000002;
116        public static final int END_COMMITTED           = 0x00000004;
117 
118        public static final int RECOVERY_ROLLBACK_FIRST = 0x00000010;
119        public static final int INTERNAL_TRANSACTION    = 0x00000020;
120        public static final int NESTED_TOP_TRANSACTION  = 0x00000040;
121 
122 
123        /**
124          private static - 
125 
126          make sure these bits don't overwrite bits in Transaction.commit commitflag
127        */
128        private static final int COMMIT_SYNC            = 0x00010000;
129        private static final int COMMIT_NO_SYNC         = 0x00020000;
130        private static final int COMMIT_PREPARE         = 0x00040000;
131 
132 
133        /*
134        ** Fields
135        */
136 
137        //
138        // set during recovery if this is the recovery transaction.  
139        //
140        private int savedEndStatus;        
141 
142        //
143        // if this transaction object was committed without syncing, then in a
144        // subsequent commit with sync, the log must be flushed even if the last
145        // transaction is read only
146        private boolean needSync;
147 
148        //
149        // When the xact is first created, it is in an IDLE state.  Since the
150        // transaction table needs an XactId, one will be made for it.  When this
151        // transaction commits, it goes back to the IDLE state.  If we then create
152        // a new XactId for it, we will waste one XactId per transaction object
153        // because it must first go thru the IDLE state before it gets closed.
154        // Therefore, the first XactId is assigned in the constructor and
155        // subsequent XactId is assigned in the setActiveState.  However, the first
156        // time it goes into setActiveState, we don't want it to create a new
157        // XactId when the one that was assigned to it in the constructore is good
158        // enough, so we use this justCreate field to indicate to setActiveState
159        // whether it needs to make a new XactId (for the next transaction) for
160        // not. 
161        private boolean justCreated = true;
162 
163 
164        protected        XactContext                xc;        // my context - set by XactContext
165 
166        // these fields remain fixed for the lifetime of this object
167        protected final XactFactory                xactFactory;
168        protected final DataFactory                dataFactory;
169        protected final LogFactory                logFactory;
170        protected final Object                   compatibilitySpace;
171 
172        // these fields remain fixedfor the lifetime
173        private LockingPolicy defaultLocking;
174 
175        // Global id, unique among all rawstores and all eternity
176        private GlobalTransactionId        myGlobalId;
177 
178        // id that is valid locally in this raw store.
179        private volatile TransactionId        myId;
180 
181        protected Logger                logger;                // the object we use to access the log.
182 
183 
184        protected volatile int        state;                 // we access this without synchronization sometimes
185        private Integer                inComplete = null;        // set between preComplete() and postComplete()
186 
187        private boolean                seenUpdates; // true if this session has written a log
188                                                                         // record to disk.  Note this is per
189                                                                         // session and not per transaction, namely
190                                                                         // during recovery, a transaction may have
191                                                                         // updates but it may not have any updates
192                                                                         // during recovery.  In that case,
193                                                                         // seenUpdates is false even though state
194                                                                         // is UPDATE. 
195                                                                         // This value is used to decide whether
196                                                                         // the log needs to get flushed at commit
197                                                                         // time. 
198 
199        private boolean        inPostCommitProcessing; // true if we are processing post
200                                                                          // commit work in the same context the
201                                                                          // work was queued.  This is used to stop
202                                                                          // recursion only.  We don't want a post
203                                                                          // commit task to queue other post commit
204                                                                          // task, ad infinitum.  PostCommitWork
205                                                                          // requested while processing
206                                                                          // postCommitWork will be processed 
207                                                                          // by the daemon, which may itself
208                                                                          // recurse once.
209 
210        private LogInstant                logStart; // If this is a read only transaction (has
211                                                                          // never written a log record to disk),
212                                                                          // then null.  Otherwise, set to the log
213                                                                          // instant of the first log record.
214 
215        private LogInstant                logLast;  // the last log record written by this
216                                                                          // transaction 
217 
218        private Stack                        savePoints;        // stack of SavePoint objects.
219 
220        protected List                   postCommitWorks; // a list of post commit work
221        protected List                    postTerminationWorks; // work to be done after
222                                                                                                  // transaction terminates,
223                                                                                                  // commit or abort
224        private boolean                        recoveryTransaction;  // this transaction is being
225                                                                                                  // used by recovery
226 
227        DynamicByteArrayOutputStream logBuffer;
228 
229        private boolean postCompleteMode;        // perform most preComplete work in postComplete
230 
231        // Use this flag to catch the case where a global transaction was closed.
232        // Normally a closed transaction should not be aborted again, but we need
233        // to allow abort of a closed global transaction for error handling.  Use
234        // this flag to make sure people are not abusing this loop hole.
235        // RESOLVE: sku to remove before GA
236        private boolean sanityCheck_xaclosed;
237 
238    // Indicates the name of the transaction, and if it is set, it is displayed
239    // by the transactiontable VTI
240    private String transName;
241 
242    // The transaction is only allowed read operations, no log writes.
243    private boolean         readOnly;
244 
245        // true, if the transaction executed some operations(like unlogged
246        // operations) that block the  online backup to prevent inconsistent
247        // backup copy.
248        private boolean backupBlocked;
249 
250 
251        /*
252        ** Constructor
253        */
254 
255        protected Xact(
256    XactFactory xactFactory, 
257    LogFactory  logFactory, 
258    DataFactory dataFactory,
259    boolean     readOnly,
260    Object      compatibilitySpace) 
261    {
262 
263                super();
264 
265                this.xactFactory = xactFactory;
266                this.logFactory  = logFactory;
267                this.dataFactory = dataFactory;
268                this.readOnly    = readOnly;
269 
270                this.compatibilitySpace = 
271            (compatibilitySpace == null ? this : compatibilitySpace);
272 
273                 if (SanityManager.DEBUG)
274                {
275                         SanityManager.ASSERT(dataFactory != null, "datafactory is null");
276                         SanityManager.ASSERT(xactFactory != null, "xactfactory is null");
277                         SanityManager.ASSERT(logFactory != null, "logfactory is null");
278                }
279 
280 
281                resetDefaultLocking();
282 
283                // TransactionTable needs this
284                xactFactory.setNewTransactionId((XactId)null, this);
285 
286                setIdleState();
287 
288                backupBlocked = false; 
289 
290        /*
291        System.out.println("Xact.constructor: readonly = " + this.readOnly +
292                ";this = " + this);
293                */
294        }
295 
296 
297        /*
298        ** Methods of RawTransaction
299        */
300 
301        /**
302        */
303        public final LockFactory getLockFactory() {
304                return xactFactory.getLockFactory();
305        }
306 
307        public final DataFactory getDataFactory() {
308                return dataFactory;
309        }
310 
311        /**
312                Get cache statistics for the specified cache
313        */
314        public long[] getCacheStats(String cacheName) {
315                return getDataFactory().getCacheStats(cacheName);
316        }
317 
318        /**
319                Reset the cache statistics for the specified cache
320        */
321        public void resetCacheStats(String cacheName)  {
322                getDataFactory().resetCacheStats(cacheName);
323        }
324 
325        /**
326                Return true if any transaction is currently blocked, even if not by
327                this transaction.
328 
329         */
330        public boolean anyoneBlocked() {
331                return getLockFactory().anyoneBlocked();
332        }
333 
334        public DynamicByteArrayOutputStream getLogBuffer() {
335 
336                if (logBuffer == null) {
337                        logBuffer = new DynamicByteArrayOutputStream(1024);
338                } else {
339                        logBuffer.reset();
340                }
341 
342                return logBuffer;
343        }
344        
345        /** Log and apply a compensation operation.
346                Only need to write out the compensation op itself, the optional data has already
347                been written by the rollforward operation this is attempting to undo.
348 
349                @see RawTransaction#logAndDo 
350                
351                @exception StandardException  Standard cloudscape exception policy
352        */
353        public void logAndUndo(Compensation compensation, LogInstant undoInstant, LimitObjectInput in)
354                 throws StandardException
355        {
356                if (SanityManager.DEBUG) {
357                        SanityManager.ASSERT(logStart != null);
358                }
359 
360                setActiveState();
361 
362                if (state == ACTIVE)
363                        setUpdateState();
364 
365                seenUpdates = true;
366                
367                LogInstant clrInstant = logger.logAndUndo(this, compensation, undoInstant, in);
368 
369                setLastLogInstant(clrInstant);
370 
371                // set the top savepoint to rollback to this record if it doesn't yet have a point saved
372                if ((savePoints != null) && !savePoints.empty()) {
373 
374                        SavePoint sp = (SavePoint) savePoints.peek();
375                        if (sp.getSavePoint() == null)
376                                sp.setSavePoint(clrInstant);
377                }
378        }
379 
380        /** 
381                Add this to the xactFactory list of update transaction.
382        */
383        public void addUpdateTransaction(int transactionStatus)
384        {
385                // during runtime, rollbackFirst == recoveryRolblackFirst(), but during
386                // recovery redo, we only use a regular transaction, so we need to get
387                // the rollbackFirst status from the log record
388                //
389                // If my Id is null, I have no identity, makes no sense to add it to a
390                // transaction table where my identity will be saved and restored
391                if (myId != null)
392                        xactFactory.addUpdateTransaction(myId, this, transactionStatus);
393 
394        }
395 
396        /** Remove this from the xactFactory list of update transaction. */
397        public void removeUpdateTransaction()
398        {
399                if (myId != null)
400                        xactFactory.removeUpdateTransaction(myId);
401 
402                // If my Id is null, I have no identity, makes no sense to remove it
403                // from transaction table
404        }
405 
406        /** Remove this from the xactFactory list of update transaction. */
407        public void prepareTransaction()
408        {
409        // RESOLVE - should I be changing the state to PREPARE?
410 
411                if (myId != null)
412        {
413            // If my Id is null, I have no identity, makes no sense to set
414            // my state in the transaction table.
415 
416                        xactFactory.prepareTransaction(myId);
417        }
418        }
419 
420        /**
421                Set the log instant for the first log record written by this transaction.
422        */
423        public void setFirstLogInstant(LogInstant instant)
424        {
425                if (SanityManager.DEBUG) {
426                        SanityManager.ASSERT(instant != null);
427                        SanityManager.ASSERT(logStart == null);
428                }
429 
430                logStart = instant;
431        }
432 
433        /**
434                Get the log instant for the first log record written by this transaction.
435        */
436        public LogInstant getFirstLogInstant()
437        {
438                return logStart;
439        }
440 
441        /**
442                Set the log instant for the last log record written by this transaction. 
443        */
444        public void setLastLogInstant(LogInstant instant)
445        {
446                if (SanityManager.DEBUG) {
447                        SanityManager.ASSERT(instant != null);
448                }
449 
450                logLast = instant;
451        }
452 
453        /**
454                Get the log instant for the last log record written by this transaction. 
455        */
456        public LogInstant getLastLogInstant()
457        {
458                return logLast;
459        }
460 
461        /**
462                Set my transaction identifier.
463        */
464        public void setTransactionId(GlobalTransactionId extid, TransactionId localid) {
465 
466                if (SanityManager.DEBUG) {
467 
468                        //SanityManager.ASSERT(myGlobalId == null, "my globalId is not null");
469            if (!(state == IDLE || state == Xact.ACTIVE || 
470                  (state== CLOSED && justCreated)))
471            {
472                SanityManager.THROWASSERT(
473                    "my state is not idle nor active " + state);
474            }
475                }
476 
477                myGlobalId = extid;
478                myId = localid;
479 
480                if (SanityManager.DEBUG)
481                {
482                        if (SanityManager.DEBUG_ON("XATrace") && extid != null)
483            {
484                                SanityManager.DEBUG(
485                    "XATrace","setting xid: " + myId + " " + myGlobalId 
486                                                           + " state " + state + " " + this);
487 
488                SanityManager.showTrace(new Throwable());
489                // Thread.dumpStack();
490            }
491                }
492 
493        }
494 
495        public void setTransactionId(Loggable beginXact, TransactionId localId)
496        {
497                if (SanityManager.DEBUG) {
498                        // SanityManager.ASSERT(myId == null);
499                        SanityManager.ASSERT((state == IDLE) || (state == ACTIVE));
500                        SanityManager.ASSERT(beginXact instanceof BeginXact);
501                }
502 
503                myId = localId;
504                myGlobalId = ((BeginXact)beginXact).getGlobalId();
505        }
506 
507        /*
508        ** Methods of Transaction
509        */
510 
511        /**
512                The default value for LOCKS_ESCALATION_THRESHOLD
513                @exception StandardException  Standard cloudscape exception policy
514         */
515        public void setup(PersistentSet set)
516                throws StandardException {
517 
518                int escalationThreshold = PropertyUtil.getServiceInt(set,
519                        Property.LOCKS_ESCALATION_THRESHOLD,
520                        Property.MIN_LOCKS_ESCALATION_THRESHOLD,
521                        Integer.MAX_VALUE,
522                        Property.DEFAULT_LOCKS_ESCALATION_THRESHOLD);
523 
524 
525                getLockFactory().setLimit(this, this, escalationThreshold, this);
526 
527        }
528 
529        /**
530                get the Global (external to raw store) transaction id that is unique
531                across all raw stores
532        */
533        public final GlobalTransactionId getGlobalId() 
534    {
535 
536                return myGlobalId;
537        }
538 
539        public final ContextManager getContextManager() 
540    {
541                return(xc.getContextManager());
542        }
543 
544    /**
545     * Get the compatibility space of the transaction.
546     * <p>
547     * Returns an object that can be used with the lock manager to provide
548     * the compatibility space of a transaction.  2 transactions with the
549     * same compatibility space will not conflict in locks.  The usual case
550     * is that each transaction has it's own unique compatibility space.
551     * <p>
552     *
553         * @return The compatibility space of the transaction.
554     **/
555    public Object getCompatibilitySpace()
556    {
557        if (SanityManager.DEBUG)
558        {
559                        SanityManager.ASSERT(
560                compatibilitySpace != null, 
561                "cannot have a null compatibilitySpace.");
562        }
563 
564        return(this.compatibilitySpace);
565    }
566 
567 
568        /**
569                get the short (internal to raw store) transaction id that is unique
570                only for this raw store
571        */
572        public final TransactionId getId() {
573 
574                if (SanityManager.DEBUG)
575                        SanityManager.ASSERT(
576                myId != null, "cannot have a transaction with null id");
577 
578                return myId;
579        }
580 
581        /**
582                Get the transaction id without sanity check, this should only be called
583                by a cloned TransactionTableEntry 
584         */
585        protected final TransactionId getIdNoCheck()
586        {
587                return myId;
588        }
589 
590        /**
591                Get my transaction context Id
592        */
593        public final String getContextId() 
594        {
595                return (xc == null) ? null : xc.getIdName();
596        }
597 
598 
599        /**
600                Get the current default locking policy for all operations within this
601                transaction. The transaction is initially started with a default
602                locking policy equivalent to
603                <PRE>
604                         newLockingPolicy(
605              LockingPolicy.MODE_RECORD, TransactionController.ISOLATION_SERIALIZABLE, true);
606                </PRE>
607        This default can be changed by subsequent calls to 
608        setDefaultLockingPolicy(LockingPolicy policy).
609 
610            @see Transaction#getDefaultLockingPolicy
611 
612 
613                @return The current default locking policy in this transaction.
614        */
615 
616        public LockingPolicy getDefaultLockingPolicy()
617    {
618        return(defaultLocking);
619    }
620 
621 
622        /** @see Transaction#newLockingPolicy */
623        public final LockingPolicy newLockingPolicy(int mode, int isolation, boolean stricterOk) {
624 
625                return xactFactory.getLockingPolicy(mode, isolation, stricterOk);
626 
627        }
628 
629        /** @see Transaction#setDefaultLockingPolicy */
630        public final void setDefaultLockingPolicy(LockingPolicy policy) {
631 
632                if (policy == null)
633                        policy = xactFactory.getLockingPolicy(LockingPolicy.MODE_NONE, TransactionController.ISOLATION_NOLOCK, false);
634                defaultLocking = policy;
635        }
636        
637        /** 
638          @exception StandardException  Standard cloudscape exception policy
639        */
640        public LogInstant commit() throws StandardException
641        {
642                return commit(COMMIT_SYNC);
643        }
644 
645        /** 
646          @exception StandardException  Standard cloudscape exception policy
647        */
648        public LogInstant commitNoSync(int commitflag) throws StandardException
649        {
650                if (SanityManager.DEBUG)
651                {
652                        int checkflag = Transaction.RELEASE_LOCKS|Transaction.KEEP_LOCKS;
653 
654                        SanityManager.ASSERT((commitflag & checkflag) != 0, 
655                          "commitNoSync must specify whether to keep or release locks");
656 
657                        SanityManager.ASSERT((commitflag & checkflag) != checkflag,
658                          "cannot set both RELEASE and KEEP LOCKS flag"); 
659 
660            if ((commitflag & 
661                 TransactionController.READONLY_TRANSACTION_INITIALIZATION) 
662                    != 0)
663            {
664                SanityManager.ASSERT((state == IDLE) || (state == ACTIVE));
665            }
666                }
667 
668                // Short circuit commit no sync if we are still initializing the
669                // transaction.  Before a new transaction object is returned to the
670                // user, it is "commit'ed" many times using commitNoSync with 
671                // TransactionController.READONLY_TRANSACTION_INITIALIZATION flag to
672                // release read locks and reset the transaction state back to Idle.  
673                // If nothing has actually happened to the transaction object, return
674                // right away and avoid the cost of going thru the commit logic.
675                //
676                if (state == IDLE && savePoints == null && 
677                        ((commitflag & TransactionController.READONLY_TRANSACTION_INITIALIZATION) != 0))
678                        return null;
679 
680                return commit(COMMIT_NO_SYNC | commitflag);
681        }
682 
683        /** 
684          @exception StandardException  Standard cloudscape exception policy
685          @see Transaction#commit
686        */
687 
688    /**
689     * Do work of commit that is common to xa_prepare and commit.
690     * <p>
691     * Do all the work necessary as part of a commit up to and including
692     * writing the commit log record.  This routine is used by both prepare
693     * and commit.  The work post commit is done by completeCommit().
694     * <p>
695     *
696     * @param commitflag various flavors of commit.
697     *
698         * @exception  StandardException  Standard exception policy.
699         * @see Transaction#commit
700     **/
701        private LogInstant prepareCommit(int commitflag) 
702        throws StandardException 
703    {
704                LogInstant flushTo = null;
705 
706                if (state == CLOSED)
707        {
708                        throw StandardException.newException(
709                    SQLState.XACT_PROTOCOL_VIOLATION);
710        }
711 
712                if (SanityManager.DEBUG)
713                {
714                        if ((commitflag & Transaction.KEEP_LOCKS) != 0)
715                        {
716                // RESOLVE (mikem) - prepare actually want's to keep locks
717                // during a prepare.
718                                SanityManager.ASSERT(
719                    (((commitflag & COMMIT_NO_SYNC) != 0) || 
720                     ((commitflag & COMMIT_PREPARE) != 0)),
721                    "can keep locks around only in commitNoSync or prepare"); 
722 
723                                SanityManager.ASSERT(
724                    isUserTransaction(),
725                    "KEEP_LOCKS can only be set on user transaction commits");
726                        }
727                }
728 
729 
730                try {
731 
732                        preComplete(COMMIT);
733 
734                        // flush the log.
735 
736                        if (seenUpdates) {
737 
738                                EndXact ex = 
739                    new EndXact(
740                        getGlobalId(), 
741                        ((commitflag & COMMIT_PREPARE) == 0 ? 
742                             END_COMMITTED : END_PREPARED)
743                                | statusForEndXactLog());
744 
745                                flushTo = logger.logAndDo(this, ex);
746 
747                                if (xactFactory.flushLogOnCommit(xc.getIdName()))
748                                {
749                                        if ((commitflag & COMMIT_SYNC) == 0)
750                    {
751                        // not flushing the log right now, subsequent commit
752                        // will need to flush the log
753                                                needSync = true; 
754                    }
755                                        else
756                                        {
757                                                logger.flush(flushTo);
758                                                needSync = false;
759                                        }
760                                }
761                        }
762                        else if (needSync && (commitflag & COMMIT_SYNC) != 0)
763                        {
764                                // this transaction object was used to lazily commit some
765                                // previous transaction without syncing.  Now that we commit
766                                // for real, make sure any outstanding log is flushed.
767                                logger.flushAll();
768                                needSync = false;
769                        }
770                } 
771        catch (StandardException se) 
772        {
773 
774                        // This catches any exceptions that have Transaction severity
775                        // or less (e.g. Statement exception). If we received any lesser
776                        // error then we abort the transaction anyway.
777 
778                        if (se.getSeverity() < ExceptionSeverity.TRANSACTION_SEVERITY)
779            {
780                                throw StandardException.newException(
781                        SQLState.XACT_COMMIT_EXCEPTION, se);
782            }
783 
784                        throw se;
785 
786                }
787                return flushTo;
788        }
789 
790    /**
791     * Do work to complete a commit which is not just a prepare.
792     * <p>
793     * Releases locks, does post commit work, and moves the state of the
794     * transaction to IDLE.
795     * <p>
796     *
797     * @param commitflag various flavors of commit.
798     *
799         * @exception  StandardException  Standard exception policy.
800     **/
801        private void completeCommit(int commitflag) 
802        throws StandardException 
803    {
804                // this releases our logical locks if commitflag don't have KEEP_LOCKS.
805                postComplete(commitflag, COMMIT);
806 
807                // this transfer postCommitWorks to PostCommit queue
808                if ((commitflag & Transaction.KEEP_LOCKS) == 0)
809                {
810                        // if locks are released, start post commit processing
811                        postTermination();
812                }
813                else
814                {
815                        // RESOLVE: actually, this transaction may not have outstanding
816                        // locks.  It didn't release them, but that doesn't mean it has got
817                        // them.  This is mostly harmless.
818 
819                        if (SanityManager.DEBUG)
820                                SanityManager.ASSERT(myGlobalId == null,
821                                 "calling commit with KEEP_LOCKS on a global transaction");
822 
823                        // we have unreleased locks, the transaction has resource and
824                        // therefore is "active"
825                        setActiveState();
826                }
827 
828                myGlobalId = null;
829                return;
830        }
831 
832        /** 
833          @exception StandardException  Standard cloudscape exception policy
834          @see Transaction#commit
835        */
836        private LogInstant commit(int commitflag) 
837        throws StandardException 
838    {
839                if (SanityManager.DEBUG)
840                {
841                        if (SanityManager.DEBUG_ON("XATrace"))
842                                SanityManager.DEBUG("XATrace","commiting ");
843                }
844 
845        LogInstant flushTo = prepareCommit(commitflag);
846 
847        completeCommit(commitflag);
848 
849        return(flushTo);
850        }
851 
852 
853        /** 
854            @exception StandardException  Standard cloudscape exception policy
855                @see Transaction#abort
856        */
857        public void abort() throws StandardException {
858 
859                if (SanityManager.DEBUG)
860                {
861                        if (SanityManager.DEBUG_ON("XATrace"))
862                                SanityManager.DEBUG("XATrace","aborting ");
863                }
864 
865                if (state == CLOSED)
866                {
867                        // I would have leave this in but close() nulls out myGlobalId
868                        // if (myGlobalId == null)
869            // {
870                        //   throw StandardException.newException(
871            //           SQLState.XACT_PROTOCOL_VIOLATION);
872            // }
873 
874                        if (SanityManager.DEBUG)
875                        {
876                                // Only global transaction is allowed to abort a closed
877                                // transaction.
878                                if (!sanityCheck_xaclosed)
879                {
880                                        throw StandardException.newException(
881                            SQLState.XACT_PROTOCOL_VIOLATION);
882                }
883                        }
884 
885                        // In global transaction, the xact object is closed automatically
886                        // on a transaction level rollback.  This cause error handling to
887                        // fail because when upper level contexts in the context manager
888                        // unwinds, it calls abort again, which would have caused a
889                        // protocol violation.
890                        return;
891                }
892 
893                /* This routine is never called by recovery redo, only by runtime and
894                   recovery undo. During recovery undo, even though no log record has
895                   been written by this session, it still need to rollback the
896                   incomplete transaction.
897 
898                   The way to tell if this trasanction has ever written a log record is
899                   by FirstLogInstant.
900                */
901 
902                try {
903                        preComplete(ABORT);
904 
905                        // rollback the log - if logger is null, nothing I can do, crash.
906                        if (getFirstLogInstant() != null) {
907                                if (logger == null)
908                {
909                                        throw StandardException.newException(SQLState.XACT_CANNOT_ABORT_NULL_LOGGER);
910                }
911 
912                                logger.undo(
913                    this, getId(), getFirstLogInstant(), getLastLogInstant());
914 
915                                EndXact ex = new EndXact(getGlobalId(),
916                                                                                 END_ABORTED | statusForEndXactLog());
917 
918                                logger.flush(logger.logAndDo(this, ex));
919                        }
920                        else if (needSync)
921                        {
922                                // this transaction object was used to lazily commit some
923                                // previous transaction without syncing.  Now that we abort
924                                // for real, make sure any outstanding log is flushed.
925                                logger.flushAll();
926                        }
927 
928                        needSync = false;
929                        
930                } catch (StandardException se) {
931 
932                        // This catches any exceptions that have System severity
933                        // or less (e.g. Statement exception).
934                        //
935                        // If we have any error during an undo we just shut the system
936                        // down, this is a bit drastic but it does ensure that the database
937                        // will not become corrupted by changes that see half committed 
938            // changes.
939            //
940                        // Note that we do not release our locks if we come thorugh this
941                        // path, if we did then another transaction could complete before
942                        // the system shuts down and make changes based upon the changes
943                        // that we couldn't back out.
944 
945                        if (se.getSeverity() < ExceptionSeverity.SYSTEM_SEVERITY)
946            {
947                                throw logFactory.markCorrupt(
948                    StandardException.newException(
949                        SQLState.XACT_ABORT_EXCEPTION, se));
950            }
951 
952                        throw se;
953 
954                }
955 
956                // this releases our locks.
957                postComplete(0, ABORT);
958 
959                // get rid of all post commit work - we aborted, therefore no post
960                // commit work
961                if (postCommitWorks != null && !postCommitWorks.isEmpty())
962                {
963                        postCommitWorks.clear();
964                }
965 
966                // Now do post termination work - must do this after the rollback is
967                // complete because the rollback itself may generate postTermination
968                // work.
969                postTermination();
970 
971                myGlobalId = null;
972        }
973 
974    /**
975     * During recovery re-prepare a transaction.
976     * <p>
977     * After redo() and undo(), this routine is called on all outstanding 
978     * in-doubt (prepared) transactions.  This routine re-acquires all 
979     * logical write locks for operations in the xact, and then modifies
980     * the transaction table entry to make the transaction look as if it
981     * had just been prepared following startup after recovery.
982     * <p>
983     * This routine is only called during Recovery.
984     *
985         * @exception  StandardException  Standard exception policy.
986     **/
987    public void reprepare()
988                throws StandardException
989    {
990                if (state == CLOSED)
991        {
992                        throw StandardException.newException(
993                    SQLState.XACT_PROTOCOL_VIOLATION);
994        }
995 
996        // Should only be called during recovery on global transactions, 
997        // after redo and undo.
998        if (SanityManager.DEBUG)
999        {
1000            SanityManager.ASSERT(myGlobalId != null);
1001            SanityManager.ASSERT(state == PREPARED);
1002        }
1003 
1004                try 
1005        {
1006            if (logger == null)
1007            {
1008                throw StandardException.newException(
1009                        SQLState.XACT_CANNOT_ABORT_NULL_LOGGER);
1010            }
1011 
1012            // temporarily set state back to UPDATE, so that the reprepare()
1013            // call can do operations on the xact that would "normally" be 
1014            // disallowed on a prepared xact - like opening a container to
1015            // lock it.
1016 
1017            state = UPDATE;
1018 
1019            // re-prepare the transaction.
1020            logger.reprepare(
1021                this, getId(), getFirstLogInstant(), getLastLogInstant());
1022 
1023            // make sure the xact is prepare state when we are done.
1024            state = PREPARED;
1025 
1026            seenUpdates = true;
1027 
1028                } catch (StandardException se) {
1029 
1030                        // This catches any exceptions that have System severity
1031                        // or less (e.g. Statement exception).
1032                        //
1033                        // If we have any error during an reprepare we just shut the system
1034                        // down, this is a bit drastic but it does ensure that the database
1035                        // will not become corrupted by changes that see data that is part
1036            // of a prepared transaction.
1037            //
1038                        // Note that we do not release our locks if we come thorugh this
1039                        // path, if we did then another transaction could complete before
1040                        // the system shuts down and make changes based upon the changes
1041                        // that we couldn't back out.
1042 
1043                        if (se.getSeverity() < ExceptionSeverity.SYSTEM_SEVERITY)
1044            {
1045                                throw logFactory.markCorrupt(
1046                    StandardException.newException(
1047                        SQLState.XACT_ABORT_EXCEPTION, se));
1048            }
1049 
1050                        throw se;
1051                }
1052 
1053        // RESOLVE - something needs to change the state of the XACT so that
1054        // it is not recovery state anymore?
1055        }
1056 
1057        /**
1058        If this transaction is not idle, abort it.  After this call close().
1059 
1060                @exception StandardException Standard Cloudscape error policy
1061        Thrown if the transaction is not idle.
1062 
1063                
1064        */
1065        public void destroy() throws StandardException 
1066    {
1067        if (state != CLOSED)
1068            abort();
1069 
1070        close();
1071    }
1072 
1073        /**
1074            @exception StandardException  Standard cloudscape exception policy
1075                @exception StandardException Thrown if the transaction is not idle, the
1076                transaction remains open.
1077                @see Transaction#close
1078 
1079                @exception StandardException        Standard cloudscape policy
1080        */
1081        public void close() throws StandardException {
1082 
1083 
1084        /*
1085 
1086        if (((LogToFile) logFactory).inRedo)
1087        {
1088            SanityManager.showTrace(new Throwable());
1089            SanityManager.THROWASSERT("in Redo while in close");
1090        }
1091        */
1092 
1093                switch (state) {
1094                case CLOSED:
1095                        return;
1096                case IDLE:
1097                        break;
1098                default:
1099                        throw StandardException.newException(
1100                SQLState.XACT_TRANSACTION_NOT_IDLE);
1101                }
1102 
1103                if (SanityManager.DEBUG) {
1104 
1105                        SanityManager.ASSERT(xc.getTransaction() == this);
1106 
1107                        SanityManager.ASSERT(
1108                (postCommitWorks == null || postCommitWorks.isEmpty()),
1109                "cannot close a transaction with post commit work pending");
1110 
1111                        // use this for sanity checking
1112                        if (myGlobalId != null)
1113                                sanityCheck_xaclosed = true;
1114                }
1115 
1116                getLockFactory().clearLimit(this, this);
1117 
1118                if (SanityManager.DEBUG)
1119                {
1120                        if (SanityManager.DEBUG_ON("XATrace"))
1121                                SanityManager.DEBUG("XATrace","closing " + myId + " " + myGlobalId);
1122                        // Thread.dumpStack();
1123                }
1124 
1125                // if we just finished recovery myId could be null
1126                if (myId != null)
1127                        xactFactory.remove((XactId)myId);                
1128 
1129                xc.popMe();
1130                xc = null;
1131 
1132                myGlobalId = null;
1133                myId = null;
1134                logStart = null;
1135                logLast = null;
1136 
1137 
1138 
1139                /* MT - no need to synchronize it, the state is current IDLE which will
1140                 * return the same result to isActive() as if it is CLOSED
1141                 */
1142                state = CLOSED;
1143 
1144        }
1145 
1146        /** 
1147                Log the operation and do it.
1148 
1149                If this transaction has not generated any log records prior to this,
1150                then log a beginXact log record.
1151 
1152                If the passed in operation is null, then do nothing (after logging the
1153                beginXact if needed).
1154 
1155            @exception StandardException  Standard cloudscape exception policy
1156                @see Transaction#logAndDo 
1157        */
1158        public void logAndDo(Loggable operation) throws StandardException {
1159 
1160                LogInstant instant = null;
1161 
1162                if (logger == null)
1163                        getLogger();
1164 
1165                if (logger == null)
1166        {
1167                        throw StandardException.newException(
1168                    SQLState.XACT_CANNOT_LOG_CHANGE);
1169        }
1170 
1171                setActiveState();
1172 
1173                if (state == ACTIVE)
1174                {
1175                        instant = 
1176                logger.logAndDo(
1177                    this, 
1178                    new BeginXact(getGlobalId(), statusForBeginXactLog()));
1179 
1180                        setUpdateState();
1181                }
1182                seenUpdates = true;
1183 
1184                if (operation != null)
1185                {
1186                        instant = logger.logAndDo(this, operation);
1187                        if (instant != null) {
1188                                setLastLogInstant(instant);
1189 
1190                                if ((savePoints != null) && !savePoints.empty()) {
1191                                        for (int i = savePoints.size() - 1; i >= 0; i--) {
1192                                            // set the top savepoint to rollback to this record if
1193                        // it doesn't yet have a point saved
1194 
1195                                                SavePoint sp = (SavePoint) savePoints.elementAt(i);
1196                                                if (sp.getSavePoint() == null) {
1197                                                        sp.setSavePoint(instant);
1198                                                } else
1199                                                        break;
1200                                        }
1201                                }
1202                        }
1203 
1204                }
1205                else
1206                {
1207                        if (instant != null)
1208                                setLastLogInstant(instant);
1209                }
1210 
1211        }
1212 
1213        public void addPostCommitWork(Serviceable work)
1214        {
1215                if (recoveryTransaction)
1216                        return;
1217 
1218                if (postCommitWorks == null)
1219                        postCommitWorks = new ArrayList(1);
1220                postCommitWorks.add(work);
1221        }
1222 
1223        public void addPostTerminationWork(Serviceable work)
1224        {
1225                if (recoveryTransaction)
1226                        return;
1227 
1228                if (postTerminationWorks == null)
1229                        postTerminationWorks = new ArrayList(2);
1230                postTerminationWorks.add(work);
1231        }
1232 
1233 
1234        /**
1235                Return a record handle that is initialized to the given page number and
1236        record id.
1237 
1238                @exception StandardException Standard cloudscape exception policy.
1239 
1240                @param segmentId    segment where the RecordHandle belongs.
1241                @param containerId  container where the RecordHandle belongs.
1242                @param pageNumber   the page number of the RecordHandle.
1243                @param recordId     the record id of the RecordHandle.
1244 
1245                @see RecordHandle
1246        */
1247//        public RecordHandle makeRecordHandle(long segmentId, long containerId, long pageNumber, int recordId)
1248//                 throws        StandardException
1249 //    {
1250//         return(this.dataFactory.makeRecordHandle(
1251//             segmentId, containerId, pageNumber, recordId));
1252//     }
1253 
1254        /** 
1255            @exception StandardException  Standard cloudscape exception policy
1256                @see Transaction#openContainer 
1257        */
1258        public ContainerHandle openContainer(ContainerKey containerId,  int mode)
1259                throws StandardException {
1260 
1261                return openContainer(containerId, defaultLockingPolicy(), mode);
1262        }
1263 
1264        /** 
1265            @exception StandardException  Standard cloudscape exception policy
1266                @see Transaction#openContainer 
1267        */
1268        public ContainerHandle openContainer(ContainerKey containerId, LockingPolicy locking, int mode)
1269                throws StandardException {
1270 
1271                setActiveState();
1272 
1273                if (locking == null)
1274                        locking = xactFactory.getLockingPolicy(LockingPolicy.MODE_NONE, TransactionController.ISOLATION_NOLOCK, false);
1275 
1276                return dataFactory.openContainer(this, containerId, locking, mode);
1277        }
1278 
1279        /**
1280                Open a container that may already have been dropped.
1281 
1282                @exception StandardException  Standard cloudscape exception policy
1283                @see RawTransaction#openDroppedContainer
1284        */
1285        public RawContainerHandle openDroppedContainer(ContainerKey containerId, LockingPolicy locking)
1286                 throws StandardException
1287        {
1288                setActiveState();
1289 
1290                if (locking == null)
1291                        locking = xactFactory.getLockingPolicy(LockingPolicy.MODE_NONE, TransactionController.ISOLATION_NOLOCK, false);
1292 
1293                RawContainerHandle hdl = null;
1294 
1295                // first try to open it for update, if that fail, open it for read
1296                try
1297                {
1298                        hdl = dataFactory.openDroppedContainer(this, containerId, locking,
1299                                                                                        ContainerHandle.MODE_FORUPDATE);
1300                }
1301                catch (StandardException se)
1302                {
1303                        // if this also fail, throw exception
1304                        hdl = dataFactory.openDroppedContainer(this, containerId,
1305                                                                                        locking,
1306                                                                                        ContainerHandle.MODE_READONLY);
1307                }
1308 
1309                return hdl;
1310        }
1311 
1312 
1313        /** 
1314            @exception StandardException  Standard cloudscape exception policy
1315                @see Transaction#addContainer 
1316        */
1317        public long addContainer(long segmentId, long containerid, int mode, Properties tableProperties, int temporaryFlag)
1318                throws StandardException {
1319 
1320                setActiveState();
1321 
1322                return dataFactory.addContainer(this, segmentId, containerid, mode, tableProperties, temporaryFlag);
1323        }
1324 
1325        /** 
1326            @exception StandardException  Standard cloudscape exception policy
1327                @see Transaction#addAndLoadStreamContainer
1328        */
1329        public long addAndLoadStreamContainer(long segmentId, Properties tableProperties, RowSource rowSource)
1330                throws StandardException {
1331 
1332                setActiveState();
1333 
1334                return dataFactory.addAndLoadStreamContainer(this, segmentId, tableProperties, rowSource);
1335 
1336        }
1337 
1338        /** 
1339            @exception StandardException  Standard cloudscape exception policy
1340                @see Transaction#openStreamContainer
1341        */
1342        public StreamContainerHandle openStreamContainer(
1343    long    segmentId, 
1344    long    containerId,
1345    boolean hold)
1346                throws StandardException 
1347    {
1348                setActiveState();
1349 
1350                return(
1351            dataFactory.openStreamContainer(
1352                this, segmentId, containerId, hold));
1353        }
1354 
1355        /**
1356                @see Transaction#dropStreamContainer
1357                @exception StandardException Standard Cloudscape error policy
1358        */
1359        public void dropStreamContainer(long segmentId, long containerId)
1360                throws StandardException {
1361 
1362                setActiveState();
1363 
1364                dataFactory.dropStreamContainer(this, segmentId, containerId); 
1365        }
1366 
1367        /**
1368                Recreate a container during redo recovery.
1369 
1370        Used only during redo recovery while processing log records which
1371        are trying to create a container, and no valid container is found
1372        in the database.
1373 
1374                @exception StandardException  Standard cloudscape exception policy
1375                @see RawTransaction#reCreateContainerForRedoRecovery
1376         */
1377        public void reCreateContainerForRedoRecovery
1378                (long segmentId, long containerId, ByteArray containerInfo)
1379                throws StandardException
1380        {
1381                setActiveState();
1382 
1383                dataFactory.reCreateContainerForRedoRecovery(
1384                        this, segmentId, containerId, containerInfo);
1385        }
1386 
1387        /**
1388                @see Transaction#dropContainer
1389                @exception StandardException Standard Cloudscape error policy
1390        */
1391        public void dropContainer(ContainerKey containerId)
1392                throws StandardException {
1393 
1394                setActiveState();
1395 
1396                dataFactory.dropContainer(this, containerId); 
1397        }
1398 
1399        /**
1400            @exception StandardException  Standard cloudscape exception policy
1401                @see Transaction#setSavePoint
1402        */
1403        public int setSavePoint(String name, Object kindOfSavepoint) 
1404        throws StandardException 
1405    {
1406 
1407                if (kindOfSavepoint != null && kindOfSavepoint instanceof String)  
1408        {
1409            //that means we are trying to set a SQL savepoint
1410 
1411            //error if this SQL savepoint is getting nested into other user 
1412            // defined savepoints
1413                        throwExceptionIfSQLSavepointNotAllowed(kindOfSavepoint);
1414        }
1415 
1416                // while setting a savepoint, we just want to see if there is a 
1417        // savepoint with the passed name already in the system.
1418                if (getSavePointPosition(name, kindOfSavepoint, false) != -1)
1419        {
1420                        throw StandardException.newException(
1421                    SQLState.XACT_SAVEPOINT_EXISTS);
1422        }
1423 
1424                if (savePoints == null)
1425                        savePoints = new Stack();
1426 
1427                savePoints.push(new SavePoint(name, kindOfSavepoint));
1428 
1429                if (SanityManager.DEBUG) {
1430 
1431                        if (SanityManager.DEBUG_ON("memoryLeakTrace")) {
1432 
1433                                if (savePoints.size() > 20)
1434                                        System.out.println("memoryLeakTrace:Xact:savepoints " + savePoints.size());
1435                        }
1436                }
1437                return savePoints.size();
1438        }
1439 
1440        // SQL savepoint can't be nested inside other user defined savepoints. To 
1441    // enforce this, we check if there are already user savepoint(SQL/JDBC)
1442    // defined in the transaction. If yes, then throw an exception
1443 
1444        /**
1445            @exception StandardException  Standard cloudscape exception policy
1446                @see Transaction#setSavePoint
1447        */
1448        private void throwExceptionIfSQLSavepointNotAllowed(Object kindOfSavepoint)
1449        throws StandardException 
1450    {
1451 
1452                boolean foundUserSavepoint = false;
1453 
1454                if ((savePoints != null) && !savePoints.empty()) {
1455                        for (int i = savePoints.size() - 1; i >= 0; i--) {
1456                                SavePoint sp = (SavePoint) savePoints.elementAt(i);
1457                                if (sp.isThisUserDefinedsavepoint()) 
1458                                {
1459                    //found a user defined savepoint
1460 
1461                                        foundUserSavepoint = true;
1462                                        break;
1463                                }
1464                        }
1465                }
1466 
1467                if (foundUserSavepoint) 
1468                        throw StandardException.newException(
1469                    SQLState.XACT_MAX_SAVEPOINT_LEVEL_REACHED);
1470        }
1471 
1472        /**
1473            @exception StandardException  Standard cloudscape exception policy
1474                @see Transaction#releaseSavePoint
1475        */
1476        public int releaseSavePoint(String name, Object kindOfSavepoint) 
1477        throws StandardException 
1478    {
1479                int position = getSavePointPosition(name, kindOfSavepoint, true);
1480 
1481                if (position == -1)
1482        {
1483                        // following means this is a JDBC savepoint. 
1484            // We prepend i./e. to JDBC savepoint names in JDBC layer.
1485                        // Need to trim that here before giving error
1486 
1487                        if (kindOfSavepoint != null && !(kindOfSavepoint instanceof String))
1488            {
1489                // this means this is a JDBC savepoint. 
1490                // We append "i."/"e." to JDBC savepoint names. 
1491                // Trimming that here before giving error
1492 
1493                                name = name.substring(2); 
1494            }
1495                        throw StandardException.newException(
1496                        SQLState.XACT_SAVEPOINT_NOT_FOUND, name);
1497        }
1498 
1499                popSavePoints(position, true);
1500                return savePoints.size();
1501        }
1502 
1503        /** 
1504            @exception StandardException  Standard cloudscape exception policy
1505                @see Transaction#rollbackToSavePoint
1506        */
1507        public int rollbackToSavePoint(String name, Object kindOfSavepoint) 
1508        throws StandardException 
1509    {
1510                int position = getSavePointPosition(name, kindOfSavepoint, true);
1511 
1512                if (position == -1)
1513        {
1514                        // following means this is a JDBC savepoint. 
1515            // We append i./e. to JDBC savepoint names in JDBC layer.
1516                        // Need to trim that here before giving error
1517                        if (kindOfSavepoint != null && !(kindOfSavepoint instanceof String))
1518                                name = name.substring(2);
1519                        throw StandardException.newException(
1520                        SQLState.XACT_SAVEPOINT_NOT_FOUND, name);
1521        }
1522 
1523                notifyObservers(SAVEPOINT_ROLLBACK);
1524 
1525                popSavePoints(position, false);
1526                return savePoints.size();
1527        }
1528 
1529 
1530        /*
1531        **        Implementation specific methods
1532        */
1533 
1534        /**
1535                Get the Logger object used to write log records to the transaction log.
1536        */
1537        private void getLogger() {
1538 
1539                logger = logFactory.getLogger();
1540        }
1541 
1542 
1543        /**
1544                Transform this identity to the one stored in transaction table entry.
1545                Used by recovery only!
1546        */
1547        protected void assumeIdentity(TransactionTableEntry ent)
1548        {
1549                if (ent != null)
1550                {
1551                        if (SanityManager.DEBUG)
1552                        {
1553                                SanityManager.ASSERT(ent.getXid() != null, "TTE.xid is null");
1554 
1555                                SanityManager.ASSERT(
1556                    ent.getFirstLog() != null, "TTE.firstLog is null");
1557                        }
1558 
1559                        // I am the transaction that is using this TransactionTableEntry
1560                        ent.setXact(this);
1561 
1562                        myId     = ent.getXid();
1563                        logStart = ent.getFirstLog();
1564                        logLast  = ent.getLastLog();
1565 
1566 
1567            // This routine is only used by recovery to assume the identity
1568            // of the transaction for each log record during redo and undo.
1569            // For this purpose the transaction should act like a local 
1570            // transaction, and ignore the fact that it may or may not be
1571            // an XA global transaction - this is necessary as global 
1572            // transactions can only be committed or aborted once, but 
1573            // recovery needs to reuse the same xact over and over again.  
1574            // For this purpose set myGlobalId to null so it is treated as
1575            // a local xact - the entry in the transaction table will 
1576            // track that in reality it is a global id and remember it's
1577            // value.
1578                        myGlobalId = null;
1579 
1580                        // I am very active
1581                        if (state == IDLE)
1582                                state = ACTIVE;
1583 
1584                        if (SanityManager.DEBUG)
1585                        {
1586                                if (state != ACTIVE && state != UPDATE && state != PREPARED)
1587                    SanityManager.THROWASSERT(
1588                        "recovery transaction have illegal state " + state +
1589                        "xact = " + this);
1590                        }
1591 
1592 
1593 
1594                        if (logger == null)
1595                                getLogger();
1596 
1597                        savedEndStatus = 0;
1598                }
1599                else
1600                {
1601                        myGlobalId = null;
1602                        myId = null;
1603                        logStart = null;
1604                        logLast = null;
1605                        state = IDLE;
1606                }
1607        }
1608 
1609    /**
1610     * Assume complete identity of the given Transaction Table Entry.
1611     * <p>
1612     * Used by the final phase of the recovery to create new real transactions
1613     * to take on the identity of in-doubt prepared transactions found during
1614     * redo.  Need to assume the globalId.
1615     *
1616     * @param ent The original entry we are assuming the identity of.
1617     *
1618     **/
1619        protected void assumeGlobalXactIdentity(
1620    TransactionTableEntry ent)
1621        {
1622        if (SanityManager.DEBUG)
1623        {
1624            SanityManager.ASSERT(ent != null);
1625            SanityManager.ASSERT(ent.getXid() != null, "TTE.xid is null");
1626            SanityManager.ASSERT(
1627                ent.getFirstLog() != null, "TTE.firstLog is null");
1628            SanityManager.ASSERT(ent.isPrepared());
1629        }
1630 
1631        myId        = ent.getXid();
1632        myGlobalId  = ent.getGid();
1633        logStart    = ent.getFirstLog();
1634        logLast     = ent.getLastLog();
1635 
1636        // I am very active
1637        if (state == IDLE)
1638                {
1639                        if (SanityManager.DEBUG)
1640                        {
1641                                if (SanityManager.DEBUG_ON("XATrace"))
1642                                        SanityManager.DEBUG("XATrace","set active state in assume Global XactIdentity");
1643                        }
1644 
1645            state = ACTIVE;
1646                }
1647 
1648        if (ent.isPrepared())
1649            state = PREPARED;
1650 
1651        // I am the transaction that is using this TransactionTableEntry
1652        ent.setXact(this);
1653 
1654        if (SanityManager.DEBUG)
1655        {
1656            if (state != ACTIVE && state != UPDATE && state != PREPARED)
1657                SanityManager.THROWASSERT(
1658                    "recovery transaction have illegal state " + state +
1659                    "xact = " + this);
1660        }
1661 
1662        if (logger == null)
1663            getLogger();
1664 
1665                savedEndStatus = 0;
1666 
1667        if (SanityManager.DEBUG)
1668        {
1669            SanityManager.ASSERT(myGlobalId != null);
1670 
1671            // at least right now only prepared xact call this during recovery.
1672            SanityManager.ASSERT(state == PREPARED);
1673        }
1674        }
1675 
1676 
1677        /**
1678                Move the transaction into the update state.
1679                @exception StandardException problem setting a transaction id
1680        */
1681        private final void setUpdateState() throws StandardException {
1682 
1683        /*
1684        System.out.println("calling setUpdateState() - readOnly = " + readOnly +
1685                ";this = " + this);
1686        System.out.println("calling setUpdateState():");
1687                (new Throwable()).printStackTrace();
1688        */
1689 
1690                if (SanityManager.DEBUG)
1691                {
1692                        SanityManager.ASSERT(
1693                state == ACTIVE, 
1694                "setting update state without first going thru ACTIVE state");
1695 
1696                        SanityManager.ASSERT(
1697                myId != null, 
1698                "setting update state to a trasnaction with Null ID");
1699                }
1700 
1701                if (SanityManager.DEBUG)
1702                {
1703                        if (SanityManager.DEBUG_ON("XATrace"))
1704            {
1705                                SanityManager.DEBUG("XATrace","set update state");
1706                SanityManager.showTrace(new Throwable());
1707            }
1708                }
1709 
1710        if (readOnly)
1711        {
1712            throw StandardException.newException(
1713                SQLState.XACT_PROTOCOL_VIOLATION);
1714        }
1715 
1716                state = UPDATE;
1717        }
1718 
1719        protected void setIdleState() {
1720 
1721                if (SanityManager.DEBUG)
1722                        SanityManager.ASSERT(myId != null, "setIdleState got null ID");
1723 
1724                if (SanityManager.DEBUG)
1725        {
1726            if (SanityManager.DEBUG_ON("TranTrace"))
1727            {
1728                SanityManager.DEBUG(
1729                    "TranTrace", "transaction going idle " + myId);
1730 
1731                SanityManager.showTrace(new Throwable("TranTrace"));
1732            }
1733                }
1734 
1735 
1736                /* MT - single thread throught synchronizing this.  Even though no other
1737                 * thread can call this, they may call isActive which needs to be
1738                 * synchronized with state transaction into or out of the idle state
1739                 */
1740                // synchronized(this) -- int access, implicit synchronization
1741                // due to atomic action
1742                {
1743                        state = IDLE;
1744                }
1745 
1746                
1747 
1748                seenUpdates = false;
1749 
1750                // these fields will NOT be accessed by the checkpoint thread at the
1751                // same time because the doMe method of EndXact removed this
1752                // transaction from the "update transaction" list, therefore when the
1753                // checkpoint writes out the transaction table, this transaction will
1754                // be skipped.  OK to just change it without synchronization here.
1755 
1756                logStart = null;
1757                logLast = null;
1758 
1759                if (SanityManager.DEBUG)
1760                {
1761                        if (SanityManager.DEBUG_ON("XATrace"))
1762                                SanityManager.DEBUG("XATrace","set idle state : " + state + " " + this);
1763                }
1764 
1765        }
1766 
1767        protected final void setActiveState() throws StandardException {
1768 
1769                if ((state == CLOSED) || (!inAbort() && (state == PREPARED)))
1770        {
1771            // This is where we catch attempted activity on a prepared xact.
1772                        throw StandardException.newException(
1773                    SQLState.XACT_PROTOCOL_VIOLATION);
1774        }
1775 
1776                if (SanityManager.DEBUG)
1777                        SanityManager.ASSERT(myId != null, "setActiveState got null ID");
1778 
1779                if (state == IDLE)
1780                {
1781                        synchronized(this)
1782                        {
1783                                state = ACTIVE;
1784                        }
1785 
1786                        if (SanityManager.DEBUG)
1787                        {
1788                                if (SanityManager.DEBUG_ON("XATrace"))
1789                {
1790                                        SanityManager.DEBUG("XATrace","set active state " + this);
1791                    SanityManager.showTrace(new Throwable("XATrace"));
1792                }
1793                        }
1794 
1795 
1796                        if (!justCreated)
1797                                xactFactory.setNewTransactionId(myId, this);
1798 
1799                        justCreated = false;
1800 
1801                        if (SanityManager.DEBUG)
1802            {
1803                                if (SanityManager.DEBUG_ON("TranTrace"))
1804                {
1805                    SanityManager.DEBUG(
1806                        "TranTrace", "transaction going active " + myId);
1807 
1808                    SanityManager.showTrace(new Throwable("TranTrace"));
1809                }
1810                        }
1811 
1812                }
1813        }
1814 
1815    /**
1816     * Move the state of the transaction from UPDATE to PREPARE.
1817     * <p>
1818     * The state transition should only be from UPDATE to PREPARE.  Read-only
1819     * transactions (IDLE and ACTIVE) will never be prepared, they will be
1820     * commited when the prepare is requested.  Only Update transactions will
1821     * be allowed to go to prepared state.
1822     * <p>
1823     *
1824         * @exception  StandardException  Standard exception policy.
1825     **/
1826        protected final void setPrepareState() 
1827        throws StandardException 
1828    {
1829                if (state == PREPARED || state == CLOSED)
1830        {
1831                        throw StandardException.newException(
1832                    SQLState.XACT_PROTOCOL_VIOLATION);
1833        }
1834 
1835                if (SanityManager.DEBUG)
1836                {
1837                        SanityManager.ASSERT(
1838                state == UPDATE, 
1839                "setting PREPARED state without first going thru UPDATE state");
1840                        SanityManager.ASSERT(
1841                myId != null, 
1842                "setting PREPARED state to a transaction with Null ID");
1843                }
1844 
1845                state = PREPARED;
1846        }
1847 
1848 
1849        public final LockingPolicy defaultLockingPolicy() {
1850                return defaultLocking;
1851        }
1852 
1853 
1854        private final void releaseAllLocks() {
1855 
1856                getLockFactory().unlockGroup(getCompatibilitySpace(), this);
1857        }
1858 
1859        void resetDefaultLocking() {
1860 
1861                setDefaultLockingPolicy(
1862                        newLockingPolicy(LockingPolicy.MODE_RECORD, TransactionController.ISOLATION_SERIALIZABLE, true));
1863 
1864                if (SanityManager.DEBUG) {
1865                        SanityManager.ASSERT(defaultLocking != null);
1866                }
1867 
1868        }
1869        
1870        protected void preComplete(Integer commitOrAbort) throws StandardException {
1871                
1872                /* If a transaction is in COMMIT/ABORT at this point, most probably
1873                 * some thing went wrong in earlier attempt to commit or abort,
1874                 * so we don't know wther the log records got written in previous
1875                 * attempt. It's is better to bring down the system than make recovery
1876                 * fail with a duplicate log records of COMMIT/ABORT for the same Transaction.
1877                 */
1878                if (inComplete != null)
1879                        if (commitOrAbort.equals(COMMIT))
1880                                throw logFactory.markCorrupt(
1881                                                 StandardException.newException(SQLState.XACT_COMMIT_EXCEPTION));
1882                        else
1883                                throw logFactory.markCorrupt(
1884                                                 StandardException.newException(SQLState.XACT_ABORT_EXCEPTION));
1885                
1886                inComplete = commitOrAbort;
1887                if (!postCompleteMode)
1888                        doComplete(commitOrAbort);
1889 
1890        }
1891 
1892        protected void postComplete(int commitflag, Integer commitOrAbort) throws StandardException {
1893 
1894                if (postCompleteMode)
1895                        doComplete(commitOrAbort);
1896 
1897                // if we are want to commitNoSync with KEEP_LOCKS flag set, don't
1898                // release any locks
1899                if ((commitflag & Transaction.KEEP_LOCKS) == 0)
1900        {
1901                        releaseAllLocks();
1902        }
1903                else 
1904                {
1905                        if (SanityManager.DEBUG)
1906                        {
1907                                SanityManager.ASSERT(commitOrAbort.equals(COMMIT),
1908                                 "cannot keep locks around after an ABORT");
1909                        }
1910                }
1911 
1912                setIdleState();
1913 
1914                inComplete = null;
1915        }
1916 
1917        protected void doComplete(Integer commitOrAbort) throws StandardException {
1918 
1919                // throw away all our savepoints
1920                if (savePoints != null)
1921                        savePoints.removeAllElements();
1922 
1923                // notify any of our observers that we are completing.
1924                notifyObservers(commitOrAbort);
1925 
1926                checkObserverException();
1927 
1928                if (SanityManager.DEBUG) 
1929        {
1930                        if (countObservers() != 0)
1931            {
1932                                System.out.println(
1933                    "There should be 0 observers, but we still have "
1934                                        + countObservers() + " observers.");
1935                                notifyObservers(null);
1936            }
1937                }
1938        }
1939 
1940        private void checkObserverException() throws StandardException {
1941                if (observerException != null) {
1942                        StandardException se = observerException;
1943                        observerException = null;
1944                        throw se;
1945                }
1946        }
1947 
1948        /**
1949          If this is a user transaction (not an internal or nested top
1950          transaction), and this is not already taking care of post
1951          commit work, and not an XA transaction, then take care of hi prioirty 
1952      work right now using this thread and this context manager.  
1953      Otherwise, leave it to the post commit daemon.
1954          */
1955        protected boolean doPostCommitWorkInTran()
1956        {
1957                return (!inPostCommitProcessing &&
1958                                !recoveryTransaction    &&
1959                isUserTransaction()     &&
1960                (myGlobalId == null));
1961        }
1962 
1963        public boolean handlesPostTerminationWork()
1964        {
1965                // recovery transaction cannot handle post termination work
1966                return (recoveryTransaction == false);
1967        }
1968 
1969        public void recoveryTransaction()
1970        {
1971                recoveryTransaction = true;
1972 
1973                // remove myself from the transaction table because I am really a
1974                // "fake" transaction.  All interaction I have with the transaction
1975                // table should happen after I have assumed the identity of one of the
1976                // recovery transaction that has its state frozen in the transaction
1977                // table. 
1978                xactFactory.remove(myId);
1979 
1980        }
1981 
1982 
1983        private final void postTermination() throws StandardException
1984        {
1985                // move all the postTermination work to the postCommit queue
1986                int count = (postTerminationWorks == null) ? 
1987                        0 : postTerminationWorks.size(); 
1988 
1989                for (int i = 0; i < count; i++)
1990                        addPostCommitWork((Serviceable)postTerminationWorks.get(i));
1991 
1992                if (count > 0)
1993                        postTerminationWorks.clear();
1994 
1995 
1996                // if there are post commit work to be done, transfer them to the
1997                // daemon.  The log is flushed, all locks released and the
1998                // transaction has ended at this point.
1999                if (postCommitWorks != null && !postCommitWorks.isEmpty())
2000                {
2001                        int pcsize = postCommitWorks.size();
2002                        
2003                        // do we want to do post commit work with this transaction object?
2004                        if (doPostCommitWorkInTran())
2005                        {
2006                                try
2007                                {
2008                                        inPostCommitProcessing = true;
2009 
2010                                        // to avoid confusion, copy the post commit work to an array if this
2011                                        // is going to do some work now
2012                                        Serviceable[] work = new Serviceable[pcsize];
2013                                        work = (Serviceable[])postCommitWorks.toArray(work);
2014 
2015                                        // clear this for post commit processing to queue its own post
2016                                        // commit works - when it commits, it will send all its post
2017                                        // commit request to the daemon instead of dealing with it here.
2018                                        postCommitWorks.clear();
2019 
2020                                        //All the post commit work that is part  of the database creation
2021                                        //should be done on this thread immediately.
2022                                        boolean doWorkInThisThread = xactFactory.inDatabaseCreation();
2023 
2024                                        for (int i = 0; i < pcsize; i++)
2025                                        {
2026 
2027                                                //process work that should be done immediately or
2028                                                //when we  are in still in database creattion.
2029                                                //All the other work should be submitted 
2030                                                //to the post commit thread to be processed asynchronously
2031                                                if (doWorkInThisThread || work[i].serviceImmediately())
2032                                                {
2033                                                        try
2034                                                        {
2035                                                                // this may cause other post commit work to be
2036                                                                // added.  when that transaction commits, those
2037                                                                // work will be transfered to the daemon
2038                                                                if (work[i].performWork(xc.getContextManager()) == Serviceable.DONE)
2039                                                                        work[i] = null;
2040 
2041                                                                // if REQUEUE, leave it on for the postcommit
2042                                                                // daemon to handle
2043                                                        }
2044                                                        catch (StandardException se)
2045                                                        {
2046                                                                // don't try to service this again
2047                                                                work[i] = null;
2048 
2049                                                                // try to handle it here.  If we fail, then let the error percolate.
2050                                                                xc.cleanupOnError(se);
2051                                                        }
2052                                                }
2053 
2054                                                // either it need not be serviedASAP or it needs
2055                                                // requeueing, send it off.   Note that this is one case
2056                                                // where a REQUEUE ends up in the high priority queue.
2057                                                // Unfortunately, there is no easy way to tell.  If the
2058                                                // Servicable is well mannered, it can change itself from
2059                                                // serviceASAP to not serviceASAP if it returns REQUEUE.
2060                                                if (work[i] != null)
2061                                                {
2062                                                        boolean needHelp = xactFactory.submitPostCommitWork(work[i]);
2063                                                        work[i] = null;
2064                                                        if (needHelp)
2065                                                                doWorkInThisThread = true;
2066                                                }
2067                                        }
2068                                }
2069                                finally
2070                                {
2071                                        inPostCommitProcessing = false;
2072 
2073                                        // if something untoward happends, clear the queue.
2074                                        if (postCommitWorks != null)
2075                                                postCommitWorks.clear();
2076                                }
2077 
2078                        }
2079                        else
2080                        {
2081                                // this is for non-user transaction or post commit work that is
2082                                // submitted in PostCommitProcessing.  (i.e., a post commit
2083                                // work submitting other post commit work)
2084                                for (int i = 0; i < pcsize; i++)
2085                                {
2086                                        // SanityManager.DEBUG_PRINT("PostTermination",postCommitWorks.elementAt((i)).toString());
2087                                        xactFactory.submitPostCommitWork((Serviceable)postCommitWorks.get((i)));
2088                                }
2089                        }
2090 
2091                        postCommitWorks.clear();
2092 
2093                }
2094 
2095        // any backup blocking operations (like unlogged ops) in this 
2096        // transaction are done with post commit/abort work that needs be
2097        // done in the same trasaction,  unblock the backup.
2098        unblockBackup();
2099        }
2100 
2101        /**
2102                Does a save point exist in the stack with the given name.
2103                Returns the position of the savepoint in the array
2104        */
2105        private int getSavePointPosition(
2106    String name, 
2107    Object kindOfSavepoint, 
2108    boolean forRollbackOrRelease) 
2109    {
2110                if ((savePoints == null) || (savePoints.empty()))
2111                        return -1;
2112 
2113        for (int i = savePoints.size() - 1; i >= 0; i--)
2114        {
2115            SavePoint savepoint = (SavePoint)savePoints.elementAt(i);
2116 
2117            if (savepoint.getName().equals(name))
2118            {
2119                if (forRollbackOrRelease && 
2120                    savepoint.getKindOfSavepoint() != null)
2121                {
2122                    if (savepoint.getKindOfSavepoint().equals(kindOfSavepoint))
2123                        return(i);
2124                }
2125                else  
2126                {
2127                    return(i);
2128                }
2129            }
2130        }   
2131                return -1;
2132        }
2133 
2134        /**
2135                Pop all savepoints upto the one with the given name and rollback
2136                all changes made since this savepoint was pushed.
2137                If release is true then this savepoint is popped as well,
2138                otherwise it is left in the stack (at the top).
2139 
2140                @return true if any work is rolled back, false if no work is rolled back
2141                @exception StandardException        Standard cloudscape policy
2142                @exception StandardException Thrown if a error of severity less than TransactionException#SEVERITY
2143                is encountered during the rollback of this savepoint.
2144        */
2145        protected boolean popSavePoints(int position, boolean release) throws StandardException {
2146 
2147                if (release) {
2148                        savePoints.setSize(position);
2149                        return false;
2150                }
2151 
2152                LogInstant rollbackTo = null;
2153 
2154                int size = savePoints.size();
2155                for (int i = position; i < size; i++) {
2156                        SavePoint rollbackSavePoint = (SavePoint) savePoints.elementAt(i);
2157 
2158                        LogInstant li = rollbackSavePoint.getSavePoint();
2159                        if (li != null) {
2160                                rollbackTo = li;
2161                                break;
2162                        }
2163                }
2164 
2165                savePoints.setSize(position + 1);
2166 
2167                if (rollbackTo == null)
2168                        return false;
2169 
2170                // now perform the rollback
2171                try {
2172 
2173                        logger.undo(this, getId(), rollbackTo, getLastLogInstant());
2174 
2175                } catch (StandardException se) {
2176 
2177                        // This catches any exceptions that have Transaction severity
2178                        // or less (e.g. Statement exception). If we received any lesser
2179                        // error then we abort the transaction anyway.
2180 
2181                        if (se.getSeverity() < ExceptionSeverity.TRANSACTION_SEVERITY)
2182            {
2183                                throw StandardException.newException(
2184                        SQLState.XACT_ROLLBACK_EXCEPTION, se);
2185            }
2186 
2187                        throw se;
2188                }
2189 
2190                return true;
2191        }
2192 
2193        /**
2194                @exception StandardException Cloudscape Standard error policy
2195         */
2196        public RawTransaction startNestedTopTransaction() throws StandardException {
2197 
2198                return xactFactory.startNestedTopTransaction(xc.getFactory(), xc.getContextManager());
2199        }
2200 
2201         /**
2202          * see if this transaction is a user transaction.
2203          *
2204          * @return true if this transaction is a user transaction
2205          */
2206         private boolean isUserTransaction()
2207         {
2208        String context_id = getContextId();
2209 
2210        return(
2211            (context_id == XactFactory.USER_CONTEXT_ID          ||
2212             context_id.equals(XactFactory.USER_CONTEXT_ID)));
2213         }
2214 
2215         /**
2216          * see if this transaction has ever done anything.
2217          *
2218          * MT - single thread through synchronizing this.  This method may be
2219          * called by other thread to test the state of this transaction.  That's
2220          * why we need to synchronize with all methods which enters or exits the
2221         * Idle state.
2222         *
2223         * Local method which read the state need not be synchronized because 
2224          * the other thread may look at the state but it may not change it.
2225          *
2226          * @return true if this transaction is not in idle or closed state
2227          */
2228         public final boolean isActive()
2229         {
2230                // synchronized(this) -- int access, implicit synchronization
2231                // due to atomic action
2232                int localState = state;
2233 
2234 
2235                 return (localState != CLOSED && localState != IDLE);
2236         }
2237 
2238         /**
2239          * see if this transaction is in PREPARED state.
2240          *
2241          * MT - single thread through synchronizing this.  This method may be
2242          * called by other thread to test the state of this transaction.
2243         *
2244          * @return true if this transaction is in PREPARED state.
2245          */
2246         public final boolean isPrepared()
2247         {
2248                // synchronized(this) -- int access, implicit synchronization
2249                // due to atomic action
2250                 return(state == PREPARED);
2251         }
2252 
2253        /**
2254                See if this transaction is in the idle state, called by other thread to
2255                test the state of this transaction.  That's why we need to synchronzied
2256                with all methods whcih enters or exits the idle state
2257 
2258                @return true if it is idle, otherwise false
2259        */
2260        public boolean isIdle()
2261        {
2262                // synchronized(this) -- int access, implicit synchronization
2263                // due to atomic action
2264                if (SanityManager.DEBUG)
2265                {
2266                        if (SanityManager.DEBUG_ON("XATrace"))
2267                                SanityManager.DEBUG("XATrace","RawTran, isIdle, state = " + state);
2268                }
2269 
2270                return (state == IDLE);
2271        }
2272 
2273        /**
2274                see if this transaction is in a pristine state.
2275 
2276                <BR>MT - called only by the same thread that owns the xact, no need to synchronize.
2277 
2278                @return true if it hasn't done any updates, otherwise false
2279        */
2280        public boolean isPristine()
2281        {
2282                return (state == IDLE  ||  state == ACTIVE);
2283        }
2284 
2285        public boolean inAbort() {
2286                return ABORT.equals(inComplete);
2287        }
2288 
2289        public FileResource getFileHandler() {
2290                return dataFactory.getFileHandler();
2291        }
2292 
2293 
2294        /**
2295         * put this into the beginXact log record to help recovery
2296         * if we needs to rolled back first, put that in
2297         */
2298        protected int statusForBeginXactLog()
2299        {
2300                return  recoveryRollbackFirst() ? RECOVERY_ROLLBACK_FIRST : 0;
2301        }
2302 
2303        /**
2304         * put this into the endXact log record to help recovery, 
2305         * nothing to add
2306         */
2307        protected int statusForEndXactLog()
2308        {
2309                // during recovery, the beginXact may be logged by a non-standard
2310                // transaction and hence the end xact it log
2311                // must also contain whatever a non-standard Transaction will output.  
2312                return savedEndStatus;
2313        }
2314 
2315        /**        
2316                Set the transaction to issue pre complete work at postComplete
2317                time, instead of preComplete time. This means that latches
2318                and containers will be held open until after a commit or an abort.
2319        */
2320        void setPostComplete() {
2321                postCompleteMode = true;
2322        }
2323 
2324 
2325    /*
2326     * Make the transaction block the online backup.
2327     *
2328     * @param wait if <tt>true</tt>, waits until the transaction
2329     *             can block the backup.
2330     * @return     <tt>true</tt> if the transaction  blocked the  
2331     *             backup.  <tt>false</tt> otherwise.
2332     * @exception StandardException if interrupted while waiting 
2333     *            for the backup in progress to complete.
2334     */
2335    public boolean blockBackup(boolean wait) 
2336        throws StandardException
2337    {
2338                if (!backupBlocked) {
2339                        backupBlocked = xactFactory.blockBackup(wait);
2340        }
2341 
2342                return backupBlocked;
2343        }
2344        
2345        /*
2346         * Unblock the backup, if it was blocked by some operation in 
2347         * this transaction. Unblocking is done at commit/abort of this 
2348         * transaction.
2349         */
2350        private void unblockBackup() {
2351                if (backupBlocked)
2352                        xactFactory.unblockBackup();        
2353                backupBlocked = false;
2354        }
2355 
2356 
2357    /**
2358     * Check if the transaction is blocking the backup ?
2359     * @return <tt> true </tt> if this transaction is 
2360     *         blocking the backup, otherwise <tt> false </tt>
2361     */
2362    public boolean isBlockingBackup() {
2363        return backupBlocked;
2364    }
2365 
2366        /*
2367        ** Lock escalation related
2368        */
2369 
2370        /*
2371        ** Methods of Limit
2372        */
2373 
2374        public void reached(Object compatabilitySpace, Object group, int limit,
2375                Enumeration lockList, int lockCount)
2376                throws StandardException {
2377 
2378                // Count row locks by table
2379                Dictionary containers = new java.util.Hashtable();
2380 
2381                for (; lockList.hasMoreElements(); ) {
2382 
2383                        Object plainLock = lockList.nextElement();
2384                        if (!(plainLock instanceof RecordHandle)) {
2385                                // only interested in rows locks
2386                                continue;
2387                        }
2388 
2389                        ContainerKey ckey = ((RecordHandle) plainLock).getContainerId();
2390                        
2391                        LockCount lc = (LockCount) containers.get(ckey);
2392                        if (lc == null) {
2393                                lc = new LockCount();
2394                                containers.put(ckey, lc);
2395                        }
2396                        lc.count++;
2397                }
2398 
2399                // Determine the threshold for lock escalation
2400                // based upon our own limit, not the current count
2401                int threshold = limit / (containers.size() + 1);
2402                if (threshold < (limit / 4))
2403                        threshold = limit / 4;
2404 
2405                // try to table lock all tables that are above
2406                // this threshold
2407 
2408                boolean didEscalate = false;
2409                for (Enumeration e = containers.keys(); e.hasMoreElements(); ) {
2410                        ContainerKey ckey = (ContainerKey) e.nextElement();
2411 
2412                        LockCount lc = (LockCount) containers.get(ckey);
2413 
2414                        if (lc.count < threshold) {
2415                                continue;
2416                        }
2417 
2418            try
2419            {
2420                if (openContainer(ckey,
2421                    new RowLocking3Escalate(getLockFactory()),
2422                    ContainerHandle.MODE_OPEN_FOR_LOCK_ONLY |
2423                    ContainerHandle.MODE_FORUPDATE |
2424                    ContainerHandle.MODE_LOCK_NOWAIT) != null) 
2425                {
2426 
2427                    didEscalate = true;
2428                }
2429            }
2430            catch (StandardException se)
2431            {
2432                if (!se.getMessageId().equals(SQLState.LOCK_TIMEOUT))
2433                {
2434                    // if it is a timeout then escalate did not happen and
2435                    // just fall through.
2436                    throw se;
2437                }
2438            }
2439                }
2440 
2441                // Now notify all open containers that an escalation
2442                // event happened. This will cause all open row locked
2443                // containers to re-get their container intent locks,
2444                // those that are now covered by a container lock due
2445                // to the above escalation will move into no locking
2446                // mode. The open containers that were not escalated
2447                // will simply bump the lock count in the lock manager
2448                // and will not have to wait for the lock they already have.
2449                //
2450                // It would be possible to pass in the notifyObservers
2451                // some indication of which tables were escalated
2452                // to reduce the extra lock call for the un-escalated
2453                // containers. This would involve passing the Hashtable
2454                // of escalated containers and having the update method
2455                // of BaseContainerHandle look for its ContainerKey within it.
2456                if (didEscalate) {
2457                        notifyObservers(LOCK_ESCALATE);
2458                        checkObserverException();
2459                }
2460        }
2461 
2462        /**
2463     * Convert a local transaction to a global transaction.
2464     * <p>
2465     * Must only be called a previous local transaction was created and exists
2466     * in the context.  Can only be called if the current transaction is in
2467     * the idle state, and no current global id.  
2468     * <p>
2469     * Simply call setTransactionId() which takes care of error checking.
2470     *
2471     * @param format_id the format id part of the Xid - ie. Xid.getFormatId().
2472     * @param global_id the global transaction identifier part of XID - ie.
2473     *                  Xid.getGlobalTransactionId().
2474     * @param branch_id The branch qualifier of the Xid - ie. 
2475     *                  Xid.getBranchQaulifier()
2476     *         
2477         * @exception StandardException Standard exception policy.
2478         **/
2479        public void createXATransactionFromLocalTransaction(
2480    int                     format_id,
2481    byte[]                  global_id,
2482    byte[]                  branch_id)
2483                throws StandardException
2484    {
2485        GlobalXactId gid = new GlobalXactId(format_id, global_id, branch_id);
2486 
2487        if (((TransactionTable) xactFactory.getTransactionTable()).
2488                findTransactionContextByGlobalId(gid) != null)
2489        {
2490            throw StandardException.newException(SQLState.STORE_XA_XAER_DUPID);
2491        }
2492 
2493        setTransactionId(gid, this.getId());
2494 
2495        if (SanityManager.DEBUG)
2496            SanityManager.ASSERT(myGlobalId != null);
2497    }
2498 
2499    /**
2500     * This method is called to commit the current XA global transaction.
2501     * <p>
2502     * RESOLVE - how do we map to the "right" XAExceptions.
2503     * <p>
2504     *
2505     * @param onePhase If true, the resource manager should use a one-phase
2506     *                 commit protocol to commit the work done on behalf of 
2507     *                 current xid.
2508     *
2509         * @exception  StandardException  Standard exception policy.
2510     **/
2511    public void xa_commit(
2512    boolean onePhase)
2513                throws StandardException
2514    {
2515        if (SanityManager.DEBUG)
2516            SanityManager.ASSERT(state != CLOSED);
2517 
2518        if (onePhase)
2519        {
2520            if (state == PREPARED)
2521            {
2522                throw StandardException.newException(
2523                        SQLState.XACT_PROTOCOL_VIOLATION);
2524            }
2525 
2526            prepareCommit(COMMIT_SYNC);
2527 
2528            completeCommit(COMMIT_SYNC);
2529        }
2530        else
2531        {
2532            if (state != PREPARED)
2533            {
2534                throw StandardException.newException(
2535                        SQLState.XACT_PROTOCOL_VIOLATION);
2536            }
2537 
2538            prepareCommit(COMMIT_SYNC);
2539 
2540            completeCommit(COMMIT_SYNC);
2541        }
2542 
2543 
2544        return;
2545    }
2546 
2547    /**
2548     * This method is called to ask the resource manager to prepare for
2549     * a transaction commit of the transaction specified in xid.
2550     * <p>
2551     *
2552     * @return         A value indicating the resource manager's vote on the
2553     *                 the outcome of the transaction.  The possible values
2554     *                 are:  XA_RDONLY or XA_OK.  If the resource manager wants
2555     *                 to roll back the transaction, it should do so by 
2556     *                 throwing an appropriate XAException in the prepare
2557     *                 method.
2558     *
2559         * @exception  StandardException  Standard exception policy.
2560     **/
2561    public int xa_prepare()
2562                throws StandardException
2563    {
2564        if (SanityManager.DEBUG)
2565        {
2566            if (state == CLOSED)
2567            {
2568                SanityManager.THROWASSERT(
2569                    "state = " + state + ";myGlobalId = " + myGlobalId); 
2570            }
2571 
2572                        if (SanityManager.DEBUG_ON("XATrace"))
2573                                SanityManager.DEBUG("XATrace","in xa_prepare, state is " + state);
2574                }
2575 
2576        if ((state == IDLE) || (state == ACTIVE))
2577        {
2578            abort();
2579            return(Transaction.XA_RDONLY);
2580        }
2581        else
2582        {
2583            prepareCommit(
2584                COMMIT_SYNC | COMMIT_PREPARE | Transaction.KEEP_LOCKS);
2585                        //we set the following variable during prepareCommit 
2586                        // to what we are doing, so we unset here.
2587                        inComplete = null;
2588 
2589            setPrepareState();
2590 
2591            return(Transaction.XA_OK);
2592        }
2593    }
2594 
2595    /**
2596     * rollback the current global transaction.
2597     * <p>
2598     * The given transaction is roll'ed back and it's history is not
2599     * maintained in the transaction table or long term log.
2600     * <p>
2601     *
2602         * @exception  StandardException  Standard exception policy.
2603     **/
2604    public void xa_rollback()
2605        throws StandardException
2606    {
2607        if (SanityManager.DEBUG)
2608            SanityManager.ASSERT(state != CLOSED);
2609 
2610        abort();
2611 
2612        return;
2613    }
2614 
2615    /**
2616     * Return the xid as a string.
2617     * <p>
2618     * The virtual lock table depends on this routine returning just the
2619     * local transaction id as a string, even if it is a global transaction.
2620     * Joins between the lock table and the transaction table will not work
2621     * if this routine returns anything other than myId.toString().
2622     * <p>
2623     *
2624         * @return The xid as a string.
2625     *
2626     **/
2627        public String toString()
2628        {
2629                // needed for virtual lock table
2630        try
2631        {
2632            return(myId.toString());
2633        }
2634        catch (Throwable t)
2635        {
2636            // using try/catch rather than if (myId != null) because on
2637            // multiple processor sometimes myId was going null after the
2638            // test but before the use.
2639            return("null");
2640        }
2641        }
2642 
2643        
2644        /* 
2645         * Get string id of the transaction that would be when the Transaction
2646         * is IN active state.
2647         *
2648         *This transaction "name" will be the same id which is returned in
2649         * the TransactionInfo information if Tx is already in Active State.
2650         * If the Transaction is in IDLE state, Transaction ID is 
2651         * incremented when getActiveStateTxIdString() on raw transaction is called,
2652         * instead of the Tx ID being incremented when Transaction gets into
2653         * active state. The reason for incrementing the Tx ID earlier than when Tx
2654         * is actually goes into active state is some debug statement cases like 
2655         * log statement text. SQL  statements are wriited  to log before they are
2656         * actully executed; In such cases we would like to display the actual TX ID on which 
2657         * locks are acquired when the statement is executed.
2658         * @return The a string which identifies the transaction.  
2659         */
2660        public String getActiveStateTxIdString()
2661        {
2662                if(!justCreated && state == IDLE)
2663                {
2664                        // TransactionTable needs this
2665                        xactFactory.setNewTransactionId(myId, this);
2666                        //mark as if this tx is just created , so that setActiveState()
2667                        //does not increment the transaction id number.
2668                        justCreated = true;
2669                }
2670                
2671                return toString();
2672        }
2673 
2674 
2675        /* package */
2676        String getState()
2677        {
2678                int localState ;
2679 
2680                // synchronized(this) -- int assignment, implicit synchronization
2681                // due to atomic action
2682                {
2683                        localState = state;
2684                }
2685 
2686                switch (localState)
2687                {
2688                case CLOSED:
2689                                        return "CLOSED";
2690                case IDLE:
2691                                        return "IDLE";
2692                case ACTIVE:
2693                case UPDATE:
2694                                        return "ACTIVE";
2695 
2696                case PREPARED:
2697                                        return "PREPARED";
2698                }
2699                return null;
2700        }
2701 
2702    public String getTransName()
2703    {
2704        return transName;
2705    }
2706 
2707    public void setTransName(String name)
2708    {
2709        transName = name;
2710    }
2711 
2712 
2713 
2714        /**        
2715                Is the transaction in rollforward recovery
2716        */
2717        public boolean inRollForwardRecovery()
2718        {
2719                return logFactory.inRFR();
2720        }
2721 
2722 
2723        /**        
2724                perform a  checkpoint during rollforward recovery
2725        */
2726        public void checkpointInRollForwardRecovery(LogInstant cinstant,
2727                                                                                                long redoLWM) 
2728                throws StandardException
2729        {
2730                logFactory.checkpointInRFR(cinstant, redoLWM, dataFactory);
2731        }
2732 
2733}
2734 
2735class LockCount {
2736        int count;
2737}
2738 
2739 

[all classes][org.apache.derby.impl.store.raw.xact]
EMMA 2.0.5312 (C) Vladimir Roubtsov