0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.store.raw.xact.XactFactory
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.impl.store.raw.xact;
0023:
0024: import org.apache.derby.iapi.reference.Property;
0025: import org.apache.derby.iapi.reference.SQLState;
0026:
0027: import org.apache.derby.iapi.services.context.ContextService;
0028: import org.apache.derby.iapi.services.context.ContextManager;
0029: import org.apache.derby.iapi.services.daemon.DaemonService;
0030: import org.apache.derby.iapi.services.daemon.Serviceable;
0031: import org.apache.derby.iapi.services.locks.LockFactory;
0032: import org.apache.derby.iapi.services.monitor.ModuleControl;
0033: import org.apache.derby.iapi.services.monitor.ModuleSupportable;
0034: import org.apache.derby.iapi.services.monitor.Monitor;
0035: import org.apache.derby.iapi.services.sanity.SanityManager;
0036: import org.apache.derby.iapi.services.io.Formatable;
0037: import org.apache.derby.iapi.services.io.FormatIdUtil;
0038: import org.apache.derby.iapi.services.uuid.UUIDFactory;
0039: import org.apache.derby.catalog.UUID;
0040:
0041: import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
0042: import org.apache.derby.iapi.store.access.TransactionController;
0043: import org.apache.derby.iapi.store.access.TransactionInfo;
0044:
0045: import org.apache.derby.iapi.store.access.AccessFactory;
0046:
0047: import org.apache.derby.iapi.store.access.xa.XAResourceManager;
0048:
0049: import org.apache.derby.iapi.store.raw.LockingPolicy;
0050: import org.apache.derby.iapi.store.raw.GlobalTransactionId;
0051: import org.apache.derby.iapi.store.raw.RawStoreFactory;
0052: import org.apache.derby.iapi.store.raw.Transaction;
0053:
0054: import org.apache.derby.iapi.store.raw.data.DataFactory;
0055:
0056: import org.apache.derby.iapi.store.raw.log.LogFactory;
0057: import org.apache.derby.iapi.store.raw.log.LogInstant;
0058:
0059: import org.apache.derby.iapi.store.raw.xact.TransactionFactory;
0060: import org.apache.derby.iapi.store.raw.xact.RawTransaction;
0061: import org.apache.derby.iapi.store.raw.xact.TransactionId;
0062:
0063: import org.apache.derby.iapi.error.StandardException;
0064:
0065: import org.apache.derby.impl.store.raw.xact.XactXAResourceManager;
0066:
0067: import java.util.Enumeration;
0068: import java.util.Properties;
0069: import java.util.Hashtable;
0070:
0071: public class XactFactory implements TransactionFactory, ModuleControl,
0072: ModuleSupportable {
0073: protected static final String USER_CONTEXT_ID = "UserTransaction";
0074: protected static final String NESTED_READONLY_USER_CONTEXT_ID = "NestedRawReadOnlyUserTransaction";
0075: protected static final String NESTED_UPDATE_USER_CONTEXT_ID = "NestedRawUpdateUserTransaction";
0076: protected static final String INTERNAL_CONTEXT_ID = "InternalTransaction";
0077: protected static final String NTT_CONTEXT_ID = "NestedTransaction";
0078:
0079: /*
0080: ** Fields
0081: */
0082:
0083: protected DaemonService rawStoreDaemon;
0084:
0085: private UUIDFactory uuidFactory;
0086: protected ContextService contextFactory;
0087: protected LockFactory lockFactory;
0088: protected LogFactory logFactory;
0089: protected DataFactory dataFactory;
0090: protected RawStoreFactory rawStoreFactory;
0091:
0092: public TransactionTable ttab;
0093: private long tranId;
0094: private LockingPolicy[][] lockingPolicies = new LockingPolicy[3][6];
0095:
0096: private boolean inCreateNoLog = false; // creating database, no logging
0097:
0098: private XAResourceManager xa_resource;
0099:
0100: private Object backupSemaphore = new Object();
0101: private long backupBlockingOperations = 0;
0102: private boolean inBackup = false;
0103:
0104: /*
0105: ** Constructor
0106: */
0107:
0108: public XactFactory() {
0109: super ();
0110: }
0111:
0112: /*
0113: ** Methods of ModuleControl
0114: */
0115: public boolean canSupport(Properties startParams) {
0116: return true;
0117: }
0118:
0119: public void boot(boolean create, Properties properties)
0120: throws StandardException {
0121:
0122: uuidFactory = Monitor.getMonitor().getUUIDFactory();
0123:
0124: contextFactory = ContextService.getFactory();
0125:
0126: lockFactory = (LockFactory) Monitor.bootServiceModule(false,
0127: this ,
0128: org.apache.derby.iapi.reference.Module.LockFactory,
0129: properties);
0130:
0131: // adding entries to locking policy table which means we support that
0132: // level of concurrency.
0133: lockingPolicies[LockingPolicy.MODE_NONE][TransactionController.ISOLATION_NOLOCK] = new NoLocking();
0134:
0135: lockingPolicies[LockingPolicy.MODE_RECORD][TransactionController.ISOLATION_NOLOCK] = new NoLocking();
0136: lockingPolicies[LockingPolicy.MODE_RECORD][TransactionController.ISOLATION_READ_UNCOMMITTED] = new RowLocking1(
0137: lockFactory);
0138: lockingPolicies[LockingPolicy.MODE_RECORD][TransactionController.ISOLATION_READ_COMMITTED] = new RowLocking2(
0139: lockFactory);
0140: lockingPolicies[LockingPolicy.MODE_RECORD][TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] = new RowLocking2nohold(
0141: lockFactory);
0142: lockingPolicies[LockingPolicy.MODE_RECORD][TransactionController.ISOLATION_REPEATABLE_READ] = new RowLockingRR(
0143: lockFactory);
0144: lockingPolicies[LockingPolicy.MODE_RECORD][TransactionController.ISOLATION_SERIALIZABLE] = new RowLocking3(
0145: lockFactory);
0146:
0147: lockingPolicies[LockingPolicy.MODE_CONTAINER][TransactionController.ISOLATION_NOLOCK] = new NoLocking();
0148:
0149: // note that current implementation of read uncommitted still gets
0150: // container and container intent locks to prevent concurrent ddl. Thus
0151: // the read uncommitted containerlocking implementation is the same as
0152: // the read committed implementation. Future customer requests may
0153: // force us to change this - we will then have to figure out how to
0154: // handle a table being dropped while a read uncommitted scanner is
0155: // reading it - currently we just block that from happening.
0156: lockingPolicies[LockingPolicy.MODE_CONTAINER][TransactionController.ISOLATION_READ_UNCOMMITTED] = new ContainerLocking2(
0157: lockFactory);
0158: lockingPolicies[LockingPolicy.MODE_CONTAINER][TransactionController.ISOLATION_READ_COMMITTED] = new ContainerLocking2(
0159: lockFactory);
0160: lockingPolicies[LockingPolicy.MODE_CONTAINER][TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK] = new ContainerLocking2(
0161: lockFactory);
0162: lockingPolicies[LockingPolicy.MODE_CONTAINER][TransactionController.ISOLATION_REPEATABLE_READ] = new ContainerLocking3(
0163: lockFactory);
0164: lockingPolicies[LockingPolicy.MODE_CONTAINER][TransactionController.ISOLATION_SERIALIZABLE] = new ContainerLocking3(
0165: lockFactory);
0166:
0167: if (create) {
0168: ttab = new TransactionTable();
0169:
0170: String noLog = properties
0171: .getProperty(Property.CREATE_WITH_NO_LOG);
0172:
0173: inCreateNoLog = (noLog != null && Boolean.valueOf(noLog)
0174: .booleanValue());
0175:
0176: }
0177: }
0178:
0179: public void stop() {
0180:
0181: if (rawStoreDaemon != null)
0182: rawStoreDaemon.stop();
0183:
0184: }
0185:
0186: /*
0187: ** Methods of TransactionFactory
0188: */
0189:
0190: /**
0191: Get the LockFactory to use with this store.
0192: */
0193: public LockFactory getLockFactory() {
0194: return lockFactory;
0195: }
0196:
0197: /**
0198: Database creation finished
0199: @exception StandardException standard cloudscape error policy
0200: */
0201: public void createFinished() throws StandardException {
0202: if (!inCreateNoLog) {
0203: throw StandardException
0204: .newException(SQLState.XACT_CREATE_NO_LOG);
0205: }
0206:
0207: // make sure there is no active update transaction
0208: if (ttab.hasActiveUpdateTransaction()) {
0209: throw StandardException
0210: .newException(SQLState.XACT_CREATE_NO_LOG);
0211: }
0212:
0213: inCreateNoLog = false;
0214: }
0215:
0216: /**
0217: * Common work done to create local or global transactions.
0218: *
0219: * @param rsf the raw store factory creating this xact.
0220: * @param cm the current context manager to associate the xact with.
0221: * @param compatibilitySpace
0222: * if null, use the transaction being created, else if
0223: * non-null use this compatibilitySpace.
0224: *
0225: * @exception StandardException Standard exception policy.
0226: **/
0227: private RawTransaction startCommonTransaction(RawStoreFactory rsf,
0228: ContextManager cm, boolean readOnly,
0229: Object compatibilitySpace, String xact_context_id,
0230: String transName, boolean excludeMe)
0231: throws StandardException {
0232:
0233: if (SanityManager.DEBUG) {
0234: if (rawStoreFactory != null)
0235: SanityManager.ASSERT(rawStoreFactory == rsf,
0236: "raw store factory different");
0237:
0238: SanityManager.ASSERT(cm == contextFactory
0239: .getCurrentContextManager());
0240: }
0241:
0242: Xact xact = new Xact(this , logFactory, dataFactory, readOnly,
0243: compatibilitySpace);
0244:
0245: xact.setTransName(transName);
0246: pushTransactionContext(cm, xact_context_id, xact,
0247: false /* abortAll */, rsf, excludeMe /* excludeMe during quiesce state */);
0248: return xact;
0249: }
0250:
0251: public RawTransaction startTransaction(RawStoreFactory rsf,
0252: ContextManager cm, String transName)
0253: throws StandardException {
0254: return (startCommonTransaction(rsf, cm, false, null,
0255: USER_CONTEXT_ID, transName, true));
0256: }
0257:
0258: public RawTransaction startNestedReadOnlyUserTransaction(
0259: RawStoreFactory rsf, Object compatibilitySpace,
0260: ContextManager cm, String transName)
0261: throws StandardException {
0262: return (startCommonTransaction(rsf, cm, true,
0263: compatibilitySpace, NESTED_READONLY_USER_CONTEXT_ID,
0264: transName, false));
0265: }
0266:
0267: public RawTransaction startNestedUpdateUserTransaction(
0268: RawStoreFactory rsf, ContextManager cm, String transName)
0269: throws StandardException {
0270: return (startCommonTransaction(rsf, cm, false, null,
0271: NESTED_UPDATE_USER_CONTEXT_ID, transName, true));
0272: }
0273:
0274: public RawTransaction startGlobalTransaction(RawStoreFactory rsf,
0275: ContextManager cm, int format_id, byte[] global_id,
0276: byte[] branch_id) throws StandardException {
0277: GlobalXactId gid = new GlobalXactId(format_id, global_id,
0278: branch_id);
0279:
0280: if (ttab.findTransactionContextByGlobalId(gid) != null) {
0281: throw StandardException
0282: .newException(SQLState.STORE_XA_XAER_DUPID);
0283: }
0284:
0285: RawTransaction xact = startCommonTransaction(rsf, cm, false,
0286: null, USER_CONTEXT_ID,
0287: AccessFactoryGlobals.USER_TRANS_NAME, true);
0288:
0289: xact.setTransactionId(gid, xact.getId());
0290:
0291: return (xact);
0292: }
0293:
0294: public RawTransaction findUserTransaction(RawStoreFactory rsf,
0295: ContextManager contextMgr, String transName)
0296: throws StandardException {
0297: if (SanityManager.DEBUG) {
0298: SanityManager
0299: .ASSERT(contextMgr == contextFactory
0300: .getCurrentContextManager(),
0301: "passed in context mgr not the same as current context mgr");
0302:
0303: if (rawStoreFactory != null)
0304: SanityManager.ASSERT(rawStoreFactory == rsf,
0305: "raw store factory different");
0306: }
0307:
0308: XactContext xc = (XactContext) contextMgr
0309: .getContext(USER_CONTEXT_ID);
0310: if (xc == null)
0311: return startTransaction(rsf, contextMgr, transName);
0312: else
0313: return xc.getTransaction();
0314: }
0315:
0316: public RawTransaction startNestedTopTransaction(
0317: RawStoreFactory rsf, ContextManager cm)
0318: throws StandardException {
0319:
0320: if (SanityManager.DEBUG) {
0321: if (rawStoreFactory != null)
0322: SanityManager.ASSERT(rawStoreFactory == rsf,
0323: "raw store factory different");
0324: }
0325:
0326: Xact xact = new Xact(this , logFactory, dataFactory, false, null);
0327:
0328: // hold latches etc. past commit in NTT
0329: xact.setPostComplete();
0330: pushTransactionContext(cm, NTT_CONTEXT_ID, xact,
0331: true /* abortAll */, rsf, true /* excludeMe during quiesce state*/);
0332: return xact;
0333: }
0334:
0335: public RawTransaction startInternalTransaction(RawStoreFactory rsf,
0336: ContextManager cm) throws StandardException {
0337: if (SanityManager.DEBUG) {
0338: if (rawStoreFactory != null)
0339: SanityManager.ASSERT(rawStoreFactory == rsf,
0340: "raw store factory different");
0341: }
0342:
0343: Xact xact = new InternalXact(this , logFactory, dataFactory);
0344: pushTransactionContext(cm, INTERNAL_CONTEXT_ID, xact,
0345: true /* abortAll*/, rsf, true /* excludeMe during quiesce state */);
0346: return xact;
0347: }
0348:
0349: /*
0350: * the following TransactionFactory methods are to support recovery and
0351: * should only be used by recovery!
0352: */
0353:
0354: /**
0355: Find the TransactionTableEntry with the given ID and make the passed in
0356: transaction assume the identity and properties of that
0357: TransactionTableEntry.
0358: Used in recovery only.
0359: */
0360: public boolean findTransaction(TransactionId id, RawTransaction tran) {
0361: return ttab.findAndAssumeTransaction(id, tran);
0362: }
0363:
0364: /**
0365: Rollback all active transactions that has updated the raw store.
0366: Use the recovery Transaction that is passed in to do all the work.
0367: Used in recovery only.
0368:
0369: <P>
0370: Transactions are rolled back in the following order:
0371: <OL>
0372: <LI>internal transactions in reversed beginXact chronological order,
0373: <LI>all other transactions in reversed beginXact chronological order,
0374: </NL>
0375:
0376: @param recoveryTransaction use this transaction to do all the user
0377: transaction work
0378:
0379: @exception StandardException any exception thrown during rollback
0380: */
0381: public void rollbackAllTransactions(
0382: RawTransaction recoveryTransaction, RawStoreFactory rsf)
0383: throws StandardException {
0384: if (SanityManager.DEBUG) {
0385: if (rawStoreFactory != null)
0386: SanityManager.ASSERT(rawStoreFactory == rsf,
0387: "raw store factory different");
0388:
0389: SanityManager.ASSERT(recoveryTransaction != null,
0390: "recovery transaction null");
0391: }
0392:
0393: int irbcount = 0;
0394:
0395: // First undo internal transactions if there is any
0396: if (ttab.hasRollbackFirstTransaction()) {
0397: RawTransaction internalTransaction = startInternalTransaction(
0398: rsf, recoveryTransaction.getContextManager());
0399:
0400: // make this transaction be aware that it is being used by recovery
0401: internalTransaction.recoveryTransaction();
0402:
0403: if (SanityManager.DEBUG)
0404: SanityManager
0405: .ASSERT(internalTransaction
0406: .handlesPostTerminationWork() == false,
0407: "internal recovery xact handles post termination work");
0408:
0409: while (ttab
0410: .getMostRecentRollbackFirstTransaction(internalTransaction)) {
0411: irbcount++;
0412: internalTransaction.abort();
0413: }
0414:
0415: internalTransaction.close();
0416: }
0417:
0418: if (SanityManager.DEBUG) {
0419: SanityManager
0420: .ASSERT(
0421: ttab.hasRollbackFirstTransaction() == false,
0422: "cant rollback user xacts with existing active internal xacts");
0423: }
0424:
0425: int rbcount = 0;
0426:
0427: // recoveryTransacion assumes the identity of the most recent xact
0428: while (ttab
0429: .getMostRecentTransactionForRollback(recoveryTransaction)) {
0430: if (SanityManager.DEBUG) {
0431: SanityManager
0432: .ASSERT(recoveryTransaction
0433: .handlesPostTerminationWork() == false,
0434: "recovery transaction handles post termination work");
0435: }
0436:
0437: rbcount++;
0438: recoveryTransaction.abort();
0439: }
0440:
0441: if (SanityManager.DEBUG) {
0442: if (rbcount > 0 || irbcount > 0) {
0443: // RESOLVE: put this in the log trace
0444: // System.out.println(
0445: // "Recovery rolled back " + irbcount +
0446: // " internal transactions,"
0447: // + rbcount + " user transactions");
0448: }
0449: }
0450:
0451: }
0452:
0453: /**
0454: Run through all prepared transactions known to this factory
0455: and restore their state such that they remain after recovery, and
0456: can be found and handled by a XA transaction manager. This includes
0457: creating a context manager for each, pushing a xact context, and
0458: reclaiming update locks on all data changed by the transaction.
0459:
0460: Expected to be called just after the redo and undo recovery loops,
0461: where the transaction table should be empty except for prepared
0462: xacts.
0463:
0464: Used only in recovery.
0465:
0466: @exception StandardException Cloudscape Standard Error policy
0467: */
0468: public void handlePreparedXacts(RawStoreFactory rsf)
0469: throws StandardException {
0470: if (SanityManager.DEBUG) {
0471:
0472: if (rawStoreFactory != null)
0473: SanityManager.ASSERT(rawStoreFactory == rsf,
0474: "raw store factory different");
0475: }
0476:
0477: int prepared_count = 0;
0478:
0479: if (ttab.hasPreparedRecoveredXact()) {
0480: // if there any prepared xacts
0481:
0482: // At this point recovery has used one context and one transaction
0483: // to deal with all transactions. Prepared transactions are to
0484: // be left in the transaction table, but the must have real and
0485: // separate CM's and transactions associated with them.
0486:
0487: // save old context. Errors may go to funky contexts (the new
0488: // context we created to bring the prepared transaction into the
0489: // real world after recovery) after we switch contexts, but any
0490: // error we get at this point is going to shut down the db.
0491:
0492: while (true) {
0493: // allocate new context and associate new xact with it.
0494: ContextManager cm = contextFactory.newContextManager();
0495: contextFactory.setCurrentContextManager(cm);
0496:
0497: try {
0498: RawTransaction rawtran = startTransaction(
0499: rawStoreFactory, cm,
0500: AccessFactoryGlobals.USER_TRANS_NAME);
0501:
0502: if (ttab
0503: .getMostRecentPreparedRecoveredXact(rawtran)) {
0504: // found a prepared xact. The reprepare() call will
0505: // accumulate locks, and change the transaction table entry
0506: // to not be "in-recovery" so that it won't show up again.
0507: rawtran.reprepare();
0508:
0509: if (SanityManager.DEBUG)
0510: prepared_count++;
0511: } else {
0512: // get rid of last transaction allocated.
0513: rawtran.destroy();
0514: break;
0515: }
0516: } finally {
0517: contextFactory.resetCurrentContextManager(cm);
0518: }
0519: }
0520:
0521: }
0522:
0523: if (SanityManager.DEBUG) {
0524: // RESOLVE - need to only do this under a debug flag.
0525: // SanityManager.DEBUG_PRINT("",
0526: // "Recovery re-prepared " + prepared_count + " xa transactions.");
0527: }
0528: }
0529:
0530: /**
0531: Get the earliest log instant that is still active, ie, the first log
0532: record logged by the earliest transaction that is still active.
0533: <BR>
0534: The logging system must guarentee that the transaction table is
0535: populated in the order transactions are started.
0536: Used in recovery only.
0537: */
0538:
0539: public LogInstant firstUpdateInstant() {
0540: return ttab.getFirstLogInstant();
0541: }
0542:
0543: /*
0544: ** Methods of Corruptable
0545: */
0546:
0547: /**
0548: Really this is just a convience routine for callers that might not
0549: have access to a log factory.
0550: */
0551: public StandardException markCorrupt(StandardException originalError) {
0552: logFactory.markCorrupt(originalError);
0553: return originalError;
0554: }
0555:
0556: /*
0557: ** Implementation specific methods.
0558: */
0559:
0560: public void setNewTransactionId(TransactionId oldxid, Xact t) {
0561: XactId xid;
0562: boolean excludeMe = true; // by default
0563:
0564: if (oldxid != null)
0565: excludeMe = remove(oldxid);
0566:
0567: synchronized (this ) {
0568: xid = new XactId(tranId++);
0569: }
0570:
0571: t.setTransactionId(t.getGlobalId(), xid);
0572:
0573: // RESOLVE: How does a real global xact id get set?
0574:
0575: // If we got rid of the oldxid, that means this transaction object has
0576: // merely committed and starting the next transaction with the same
0577: // xact object. In that case, the transaction context will remain the
0578: // same and won't be pushed. We need to add this transaction with the
0579: // new id back into the transaction table. If we did not get rid of
0580: // the old oldxid, that means this is a brand new transaction being
0581: // created. The pushTransactionContext call will add it to the
0582: // transaction table with the appropriate flags
0583: if (oldxid != null)
0584: add(t, excludeMe);
0585: }
0586:
0587: /*
0588: ** Set the shortTranId, this is called by the log factory after recovery
0589: */
0590: public void resetTranId() {
0591: XactId xid = (XactId) ttab.largestUpdateXactId();
0592: if (xid != null)
0593: tranId = xid.getId() + 1;
0594: else
0595: tranId = 1;
0596: }
0597:
0598: /**
0599: Create a new RawTransaction, a context for it and push the context
0600: onto the current context manager. Then add the transacion to the
0601: transaction table.
0602:
0603: @param contextName the name of the transaction context
0604: @param xact the Transaction object
0605: @param abortAll if true, then any error will abort the whole
0606: transaction. Otherwise, let XactContext.cleanupOnError decide what to
0607: do
0608: @param rsf the raw store factory
0609: @param excludeMe during systeme quiesce, i.e., this transaction should
0610: not be allowed to be active during a quiesce state.
0611:
0612:
0613: @exception StandardException Standard Cloudscape error policy
0614:
0615: */
0616: protected void pushTransactionContext(ContextManager cm,
0617: String contextName, Xact xact, boolean abortAll,
0618: RawStoreFactory rsf, boolean excludeMe)
0619: throws StandardException {
0620: if (cm.getContext(contextName) != null) {
0621: throw StandardException
0622: .newException(SQLState.XACT_TRANSACTION_ACTIVE);
0623: }
0624:
0625: XactContext xc = new XactContext(cm, contextName, xact,
0626: abortAll, rsf);
0627:
0628: // this transaction is now added to the transaction table.
0629: // This will cause an idle transaction to take on an identity, which is
0630: // unfortunate. The reason why we have to add the transaction to the
0631: // table right now is because the transaction table is used to bring
0632: // system to quisce state to regulate who can go active during quiesce
0633: // state, and if we add the transaction
0634: // when it goes active, then there is a window where this transaction
0635: // can sneak in. The transaction table itself does not keep track of
0636: // whether transactions can be started or not because quiesce related
0637: // transactions can start after all other user
0638: // transactions are excluded.
0639: // RESOLVE: need to put more thought on the overall requirement and
0640: // design of the transaction table that satisfies the need of all the
0641: // clients, namely: checkpoint, recovery, quiesce mode, transaction table.
0642:
0643: add(xact, excludeMe);
0644:
0645: }
0646:
0647: /**
0648: Add a transaction to the list of transactions that has updated
0649: the raw store.
0650: <P>
0651: This is called underneath the BeginXact log operation's doMe method.
0652: The logging system must guarentee that transactions are added in the
0653: true order they are started, as defined by the order of beginXact log
0654: record in the log.
0655: */
0656: protected void addUpdateTransaction(TransactionId id,
0657: RawTransaction t, int transactionStatus) {
0658: if (SanityManager.DEBUG)
0659: SanityManager.ASSERT(id != null,
0660: "addding update transaction with null id");
0661:
0662: ttab.addUpdateTransaction(id, t, transactionStatus);
0663: }
0664:
0665: /**
0666: Remove a transaction from the list of transactions that has updated the
0667: raw store.
0668: */
0669: protected void removeUpdateTransaction(TransactionId id) {
0670: if (SanityManager.DEBUG)
0671: SanityManager.ASSERT(id != null,
0672: "remove update transaction with null id");
0673:
0674: ttab.removeUpdateTransaction(id);
0675: }
0676:
0677: /**
0678: Change state of transaction to prepared. Used by recovery to update
0679: the transaction table entry to prepared state.
0680: */
0681: protected void prepareTransaction(TransactionId id) {
0682: if (SanityManager.DEBUG)
0683: SanityManager.ASSERT(id != null,
0684: "prepare transaction with null id");
0685:
0686: ttab.prepareTransaction(id);
0687: }
0688:
0689: /**
0690: Submit this post commit work to the post commit daemon
0691: */
0692: public boolean submitPostCommitWork(Serviceable work) {
0693: if (rawStoreDaemon != null)
0694: return rawStoreDaemon.enqueue(work, work.serviceASAP());
0695: return false;
0696: }
0697:
0698: public void setRawStoreFactory(RawStoreFactory rsf)
0699: throws StandardException {
0700: if (SanityManager.DEBUG) {
0701: SanityManager
0702: .ASSERT(rsf != null, "rawStoreFactory == null");
0703: }
0704:
0705: rawStoreFactory = rsf;
0706:
0707: // no need to remember raw store factory,
0708: // just remember which daemon to use
0709: rawStoreDaemon = rsf.getDaemon();
0710:
0711: // now its ok to look for the log and data factory
0712: // log factory is booted by the data factory
0713: logFactory = (LogFactory) Monitor.findServiceModule(this , rsf
0714: .getLogFactoryModule());
0715:
0716: // data factory is booted by the raw store implementation
0717: dataFactory = (DataFactory) Monitor.findServiceModule(this , rsf
0718: .getDataFactoryModule());
0719: }
0720:
0721: /**
0722: Returns true if there is no in flight updating tranasaction.
0723: Caller must be aware that if there is no other mechanism to stop
0724: transactions from starting and ending, then this information is
0725: outdated as soon as it is reported.
0726:
0727: Only call this function in special times - e.g, during recovery
0728: */
0729: public boolean noActiveUpdateTransaction() {
0730: return (ttab.hasActiveUpdateTransaction() == false);
0731: }
0732:
0733: /**
0734: * Check if there are any prepared transanctions in the
0735: * transaction table.
0736: *
0737: * Caller must be aware that if there is no other mechanism to stop
0738: * transactions from starting and ending, then this information is
0739: * outdated as soon as it is reported.
0740: *
0741: * @return <tt>true</tt> if there are prepared
0742: * transactions in the transaction table,
0743: * <tt>false</tt> otherwise.
0744: */
0745: public boolean hasPreparedXact() {
0746: return (ttab.hasPreparedXact());
0747: }
0748:
0749: /*
0750: remove the transaction Id an return false iff the transaction is found
0751: in the table and it doesn't need exclusion from quiesce state
0752: */
0753: protected boolean remove(TransactionId xactId) {
0754: return ttab.remove(xactId);
0755: }
0756:
0757: protected void add(Xact xact, boolean excludeMe) {
0758: ttab.add(xact, excludeMe);
0759: }
0760:
0761: /**
0762: Make a new UUID for whomever that wants it
0763: */
0764: public UUID makeNewUUID() {
0765: return uuidFactory.createUUID();
0766: }
0767:
0768: /**
0769: Decide if a transaction of this contextId needs to flush the log when
0770: it commits
0771: */
0772: public boolean flushLogOnCommit(String contextName) {
0773: //
0774: // if this is a user transaction, flush the log
0775: // if this is an internal or nested top transaction, do not
0776: // flush, let it age out.
0777: //
0778: return (contextName == USER_CONTEXT_ID || contextName
0779: .equals(USER_CONTEXT_ID));
0780: }
0781:
0782: /**
0783: Get a locking policy for a transaction.
0784: */
0785: final LockingPolicy getLockingPolicy(int mode, int isolation,
0786: boolean stricterOk) {
0787:
0788: if (mode == LockingPolicy.MODE_NONE)
0789: isolation = TransactionController.ISOLATION_NOLOCK;
0790:
0791: LockingPolicy policy = lockingPolicies[mode][isolation];
0792:
0793: if ((policy != null) || (!stricterOk))
0794: return policy;
0795:
0796: for (mode++; mode <= LockingPolicy.MODE_CONTAINER; mode++) {
0797: for (int i = isolation; i <= TransactionController.ISOLATION_SERIALIZABLE; i++) {
0798: policy = lockingPolicies[mode][i];
0799: if (policy != null)
0800: return policy;
0801: }
0802: }
0803:
0804: return null;
0805: }
0806:
0807: /*
0808: Return the transaction table to be logged with the checkpoint operation
0809: */
0810: public Formatable getTransactionTable() {
0811: return ttab;
0812: }
0813:
0814: /*
0815: Use this transaction table, which is gotten from a checkpoint
0816: operation. Use ONLY during recovery.
0817: */
0818: public void useTransactionTable(Formatable transactionTable)
0819: throws StandardException {
0820: if (ttab != null && transactionTable != null) {
0821: throw StandardException
0822: .newException(SQLState.XACT_TRANSACTION_TABLE_IN_USE);
0823: }
0824:
0825: if (ttab == null) {
0826: if (transactionTable == null)
0827: ttab = new TransactionTable();
0828: else {
0829: if (SanityManager.DEBUG) {
0830: if ((transactionTable instanceof TransactionTable) == false) {
0831: SanityManager
0832: .THROWASSERT("using transaction table which is of class "
0833: + transactionTable.getClass()
0834: .getName());
0835: }
0836: }
0837: ttab = (TransactionTable) transactionTable;
0838: }
0839: }
0840: // else transactionTable must be null, if we already have a transaction
0841: // table, no need to do anything
0842: }
0843:
0844: public TransactionInfo[] getTransactionInfo() {
0845: if (SanityManager.DEBUG)
0846: SanityManager.ASSERT(ttab != null,
0847: "transaction table is null");
0848: return ttab.getTransactionInfo();
0849: }
0850:
0851: // @return false, if the Database creation finished
0852: public boolean inDatabaseCreation() {
0853: return inCreateNoLog;
0854: }
0855:
0856: /*
0857: * Return the module providing XAresource interface to the transaction
0858: * table.
0859: *
0860: * @exception StandardException Standard cloudscape exception policy.
0861: */
0862: public/* XAResourceManager */Object getXAResourceManager()
0863: throws StandardException {
0864: if (xa_resource == null)
0865: xa_resource = new XactXAResourceManager(rawStoreFactory,
0866: ttab);
0867:
0868: return (xa_resource);
0869: }
0870:
0871: /**
0872: * Block the online backup. Backup needs to be blocked while
0873: * executing any unlogged operations or any opearation that
0874: * prevents from making a consistent backup.
0875: *
0876: * @param wait if <tt>true</tt>, waits until the backup
0877: * is blocked.
0878: * @return <tt>true</tt> if backup is blocked.
0879: * <tt>false</tt> otherwise.
0880: * @exception StandardException if interrupted while waiting for a
0881: * backup to complete.
0882: */
0883: protected boolean blockBackup(boolean wait)
0884: throws StandardException {
0885: synchronized (backupSemaphore) {
0886: // do not allow backup blocking operations, if online backup is
0887: // is in progress.
0888: if (inBackup) {
0889: if (wait) {
0890: while (inBackup) {
0891: try {
0892: backupSemaphore.wait();
0893: } catch (InterruptedException ie) {
0894: throw StandardException.interrupt(ie);
0895: }
0896: }
0897: } else {
0898: return false;
0899: }
0900: }
0901:
0902: // not in online backup, allow backup blocking operations
0903: backupBlockingOperations++;
0904: return true;
0905: }
0906: }
0907:
0908: /**
0909: * Unblock the backup, a backup blocking operation finished.
0910: */
0911: protected void unblockBackup() {
0912: synchronized (backupSemaphore) {
0913: if (SanityManager.DEBUG)
0914: SanityManager.ASSERT(backupBlockingOperations > 0,
0915: "no backup blocking opeations in progress");
0916:
0917: backupBlockingOperations--;
0918:
0919: if (inBackup) {
0920: // wake up the online backupthread
0921: backupSemaphore.notifyAll();
0922: }
0923: }
0924: }
0925:
0926: /**
0927: * Checks if there are any backup blocking operations in progress and
0928: * prevents new ones from starting until the backup is finished.
0929: * If backup blocking operations are in progress and <code> wait </code>
0930: * parameter value is <tt>true</tt>, then it will wait for the current
0931: * backup blocking operations to finish.
0932: *
0933: * A Consistent backup can not be made if there are any backup
0934: * blocking operations (like unlogged operations) are in progress
0935: *
0936: * @param wait if <tt>true</tt>, waits for the current backup blocking
0937: * operation in progress to finish.
0938: * @return <tt>true</tt> if no backup blocking operations are in
0939: * progress
0940: * <tt>false</tt> otherwise.
0941: * @exception StandardException if interrupted or a runtime exception occurs
0942: */
0943: public boolean blockBackupBlockingOperations(boolean wait)
0944: throws StandardException {
0945: synchronized (backupSemaphore) {
0946: if (wait) {
0947: // set the inBackup state to true first to stop new backup
0948: // blocking operation from starting.
0949: inBackup = true;
0950: try {
0951: // wait for backup blocking operation in progress to finish
0952: while (backupBlockingOperations > 0) {
0953: try {
0954: backupSemaphore.wait();
0955: } catch (InterruptedException ie) {
0956: // make sure we are not stuck in the backup state
0957: // if we caught an interrupt exception and the
0958: // calling thread may not have a chance to clear
0959: // the in backup state.
0960:
0961: inBackup = false;
0962: backupSemaphore.notifyAll();
0963: throw StandardException.interrupt(ie);
0964: }
0965: }
0966: } catch (RuntimeException rte) {
0967: // make sure we are not stuck in backup state if we
0968: // caught a run time exception and the calling thread may
0969: // not have a chance to clear the in backup state.
0970: inBackup = false;
0971: backupSemaphore.notifyAll();
0972: throw rte; // rethrow run time exception
0973: }
0974: } else {
0975: // check if any backup blocking operations that are in progress
0976: if (backupBlockingOperations == 0)
0977: inBackup = true;
0978: }
0979:
0980: }
0981:
0982: if (SanityManager.DEBUG) {
0983: if (inBackup) {
0984: SanityManager.ASSERT(backupBlockingOperations == 0,
0985: "store is not in correct state for backup");
0986: }
0987: }
0988:
0989: return inBackup;
0990: }
0991:
0992: /**
0993: * Backup completed. Allow backup blocking operations.
0994: */
0995: public void unblockBackupBlockingOperations() {
0996: synchronized (backupSemaphore) {
0997: inBackup = false;
0998: backupSemaphore.notifyAll();
0999: }
1000: }
1001:
1002: }
|