KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.xact.XactFactory
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.reference.Property;
25 import org.apache.derby.iapi.reference.SQLState;
26
27 import org.apache.derby.iapi.services.context.ContextService;
28 import org.apache.derby.iapi.services.context.ContextManager;
29 import org.apache.derby.iapi.services.daemon.DaemonService;
30 import org.apache.derby.iapi.services.daemon.Serviceable;
31 import org.apache.derby.iapi.services.locks.LockFactory;
32 import org.apache.derby.iapi.services.monitor.ModuleControl;
33 import org.apache.derby.iapi.services.monitor.ModuleSupportable;
34 import org.apache.derby.iapi.services.monitor.Monitor;
35 import org.apache.derby.iapi.services.sanity.SanityManager;
36 import org.apache.derby.iapi.services.io.Formatable;
37 import org.apache.derby.iapi.services.io.FormatIdUtil;
38 import org.apache.derby.iapi.services.uuid.UUIDFactory;
39 import org.apache.derby.catalog.UUID;
40
41 import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
42 import org.apache.derby.iapi.store.access.TransactionController;
43 import org.apache.derby.iapi.store.access.TransactionInfo;
44
45 import org.apache.derby.iapi.store.access.AccessFactory;
46
47 import org.apache.derby.iapi.store.access.xa.XAResourceManager;
48
49 import org.apache.derby.iapi.store.raw.LockingPolicy;
50 import org.apache.derby.iapi.store.raw.GlobalTransactionId;
51 import org.apache.derby.iapi.store.raw.RawStoreFactory;
52 import org.apache.derby.iapi.store.raw.Transaction;
53
54 import org.apache.derby.iapi.store.raw.data.DataFactory;
55
56 import org.apache.derby.iapi.store.raw.log.LogFactory;
57 import org.apache.derby.iapi.store.raw.log.LogInstant;
58
59 import org.apache.derby.iapi.store.raw.xact.TransactionFactory;
60 import org.apache.derby.iapi.store.raw.xact.RawTransaction;
61 import org.apache.derby.iapi.store.raw.xact.TransactionId;
62
63 import org.apache.derby.iapi.error.StandardException;
64
65 import org.apache.derby.impl.store.raw.xact.XactXAResourceManager;
66
67 import java.util.Enumeration JavaDoc;
68 import java.util.Properties JavaDoc;
69 import java.util.Hashtable JavaDoc;
70
71 public class XactFactory implements TransactionFactory, ModuleControl, ModuleSupportable
72 {
73     protected static final String JavaDoc USER_CONTEXT_ID = "UserTransaction";
74     protected static final String JavaDoc NESTED_READONLY_USER_CONTEXT_ID =
75         "NestedRawReadOnlyUserTransaction";
76     protected static final String JavaDoc NESTED_UPDATE_USER_CONTEXT_ID =
77         "NestedRawUpdateUserTransaction";
78     protected static final String JavaDoc INTERNAL_CONTEXT_ID = "InternalTransaction";
79     protected static final String JavaDoc NTT_CONTEXT_ID = "NestedTransaction";
80
81     /*
82     ** Fields
83     */

84
85     protected DaemonService rawStoreDaemon;
86
87     private UUIDFactory uuidFactory;
88     protected ContextService contextFactory;
89     protected LockFactory lockFactory;
90     protected LogFactory logFactory;
91     protected DataFactory dataFactory;
92     protected RawStoreFactory rawStoreFactory;
93
94     public TransactionTable ttab;
95     private long tranId;
96     private LockingPolicy[][] lockingPolicies = new LockingPolicy[3][6];
97
98     private boolean inCreateNoLog = false; // creating database, no logging
99

100     private XAResourceManager xa_resource;
101
102     private Object JavaDoc backupSemaphore = new Object JavaDoc();
103     private long backupBlockingOperations = 0;
104     private boolean inBackup = false;
105
106     /*
107     ** Constructor
108     */

109
110     public XactFactory() {
111         super();
112     }
113
114     /*
115     ** Methods of ModuleControl
116     */

117     public boolean canSupport(Properties JavaDoc startParams) {
118         return true;
119     }
120
121     public void boot(boolean create, Properties JavaDoc properties)
122         throws StandardException
123     {
124
125         uuidFactory = Monitor.getMonitor().getUUIDFactory();
126         
127         contextFactory = ContextService.getFactory();
128
129         lockFactory =
130             (LockFactory) Monitor.bootServiceModule(false, this,
131                 org.apache.derby.iapi.reference.Module.LockFactory, properties);
132
133         
134         // adding entries to locking policy table which means we support that
135
// level of concurrency.
136
lockingPolicies[LockingPolicy.MODE_NONE]
137                        [TransactionController.ISOLATION_NOLOCK] =
138                             new NoLocking();
139
140         lockingPolicies[LockingPolicy.MODE_RECORD]
141                        [TransactionController.ISOLATION_NOLOCK] =
142                             new NoLocking();
143         lockingPolicies[LockingPolicy.MODE_RECORD]
144                        [TransactionController.ISOLATION_READ_UNCOMMITTED] =
145                             new RowLocking1(lockFactory);
146         lockingPolicies[LockingPolicy.MODE_RECORD]
147                        [TransactionController.ISOLATION_READ_COMMITTED] =
148                             new RowLocking2(lockFactory);
149         lockingPolicies[LockingPolicy.MODE_RECORD]
150                        [TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] =
151                             new RowLocking2nohold(lockFactory);
152         lockingPolicies[LockingPolicy.MODE_RECORD]
153                        [TransactionController.ISOLATION_REPEATABLE_READ] =
154                             new RowLockingRR(lockFactory);
155         lockingPolicies[LockingPolicy.MODE_RECORD]
156                        [TransactionController.ISOLATION_SERIALIZABLE] =
157                             new RowLocking3(lockFactory);
158
159         lockingPolicies[LockingPolicy.MODE_CONTAINER]
160                        [TransactionController.ISOLATION_NOLOCK] =
161                             new NoLocking();
162
163         // note that current implementation of read uncommitted still gets
164
// container and container intent locks to prevent concurrent ddl. Thus
165
// the read uncommitted containerlocking implementation is the same as
166
// the read committed implementation. Future customer requests may
167
// force us to change this - we will then have to figure out how to
168
// handle a table being dropped while a read uncommitted scanner is
169
// reading it - currently we just block that from happening.
170
lockingPolicies[LockingPolicy.MODE_CONTAINER]
171                        [TransactionController.ISOLATION_READ_UNCOMMITTED] =
172                             new ContainerLocking2(lockFactory);
173         lockingPolicies[LockingPolicy.MODE_CONTAINER]
174                        [TransactionController.ISOLATION_READ_COMMITTED] =
175                             new ContainerLocking2(lockFactory);
176         lockingPolicies[LockingPolicy.MODE_CONTAINER]
177                        [TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] =
178                             new ContainerLocking2(lockFactory);
179         lockingPolicies[LockingPolicy.MODE_CONTAINER]
180                        [TransactionController.ISOLATION_REPEATABLE_READ] =
181                             new ContainerLocking3(lockFactory);
182         lockingPolicies[LockingPolicy.MODE_CONTAINER]
183                        [TransactionController.ISOLATION_SERIALIZABLE] =
184                             new ContainerLocking3(lockFactory);
185
186
187         if (create)
188         {
189             ttab = new TransactionTable();
190
191             String JavaDoc noLog =
192                 properties.getProperty(Property.CREATE_WITH_NO_LOG);
193
194             inCreateNoLog = (noLog != null && Boolean.valueOf(noLog).booleanValue());
195
196         }
197     }
198
199     public void stop() {
200
201         if (rawStoreDaemon != null)
202             rawStoreDaemon.stop();
203
204     }
205
206     /*
207     ** Methods of TransactionFactory
208     */

209
210     /**
211         Get the LockFactory to use with this store.
212     */

213     public LockFactory getLockFactory() {
214         return lockFactory;
215     }
216
217
218     /**
219         Database creation finished
220         @exception StandardException standard cloudscape error policy
221     */

222     public void createFinished() throws StandardException
223     {
224         if (!inCreateNoLog)
225         {
226             throw StandardException.newException(SQLState.XACT_CREATE_NO_LOG);
227         }
228
229         // make sure there is no active update transaction
230
if (ttab.hasActiveUpdateTransaction())
231         {
232             throw StandardException.newException(SQLState.XACT_CREATE_NO_LOG);
233         }
234
235         inCreateNoLog = false;
236     }
237
238     /**
239      * Common work done to create local or global transactions.
240      *
241      * @param rsf the raw store factory creating this xact.
242      * @param cm the current context manager to associate the xact with.
243      * @param compatibilitySpace
244      * if null, use the transaction being created, else if
245      * non-null use this compatibilitySpace.
246      *
247      * @exception StandardException Standard exception policy.
248      **/

249     private RawTransaction startCommonTransaction(
250     RawStoreFactory rsf,
251     ContextManager cm,
252     boolean readOnly,
253     Object JavaDoc compatibilitySpace,
254     String JavaDoc xact_context_id,
255     String JavaDoc transName,
256     boolean excludeMe)
257         throws StandardException
258     {
259
260         if (SanityManager.DEBUG)
261         {
262             if (rawStoreFactory != null)
263                 SanityManager.ASSERT(
264                     rawStoreFactory == rsf, "raw store factory different");
265
266                 SanityManager.ASSERT(
267                     cm == contextFactory.getCurrentContextManager());
268         }
269
270         Xact xact =
271             new Xact(this, logFactory, dataFactory, readOnly, compatibilitySpace);
272
273         xact.setTransName(transName);
274         pushTransactionContext(cm, xact_context_id, xact,
275                                false /* abortAll */,
276                                rsf,
277                                excludeMe /* excludeMe during quiesce state */);
278         return xact;
279     }
280
281     public RawTransaction startTransaction(
282     RawStoreFactory rsf,
283     ContextManager cm,
284     String JavaDoc transName)
285         throws StandardException
286     {
287         return(startCommonTransaction(
288                 rsf, cm, false, null, USER_CONTEXT_ID, transName, true));
289     }
290
291     public RawTransaction startNestedReadOnlyUserTransaction(
292     RawStoreFactory rsf,
293     Object JavaDoc compatibilitySpace,
294     ContextManager cm,
295     String JavaDoc transName)
296         throws StandardException
297     {
298         return(startCommonTransaction(
299             rsf, cm, true, compatibilitySpace,
300             NESTED_READONLY_USER_CONTEXT_ID, transName, false));
301     }
302
303     public RawTransaction startNestedUpdateUserTransaction(
304     RawStoreFactory rsf,
305     ContextManager cm,
306     String JavaDoc transName)
307         throws StandardException
308     {
309         return(startCommonTransaction(
310             rsf, cm, false, null,
311             NESTED_UPDATE_USER_CONTEXT_ID, transName, true));
312     }
313
314     public RawTransaction startGlobalTransaction(
315     RawStoreFactory rsf,
316     ContextManager cm,
317     int format_id,
318     byte[] global_id,
319     byte[] branch_id)
320         throws StandardException
321     {
322         GlobalXactId gid = new GlobalXactId(format_id, global_id, branch_id);
323
324         if (ttab.findTransactionContextByGlobalId(gid) != null)
325         {
326             throw StandardException.newException(SQLState.STORE_XA_XAER_DUPID);
327         }
328
329         RawTransaction xact =
330             startCommonTransaction(
331                 rsf, cm, false, null,
332                 USER_CONTEXT_ID, AccessFactoryGlobals.USER_TRANS_NAME, true);
333
334         xact.setTransactionId(gid, xact.getId());
335
336         return(xact);
337     }
338
339
340
341     public RawTransaction findUserTransaction(
342     RawStoreFactory rsf,
343     ContextManager contextMgr,
344     String JavaDoc transName)
345          throws StandardException
346     {
347         if (SanityManager.DEBUG)
348         {
349             SanityManager.ASSERT(
350                 contextMgr == contextFactory.getCurrentContextManager(),
351                 "passed in context mgr not the same as current context mgr");
352
353             if (rawStoreFactory != null)
354                 SanityManager.ASSERT(
355                     rawStoreFactory == rsf, "raw store factory different");
356         }
357
358         XactContext xc = (XactContext)contextMgr.getContext(USER_CONTEXT_ID);
359         if (xc == null)
360             return startTransaction(rsf, contextMgr, transName);
361         else
362             return xc.getTransaction();
363     }
364
365
366     public RawTransaction startNestedTopTransaction(RawStoreFactory rsf, ContextManager cm)
367         throws StandardException
368     {
369
370         if (SanityManager.DEBUG)
371         {
372             if (rawStoreFactory != null)
373                 SanityManager.ASSERT(
374                     rawStoreFactory == rsf, "raw store factory different");
375         }
376
377         Xact xact =
378             new Xact(this, logFactory, dataFactory, false, null);
379
380         // hold latches etc. past commit in NTT
381
xact.setPostComplete();
382         pushTransactionContext(cm, NTT_CONTEXT_ID, xact,
383                                true /* abortAll */,
384                                rsf,
385                                true /* excludeMe during quiesce state*/);
386         return xact;
387     }
388
389     public RawTransaction startInternalTransaction(RawStoreFactory rsf, ContextManager cm)
390         throws StandardException
391     {
392         if (SanityManager.DEBUG)
393         {
394             if (rawStoreFactory != null)
395                 SanityManager.ASSERT(
396                     rawStoreFactory == rsf, "raw store factory different");
397         }
398
399
400         Xact xact = new InternalXact(this, logFactory, dataFactory);
401         pushTransactionContext(cm, INTERNAL_CONTEXT_ID, xact,
402                                true /* abortAll*/,
403                                rsf,
404                                true /* excludeMe during quiesce state */);
405         return xact;
406     }
407
408     /*
409      * the following TransactionFactory methods are to support recovery and
410      * should only be used by recovery!
411      */

412
413     /**
414         Find the TransactionTableEntry with the given ID and make the passed in
415         transaction assume the identity and properties of that
416         TransactionTableEntry.
417         Used in recovery only.
418     */

419     public boolean findTransaction(TransactionId id, RawTransaction tran)
420     {
421         return ttab.findAndAssumeTransaction(id, tran);
422     }
423
424
425     /**
426         Rollback all active transactions that has updated the raw store.
427         Use the recovery Transaction that is passed in to do all the work.
428         Used in recovery only.
429
430         <P>
431         Transactions are rolled back in the following order:
432         <OL>
433         <LI>internal transactions in reversed beginXact chronological order,
434         <LI>all other transactions in reversed beginXact chronological order,
435         </NL>
436
437         @param recoveryTransaction use this transaction to do all the user
438                                    transaction work
439
440         @exception StandardException any exception thrown during rollback
441     */

442     public void rollbackAllTransactions(
443     RawTransaction recoveryTransaction,
444     RawStoreFactory rsf)
445         throws StandardException
446     {
447         if (SanityManager.DEBUG)
448         {
449             if (rawStoreFactory != null)
450                 SanityManager.ASSERT(
451                     rawStoreFactory == rsf, "raw store factory different");
452
453             SanityManager.ASSERT(
454                 recoveryTransaction != null, "recovery transaction null");
455         }
456
457         int irbcount = 0;
458
459         // First undo internal transactions if there is any
460
if (ttab.hasRollbackFirstTransaction())
461         {
462             RawTransaction internalTransaction = startInternalTransaction(rsf,
463                 recoveryTransaction.getContextManager());
464
465             // make this transaction be aware that it is being used by recovery
466
internalTransaction.recoveryTransaction();
467
468             if (SanityManager.DEBUG)
469                 SanityManager.ASSERT(
470                     internalTransaction.handlesPostTerminationWork() == false,
471                     "internal recovery xact handles post termination work");
472
473             while(ttab.getMostRecentRollbackFirstTransaction(
474                                                 internalTransaction))
475             {
476                 irbcount++;
477                 internalTransaction.abort();
478             }
479
480             internalTransaction.close();
481         }
482
483         if (SanityManager.DEBUG)
484         {
485             SanityManager.ASSERT(
486                 ttab.hasRollbackFirstTransaction() == false,
487                 "cant rollback user xacts with existing active internal xacts");
488         }
489
490         int rbcount = 0;
491
492         // recoveryTransacion assumes the identity of the most recent xact
493
while(ttab.getMostRecentTransactionForRollback(recoveryTransaction))
494         {
495             if (SanityManager.DEBUG)
496             {
497                 SanityManager.ASSERT(
498                     recoveryTransaction.handlesPostTerminationWork() == false,
499                     "recovery transaction handles post termination work");
500             }
501
502             rbcount++;
503             recoveryTransaction.abort();
504         }
505
506         if (SanityManager.DEBUG)
507         {
508             if (rbcount > 0 || irbcount > 0)
509             {
510                 // RESOLVE: put this in the log trace
511
// System.out.println(
512
// "Recovery rolled back " + irbcount +
513
// " internal transactions,"
514
// + rbcount + " user transactions");
515
}
516         }
517
518     }
519
520
521     /**
522         Run through all prepared transactions known to this factory
523         and restore their state such that they remain after recovery, and
524         can be found and handled by a XA transaction manager. This includes
525         creating a context manager for each, pushing a xact context, and
526         reclaiming update locks on all data changed by the transaction.
527
528         Expected to be called just after the redo and undo recovery loops,
529         where the transaction table should be empty except for prepared
530         xacts.
531
532         Used only in recovery.
533
534         @exception StandardException Cloudscape Standard Error policy
535     */

536     public void handlePreparedXacts(
537     RawStoreFactory rsf)
538         throws StandardException
539     {
540         if (SanityManager.DEBUG)
541         {
542
543             if (rawStoreFactory != null)
544                 SanityManager.ASSERT(
545                     rawStoreFactory == rsf, "raw store factory different");
546         }
547
548         int prepared_count = 0;
549
550         if (ttab.hasPreparedRecoveredXact())
551         {
552             // if there any prepared xacts
553

554             // At this point recovery has used one context and one transaction
555
// to deal with all transactions. Prepared transactions are to
556
// be left in the transaction table, but the must have real and
557
// separate CM's and transactions associated with them.
558

559             // save old context. Errors may go to funky contexts (the new
560
// context we created to bring the prepared transaction into the
561
// real world after recovery) after we switch contexts, but any
562
// error we get at this point is going to shut down the db.
563

564             while (true)
565             {
566                 // allocate new context and associate new xact with it.
567
ContextManager cm = contextFactory.newContextManager();
568                 contextFactory.setCurrentContextManager(cm);
569
570                 try {
571                 RawTransaction rawtran =
572                     startTransaction(
573                         rawStoreFactory, cm,
574                         AccessFactoryGlobals.USER_TRANS_NAME);
575
576                 if (ttab.getMostRecentPreparedRecoveredXact(rawtran))
577                 {
578                     // found a prepared xact. The reprepare() call will
579
// accumulate locks, and change the transaction table entry
580
// to not be "in-recovery" so that it won't show up again.
581
rawtran.reprepare();
582
583                     if (SanityManager.DEBUG)
584                         prepared_count++;
585                 }
586                 else
587                 {
588                     // get rid of last transaction allocated.
589
rawtran.destroy();
590                     break;
591                 }
592                 }
593                 finally
594                 {
595                      contextFactory.resetCurrentContextManager(cm);
596                 }
597             }
598
599         }
600
601         if (SanityManager.DEBUG)
602         {
603             // RESOLVE - need to only do this under a debug flag.
604
// SanityManager.DEBUG_PRINT("",
605
// "Recovery re-prepared " + prepared_count + " xa transactions.");
606
}
607     }
608
609
610     /**
611         Get the earliest log instant that is still active, ie, the first log
612         record logged by the earliest transaction that is still active.
613         <BR>
614         The logging system must guarentee that the transaction table is
615         populated in the order transactions are started.
616         Used in recovery only.
617     */

618
619     public LogInstant firstUpdateInstant()
620     {
621         return ttab.getFirstLogInstant();
622     }
623
624     /*
625     ** Methods of Corruptable
626     */

627
628     /**
629         Really this is just a convience routine for callers that might not
630         have access to a log factory.
631     */

632     public StandardException markCorrupt(StandardException originalError) {
633         logFactory.markCorrupt(originalError);
634         return originalError;
635     }
636
637     /*
638     ** Implementation specific methods.
639     */

640
641     public void setNewTransactionId(TransactionId oldxid, Xact t)
642     {
643         XactId xid;
644         boolean excludeMe = true; // by default
645

646         if (oldxid != null)
647             excludeMe = remove(oldxid);
648
649         synchronized(this)
650         {
651             xid = new XactId(tranId++);
652         }
653
654         t.setTransactionId(t.getGlobalId(), xid);
655
656         // RESOLVE: How does a real global xact id get set?
657

658         // If we got rid of the oldxid, that means this transaction object has
659
// merely committed and starting the next transaction with the same
660
// xact object. In that case, the transaction context will remain the
661
// same and won't be pushed. We need to add this transaction with the
662
// new id back into the transaction table. If we did not get rid of
663
// the old oldxid, that means this is a brand new transaction being
664
// created. The pushTransactionContext call will add it to the
665
// transaction table with the appropriate flags
666
if (oldxid != null)
667             add(t, excludeMe);
668     }
669
670     /*
671     ** Set the shortTranId, this is called by the log factory after recovery
672     */

673     public void resetTranId()
674     {
675         XactId xid = (XactId)ttab.largestUpdateXactId();
676         if (xid != null)
677             tranId = xid.getId() + 1;
678         else
679             tranId = 1;
680     }
681
682
683     /**
684         Create a new RawTransaction, a context for it and push the context
685         onto the current context manager. Then add the transacion to the
686         transaction table.
687
688         @param contextName the name of the transaction context
689         @param xact the Transaction object
690         @param abortAll if true, then any error will abort the whole
691         transaction. Otherwise, let XactContext.cleanupOnError decide what to
692         do
693         @param rsf the raw store factory
694         @param excludeMe during systeme quiesce, i.e., this transaction should
695         not be allowed to be active during a quiesce state.
696
697
698         @exception StandardException Standard Cloudscape error policy
699
700     */

701     protected void pushTransactionContext(ContextManager cm, String JavaDoc contextName,
702                                           Xact xact,
703                                           boolean abortAll,
704                                           RawStoreFactory rsf,
705                                           boolean excludeMe)
706          throws StandardException
707     {
708         if (cm.getContext(contextName) != null)
709         {
710             throw StandardException.newException(
711                     SQLState.XACT_TRANSACTION_ACTIVE);
712         }
713         
714         XactContext xc = new XactContext(cm, contextName, xact, abortAll, rsf);
715
716         // this transaction is now added to the transaction table.
717
// This will cause an idle transaction to take on an identity, which is
718
// unfortunate. The reason why we have to add the transaction to the
719
// table right now is because the transaction table is used to bring
720
// system to quisce state to regulate who can go active during quiesce
721
// state, and if we add the transaction
722
// when it goes active, then there is a window where this transaction
723
// can sneak in. The transaction table itself does not keep track of
724
// whether transactions can be started or not because quiesce related
725
// transactions can start after all other user
726
// transactions are excluded.
727
// RESOLVE: need to put more thought on the overall requirement and
728
// design of the transaction table that satisfies the need of all the
729
// clients, namely: checkpoint, recovery, quiesce mode, transaction table.
730

731         add(xact, excludeMe);
732
733     }
734
735     /**
736         Add a transaction to the list of transactions that has updated
737         the raw store.
738         <P>
739         This is called underneath the BeginXact log operation's doMe method.
740         The logging system must guarentee that transactions are added in the
741         true order they are started, as defined by the order of beginXact log
742         record in the log.
743     */

744     protected void addUpdateTransaction(
745     TransactionId id,
746     RawTransaction t,
747     int transactionStatus)
748     {
749         if (SanityManager.DEBUG)
750             SanityManager.ASSERT(
751                 id != null, "addding update transaction with null id");
752
753         ttab.addUpdateTransaction(id, t, transactionStatus);
754     }
755
756     /**
757         Remove a transaction from the list of transactions that has updated the
758         raw store.
759     */

760     protected void removeUpdateTransaction(TransactionId id)
761     {
762         if (SanityManager.DEBUG)
763             SanityManager.ASSERT(
764                 id != null, "remove update transaction with null id");
765
766         ttab.removeUpdateTransaction(id);
767     }
768
769     /**
770         Change state of transaction to prepared. Used by recovery to update
771         the transaction table entry to prepared state.
772     */

773     protected void prepareTransaction(TransactionId id)
774     {
775         if (SanityManager.DEBUG)
776             SanityManager.ASSERT(
777                 id != null, "prepare transaction with null id");
778
779         ttab.prepareTransaction(id);
780     }
781
782     /**
783         Submit this post commit work to the post commit daemon
784     */

785     public boolean submitPostCommitWork(Serviceable work)
786     {
787         if (rawStoreDaemon != null)
788             return rawStoreDaemon.enqueue(work, work.serviceASAP());
789         return false;
790     }
791
792     public void setRawStoreFactory(RawStoreFactory rsf) throws StandardException
793     {
794         if (SanityManager.DEBUG)
795         {
796             SanityManager.ASSERT(rsf != null, "rawStoreFactory == null");
797         }
798
799         rawStoreFactory = rsf;
800
801         // no need to remember raw store factory,
802
// just remember which daemon to use
803
rawStoreDaemon = rsf.getDaemon();
804
805         // now its ok to look for the log and data factory
806
// log factory is booted by the data factory
807
logFactory = (LogFactory) Monitor.findServiceModule(this, rsf.getLogFactoryModule());
808
809         // data factory is booted by the raw store implementation
810
dataFactory = (DataFactory) Monitor.findServiceModule(this, rsf.getDataFactoryModule());
811     }
812
813     /**
814         Returns true if there is no in flight updating tranasaction.
815         Caller must be aware that if there is no other mechanism to stop
816         transactions from starting and ending, then this information is
817         outdated as soon as it is reported.
818
819         Only call this function in special times - e.g, during recovery
820     */

821     public boolean noActiveUpdateTransaction()
822     {
823         return (ttab.hasActiveUpdateTransaction() == false);
824     }
825
826
827     /**
828      * Check if there are any prepared transanctions in the
829      * transaction table.
830      *
831      * Caller must be aware that if there is no other mechanism to stop
832      * transactions from starting and ending, then this information is
833      * outdated as soon as it is reported.
834      *
835      * @return <tt>true</tt> if there are prepared
836      * transactions in the transaction table,
837      * <tt>false</tt> otherwise.
838      */

839     public boolean hasPreparedXact()
840     {
841         return (ttab.hasPreparedXact());
842     }
843
844
845
846     /*
847         remove the transaction Id an return false iff the transaction is found
848         in the table and it doesn't need exclusion from quiesce state
849      */

850     protected boolean remove(TransactionId xactId)
851     {
852         return ttab.remove(xactId);
853     }
854
855     protected void add(Xact xact, boolean excludeMe)
856     {
857         ttab.add(xact, excludeMe);
858     }
859
860
861     /**
862         Make a new UUID for whomever that wants it
863     */

864     public UUID makeNewUUID()
865     {
866         return uuidFactory.createUUID();
867     }
868
869     /**
870         Decide if a transaction of this contextId needs to flush the log when
871         it commits
872     */

873     public boolean flushLogOnCommit(String JavaDoc contextName)
874     {
875         //
876
// if this is a user transaction, flush the log
877
// if this is an internal or nested top transaction, do not
878
// flush, let it age out.
879
//
880
return (contextName == USER_CONTEXT_ID ||
881                 contextName.equals(USER_CONTEXT_ID));
882     }
883
884
885     /**
886         Get a locking policy for a transaction.
887     */

888     final LockingPolicy getLockingPolicy(
889     int mode,
890     int isolation,
891     boolean stricterOk)
892     {
893
894         if (mode == LockingPolicy.MODE_NONE)
895             isolation = TransactionController.ISOLATION_NOLOCK;
896
897         LockingPolicy policy = lockingPolicies[mode][isolation];
898
899         if ((policy != null) || (!stricterOk))
900             return policy;
901
902         for (mode++; mode <= LockingPolicy.MODE_CONTAINER; mode++)
903         {
904             for (int i = isolation;
905                  i <= TransactionController.ISOLATION_SERIALIZABLE;
906                  i++)
907             {
908                 policy = lockingPolicies[mode][i];
909                 if (policy != null)
910                     return policy;
911             }
912         }
913
914         return null;
915     }
916
917     /*
918         Return the transaction table to be logged with the checkpoint operation
919      */

920     public Formatable getTransactionTable()
921     {
922         return ttab;
923     }
924
925     /*
926         Use this transaction table, which is gotten from a checkpoint
927         operation. Use ONLY during recovery.
928      */

929     public void useTransactionTable(Formatable transactionTable)
930          throws StandardException
931     {
932         if (ttab != null && transactionTable != null)
933         {
934             throw StandardException.newException(
935                     SQLState.XACT_TRANSACTION_TABLE_IN_USE);
936         }
937
938         if (ttab == null)
939         {
940             if (transactionTable == null)
941                 ttab = new TransactionTable();
942             else
943             {
944                 if (SanityManager.DEBUG)
945                 {
946                     if ((transactionTable instanceof TransactionTable) ==
947                         false)
948                     {
949                         SanityManager.THROWASSERT(
950                             "using transaction table which is of class " +
951                             transactionTable.getClass().getName());
952                     }
953                 }
954                 ttab = (TransactionTable)transactionTable;
955             }
956         }
957         // else transactionTable must be null, if we already have a transaction
958
// table, no need to do anything
959
}
960
961     public TransactionInfo[] getTransactionInfo()
962     {
963         if (SanityManager.DEBUG)
964             SanityManager.ASSERT(ttab != null, "transaction table is null");
965         return ttab.getTransactionInfo();
966     }
967
968
969     // @return false, if the Database creation finished
970
public boolean inDatabaseCreation()
971     {
972         return inCreateNoLog;
973     }
974     
975     /*
976      * Return the module providing XAresource interface to the transaction
977      * table.
978      *
979      * @exception StandardException Standard cloudscape exception policy.
980      */

981     public /* XAResourceManager */ Object JavaDoc getXAResourceManager()
982         throws StandardException
983     {
984         if (xa_resource == null)
985             xa_resource = new XactXAResourceManager(rawStoreFactory, ttab);
986
987         return(xa_resource);
988     }
989
990
991     /**
992      * Block the online backup. Backup needs to be blocked while
993      * executing any unlogged operations or any opearation that
994      * prevents from making a consistent backup.
995      *
996      * @param wait if <tt>true</tt>, waits until the backup
997      * is blocked.
998      * @return <tt>true</tt> if backup is blocked.
999      * <tt>false</tt> otherwise.
1000     * @exception StandardException if interrupted while waiting for a
1001     * backup to complete.
1002     */

1003    protected boolean blockBackup(boolean wait)
1004        throws StandardException
1005    {
1006        synchronized(backupSemaphore) {
1007            // do not allow backup blocking operations, if online backup is
1008
// is in progress.
1009
if (inBackup)
1010            {
1011                if(wait) {
1012                    while(inBackup) {
1013                        try {
1014                            backupSemaphore.wait();
1015                        } catch (InterruptedException JavaDoc ie) {
1016                            throw StandardException.interrupt(ie);
1017                        }
1018                    }
1019                }else {
1020                    return false;
1021                }
1022            }
1023
1024            // not in online backup, allow backup blocking operations
1025
backupBlockingOperations++;
1026            return true;
1027        }
1028    }
1029
1030
1031    /**
1032     * Unblock the backup, a backup blocking operation finished.
1033     */

1034    protected void unblockBackup()
1035    {
1036        synchronized(backupSemaphore) {
1037            if (SanityManager.DEBUG)
1038                SanityManager.ASSERT(backupBlockingOperations > 0,
1039                    "no backup blocking opeations in progress");
1040            
1041            backupBlockingOperations--;
1042
1043            if (inBackup) {
1044                // wake up the online backupthread
1045
backupSemaphore.notifyAll();
1046            }
1047        }
1048    }
1049
1050    /**
1051     * Checks if there are any backup blocking operations in progress and
1052     * prevents new ones from starting until the backup is finished.
1053     * If backup blocking operations are in progress and <code> wait </code>
1054     * parameter value is <tt>true</tt>, then it will wait for the current
1055     * backup blocking operations to finish.
1056     *
1057     * A Consistent backup can not be made if there are any backup
1058     * blocking operations (like unlogged operations) are in progress
1059     *
1060     * @param wait if <tt>true</tt>, waits for the current backup blocking
1061     * operation in progress to finish.
1062     * @return <tt>true</tt> if no backup blocking operations are in
1063     * progress
1064     * <tt>false</tt> otherwise.
1065     * @exception StandardException if interrupted or a runtime exception occurs
1066     */

1067    public boolean blockBackupBlockingOperations(boolean wait)
1068        throws StandardException
1069    {
1070        synchronized(backupSemaphore) {
1071            if (wait) {
1072                // set the inBackup state to true first to stop new backup
1073
// blocking operation from starting.
1074
inBackup= true;
1075                try {
1076                    // wait for backup blocking operation in progress to finish
1077
while(backupBlockingOperations > 0)
1078                    {
1079                        try {
1080                            backupSemaphore.wait();
1081                        }
1082                        catch (InterruptedException JavaDoc ie) {
1083                            // make sure we are not stuck in the backup state
1084
// if we caught an interrupt exception and the
1085
// calling thread may not have a chance to clear
1086
// the in backup state.
1087

1088                            inBackup = false;
1089                            backupSemaphore.notifyAll();
1090                            throw StandardException.interrupt(ie);
1091                        }
1092                    }
1093                }
1094                catch (RuntimeException JavaDoc rte) {
1095                    // make sure we are not stuck in backup state if we
1096
// caught a run time exception and the calling thread may
1097
// not have a chance to clear the in backup state.
1098
inBackup= false;
1099                    backupSemaphore.notifyAll();
1100                    throw rte; // rethrow run time exception
1101
}
1102            } else {
1103                // check if any backup blocking operations that are in progress
1104
if (backupBlockingOperations == 0)
1105                    inBackup = true;
1106            }
1107            
1108        }
1109
1110        if (SanityManager.DEBUG) {
1111            if (inBackup) {
1112                SanityManager.ASSERT(backupBlockingOperations == 0 ,
1113                                 "store is not in correct state for backup");
1114            }
1115        }
1116
1117        return inBackup;
1118    }
1119
1120
1121    /**
1122     * Backup completed. Allow backup blocking operations.
1123     */

1124    public void unblockBackupBlockingOperations()
1125    {
1126        synchronized(backupSemaphore) {
1127            inBackup = false;
1128            backupSemaphore.notifyAll();
1129        }
1130    }
1131    
1132}
1133
Popular Tags