KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > raw > xact > TransactionTableEntry


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.xact.TransactionTableEntry
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.store.raw.xact;
23
24 import org.apache.derby.iapi.services.sanity.SanityManager;
25 import org.apache.derby.iapi.services.io.Formatable;
26 import org.apache.derby.iapi.services.io.FormatIdUtil;
27 import org.apache.derby.iapi.services.io.StoredFormatIds;
28
29 import org.apache.derby.iapi.error.StandardException;
30 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
31 import org.apache.derby.iapi.sql.conn.StatementContext;
32 import org.apache.derby.iapi.store.access.TransactionInfo;
33 import org.apache.derby.iapi.store.raw.GlobalTransactionId;
34 import org.apache.derby.iapi.store.raw.xact.TransactionId;
35 import org.apache.derby.iapi.store.raw.log.LogInstant;
36
37 import java.io.ObjectOutput JavaDoc;
38 import java.io.ObjectInput JavaDoc;
39 import java.io.IOException JavaDoc;
40
41 /**
42     Transaction table entry is used to store all relavent information of a
43     transaction into the transaction table for the use of checkpoint, recovery,
44     Transaction management during Quiesce state, and for dumping transaction table. Only works
45     with the following classes: TransactionTable, XactFactory, Xact
46     <BR>
47     During run time, whenever any transaction is started, it is put into the
48     transaction table. Whenever any transaction is closed, it is removed from
49     the transaction table.
50
51
52 */

53
54 public class TransactionTableEntry implements Formatable, TransactionInfo, Cloneable JavaDoc
55 {
56     // These fields are only populated if this TTE has been read in from the
57
// log. Otherwise, they are gotten from the transaction object myxact.
58
private TransactionId xid;
59     private GlobalTransactionId gid;
60     private LogInstant firstLog;
61     private LogInstant lastLog;
62
63     // this field is always present - it is 0 for read only transaction, this
64
// is a copy of the status from the Xact (the copy is necessary as during
65
// recovery the Xact is shared by all transaction table entries during
66
// redo and undo).
67
private int transactionStatus;
68
69     // fields useful for returning transaction information if read from
70
// transaction log during recovery
71
private transient Xact myxact;
72     private transient boolean update;
73     private transient boolean recovery; // is this a transaction read
74
// from the log during recovery?
75
private transient boolean needExclusion; // in a quiesce state , this
76
// transaction needs to be
77
// barred from activation
78
// during quiesce state
79

80     private boolean isClone; // am I a clone made for the
81
// TransactionVTI?
82

83     private transient LanguageConnectionContext lcc;
84
85
86     /* package */
87     // entry attribute
88
static final int UPDATE = 0x1;
89     static final int RECOVERY = 0x2;
90     static final int EXCLUDE = 0x4;
91
92     TransactionTableEntry(
93     Xact xact,
94     TransactionId tid,
95     int status,
96     int attribute)
97     {
98         myxact = xact;
99         xid = tid;
100         transactionStatus = status;
101
102         update = (attribute & UPDATE) != 0;
103         needExclusion = (attribute & EXCLUDE) != 0;
104         recovery = (attribute & RECOVERY) != 0;
105
106         if (SanityManager.DEBUG)
107         {
108             SanityManager.ASSERT(tid != null, "tid is null");
109             if (update && xact.getFirstLogInstant() == null)
110             {
111                 SanityManager.THROWASSERT(
112                     "update transaction has firstLog = null");
113             }
114
115
116             /*
117             if (!update && xact.getFirstLogInstant() != null)
118             {
119                 SanityManager.THROWASSERT(
120                     "read only transaction has firstLog = " +
121                     xact.getFirstLogInstant());
122             }
123             */

124         }
125
126         // Normally, we don't need to remember the gid, firstLog and lastLog
127
// because myxact will have the same information. However, in
128
// recovery, there is only one transaction taking on different identity
129
// as the log is replayed. Then each transaction table entry has keep
130
// its own identity and not rely on myxact. These recovery
131
// transactions are materialized in the transaction table via a
132
// readObject in the checkpoint log record, or are added by
133
// addUpdateTransaction when the log is scanned.
134
if (recovery)
135         {
136             // make a copy of everything
137
if (SanityManager.DEBUG)
138             {
139                 SanityManager.ASSERT(update, "recovery but not update");
140
141                 if (tid != xact.getId())
142                 {
143                     SanityManager.THROWASSERT(
144                         "adding a update transaction during recovery " +
145                         " but the tids doesn't match" +
146                         tid + " " + xact.getId());
147                 }
148             }
149
150             gid = xact.getGlobalId();
151             firstLog = xact.getFirstLogInstant();
152             lastLog = xact.getLastLogInstant();
153         }
154     }
155
156     /*
157      * Formatable methods
158      */

159     public TransactionTableEntry()
160     { }
161
162     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc
163     {
164         if (SanityManager.DEBUG)
165         {
166             SanityManager.ASSERT(!recovery, "writing out a recovery transaction");
167             SanityManager.ASSERT(update, "writing out read only transaction");
168             SanityManager.ASSERT(myxact.getFirstLogInstant() != null,
169                                  "myxact.getFirstLogInstant is null");
170             SanityManager.ASSERT(!isClone, "cannot write out a clone");
171         }
172
173         // Why is is safe to access first and last log instant in myxact while
174
// this is happening? Because we only writes out update transaction
175
// during run time. When a read only transactions becomes an update
176
// transaction , or when an update transaction commits, the beginXact
177
// and endXact log record's doMe method will try to change the
178
// transaction table entry's state to updat and non-update
179
// respectively. That change needs to go thru the transaction table
180
// which is mutually exclusive to writing out the transaction table.
181
// Since we are only looking at update transactions and it is "stuck"
182
// in update state in the middle of a TransactionTable.writeExternal
183
// call, all the fields we access in myxact is stable (actually the xid
184
// is also stable but we already have it).
185
//
186
out.writeObject(xid);
187         out.writeObject(myxact.getGlobalId());
188         out.writeObject(myxact.getFirstLogInstant());
189         out.writeObject(myxact.getLastLogInstant());
190         out.writeInt(transactionStatus);
191     }
192
193     public void readExternal(ObjectInput JavaDoc in)
194          throws ClassNotFoundException JavaDoc, IOException JavaDoc
195     {
196         // the only time a transaction table entry is written out is to the
197
// log, so this must be read in during recovery.
198
if (SanityManager.DEBUG)
199             SanityManager.ASSERT(!isClone, "cannot write out a clone");
200
201         xid = (TransactionId)in.readObject();
202         gid = (GlobalTransactionId)in.readObject();
203         firstLog = (LogInstant)in.readObject();
204         lastLog = (LogInstant)in.readObject();
205         transactionStatus = in.readInt();
206         update = true;
207         recovery = true;
208         needExclusion = true;
209
210         if (SanityManager.DEBUG)
211         {
212             SanityManager.ASSERT(xid != null, "read in transaction table entry with null id");
213             SanityManager.ASSERT(firstLog != null, "read in transaction table entry with firstLog");
214         }
215
216     }
217
218
219     // set my transaction instance variable for a recovery transaction
220
void setXact(Xact xact)
221     {
222         /*
223         RESOLVE (mikem) - prepared transactions now call setXact() when they are
224         not in recovery.
225         if (SanityManager.DEBUG)
226         {
227             SanityManager.ASSERT(recovery,
228                                  "setting non-recovery transaction table entry xact");
229             SanityManager.ASSERT(!isClone, "cannot setXact with a clone");
230         }
231         */

232         myxact = xact;
233
234     }
235
236     /**
237         Return my format identifier.
238     */

239     public int getTypeFormatId() {
240         return StoredFormatIds.RAW_STORE_TRANSACTION_TABLE_ENTRY;
241     }
242
243     public String JavaDoc toString()
244     {
245         if (SanityManager.DEBUG)
246         {
247             StringBuffer JavaDoc str = new StringBuffer JavaDoc(500).
248                 append("Xid=").append(getXid()).
249                 append(" gid=").append(getGid()).
250                 append(" firstLog=").append(getFirstLog()).
251                 append(" lastLog=").append(getLastLog()).
252                 append(" transactionStatus=").append(transactionStatus).
253                 append(" myxact=").append(myxact).
254                 append(" update=").append(update).
255                 append(" recovery=").append(recovery).
256                 append(" prepare=").append(isPrepared()).
257                 append(" needExclusion=").append(needExclusion).
258                 append("\n");
259             return str.toString();
260         }
261         else
262             return null;
263     }
264
265     void updateTransactionStatus(Xact xact, int status, int attribute)
266     {
267         if (SanityManager.DEBUG)
268         {
269             SanityManager.ASSERT(myxact == xact,
270                 "update transaction status for wrong xact");
271             SanityManager.ASSERT(!isClone, "cannot change a clone");
272         }
273
274         this.update = (attribute & UPDATE) != 0;
275     }
276
277     void removeUpdateTransaction()
278     {
279         if (SanityManager.DEBUG)
280             SanityManager.ASSERT(!isClone, "cannot change a clone");
281
282         this.update = false;
283         transactionStatus = 0;
284         
285     }
286
287     void unsetRecoveryStatus()
288     {
289         if (SanityManager.DEBUG)
290             SanityManager.ASSERT(!isClone, "cannot change a clone");
291
292         // RESOLVE (mikem) - this is kind of ugly. move to a better place?
293

294         firstLog = null;
295
296         this.recovery = false;
297     }
298
299     void prepareTransaction()
300     {
301         if (SanityManager.DEBUG)
302             SanityManager.ASSERT(!isClone, "cannot change a clone");
303
304         transactionStatus |= Xact.END_PREPARED;
305     }
306
307     /**************************************************************************
308      * get instance variables
309      **************************************************************************
310      */

311
312     TransactionId getXid()
313     {
314         if (SanityManager.DEBUG)
315         {
316             SanityManager.ASSERT(xid != null, "TTE with null xid");
317             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
318         }
319
320         return xid;
321     }
322
323     public final GlobalTransactionId getGid()
324     {
325         if (SanityManager.DEBUG)
326             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
327
328         if (gid != null)
329             return gid;
330
331         if (myxact != null)
332             return myxact.getGlobalId();
333
334         return null;
335     }
336
337     LogInstant getFirstLog()
338     {
339         if (SanityManager.DEBUG)
340         {
341             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
342
343             if (recovery)
344             {
345                 SanityManager.ASSERT(
346                     firstLog != null,
347                     "a recovery transaction with a null firstLog");
348             }
349             else
350             {
351                 SanityManager.ASSERT(
352                     firstLog == null,
353                     "a normal transaction with a non-null firstLog" +
354                     "myxact.getFirstLogInstant() = " + myxact.getFirstLogInstant());
355             }
356         }
357
358         if (firstLog != null)
359             return firstLog;
360
361         if (myxact != null)
362             return myxact.getFirstLogInstant();
363
364         return null;
365     }
366
367     LogInstant getLastLog()
368     {
369         if (SanityManager.DEBUG)
370             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
371
372         if (lastLog != null)
373             return lastLog;
374
375         if (myxact != null)
376             return myxact.getLastLogInstant();
377
378         return null;
379     }
380
381     public final Xact getXact()
382     {
383         if (SanityManager.DEBUG)
384             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
385
386         return myxact;
387     }
388
389     int getTransactionStatus()
390     {
391         if (SanityManager.DEBUG)
392             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
393
394         return transactionStatus;
395     }
396
397     boolean isUpdate()
398     {
399         if (SanityManager.DEBUG)
400             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
401
402         return update;
403     }
404
405     boolean isRecovery()
406     {
407         if (SanityManager.DEBUG)
408             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
409
410         return recovery;
411     }
412
413     boolean isPrepared()
414     {
415         if (SanityManager.DEBUG)
416             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
417
418         return((transactionStatus & Xact.END_PREPARED) != 0);
419     }
420
421
422
423
424     public boolean needExclusion()
425     {
426         if (SanityManager.DEBUG)
427             SanityManager.ASSERT(!isClone, "cannot call method with a clone");
428
429         return needExclusion;
430     }
431
432     /**
433         Methods of TransactionInfo
434      */

435     public String JavaDoc getTransactionIdString()
436     {
437         if (SanityManager.DEBUG)
438         {
439             SanityManager.ASSERT(
440                 !recovery, "trying to display recovery transaction");
441             SanityManager.ASSERT(myxact != null, "my xact is null");
442             SanityManager.ASSERT(isClone, "Should only call method on a clone");
443         }
444
445         TransactionId t = myxact.getIdNoCheck();
446         return (t == null) ? "CLOSED" : t.toString();
447     }
448
449     public String JavaDoc getGlobalTransactionIdString()
450     {
451         if (SanityManager.DEBUG)
452         {
453             SanityManager.ASSERT(
454                 !recovery, "trying to display recovery transaction");
455             SanityManager.ASSERT(myxact != null, "my xact is null");
456             SanityManager.ASSERT(isClone, "Should only call method on a clone");
457         }
458
459         GlobalTransactionId gid = myxact.getGlobalId();
460         return (gid == null) ? null : gid.toString();
461     }
462
463     public String JavaDoc getUsernameString()
464     {
465         if (SanityManager.DEBUG)
466             SanityManager.ASSERT(isClone, "Should only call method on a clone");
467
468         getlcc();
469         return (lcc == null) ? null : lcc.getAuthorizationId();
470     }
471
472     public String JavaDoc getTransactionTypeString()
473     {
474         if (SanityManager.DEBUG)
475             SanityManager.ASSERT(isClone, "Should only call method on a clone");
476
477         if (myxact == null)
478             return null;
479         else if (myxact.getTransName() != null)
480             return myxact.getTransName();
481         else
482             return myxact.getContextId();
483     }
484
485     public String JavaDoc getTransactionStatusString()
486     {
487         if (SanityManager.DEBUG)
488             SanityManager.ASSERT(isClone, "Should only call method on a clone");
489
490         return (myxact == null) ? null : myxact.getState();
491     }
492
493     public String JavaDoc getStatementTextString()
494     {
495         if (SanityManager.DEBUG)
496             SanityManager.ASSERT(isClone, "Should only call method on a clone");
497
498         getlcc();
499         if (lcc != null)
500         {
501             StatementContext sc = lcc.getStatementContext();
502             if (sc != null)
503                 return sc.getStatementText() ;
504         }
505         return null;
506
507     }
508
509     public String JavaDoc getFirstLogInstantString()
510     {
511         if (SanityManager.DEBUG)
512             SanityManager.ASSERT(isClone, "Should only call method on a clone");
513
514         LogInstant logInstant =
515             (myxact == null) ? null : myxact.getFirstLogInstant();
516
517         return (logInstant == null) ? null : logInstant.toString();
518
519     }
520
521     private void getlcc()
522     {
523         if (SanityManager.DEBUG)
524             SanityManager.ASSERT(isClone, "Should only call method on a clone");
525
526         if (lcc == null && myxact != null && myxact.xc != null)
527         {
528             XactContext xc = myxact.xc;
529
530             lcc = (LanguageConnectionContext)
531                 xc.getContextManager().getContext(
532                     LanguageConnectionContext.CONTEXT_ID);
533         }
534     }
535
536     /**
537         Cloneable
538      */

539     protected Object JavaDoc clone()
540     {
541         try
542         {
543             Object JavaDoc c = super.clone();
544             ((TransactionTableEntry)c).isClone = true;
545
546             return c;
547         }
548         catch (CloneNotSupportedException JavaDoc e)
549         {
550             // this should not happen, we are cloneable
551
if (SanityManager.DEBUG)
552             {
553                 SanityManager.THROWASSERT(
554                     "TransactionTableEntry cloneable but throws CloneNotSupportedException " + e);
555             }
556             return null;
557         }
558     }
559 }
560
Popular Tags