KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.xact.TransactionTable
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.context.ContextManager;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27 import org.apache.derby.iapi.services.io.Formatable;
28 import org.apache.derby.iapi.services.io.FormatIdUtil;
29 import org.apache.derby.iapi.services.io.StoredFormatIds;
30
31 import org.apache.derby.iapi.store.access.TransactionInfo;
32
33 import org.apache.derby.iapi.store.raw.GlobalTransactionId;
34
35 import org.apache.derby.iapi.store.raw.log.LogInstant;
36
37 import org.apache.derby.iapi.store.raw.xact.RawTransaction;
38 import org.apache.derby.iapi.store.raw.xact.TransactionId;
39
40 import org.apache.derby.iapi.error.StandardException;
41
42 import org.apache.derby.iapi.services.io.CompressedNumber;
43
44 import java.util.Hashtable JavaDoc;
45 import java.util.Enumeration JavaDoc;
46 import java.io.ObjectOutput JavaDoc;
47 import java.io.ObjectInput JavaDoc;
48 import java.io.IOException JavaDoc;
49
50 /**
51     The transaction table is used by the transaction factory to keep track of
52     all transactions that are in the system.
53
54     <BR> The transction table serves the following purposes: <OL>
55
56     <LI> checkpoint - when a checkpoint log record is written out, it writes
57     out also all transactions that have updated the database. RESOLVE: this is
58     actually not used right now - rather, the transaction table is
59     reconstructed during the redo phase by traversing from the undo LWM. It is
60     a goal to use this transaction table (and traversing from the redoLWM)
61     instead of rebuilding it to speed up recovery.
62
63     <LI> Quiesce State - when a system enters the quiesce state, it needs to account
64     for all transactions in the system, even those which are just started and
65     are in their IDLE state.
66
67     <LI> TransactionTable VTI - we need to get a snapshot of all transactions
68     in the system for diagnostic purposes.
69     </OL>
70
71     In order to speed up the time it takes to look up a transaction from the
72     transaction table, each transaction must have a unique transaction Id.
73     This means newly coined transaction must also have a transaction Id.
74
75     <P>During recovery, there is only one real xact object doing all the
76     recovery work, but there could be many outstanding transactions that are
77     gleamed from the log. Each of these "recovery transactions" have its on
78     entry into the transaction table but they all share the same Xact object.
79
80     <P>Multithreading considerations:<BR>
81     TransactionTable must be MT-safe it is called upon by many threads
82     simultaneously (except during recovery)
83
84     <P><B> This class depends on Hashtable synchronization!! </B>
85
86 */

87
88 public class TransactionTable implements Formatable
89 {
90     /*
91      * Fields
92      */

93
94     private Hashtable JavaDoc trans;
95
96     private TransactionId largestUpdateXactId;
97
98     /**
99         MT - not needed for constructor
100     */

101     public TransactionTable()
102     {
103         trans = new Hashtable JavaDoc(17);
104     }
105
106     /*************************************************************
107      * generic methods called by all clients of transaction table
108      * Must be MT -safe
109      ************************************************************/

110     private TransactionTableEntry findTransactionEntry(TransactionId id)
111     {
112
113         if (SanityManager.DEBUG)
114             SanityManager.ASSERT(
115                 id != null, "findTransacionEntry with null id");
116
117         // Hashtable is synchronized
118
return (TransactionTableEntry)trans.get(id);
119     }
120
121
122
123
124     void add(Xact xact, boolean exclude)
125     {
126         TransactionId id = xact.getId();
127
128         synchronized(this)
129         {
130             TransactionTableEntry ent = findTransactionEntry(id);
131
132             if (ent == null)
133             {
134                 ent = new TransactionTableEntry
135                     (xact, id, 0,
136                      exclude ? TransactionTableEntry.EXCLUDE : 0);
137
138                 trans.put(id, ent);
139
140                 if (SanityManager.DEBUG)
141                 {
142                     if (SanityManager.DEBUG_ON("TranTrace"))
143                     {
144                         SanityManager.DEBUG(
145                             "TranTrace", "adding transaction " + id);
146                         SanityManager.showTrace(new Throwable JavaDoc("TranTrace"));
147                     }
148                 }
149             }
150
151             if (SanityManager.DEBUG)
152             {
153                 if (exclude != ent.needExclusion())
154                     SanityManager.THROWASSERT(
155                       "adding the same transaction with different exclusion: " +
156                       exclude + " " + ent.needExclusion());
157             }
158         }
159
160         if (SanityManager.DEBUG) {
161
162             if (SanityManager.DEBUG_ON("memoryLeakTrace")) {
163
164                 if (trans.size() > 50)
165                     System.out.println("memoryLeakTrace:TransactionTable " + trans.size());
166             }
167         }
168     }
169
170     /*
171         remove the transaction Id an return false iff the transaction is found
172         in the table and it doesn't need exclusion during quiesce state
173      */

174     boolean remove(TransactionId id)
175     {
176         if (SanityManager.DEBUG)
177             SanityManager.ASSERT(
178                 id != null,
179                 "cannot remove transaction from table with null id");
180
181         if (SanityManager.DEBUG)
182         {
183             if (SanityManager.DEBUG_ON("TranTrace"))
184             {
185                 SanityManager.DEBUG(
186                     "TranTrace", "removing transaction " + id);
187                 SanityManager.showTrace(new Throwable JavaDoc("TranTrace"));
188             }
189         }
190
191         // Hashtable is synchronized
192
TransactionTableEntry ent = (TransactionTableEntry)trans.remove(id);
193          return (ent == null || ent.needExclusion());
194     }
195
196
197     /**
198         Change a transaction to update or add an update transaction to this table.
199
200         @param tid the transaction id
201         @param tran the transaction to be added
202         @param transactionStatus the transaction status that is stored in the
203                 BeginXact log record
204      */

205     public void addUpdateTransaction(TransactionId tid, RawTransaction tran,
206                                      int transactionStatus)
207     {
208
209         // we need to synchronize on the transaction table because we have to
210
// prevent this state change from happening when the transaction table
211
// itself is written out to the checkpoint. This is the only
212
// protection the TransactionTableEntry has to prevent fields in myxact
213
// from changing underneath it while it is being written out.
214
synchronized(this)
215         {
216             TransactionTableEntry ent = findTransactionEntry(tid);
217
218             if (ent != null)
219             {
220                 // this happens during run time, when a transaction that is
221
// already started changed status to an update transaction
222

223                 ent.updateTransactionStatus((Xact)tran, transactionStatus,
224                                             TransactionTableEntry.UPDATE) ;
225             }
226             else
227             {
228                 // this happens during recovery, that's why we haven't seen
229
// this transaction before - it is added in the doMe of the
230
// BeginXact log record.
231
//
232
// No matter what this transaction is, it won't need to be run
233
// in quiesce state because we are in recovery.
234
ent = new TransactionTableEntry((Xact)tran, tid, transactionStatus,
235                                                 TransactionTableEntry.UPDATE |
236                                                 TransactionTableEntry.EXCLUDE |
237                                                 TransactionTableEntry.RECOVERY);
238                 trans.put(tid, ent);
239
240             }
241
242             if (XactId.compare(ent.getXid(), largestUpdateXactId) > 0)
243                 largestUpdateXactId = ent.getXid();
244         }
245     }
246
247     /**
248         Change update transaction to non-update
249
250         <P>MT - MT safe, since vector is MT-safe.
251
252         @param id the transaction Id
253       */

254     void removeUpdateTransaction(TransactionId id)
255     {
256         // we need to synchronize on the transaction table because we have to
257
// prevent this state change from happening when the transaction table
258
// itself is written out to the checkpoint. This is the only
259
// protection the TransactionTableEntry has to prevent fields in myxact
260
// from changing underneath it while it is being written out.
261

262         synchronized (this)
263         {
264             TransactionTableEntry ent = findTransactionEntry(id);
265
266             if (SanityManager.DEBUG)
267             {
268                 SanityManager.ASSERT(ent != null,
269                  "removing update transaction that is not there");
270             }
271
272             ent.removeUpdateTransaction();
273
274             // If we are committing a recovery transaction, remove it from the
275
// transaction table. The xact object which is doing the work is
276
// not going to be closed even though the transaction is done.
277
if (ent.isRecovery())
278                 remove(id);
279         }
280
281         return;
282     }
283
284     /**************************************************************************
285      * Transaction table methods used by XA.
286      **************************************************************************
287      */

288
289     /**
290      * Return the hash table to the XA layer.
291      * <p>
292      * The XA code will do linear read-only operations on the hash table,
293      * write operations are only done in this module. It is a little ugly
294      * to export the hash table, but I wanted to move the XA specific code
295      * into the XA module, so that we could configure out the XA code if
296      * necessary.
297      * <p>
298      *
299      * Must be MT -safe, depends on sync hash table, and must get
300      * synchronized(hash_table) for linear searches.
301      *
302      * @return The ContextManager of the transaction being searched for.
303      *
304      **/

305     public Hashtable JavaDoc getTableForXA()
306     {
307         return(trans);
308     }
309
310     /**
311         Change transaction to prepared.
312
313         <P>MT - unsafe, caller is recovery, which is single threaded.
314
315         @param id the transaction Id
316       */

317     void prepareTransaction(TransactionId id)
318     {
319         // we need to synchronize on the transaction table because we have to
320
// prevent this state change from happening when the transaction table
321
// itself is written out to the checkpoint. This is the only
322
// protection the TransactionTableEntry has to prevent fields in myxact
323
// from changing underneath it while it is being written out.
324

325         TransactionTableEntry ent = findTransactionEntry(id);
326
327         if (SanityManager.DEBUG)
328         {
329             SanityManager.ASSERT(
330                 ent != null, "preparing transaction that is not there");
331         }
332
333         ent.prepareTransaction();
334
335         return;
336     }
337
338     /**
339      * Find a transaction in the table by Global transaction id.
340      * <p>
341      * This routine use to be only called during offline recovery so performance
342      * was not critical. Since that time more calls have been made, including
343      * one in startGlobalTransaction() so a linear search may no longer
344      * be appropriate. See DERBY-828.
345      *
346      * @return The ContextManager of the transaction being searched for.
347      *
348      * @param global_id The global transaction we are searching for.
349      **/

350     public ContextManager findTransactionContextByGlobalId(
351     GlobalXactId global_id)
352     {
353         ContextManager cm = null;
354
355         // Need to hold sync while linear searching the hash table.
356
synchronized (trans)
357         {
358             for (Enumeration JavaDoc e = trans.elements(); e.hasMoreElements();)
359             {
360                 TransactionTableEntry entry =
361                     (TransactionTableEntry) e.nextElement();
362
363                 if (entry != null)
364                 {
365                     GlobalTransactionId entry_gid = entry.getGid();
366
367                     if (entry_gid != null && entry_gid.equals(global_id))
368                     {
369                         cm = entry.getXact().getContextManager();
370                         break;
371                     }
372                 }
373             }
374         }
375               
376         return(cm);
377     }
378
379
380     /***********************************************************
381      * called when system is being quiesced, must be MT - safe
382      ***********************************************************/

383     /**
384         Return true if there is no transaction actively updating the database.
385         New transaction may be started or old transaction committed
386         right afterward, the caller of this routine must have other ways to
387         stop transactions from starting or ending.
388
389         <P>MT - safe
390     */

391     boolean hasActiveUpdateTransaction()
392     {
393         synchronized (this)
394         {
395             for (Enumeration JavaDoc e = trans.elements(); e.hasMoreElements(); )
396             {
397                 TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
398                 if (ent != null && ent.isUpdate())
399                     return true;
400             }
401         }
402         return false;
403     }
404
405
406
407     /************************************************************
408      * methods called only by checkpoint
409      ***********************************************************/

410     /*
411      * Formatable methods
412      */

413
414     /**
415         Return my format identifier.
416     */

417     public int getTypeFormatId() {
418         return StoredFormatIds.RAW_STORE_TRANSACTION_TABLE;
419     }
420
421     /**
422       @exception IOException problem reading the transaction table
423     */

424     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc
425     {
426         //don't let the transactions status change while writing out(beetle:5533)
427
//Note: syncing both on trans and this variable could be avoided if
428
//all the routines in this class are sycned on "this" and does not
429
//depend on hash table synchronization. But that will be overkill
430
//because this routine gets called only on checkpoints and others
431
//are used more often.
432

433         synchronized(this)
434         {
435             // don't touch the transaction table when I am being written out
436
synchronized(trans)
437             {
438                 int count = 0;
439                 int maxcount = trans.size();
440
441                 // first count up the number of active update transactions
442
for (Enumeration JavaDoc e = trans.elements();
443                      e.hasMoreElements(); )
444                 {
445                     TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
446                     if (ent != null && ent.isUpdate())
447                         count++;
448                 }
449
450                 CompressedNumber.writeInt(out, count);
451
452                 // now write them out
453
if (count > 0)
454                 {
455                     for (Enumeration JavaDoc e = trans.elements();
456                          e.hasMoreElements() ; )
457                     {
458                         TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
459                         if (ent != null && ent.isUpdate())
460                         {
461                             // only writes out update transaction
462
out.writeObject(ent);
463                         }
464                     }
465                 }
466             }
467         }
468     }
469
470     /************************************************************
471      * methods called only by recovery
472      ************************************************************/

473
474
475     /**
476       @exception IOException problem reading the transaction table
477       @exception ClassNotFoundException problem reading the transaction table
478      */

479     public void readExternal(ObjectInput JavaDoc in)
480          throws IOException JavaDoc, ClassNotFoundException JavaDoc
481     {
482         // RESOLVE: this is only read in checkpoint record, but we have not
483
// finish the work on using this transaction table to cut down on redo
484
// so this transaction table is effectively and futilely thrown away!
485

486         int count = CompressedNumber.readInt(in);
487         if (count == 0)
488             return;
489
490         for (int i = 0; i < count; i++)
491         {
492             TransactionTableEntry ent =
493                 (TransactionTableEntry)in.readObject();
494
495             if (SanityManager.DEBUG)
496                 SanityManager.ASSERT(
497                     ent.getXid() != null,
498                     "read in transaction table entry with null id");
499
500             trans.put(ent.getXid(), ent);
501
502             if (ent.isUpdate() &&
503                 XactId.compare(ent.getXid(), largestUpdateXactId) > 0)
504             {
505                 largestUpdateXactId = ent.getXid();
506             }
507         }
508
509
510     }
511
512     /**
513         Return the largest update transactionId I have seen so far.
514
515         <P>MT - unsafe, caller is recovery, which is single threaded.
516     */

517     public TransactionId largestUpdateXactId()
518     {
519         return largestUpdateXactId;
520     }
521
522
523     /**
524         Is there an active internal transaction in the transaction table.
525
526         <P>MT - unsafe, caller is recovery, which is single threaded.
527     */

528     public boolean hasRollbackFirstTransaction()
529     {
530         for (Enumeration JavaDoc e = trans.elements();
531              e.hasMoreElements() ; )
532         {
533             TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
534
535             if (ent != null && ent.isRecovery() &&
536                 (ent.getTransactionStatus() &
537                      Xact.RECOVERY_ROLLBACK_FIRST) != 0)
538             {
539                 return true;
540             }
541         }
542         return false;
543     }
544
545     /**
546        Is there a prepared transaction that are recovered
547        durring the recovery in the transaction table.
548
549        <P>MT - unsafe, caller is recovery, which is single threaded.
550     */

551     public boolean hasPreparedRecoveredXact()
552     {
553         return hasPreparedXact(true);
554     }
555
556
557     /**
558        Is there a prepared transaction in the transaction table.
559        <P>MT - unsafe, called during boot, which is single threaded.
560     */

561     public boolean hasPreparedXact()
562     {
563         return hasPreparedXact(false);
564     }
565
566     /**
567      * Is there a prepared transaction in the transaction table.
568      *
569      * <P>MT - unsafe, caller is recovery/at boot, which is single threaded.
570      *
571      * @param recovered <code> true </code> to search for transaction
572      * that are in prepared during recovery.
573      * recovered tranaction.
574      * <code> false > to search for just prepared
575      * transactons.
576      * @return <code> true if there is a prepared transaction and
577      * recovered when <code> recovered </code> argument is
578      * <code> true </code>
579      */

580
581     private boolean hasPreparedXact(boolean recovered)
582     {
583         for (Enumeration JavaDoc e = trans.elements(); e.hasMoreElements(); )
584         {
585             TransactionTableEntry ent = (TransactionTableEntry) e.nextElement();
586
587             if (ent != null &&
588                 (ent.getTransactionStatus() & Xact.END_PREPARED) != 0)
589             {
590                 if (recovered) {
591                     if(ent.isRecovery())
592                         return true;
593                 } else {
594                     return true;
595                 }
596             }
597         }
598         return false;
599     }
600
601
602
603
604     /**
605         Get the most recently added transaction that says it needs to be
606         rolled back first (an InternalXact) from the transaction table and make
607         the passed in transaction assume its identity.
608         <B> Should only be used in recovery undo !! </B>
609         RESOLVE: (sku)I don't think even these internal transactions need to be
610         rolled back in the reverse order, because they are physical in nature.
611         But it won't hurt.
612
613         <P>MT - unsafe, caller is recovery, which is single threaded.
614     */

615     public boolean getMostRecentRollbackFirstTransaction(RawTransaction tran)
616     {
617
618         if (trans.isEmpty())
619         {
620             // set tranaction to idle
621
return findAndAssumeTransaction((TransactionId)null, tran);
622         }
623
624         TransactionId id = null;
625         for (Enumeration JavaDoc e = trans.elements();
626              e.hasMoreElements() ; )
627         {
628             TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
629
630             if (ent != null && ent.isUpdate() && ent.isRecovery() &&
631                 (ent.getTransactionStatus() & Xact.RECOVERY_ROLLBACK_FIRST) != 0)
632             {
633                 // try to locate the most recent one
634
if (id == null || XactId.compare(id, ent.getXid()) < 0)
635                     id = ent.getXid();
636             }
637         }
638
639         if (id == null) // set transaction to idle
640
{
641             return findAndAssumeTransaction(id, tran);
642         }
643         else
644         {
645             // there is a rollback first transaction
646
boolean found =
647                 findAndAssumeTransaction(id, tran);
648
649             if (SanityManager.DEBUG)
650             {
651                 if (!found)
652                 {
653                     SanityManager.THROWASSERT(
654                         "cannot find transaction " + id + " in table");
655                 }
656             }
657
658             return true;
659         }
660     }
661
662     /**
663         Get the most recently non-prepared added transaction from the
664         transaction table and make the passed in transaction assume its
665         identity. Prepared transactions will not be undone.
666
667         RESOLVE: (sku) I don't think normal user transactions needs to be
668         rolled back in order, but it won't hurt.
669
670         <B> Should only be used in recovery undo !! </B>
671
672         <P>MT - unsafe, caller is recovery, which is single threaded.
673     */

674     public boolean getMostRecentTransactionForRollback(RawTransaction tran)
675     {
676         TransactionId id = null;
677
678         if (!trans.isEmpty())
679         {
680             for (Enumeration JavaDoc e = trans.elements();
681                  e.hasMoreElements() ; )
682             {
683                 TransactionTableEntry ent =
684                      (TransactionTableEntry)e.nextElement();
685
686                 if (ent != null &&
687                     ent.isUpdate() &&
688                     ent.isRecovery() &&
689                     !ent.isPrepared())
690                 {
691                     // try to locate the most recent one
692
if (id == null || XactId.compare(id, ent.getXid()) < 0)
693                         id = ent.getXid();
694                 }
695
696                 if (SanityManager.DEBUG)
697                 {
698                     if (ent != null &&
699                         ent.isUpdate() &&
700                         ent.isRecovery() &&
701                         (ent.getTransactionStatus() &
702                          Xact.RECOVERY_ROLLBACK_FIRST) != 0)
703                     {
704                         SanityManager.THROWASSERT(
705                             "still rollback first xacts in the tran table!");
706                     }
707                 }
708             }
709
710             if (SanityManager.DEBUG)
711             {
712                 // if all transactions are prepared then it is possible that
713
// no transaction will be found, in that case id will be null.
714
if (id != null)
715                 {
716                     SanityManager.ASSERT(findTransactionEntry(id) != null);
717                 }
718                 else
719                 {
720                     // all transactions in the table must be prepared.
721
for (Enumeration JavaDoc e = trans.elements(); e.hasMoreElements();)
722                     {
723                         TransactionTableEntry ent =
724                             (TransactionTableEntry)e.nextElement();
725                         SanityManager.ASSERT(ent.isPrepared());
726                     }
727                 }
728             }
729         }
730
731         return(findAndAssumeTransaction(id, tran));
732     }
733
734     /**
735         Get the most recently added transaction that says it is prepared during
736         recovery the transaction table and make the passed in transaction
737         assume its identity. This routine turns off the isRecovery() state
738         <B> Should only be used in recovery handle prepare after undo !! </B>
739
740         <P>MT - unsafe, caller is recovery, which is single threaded.
741     */

742
743     /**
744      * Get the most recent recovered prepared transaction.
745      * <p>
746      * Get the most recently added transaction that says it is prepared during
747      * recovery the transaction table and make the passed in transaction
748      * assume its identity.
749      * <p>
750      * This routine, unlike the redo and rollback getMostRecent*() routines
751      * expects a brand new transaction to be passed in. If a candidate
752      * transaction is found, then upon return the transaction table will
753      * be altered such that the old entry no longer exists, and a new entry
754      * will exist pointing to the transaction passed in. The new entry will
755      * look the same as if the prepared transaction had been created during
756      * runtime rather than recovery.
757      *
758      * <B> Should only be used in recovery handle prepare after undo !! </B>
759      *
760      * <P>MT - unsafe, caller is recovery, which is single threaded.
761      *
762      * @return true if a candidate transaction has been found. false if no
763      * prepared/recovery transactions found in the table.
764      *
765      * @param tran Newly allocated transaction to add to link to a entry.
766      *
767      **/

768     public boolean getMostRecentPreparedRecoveredXact(
769     RawTransaction tran)
770     {
771         TransactionTableEntry found_ent = null;
772
773         if (!trans.isEmpty())
774         {
775             TransactionId id = null;
776             GlobalTransactionId gid = null;
777             TransactionTableEntry ent;
778
779             for (Enumeration JavaDoc e = trans.elements(); e.hasMoreElements(); )
780             {
781                 ent = (TransactionTableEntry)e.nextElement();
782
783                 if (ent != null &&
784                     ent.isRecovery() &&
785                     ent.isPrepared())
786                 {
787                     // try to locate the most recent one
788
if (id == null || XactId.compare(id, ent.getXid()) < 0)
789                     {
790                         found_ent = ent;
791                         id = ent.getXid();
792                         gid = ent.getGid();
793                     }
794                 }
795             }
796
797             if (SanityManager.DEBUG)
798             {
799                 if (found_ent == null)
800                 {
801                     // if no entry's were found then the transaction table
802
// should have the passed in idle tran, and the rest should
803
// be non-recover, prepared global transactions.
804
for (Enumeration JavaDoc e = trans.elements(); e.hasMoreElements();)
805                     {
806                         ent = (TransactionTableEntry)e.nextElement();
807
808                         if (XactId.compare(ent.getXid(), tran.getId()) != 0)
809                         {
810                             SanityManager.ASSERT(
811                                 !ent.isRecovery() && ent.isPrepared());
812                             SanityManager.ASSERT(ent.getGid() != null);
813                         }
814                     }
815                 }
816             }
817
818             if (found_ent != null)
819             {
820                 // At this point there are 2 tt entries of interest:
821
// new_ent - the read only transaction entry that was
822
// created when we allocated a new transaction.
823
// We will just throw this one away after
824
// assuming the identity of the global xact.
825
// found_ent
826
// - the entry of the transaction that we are going
827
// to take over.
828
TransactionTableEntry new_ent =
829                     (TransactionTableEntry) trans.remove(tran.getId());
830
831                 // At this point only the found_ent should be in the table.
832
if (SanityManager.DEBUG)
833                 {
834                     SanityManager.ASSERT(findTransactionEntry(id) == found_ent);
835                 }
836
837                 ((Xact) tran).assumeGlobalXactIdentity(found_ent);
838
839                 // transform this recovery entry, into a runtime entry.
840
found_ent.unsetRecoveryStatus();
841             }
842         }
843
844         return(found_ent != null);
845     }
846
847     /**
848         Get the least recently added (oldest) transaction
849         @return the RawTransaction's first log instant
850
851         <P>MT - safe, caller can be recovery or checkpoint
852     */

853     public LogInstant getFirstLogInstant()
854     {
855         // assume for now that it is acceptable to return null if a transaction
856
// starts right in the middle of this call.
857

858         if (trans.isEmpty())
859         {
860             return null;
861         }
862         else
863         {
864             LogInstant logInstant = null;
865             
866             // bug 5632: need to sychronize so that another thread does not
867
// come in and disrupt the for loop, we got an exception on next,
868
// likely because hash table changed by another thread after
869
// hasMoreElements() called, but before nextElement().
870

871             synchronized (trans)
872             {
873                 for (Enumeration JavaDoc e = trans.elements(); e.hasMoreElements(); )
874                 {
875                     TransactionTableEntry ent =
876                         (TransactionTableEntry)e.nextElement();
877
878                     if (ent != null && ent.isUpdate())
879                     {
880                         if (logInstant == null ||
881                             ent.getFirstLog().lessThan(logInstant))
882                         {
883                             logInstant = ent.getFirstLog();
884                         }
885                     }
886                 }
887             }
888
889             return logInstant;
890         }
891     }
892
893     /**
894         Find a transaction using the transaction id, and make the passed in
895         transaction assume the identity and properties of that transaction.
896
897         <P>MT - unsafe, caller is recovery, which is single threaded.
898
899         @param id transaction Id
900         @param tran the transaction that was made to assume the transactionID
901         and all other relavent information stored in the transaction table
902         @return true if transaction can be found, false otherwise
903     */

904     boolean findAndAssumeTransaction(
905     TransactionId id,
906     RawTransaction tran)
907     {
908         // the only caller for this method right now is recovery.
909
// No need to put in any concurrency control
910
TransactionTableEntry ent = null;
911
912         if (id != null && !trans.isEmpty())
913         {
914             ent = findTransactionEntry(id);
915
916             if (SanityManager.DEBUG)
917             {
918                 if (ent != null)
919                     SanityManager.ASSERT(ent.isRecovery(),
920                     "assuming the id of a non-recovery transaction");
921             }
922         }
923
924         // if no transaction entry found, set transaction to idle
925
((Xact)tran).assumeIdentity(ent);
926
927         return(ent != null);
928
929     }
930
931     /**********************************************************
932      * Transaction table vti and diagnostics
933      * MT - unsafe, caller is getting a snap shot which may be inconsistent
934      *********************************************************/

935
936     /**
937         Get a printable version of the transaction table
938      */

939     public TransactionInfo[] getTransactionInfo()
940     {
941         if (trans.isEmpty())
942             return null;
943
944         // while taking a snap shot, no adding or removing of transaction
945
TransactionInfo[] tinfo;
946
947         if (SanityManager.DEBUG)
948             SanityManager.DEBUG("TranTrace", toString());
949
950         synchronized(this)
951         {
952             int ntran = trans.size();
953             tinfo = new TransactionTableEntry[ntran];
954
955             LogInstant logInstant = null;
956             int i = 0;
957
958             for (Enumeration JavaDoc e = trans.elements();
959                  e.hasMoreElements(); )
960             {
961                 TransactionTableEntry ent =
962                     (TransactionTableEntry)e.nextElement();
963
964                 if (ent != null)
965                     tinfo[i++] = (TransactionTableEntry)ent.clone();
966
967                 if (SanityManager.DEBUG)
968                     SanityManager.ASSERT(ent != null, "transaction table has null entry");
969             }
970         }
971
972         return tinfo;
973     }
974
975     public String JavaDoc toString()
976     {
977         if (SanityManager.DEBUG)
978         {
979             StringBuffer JavaDoc str = new StringBuffer JavaDoc(1000).
980                 append("\n**************************\n").
981                 append(super.toString()).
982                 append("\nTransaction Table: size = ").append(trans.size()).
983                 append(" largestUpdateXactId = ").append(largestUpdateXactId).
984                 append("\n");
985
986             boolean hasReadOnlyTransaction = false;
987
988             for (Enumeration JavaDoc e = trans.elements();
989                  e.hasMoreElements(); )
990             {
991                 TransactionTableEntry ent =
992                     (TransactionTableEntry)e.nextElement();
993
994                 if (ent != null && ent.isUpdate())
995                     str.append(ent.toString());
996
997                 if (ent != null && !ent.isUpdate())
998                     hasReadOnlyTransaction = true;
999             }
1000
1001            if (hasReadOnlyTransaction)
1002            {
1003                str.append("\n READ ONLY TRANSACTIONS \n");
1004
1005                for (Enumeration JavaDoc e = trans.elements();
1006                     e.hasMoreElements(); )
1007                {
1008                    TransactionTableEntry ent =
1009                        (TransactionTableEntry)e.nextElement();
1010
1011                    if (ent != null && !ent.isUpdate())
1012                        str.append(ent.toString());
1013                }
1014            }
1015            str.append("---------------------------");
1016            return str.toString();
1017        }
1018        else
1019            return null;
1020    }
1021
1022
1023}
1024
1025
Popular Tags