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 [TransactionTable.java]

nameclass, %method, %block, %line, %
TransactionTable.java100% (1/1)100% (23/23)87%  (895/1031)91%  (197.3/216)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TransactionTable100% (1/1)100% (23/23)87%  (895/1031)91%  (197.3/216)
TransactionTable (): void 100% (1/1)100% (9/9)100% (3/3)
add (Xact, boolean): void 100% (1/1)47%  (45/96)65%  (10.4/16)
addUpdateTransaction (TransactionId, RawTransaction, int): void 100% (1/1)91%  (48/53)94%  (9.4/10)
findAndAssumeTransaction (TransactionId, RawTransaction): boolean 100% (1/1)100% (28/28)100% (7/7)
findTransactionContextByGlobalId (GlobalXactId): ContextManager 100% (1/1)89%  (40/45)94%  (10.4/11)
findTransactionEntry (TransactionId): TransactionTableEntry 100% (1/1)92%  (12/13)96%  (1.9/2)
getFirstLogInstant (): LogInstant 100% (1/1)86%  (43/50)85%  (9.4/11)
getMostRecentPreparedRecoveredXact (RawTransaction): boolean 100% (1/1)97%  (113/116)99%  (22.8/23)
getMostRecentRollbackFirstTransaction (RawTransaction): boolean 100% (1/1)86%  (65/76)93%  (14/15)
getMostRecentTransactionForRollback (RawTransaction): boolean 100% (1/1)97%  (84/87)95%  (15.2/16)
getTableForXA (): Hashtable 100% (1/1)100% (3/3)100% (1/1)
getTransactionInfo (): TransactionInfo [] 100% (1/1)87%  (55/63)89%  (14.2/16)
getTypeFormatId (): int 100% (1/1)100% (2/2)100% (1/1)
hasActiveUpdateTransaction (): boolean 100% (1/1)83%  (29/35)88%  (6.2/7)
hasPreparedRecoveredXact (): boolean 100% (1/1)96%  (25/26)93%  (4.7/5)
hasRollbackFirstTransaction (): boolean 100% (1/1)100% (26/26)100% (6/6)
largestUpdateXactId (): TransactionId 100% (1/1)100% (3/3)100% (1/1)
prepareTransaction (TransactionId): void 100% (1/1)93%  (13/14)98%  (3.9/4)
readExternal (ObjectInput): void 100% (1/1)96%  (46/48)89%  (9/10)
remove (TransactionId): boolean 100% (1/1)60%  (24/40)65%  (3.9/6)
removeUpdateTransaction (TransactionId): void 100% (1/1)82%  (27/33)92%  (7.3/8)
toString (): String 100% (1/1)100% (89/89)100% (18/18)
writeExternal (ObjectOutput): void 100% (1/1)87%  (66/76)93%  (17.7/19)

1/*
2 
3   Derby - Class org.apache.derby.impl.store.raw.xact.TransactionTable
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.services.context.ContextManager;
24 
25import org.apache.derby.iapi.services.sanity.SanityManager;
26import org.apache.derby.iapi.services.io.Formatable;
27import org.apache.derby.iapi.services.io.FormatIdUtil;
28import org.apache.derby.iapi.services.io.StoredFormatIds;
29 
30import org.apache.derby.iapi.store.access.TransactionInfo;
31 
32import org.apache.derby.iapi.store.raw.GlobalTransactionId;
33 
34import org.apache.derby.iapi.store.raw.log.LogInstant;
35 
36import org.apache.derby.iapi.store.raw.xact.RawTransaction;
37import org.apache.derby.iapi.store.raw.xact.TransactionId;
38 
39import org.apache.derby.iapi.error.StandardException;
40 
41import org.apache.derby.iapi.services.io.CompressedNumber;
42 
43import java.util.Hashtable;
44import java.util.Enumeration;
45import java.io.ObjectOutput;
46import java.io.ObjectInput;
47import java.io.IOException;
48 
49/**
50        The transaction table is used by the transaction factory to keep track of
51        all transactions that are in the system.
52 
53        <BR> The transction table serves the following purposes: <OL> 
54 
55        <LI> checkpoint - when a checkpoint log record is written out, it writes
56        out also all transactions that have updated the database.  RESOLVE: this is
57        actually not used right now - rather, the transaction table is
58        reconstructed during the redo phase by traversing from the undo LWM.  It is
59        a goal to use this transaction table (and traversing from the redoLWM)
60        instead of rebuilding it to speed up recovery.
61 
62        <LI> Quiesce State - when a  system enters the quiesce state, it needs to account
63        for all transactions in the system, even those which are just started and
64        are in their IDLE state.
65 
66        <LI> TransactionTable VTI - we need to get a snapshot of all transactions
67        in the system for diagnostic purposes.
68        </OL>
69 
70        In order to speed up the time it takes to look up a transaction from the
71        transaction table, each transaction must have a unique transaction Id.
72        This means newly coined transaction must also have a transaction Id.
73 
74        <P>During recovery, there is only one real xact object doing all the
75        recovery work, but there could be many outstanding transactions that are
76        gleamed from the log.  Each of these "recovery transactions" have its on
77        entry into the transaction table but they all share the same Xact object.
78 
79        <P>Multithreading considerations:<BR>
80        TransactionTable must be MT-safe it is called upon by many threads
81        simultaneously (except during recovery)
82 
83        <P><B> This class depends on Hashtable synchronization!! </B>
84 
85*/
86 
87public class TransactionTable implements Formatable
88{
89        /*
90         * Fields
91         */
92 
93        private Hashtable trans;
94 
95        private TransactionId largestUpdateXactId;
96 
97        /**
98                MT - not needed for constructor
99        */
100        public TransactionTable()
101        {
102                trans = new Hashtable(17);
103        }
104 
105        /*************************************************************
106         * generic methods called by all clients of transaction table
107         * Must be MT -safe
108         ************************************************************/
109        private TransactionTableEntry findTransactionEntry(TransactionId id)
110        {
111 
112                if (SanityManager.DEBUG)
113                        SanityManager.ASSERT(
114                id != null, "findTransacionEntry with null id");
115 
116                // Hashtable is synchronized
117                return (TransactionTableEntry)trans.get(id);
118        }
119 
120 
121 
122 
123        void add(Xact xact, boolean exclude)
124        {
125                TransactionId id = xact.getId();
126 
127                synchronized(this)
128                {
129                        TransactionTableEntry ent = findTransactionEntry(id);
130 
131                        if (ent == null)
132                        {
133                                ent = new TransactionTableEntry
134                                        (xact, id, 0, 
135                                         exclude ? TransactionTableEntry.EXCLUDE : 0);
136 
137                                trans.put(id, ent);
138 
139                                if (SanityManager.DEBUG)
140                {
141                    if (SanityManager.DEBUG_ON("TranTrace"))
142                    {
143                        SanityManager.DEBUG(
144                            "TranTrace", "adding transaction " + id);
145                        SanityManager.showTrace(new Throwable("TranTrace"));
146                    }
147                }
148                        }
149 
150                        if (SanityManager.DEBUG)
151                        {
152                                if (exclude != ent.needExclusion())
153                                        SanityManager.THROWASSERT(
154                                          "adding the same transaction with different exclusion: " +
155                                          exclude + " " + ent.needExclusion());
156                        }
157                }
158 
159                if (SanityManager.DEBUG) {
160 
161                        if (SanityManager.DEBUG_ON("memoryLeakTrace")) {
162 
163                                if (trans.size() > 50)
164                                        System.out.println("memoryLeakTrace:TransactionTable " + trans.size());
165                        }
166                }
167        }
168 
169        /*
170                remove the transaction Id an return false iff the transaction is found
171                in the table and it doesn't need exclusion during quiesce state
172         */
173        boolean remove(TransactionId id)
174        {
175                if (SanityManager.DEBUG)
176                        SanityManager.ASSERT(
177                id != null, 
178                "cannot remove transaction from table with null id");
179 
180                if (SanityManager.DEBUG)
181        {
182            if (SanityManager.DEBUG_ON("TranTrace"))
183            {
184                SanityManager.DEBUG(
185                    "TranTrace", "removing transaction " + id);
186                SanityManager.showTrace(new Throwable("TranTrace"));
187            }
188        }
189 
190                // Hashtable is synchronized
191                 TransactionTableEntry ent = (TransactionTableEntry)trans.remove(id);
192                 return (ent == null || ent.needExclusion());
193        }
194 
195 
196        /**
197                Change a transaction to update or add an update transaction to this table.
198 
199                @param tid the transaction id
200                @param tran the transaction to be added
201                @param transactionStatus the transaction status that is stored in the
202                                BeginXact log record
203         */
204        public void addUpdateTransaction(TransactionId tid, RawTransaction tran,
205                                                                         int transactionStatus)
206        {
207 
208                // we need to synchronize on the transaction table because we have to
209                // prevent this state change from happening when the transaction table
210                // itself is written out to the checkpoint.  This is the only
211                // protection the TransactionTableEntry has to prevent fields in myxact
212                // from changing underneath it while it is being written out.
213                synchronized(this)
214                {
215                        TransactionTableEntry ent = findTransactionEntry(tid);
216 
217                        if (ent != null)
218                        {
219                                // this happens during run time, when a transaction that is
220                                // already started changed status to an update transaction
221 
222                                ent.updateTransactionStatus((Xact)tran, transactionStatus,
223                                                                                        TransactionTableEntry.UPDATE) ;
224                        }
225                        else
226                        {
227                                // this happens during recovery, that's why we haven't seen
228                                // this transaction before - it is added in the doMe of the 
229                                // BeginXact log record.
230                                //
231                                // No matter what this transaction is, it won't need to be run
232                                // in quiesce state because we are in recovery.
233                                ent = new TransactionTableEntry((Xact)tran, tid, transactionStatus, 
234                                                                                                TransactionTableEntry.UPDATE | 
235                                                                                                TransactionTableEntry.EXCLUDE |
236                                                                                                TransactionTableEntry.RECOVERY);
237                                trans.put(tid, ent);
238 
239                        }
240 
241                        if (XactId.compare(ent.getXid(), largestUpdateXactId) > 0)
242                                largestUpdateXactId = ent.getXid();
243                }
244        }
245 
246        /**
247            Change update transaction to non-update
248 
249                <P>MT - MT safe, since vector is MT-safe.
250 
251                @param id the transaction Id
252          */
253        void removeUpdateTransaction(TransactionId id)
254        {
255                // we need to synchronize on the transaction table because we have to
256                // prevent this state change from happening when the transaction table
257                // itself is written out to the checkpoint.  This is the only
258                // protection the TransactionTableEntry has to prevent fields in myxact
259                // from changing underneath it while it is being written out.
260 
261                synchronized (this)
262                {
263                        TransactionTableEntry ent = findTransactionEntry(id);
264 
265                        if (SanityManager.DEBUG)
266                        {
267                                SanityManager.ASSERT(ent != null, 
268                                 "removing update transaction that is not there");
269                        }
270 
271                        ent.removeUpdateTransaction();
272 
273                        // If we are committing a recovery transaction, remove it from the
274                        // transaction table.  The xact object which is doing the work is
275                        // not going to be closed even though the transaction is done.
276                        if (ent.isRecovery())
277                                remove(id);
278                }
279 
280                return;
281        }
282 
283    /**************************************************************************
284     * Transaction table methods used by XA.
285     **************************************************************************
286     */
287 
288    /**
289     * Return the hash table to the XA layer.
290     * <p>
291     * The XA code will do linear read-only operations on the hash table,
292     * write operations are only done in this module.  It is a little ugly
293     * to export the hash table, but I wanted to move the XA specific code
294     * into the XA module, so that we could configure out the XA code if
295     * necessary.
296     * <p>
297     *
298         * Must be MT -safe, depends on sync hash table, and must get 
299     *     synchronized(hash_table) for linear searches.
300     *
301         * @return The ContextManager of the transaction being searched for.
302     *
303     **/
304        public Hashtable getTableForXA()
305        {
306        return(trans);
307        }
308 
309        /**
310            Change transaction to prepared.
311 
312                <P>MT - unsafe, caller is recovery, which is single threaded.
313 
314                @param id the transaction Id
315          */
316        void prepareTransaction(TransactionId id)
317        {
318                // we need to synchronize on the transaction table because we have to
319                // prevent this state change from happening when the transaction table
320                // itself is written out to the checkpoint.  This is the only
321                // protection the TransactionTableEntry has to prevent fields in myxact
322                // from changing underneath it while it is being written out.
323 
324        TransactionTableEntry ent = findTransactionEntry(id);
325 
326        if (SanityManager.DEBUG)
327        {
328            SanityManager.ASSERT(
329                ent != null, "preparing transaction that is not there");
330        }
331 
332        ent.prepareTransaction();
333 
334                return;
335        }
336 
337    /**
338     * Find a transaction in the table by Global transaction id.
339     * <p>
340     * This routine use to be only called during offline recovery so performance
341     * was not critical.  Since that time more calls have been made, including
342     * one in startGlobalTransaction() so a linear search may no longer
343     * be appropriate.  See DERBY-828.
344     *
345         * @return The ContextManager of the transaction being searched for.
346     *
347     * @param global_id The global transaction we are searching for.
348     **/
349        public ContextManager findTransactionContextByGlobalId(
350    GlobalXactId global_id)
351        {
352        ContextManager cm              = null;
353 
354        // Need to hold sync while linear searching the hash table.
355        synchronized (trans)
356        {
357            for (Enumeration e = trans.elements(); e.hasMoreElements();) 
358            {
359                TransactionTableEntry entry = 
360                    (TransactionTableEntry) e.nextElement();
361 
362                if (entry != null)
363                {
364                    GlobalTransactionId entry_gid = entry.getGid();
365 
366                    if (entry_gid != null && entry_gid.equals(global_id))
367                    {
368                        cm = entry.getXact().getContextManager();
369                        break;
370                    }
371                }
372            }
373        }
374              
375                return(cm);
376        }
377 
378 
379        /***********************************************************
380         * called when system is being quiesced, must be MT - safe
381         ***********************************************************/
382        /**
383                Return true if there is no transaction actively updating the database.
384                New transaction may be started or old transaction committed
385                right afterward, the caller of this routine must have other ways to
386                stop transactions from starting or ending.
387 
388                <P>MT - safe
389        */
390        boolean hasActiveUpdateTransaction()
391        {
392                synchronized (this)
393                {
394                        for (Enumeration e = trans.elements(); e.hasMoreElements(); )
395                        {
396                                TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
397                                if (ent != null && ent.isUpdate())
398                                        return true;
399                        }
400                }
401                return false;
402        }
403 
404 
405 
406        /************************************************************
407         * methods called only by checkpoint
408         ***********************************************************/
409        /*
410         * Formatable methods
411         */
412 
413        /**
414                Return my format identifier.
415        */
416        public int getTypeFormatId() {
417                return StoredFormatIds.RAW_STORE_TRANSACTION_TABLE;
418        }
419 
420        /**
421          @exception IOException problem reading the transaction table
422        */
423        public void writeExternal(ObjectOutput out) throws IOException 
424        {
425                //don't let the transactions status change while writing out(beetle:5533)
426                //Note: syncing both on trans and this variable could be avoided if
427                //all the routines in this class are sycned on "this" and does not
428                //depend on hash table synchronization. But that will be overkill 
429                //because this routine gets called only on checkpoints and others
430                //are used more often.
431 
432                synchronized(this)
433                {        
434                        // don't touch the transaction table when I am being written out
435                        synchronized(trans)
436                        {
437                                int count = 0;
438                                int maxcount = trans.size();
439 
440                                // first count up the number of active update transactions 
441                                for (Enumeration e = trans.elements();
442                                         e.hasMoreElements(); )
443                                {
444                                        TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
445                                        if (ent != null && ent.isUpdate())
446                                                count++;
447                                }
448 
449                                CompressedNumber.writeInt(out, count);
450 
451                                // now write them out
452                                if (count > 0)
453                                {
454                                        for (Enumeration e = trans.elements();
455                                                 e.hasMoreElements() ; )
456                                        {
457                                                TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
458                                                if (ent != null && ent.isUpdate())
459                                                {
460                                                        // only writes out update transaction
461                                                        out.writeObject(ent);
462                                                }
463                                        }
464                                }
465                        }
466                }
467        }
468 
469        /************************************************************
470         * methods called only by recovery
471         ************************************************************/
472 
473 
474        /**
475          @exception IOException problem reading the transaction table
476          @exception ClassNotFoundException problem reading the transaction table
477         */
478        public void readExternal(ObjectInput in) 
479                 throws IOException, ClassNotFoundException
480        {
481                // RESOLVE: this is only read in checkpoint record, but we have not
482                // finish the work on using this transaction table to cut down on redo
483                // so this transaction table is effectively and futilely thrown away!
484 
485                int count = CompressedNumber.readInt(in);
486                if (count == 0)
487                        return;
488 
489                for (int i = 0; i < count; i++)
490                {
491                        TransactionTableEntry ent = 
492                                (TransactionTableEntry)in.readObject();
493 
494                        if (SanityManager.DEBUG)
495                                SanityManager.ASSERT(
496                    ent.getXid() != null,
497                    "read in transaction table entry with null id");
498 
499                        trans.put(ent.getXid(), ent);
500 
501                        if (ent.isUpdate() && 
502                XactId.compare(ent.getXid(), largestUpdateXactId) > 0)
503            {
504                                largestUpdateXactId = ent.getXid();
505            }
506                }
507 
508 
509        }
510 
511        /**
512                Return the largest update transactionId I have seen so far.
513 
514                <P>MT - unsafe, caller is recovery, which is single threaded.
515        */
516        public TransactionId largestUpdateXactId()
517        {
518                return largestUpdateXactId;
519        }
520 
521 
522        /**
523                Is there an active internal transaction in the transaction table.
524 
525                <P>MT - unsafe, caller is recovery, which is single threaded.
526        */
527        public boolean hasRollbackFirstTransaction()
528        {
529                for (Enumeration e = trans.elements();
530                         e.hasMoreElements() ; )
531                {
532                        TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
533 
534                        if (ent != null && ent.isRecovery() && 
535                                (ent.getTransactionStatus() & 
536                     Xact.RECOVERY_ROLLBACK_FIRST) != 0)
537            {
538                                return true;
539            }
540                }
541                return false;
542        }
543 
544        /**
545                Is there a prepared transaction in the transaction table.
546 
547                <P>MT - unsafe, caller is recovery, which is single threaded.
548        */
549        public boolean hasPreparedRecoveredXact()
550        {
551                for (Enumeration e = trans.elements(); e.hasMoreElements(); )
552                {
553                        TransactionTableEntry ent = (TransactionTableEntry) e.nextElement();
554 
555                        if (ent != null && ent.isRecovery() && 
556                                (ent.getTransactionStatus() & Xact.END_PREPARED) != 0)
557            {
558                                return true;
559            }
560                }
561                return false;
562        }
563 
564 
565        /**
566                Get the most recently added transaction that says it needs to be
567                rolled back first (an InternalXact) from the transaction table and make
568                the passed in transaction assume its identity. 
569                <B> Should only be used in recovery undo !! </B>
570                RESOLVE: (sku)I don't think even these internal transactions need to be
571                rolled back in the reverse order, because they are physical in nature.
572                But it won't hurt.
573 
574                <P>MT - unsafe, caller is recovery, which is single threaded.
575        */
576        public boolean getMostRecentRollbackFirstTransaction(RawTransaction tran)
577        {
578 
579                if (trans.isEmpty())
580                {
581                        // set tranaction to idle
582                        return findAndAssumeTransaction((TransactionId)null, tran);
583                }
584 
585                TransactionId id = null;
586                for (Enumeration e = trans.elements();
587                         e.hasMoreElements() ; )
588                {
589                        TransactionTableEntry ent = (TransactionTableEntry)e.nextElement();
590 
591                        if (ent != null && ent.isUpdate() && ent.isRecovery() &&
592                                (ent.getTransactionStatus() & Xact.RECOVERY_ROLLBACK_FIRST) != 0)
593                        {
594                                // try to locate the most recent one
595                                if (id == null || XactId.compare(id, ent.getXid()) < 0)
596                                        id = ent.getXid();
597                        }
598                }
599 
600                if (id == null)                        // set transaction to idle
601                {
602                        return findAndAssumeTransaction(id, tran);
603                }
604                else
605                {
606                        // there is a rollback first transaction
607                        boolean found = 
608                findAndAssumeTransaction(id, tran);
609 
610                        if (SanityManager.DEBUG)
611            {
612                if (!found)
613                {
614                    SanityManager.THROWASSERT(
615                        "cannot find transaction " + id + " in table");
616                }
617            }
618 
619                        return true;
620                }
621        }
622 
623        /**
624                Get the most recently non-prepared added transaction from the 
625        transaction table and make the passed in transaction assume its 
626        identity.  Prepared transactions will not be undone.
627 
628                RESOLVE: (sku) I don't think normal user transactions needs to be
629                rolled back in order, but it won't hurt.
630 
631                <B> Should only be used in recovery undo !! </B>
632 
633                <P>MT - unsafe, caller is recovery, which is single threaded.
634        */
635        public boolean getMostRecentTransactionForRollback(RawTransaction tran)
636        {
637        TransactionId id = null;
638 
639        if (!trans.isEmpty())
640                {
641                        for (Enumeration e = trans.elements();
642                                 e.hasMoreElements() ; )
643                        {
644                                TransactionTableEntry ent =
645                                         (TransactionTableEntry)e.nextElement();
646 
647                                if (ent != null         && 
648                    ent.isUpdate()      && 
649                    ent.isRecovery()    && 
650                    !ent.isPrepared())
651                                {
652                                        // try to locate the most recent one
653                                        if (id == null || XactId.compare(id, ent.getXid()) < 0)
654                                                id = ent.getXid();
655                                }
656 
657                                if (SanityManager.DEBUG)
658                                {
659                                        if (ent != null         && 
660                        ent.isUpdate()      && 
661                        ent.isRecovery()    &&
662                                                (ent.getTransactionStatus() & 
663                         Xact.RECOVERY_ROLLBACK_FIRST) != 0)
664                    {
665                                                SanityManager.THROWASSERT(
666                            "still rollback first xacts in the tran table!");
667                    }
668                                }
669                        }
670 
671                        if (SanityManager.DEBUG)
672            {
673                // if all transactions are prepared then it is possible that
674                // no transaction will be found, in that case id will be null.
675                if (id != null)
676                {
677                    SanityManager.ASSERT(findTransactionEntry(id) != null);
678                }
679                else
680                {
681                    // all transactions in the table must be prepared.
682                    for (Enumeration e = trans.elements(); e.hasMoreElements();)
683                    {
684                        TransactionTableEntry ent =
685                            (TransactionTableEntry)e.nextElement();
686                        SanityManager.ASSERT(ent.isPrepared());
687                    }
688                }
689            }
690                }
691 
692        return(findAndAssumeTransaction(id, tran));
693        }        
694 
695        /**
696                Get the most recently added transaction that says it is prepared during
697        recovery the transaction table and make the passed in transaction 
698        assume its identity. This routine turns off the isRecovery() state
699                <B> Should only be used in recovery handle prepare after undo !! </B>
700 
701                <P>MT - unsafe, caller is recovery, which is single threaded.
702        */
703 
704    /**
705     * Get the most recent recovered prepared transaction.
706     * <p>
707     * Get the most recently added transaction that says it is prepared during 
708     * recovery the transaction table and make the passed in transaction 
709     * assume its identity. 
710     * <p>
711     * This routine, unlike the redo and rollback getMostRecent*() routines
712     * expects a brand new transaction to be passed in.  If a candidate 
713     * transaction is found, then upon return the transaction table will 
714     * be altered such that the old entry no longer exists, and a new entry
715     * will exist pointing to the transaction passed in.  The new entry will
716     * look the same as if the prepared transaction had been created during
717     * runtime rather than recovery.
718     *
719     * <B> Should only be used in recovery handle prepare after undo !! </B>
720     *
721     * <P>MT - unsafe, caller is recovery, which is single threaded.
722     *
723         * @return true if a candidate transaction has been found.  false if no
724     *         prepared/recovery transactions found in the table.
725     *
726     * @param tran   Newly allocated transaction to add to link to a entry.
727     *
728     **/
729        public boolean getMostRecentPreparedRecoveredXact(
730    RawTransaction tran)
731        {
732        TransactionTableEntry   found_ent   = null;
733 
734        if (!trans.isEmpty())
735                {
736            TransactionId           id          = null;
737            GlobalTransactionId     gid         = null;
738            TransactionTableEntry   ent;
739 
740                        for (Enumeration e = trans.elements(); e.hasMoreElements(); )
741                        {
742                                ent = (TransactionTableEntry)e.nextElement();
743 
744                                if (ent != null         && 
745                    ent.isRecovery()    && 
746                    ent.isPrepared())
747                                {
748                                        // try to locate the most recent one
749                                        if (id == null || XactId.compare(id, ent.getXid()) < 0)
750                    {
751                        found_ent = ent;
752                                                id        = ent.getXid();
753                                                gid       = ent.getGid();
754                    }
755                                }
756                        }
757 
758            if (SanityManager.DEBUG)
759            {
760                if (found_ent == null)
761                {
762                    // if no entry's were found then the transaction table
763                    // should have the passed in idle tran, and the rest should
764                    // be non-recover, prepared global transactions.
765                    for (Enumeration e = trans.elements(); e.hasMoreElements();)
766                    {
767                        ent = (TransactionTableEntry)e.nextElement();
768 
769                        if (XactId.compare(ent.getXid(), tran.getId()) != 0)
770                        {
771                            SanityManager.ASSERT(
772                                !ent.isRecovery() && ent.isPrepared());
773                            SanityManager.ASSERT(ent.getGid() != null);
774                        }
775                    }
776                }
777            }
778 
779            if (found_ent != null)
780            {
781                // At this point there are 2 tt entries of interest:
782                //     new_ent - the read only transaction entry that was 
783                //               created when we allocated a new transaction.
784                //               We will just throw this one away after 
785                //               assuming the identity of the global xact.
786                //     found_ent
787                //             - the entry of the transaction that we are going
788                //               to take over.
789                TransactionTableEntry new_ent =
790                    (TransactionTableEntry) trans.remove(tran.getId());
791 
792                // At this point only the found_ent should be in the table.
793                if (SanityManager.DEBUG)
794                {
795                        SanityManager.ASSERT(findTransactionEntry(id) == found_ent);
796                }
797 
798                ((Xact) tran).assumeGlobalXactIdentity(found_ent);
799 
800                // transform this recovery entry, into a runtime entry.
801                found_ent.unsetRecoveryStatus();
802            }
803                }
804 
805        return(found_ent != null);
806        }
807 
808        /**
809                Get the least recently added (oldest) transaction
810                @return the RawTransaction's first log instant
811 
812                <P>MT - safe, caller can be recovery or checkpoint
813        */
814        public LogInstant getFirstLogInstant()
815        {
816                // assume for now that it is acceptable to return null if a transaction
817                // starts right in the middle of this call.
818 
819                if (trans.isEmpty())
820        {
821                        return null;
822        }
823                else
824                {
825                        LogInstant logInstant = null;
826            
827            // bug 5632: need to sychronize so that another thread does not 
828            // come in and disrupt the for loop, we got an exception on next,
829            // likely because hash table changed by another thread after
830            // hasMoreElements() called, but before nextElement().
831 
832            synchronized (trans)
833            {
834                for (Enumeration e = trans.elements(); e.hasMoreElements(); )
835                {
836                    TransactionTableEntry ent =
837                        (TransactionTableEntry)e.nextElement();
838 
839                    if (ent != null && ent.isUpdate())
840                    {
841                        if (logInstant == null || 
842                            ent.getFirstLog().lessThan(logInstant))
843                        {
844                            logInstant = ent.getFirstLog();
845                        }
846                    }
847                }
848            }
849 
850                        return logInstant;
851                }
852        }
853 
854        /**
855                Find a transaction using the transaction id, and make the passed in
856                transaction assume the identity and properties of that transaction.
857 
858                <P>MT - unsafe, caller is recovery, which is single threaded.
859 
860                @param id transaction Id
861                @param tran the transaction that was made to assume the transactionID
862                and all other relavent information stored in the transaction table
863                @return true if transaction can be found, false otherwise
864        */
865        boolean findAndAssumeTransaction(
866    TransactionId       id, 
867    RawTransaction      tran)
868        {
869                // the only caller for this method right now is recovery.  
870        // No need to put in any concurrency control
871                TransactionTableEntry ent = null;
872 
873                if (id != null && !trans.isEmpty())
874                {
875                        ent = findTransactionEntry(id);
876 
877                        if (SanityManager.DEBUG)
878                        {
879                                if (ent != null)
880                                        SanityManager.ASSERT(ent.isRecovery(),
881                                        "assuming the id of a non-recovery transaction");
882                        }
883                }
884 
885                // if no transaction entry found, set transaction to idle
886        ((Xact)tran).assumeIdentity(ent);
887 
888                return(ent != null);
889 
890        }
891 
892        /**********************************************************
893         * Transaction table vti and diagnostics
894         * MT - unsafe, caller is getting a snap shot which may be inconsistent 
895         *********************************************************/
896 
897        /**
898                Get a printable version of the transaction table
899         */
900        public TransactionInfo[] getTransactionInfo()
901        {
902                if (trans.isEmpty())
903                        return null;
904 
905                // while taking a snap shot, no adding or removing of transaction
906                TransactionInfo[] tinfo;
907 
908                if (SanityManager.DEBUG)
909                        SanityManager.DEBUG("TranTrace", toString());
910 
911                synchronized(this)
912                {
913                        int ntran = trans.size();
914                        tinfo = new TransactionTableEntry[ntran];
915 
916                        LogInstant logInstant = null;
917                        int i = 0;
918 
919                        for (Enumeration e = trans.elements();
920                                 e.hasMoreElements(); )
921                        {
922                                TransactionTableEntry ent =
923                                        (TransactionTableEntry)e.nextElement();
924 
925                                if (ent != null)
926                                        tinfo[i++] = (TransactionTableEntry)ent.clone();
927 
928                                if (SanityManager.DEBUG)
929                                        SanityManager.ASSERT(ent != null, "transaction table has null entry");
930                        }
931                }
932 
933                return tinfo;
934        }
935 
936        public String toString()
937        {
938                if (SanityManager.DEBUG)
939                {
940                        StringBuffer str = new StringBuffer(1000).
941                                append("\n**************************\n").
942                                append(super.toString()).
943                                append("\nTransaction Table: size = ").append(trans.size()).
944                                append(" largestUpdateXactId = ").append(largestUpdateXactId).
945                                append("\n");
946 
947                        boolean hasReadOnlyTransaction = false;
948 
949                        for (Enumeration e = trans.elements();
950                                 e.hasMoreElements(); )
951                        {
952                                TransactionTableEntry ent =
953                                        (TransactionTableEntry)e.nextElement(); 
954 
955                                if (ent != null && ent.isUpdate())
956                                        str.append(ent.toString());
957 
958                                if (ent != null && !ent.isUpdate())
959                                        hasReadOnlyTransaction = true;
960                        }
961 
962                        if (hasReadOnlyTransaction)
963                        {
964                                str.append("\n READ ONLY TRANSACTIONS \n");
965 
966                                for (Enumeration e = trans.elements();
967                                         e.hasMoreElements(); )
968                                {
969                                        TransactionTableEntry ent =
970                                                (TransactionTableEntry)e.nextElement(); 
971 
972                                        if (ent != null && !ent.isUpdate())
973                                                str.append(ent.toString());
974                                }
975                        }
976                        str.append("---------------------------");
977                        return str.toString();
978                }
979                else
980                        return null;
981        }
982 
983 
984}
985 

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