Source Code Cross Referenced for Txn.java in  » JMX » je » com » sleepycat » je » txn » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » JMX » je » com.sleepycat.je.txn 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*-
0002:         * See the file LICENSE for redistribution information.
0003:         *
0004:         * Copyright (c) 2002,2008 Oracle.  All rights reserved.
0005:         *
0006:         * $Id: Txn.java,v 1.148.2.9 2008/01/07 15:14:17 cwl Exp $
0007:         */
0008:
0009:        package com.sleepycat.je.txn;
0010:
0011:        import java.nio.ByteBuffer;
0012:        import java.util.ArrayList;
0013:        import java.util.HashMap;
0014:        import java.util.HashSet;
0015:        import java.util.Iterator;
0016:        import java.util.List;
0017:        import java.util.Map;
0018:        import java.util.Set;
0019:        import java.util.logging.Level;
0020:        import java.util.logging.Logger;
0021:
0022:        import javax.transaction.xa.XAResource;
0023:        import javax.transaction.xa.Xid;
0024:
0025:        import com.sleepycat.je.Database;
0026:        import com.sleepycat.je.DatabaseException;
0027:        import com.sleepycat.je.DbInternal;
0028:        import com.sleepycat.je.LockStats;
0029:        import com.sleepycat.je.RunRecoveryException;
0030:        import com.sleepycat.je.TransactionConfig;
0031:        import com.sleepycat.je.dbi.CursorImpl;
0032:        import com.sleepycat.je.dbi.DatabaseId;
0033:        import com.sleepycat.je.dbi.DatabaseImpl;
0034:        import com.sleepycat.je.dbi.EnvironmentImpl;
0035:        import com.sleepycat.je.dbi.MemoryBudget;
0036:        import com.sleepycat.je.log.LogEntryType;
0037:        import com.sleepycat.je.log.LogManager;
0038:        import com.sleepycat.je.log.LogUtils;
0039:        import com.sleepycat.je.log.Loggable;
0040:        import com.sleepycat.je.log.entry.LNLogEntry;
0041:        import com.sleepycat.je.log.entry.SingleItemEntry;
0042:        import com.sleepycat.je.recovery.RecoveryManager;
0043:        import com.sleepycat.je.tree.LN;
0044:        import com.sleepycat.je.tree.TreeLocation;
0045:        import com.sleepycat.je.utilint.DbLsn;
0046:        import com.sleepycat.je.utilint.Tracer;
0047:
0048:        /**
0049:         * A Txn is one that's created by a call to Environment.txnBegin.  This class
0050:         * must support multithreaded use.
0051:         */
0052:        public class Txn extends Locker implements  Loggable {
0053:            public static final byte TXN_NOSYNC = 0;
0054:            public static final byte TXN_WRITE_NOSYNC = 1;
0055:            public static final byte TXN_SYNC = 2;
0056:
0057:            private static final String DEBUG_NAME = Txn.class.getName();
0058:
0059:            private byte txnState;
0060:
0061:            /*
0062:             * Cursors opened under this txn. Implemented as a simple linked list to
0063:             * conserve on memory.
0064:             */
0065:            private CursorImpl cursorSet;
0066:
0067:            /* txnState bits. */
0068:            private static final byte USABLE = 0;
0069:            private static final byte CLOSED = 1;
0070:            private static final byte ONLY_ABORTABLE = 2;
0071:            private static final byte STATE_BITS = 3;
0072:            /* Set if prepare() has been called on this transaction. */
0073:            private static final byte IS_PREPARED = 4;
0074:            /* Set if xa_end(TMSUSPEND) has been called on this transaction. */
0075:            private static final byte XA_SUSPENDED = 8;
0076:
0077:            /*
0078:             * A Txn can be used by multiple threads. Modification to the read and
0079:             * write lock collections is done by synchronizing on the txn.
0080:             */
0081:            private Set readLocks; // Set<Long> (nodeIds)
0082:            private Map writeInfo; // key=nodeid, data = WriteLockInfo
0083:
0084:            private final int READ_LOCK_OVERHEAD = MemoryBudget.HASHSET_ENTRY_OVERHEAD;
0085:            private final int WRITE_LOCK_OVERHEAD = MemoryBudget.HASHMAP_ENTRY_OVERHEAD
0086:                    + MemoryBudget.WRITE_LOCKINFO_OVERHEAD;
0087:
0088:            /*
0089:             * We have to keep a set of DatabaseCleanupInfo objects so after
0090:             * commit or abort of Environment.truncateDatabase() or
0091:             * Environment.removeDatabase(), we can appropriately purge the
0092:             * unneeded MapLN and DatabaseImpl.
0093:             * Synchronize access to this set on this object.
0094:             */
0095:            private Set deletedDatabases;
0096:
0097:            /*
0098:             * We need a map of the latest databaseImpl objects to drive the undo
0099:             * during an abort, because it's too hard to look up the database object in
0100:             * the mapping tree. (The normal code paths want to take locks, add
0101:             * cursors, etc.
0102:             */
0103:            private Map undoDatabases;
0104:
0105:            /* Last LSN logged for this transaction. */
0106:            private long lastLoggedLsn = DbLsn.NULL_LSN;
0107:
0108:            /*
0109:             * First LSN logged for this transaction -- used for keeping track of the
0110:             * first active LSN point, for checkpointing. This field is not persistent.
0111:             */
0112:            private long firstLoggedLsn = DbLsn.NULL_LSN;
0113:
0114:            /* Whether to flush and sync on commit by default. */
0115:            private byte defaultFlushSyncBehavior;
0116:
0117:            /* Whether to use Serializable isolation (prevent phantoms). */
0118:            private boolean serializableIsolation;
0119:
0120:            /* Whether to use Read-Committed isolation. */
0121:            private boolean readCommittedIsolation;
0122:
0123:            /*
0124:             * In-memory size, in bytes. A Txn tracks the memory needed for itself and
0125:             * the readlock, writeInfo, undoDatabases, and deletedDatabases
0126:             * collections, including the cost of each collection entry. However, the
0127:             * actual Lock object memory cost is maintained within the Lock class.
0128:             */
0129:            private int inMemorySize;
0130:
0131:            /*
0132:             * accumluted memory budget delta.  Once this exceeds
0133:             * ACCUMULATED_LIMIT we inform the MemoryBudget that a change
0134:             * has occurred.
0135:             */
0136:            private int accumulatedDelta = 0;
0137:
0138:            /*
0139:             * Max allowable accumulation of memory budget changes before MemoryBudget
0140:             * should be updated. This allows for consolidating multiple calls to
0141:             * updateXXXMemoryBudget() into one call.  Not declared final so that unit
0142:             * tests can modify this.  See SR 12273.
0143:             */
0144:            public static int ACCUMULATED_LIMIT = 10000;
0145:
0146:            /**
0147:             * Create a transaction from Environment.txnBegin.
0148:             */
0149:            public Txn(EnvironmentImpl envImpl, TransactionConfig config)
0150:                    throws DatabaseException {
0151:
0152:                /*
0153:                 * Initialize using the config but don't hold a reference to it, since
0154:                 * it has not been cloned.
0155:                 */
0156:                super (envImpl, config.getReadUncommitted(), config.getNoWait());
0157:                init(envImpl, config);
0158:            }
0159:
0160:            public Txn(EnvironmentImpl envImpl, TransactionConfig config,
0161:                    long id) throws DatabaseException {
0162:
0163:                /*
0164:                 * Initialize using the config but don't hold a reference to it, since
0165:                 * it has not been cloned.
0166:                 */
0167:                super (envImpl, config.getReadUncommitted(), config.getNoWait());
0168:                init(envImpl, config);
0169:
0170:                this .id = id;
0171:            }
0172:
0173:            private void init(EnvironmentImpl envImpl, TransactionConfig config)
0174:                    throws DatabaseException {
0175:
0176:                serializableIsolation = config.getSerializableIsolation();
0177:                readCommittedIsolation = config.getReadCommitted();
0178:
0179:                /*
0180:                 * Figure out what we should do on commit. TransactionConfig could be
0181:                 * set with conflicting values; take the most stringent ones first.
0182:                 * All environment level defaults were applied by the caller.
0183:                 *
0184:                 * ConfigSync  ConfigWriteNoSync ConfigNoSync   default
0185:                 *    0                 0             0         sync
0186:                 *    0                 0             1         nosync
0187:                 *    0                 1             0         write nosync
0188:                 *    0                 1             1         write nosync
0189:                 *    1                 0             0         sync
0190:                 *    1                 0             1         sync
0191:                 *    1                 1             0         sync
0192:                 *    1                 1             1         sync
0193:                 */
0194:                if (config.getSync()) {
0195:                    defaultFlushSyncBehavior = TXN_SYNC;
0196:                } else if (config.getWriteNoSync()) {
0197:                    defaultFlushSyncBehavior = TXN_WRITE_NOSYNC;
0198:                } else if (config.getNoSync()) {
0199:                    defaultFlushSyncBehavior = TXN_NOSYNC;
0200:                } else {
0201:                    defaultFlushSyncBehavior = TXN_SYNC;
0202:                }
0203:
0204:                lastLoggedLsn = DbLsn.NULL_LSN;
0205:                firstLoggedLsn = DbLsn.NULL_LSN;
0206:
0207:                txnState = USABLE;
0208:
0209:                /*
0210:                 * Note: readLocks, writeInfo, undoDatabases, deleteDatabases are
0211:                 * initialized lazily in order to conserve memory. WriteInfo and
0212:                 * undoDatabases are treated as a package deal, because they are both
0213:                 * only needed if a transaction does writes.
0214:                 *
0215:                 * When a lock is added to this transaction, we add the collection
0216:                 * entry overhead to the memory cost, but don't add the lock
0217:                 * itself. That's taken care of by the Lock class.
0218:                 */
0219:                updateMemoryUsage(MemoryBudget.TXN_OVERHEAD);
0220:
0221:                this .envImpl.getTxnManager().registerTxn(this );
0222:            }
0223:
0224:            /**
0225:             * Constructor for reading from log.
0226:             */
0227:            public Txn() {
0228:                lastLoggedLsn = DbLsn.NULL_LSN;
0229:            }
0230:
0231:            /**
0232:             * UserTxns get a new unique id for each instance.
0233:             */
0234:            protected long generateId(TxnManager txnManager) {
0235:                return txnManager.incTxnId();
0236:            }
0237:
0238:            /**
0239:             * Access to last LSN.
0240:             */
0241:            long getLastLsn() {
0242:                return lastLoggedLsn;
0243:            }
0244:
0245:            public boolean getPrepared() {
0246:                return (txnState & IS_PREPARED) != 0;
0247:            }
0248:
0249:            public void setPrepared(boolean prepared) {
0250:                if (prepared) {
0251:                    txnState |= IS_PREPARED;
0252:                } else {
0253:                    txnState &= ~IS_PREPARED;
0254:                }
0255:            }
0256:
0257:            public void setSuspended(boolean suspended) {
0258:                if (suspended) {
0259:                    txnState |= XA_SUSPENDED;
0260:                } else {
0261:                    txnState &= ~XA_SUSPENDED;
0262:                }
0263:            }
0264:
0265:            public boolean isSuspended() {
0266:                return (txnState & XA_SUSPENDED) != 0;
0267:            }
0268:
0269:            /**
0270:             * Gets a lock on this nodeId and, if it is a write lock, saves an abort
0271:             * LSN.  Caller will set the abortLsn later, after the write lock has been
0272:             * obtained.
0273:             *
0274:             * @see Locker#lockInternal
0275:             * @Override
0276:             */
0277:            LockResult lockInternal(long nodeId, LockType lockType,
0278:                    boolean noWait, DatabaseImpl database)
0279:                    throws DatabaseException {
0280:
0281:                long timeout = 0;
0282:                boolean useNoWait = noWait || defaultNoWait;
0283:                synchronized (this ) {
0284:                    checkState(false);
0285:                    if (!useNoWait) {
0286:                        timeout = lockTimeOutMillis;
0287:                    }
0288:                }
0289:
0290:                /* Ask for the lock. */
0291:                LockGrantType grant = lockManager.lock(nodeId, this , lockType,
0292:                        timeout, useNoWait, database);
0293:
0294:                WriteLockInfo info = null;
0295:                if (writeInfo != null) {
0296:                    if (grant != LockGrantType.DENIED && lockType.isWriteLock()) {
0297:                        synchronized (this ) {
0298:                            info = (WriteLockInfo) writeInfo.get(new Long(
0299:                                    nodeId));
0300:                            /* Save the latest version of this database for undoing. */
0301:                            undoDatabases.put(database.getId(), database);
0302:                        }
0303:                    }
0304:                }
0305:
0306:                return new LockResult(grant, info);
0307:            }
0308:
0309:            public int prepare(Xid xid) throws DatabaseException {
0310:
0311:                if ((txnState & IS_PREPARED) != 0) {
0312:                    throw new DatabaseException(
0313:                            "prepare() has already been called for Transaction "
0314:                                    + id + ".");
0315:                }
0316:                synchronized (this ) {
0317:                    checkState(false);
0318:                    if (checkCursorsForClose()) {
0319:                        throw new DatabaseException(
0320:                                "Transaction "
0321:                                        + id
0322:                                        + " prepare failed because there were open cursors.");
0323:                    }
0324:
0325:                    setPrepared(true);
0326:                    if (writeInfo == null) {
0327:                        return XAResource.XA_RDONLY;
0328:                    }
0329:
0330:                    SingleItemEntry prepareEntry = new SingleItemEntry(
0331:                            LogEntryType.LOG_TXN_PREPARE, new TxnPrepare(id,
0332:                                    xid));
0333:                    /* Flush required. */
0334:                    LogManager logManager = envImpl.getLogManager();
0335:                    logManager.logForceFlush(prepareEntry, true); // sync required
0336:                }
0337:                return XAResource.XA_OK;
0338:            }
0339:
0340:            public void commit(Xid xid) throws DatabaseException {
0341:
0342:                commit(TXN_SYNC);
0343:                envImpl.getTxnManager().unRegisterXATxn(xid, true);
0344:                return;
0345:            }
0346:
0347:            public void abort(Xid xid) throws DatabaseException {
0348:
0349:                abort(true);
0350:                envImpl.getTxnManager().unRegisterXATxn(xid, false);
0351:                return;
0352:            }
0353:
0354:            /**
0355:             * Call commit() with the default sync configuration property.
0356:             */
0357:            public long commit() throws DatabaseException {
0358:
0359:                return commit(defaultFlushSyncBehavior);
0360:            }
0361:
0362:            /**
0363:             * Commit this transaction
0364:             * 1. Releases read locks
0365:             * 2. Writes a txn commit record into the log
0366:             * 3. Flushes the log to disk.
0367:             * 4. Add deleted LN info to IN compressor queue
0368:             * 5. Release all write locks
0369:             *
0370:             * If any step of this fails, we must convert this transaction to an abort.
0371:             */
0372:            public long commit(byte flushSyncBehavior) throws DatabaseException {
0373:
0374:                try {
0375:                    long commitLsn = DbLsn.NULL_LSN;
0376:                    synchronized (this ) {
0377:                        checkState(false);
0378:                        if (checkCursorsForClose()) {
0379:                            throw new DatabaseException(
0380:                                    "Transaction "
0381:                                            + id
0382:                                            + " commit failed because there were open cursors.");
0383:                        }
0384:
0385:                        /*
0386:                         * Save transferred write locks, if any.  Their abort LSNs are
0387:                         * counted as obsolete further below.  Create the list lazily
0388:                         * to avoid creating it in the normal case (no handle locks).
0389:                         */
0390:                        List transferredWriteLockInfo = null;
0391:
0392:                        /* Transfer handle locks to their owning handles. */
0393:                        if (handleLockToHandleMap != null) {
0394:                            Iterator handleLockIter = handleLockToHandleMap
0395:                                    .entrySet().iterator();
0396:                            while (handleLockIter.hasNext()) {
0397:                                Map.Entry entry = (Map.Entry) handleLockIter
0398:                                        .next();
0399:                                Long nodeId = (Long) entry.getKey();
0400:                                if (writeInfo != null) {
0401:                                    WriteLockInfo info = (WriteLockInfo) writeInfo
0402:                                            .get(nodeId);
0403:                                    if (info != null) {
0404:                                        if (transferredWriteLockInfo == null) {
0405:                                            transferredWriteLockInfo = new ArrayList();
0406:                                        }
0407:                                        transferredWriteLockInfo.add(info);
0408:                                    }
0409:                                }
0410:                                transferHandleLockToHandleSet(nodeId,
0411:                                        (Set) entry.getValue());
0412:                            }
0413:                        }
0414:
0415:                        LogManager logManager = envImpl.getLogManager();
0416:
0417:                        /*
0418:                         * Release all read locks, clear lock collection. Optimize for
0419:                         * the case where there are no read locks.
0420:                         */
0421:                        int numReadLocks = clearReadLocks();
0422:
0423:                        /*
0424:                         * Log the commit if we ever held any write locks. Note that
0425:                         * with dbhandle write locks, we may have held the write lock
0426:                         * but then had it transferred away.
0427:                         */
0428:                        int numWriteLocks = 0;
0429:                        if (writeInfo != null) {
0430:                            numWriteLocks = writeInfo.size();
0431:                            SingleItemEntry commitEntry = new SingleItemEntry(
0432:                                    LogEntryType.LOG_TXN_COMMIT, new TxnCommit(
0433:                                            id, lastLoggedLsn));
0434:                            if (flushSyncBehavior == TXN_SYNC) {
0435:                                /* Flush and sync required. */
0436:                                commitLsn = logManager.logForceFlush(
0437:                                        commitEntry, true);
0438:                            } else if (flushSyncBehavior == TXN_WRITE_NOSYNC) {
0439:                                /* Flush but no sync required. */
0440:                                commitLsn = logManager.logForceFlush(
0441:                                        commitEntry, false);
0442:                            } else {
0443:                                /* No flush, no sync required. */
0444:                                commitLsn = logManager.log(commitEntry);
0445:                            }
0446:
0447:                            /*
0448:                             * Set database state for deletes before releasing any
0449:                             * write locks.
0450:                             */
0451:                            setDeletedDatabaseState(true);
0452:
0453:                            /*
0454:                             * Used to prevent double counting abortLNS if there is
0455:                             * more then one node with the same abortLSN in this txn.
0456:                             * Two nodes with the same abortLSN occur when a deleted
0457:                             * slot is reused in the same txn.
0458:                             */
0459:                            Set alreadyCountedLsnSet = new HashSet();
0460:
0461:                            /* Release all write locks, clear lock collection. */
0462:                            Iterator iter = writeInfo.entrySet().iterator();
0463:                            while (iter.hasNext()) {
0464:                                Map.Entry entry = (Map.Entry) iter.next();
0465:                                Long nodeId = (Long) entry.getKey();
0466:                                lockManager.release(nodeId.longValue(), this );
0467:                                countWriteAbortLSN((WriteLockInfo) entry
0468:                                        .getValue(), alreadyCountedLsnSet);
0469:                            }
0470:                            writeInfo = null;
0471:
0472:                            /* Count obsolete LSNs for transferred write locks. */
0473:                            if (transferredWriteLockInfo != null) {
0474:                                for (int i = 0; i < transferredWriteLockInfo
0475:                                        .size(); i += 1) {
0476:                                    WriteLockInfo info = (WriteLockInfo) transferredWriteLockInfo
0477:                                            .get(i);
0478:                                    countWriteAbortLSN(info,
0479:                                            alreadyCountedLsnSet);
0480:                                }
0481:                            }
0482:
0483:                            /* Unload delete info, but don't wake up the compressor. */
0484:                            if ((deleteInfo != null) && deleteInfo.size() > 0) {
0485:                                envImpl.addToCompressorQueue(deleteInfo
0486:                                        .values(), false); // don't wakeup
0487:                                deleteInfo.clear();
0488:                            }
0489:                        }
0490:
0491:                        traceCommit(numWriteLocks, numReadLocks);
0492:                    }
0493:
0494:                    /*
0495:                     * Purge any databaseImpls not needed as a result of the commit.
0496:                     * Be sure to do this outside the synchronization block, to avoid
0497:                     * conflict w/checkpointer.
0498:                     */
0499:                    cleanupDatabaseImpls(true);
0500:
0501:                    /*
0502:                     * Unregister this txn. Be sure to do this outside the
0503:                     * synchronization block, to avoid conflict w/checkpointer.
0504:                     */
0505:                    close(true);
0506:                    return commitLsn;
0507:                } catch (RunRecoveryException e) {
0508:
0509:                    /* May have received a thread interrupt. */
0510:                    throw e;
0511:                } catch (Error e) {
0512:                    envImpl.invalidate(e);
0513:                    throw e;
0514:                } catch (Exception t) {
0515:
0516:                    try {
0517:
0518:                        /*
0519:                         * If the exception thrown is a DatabaseException it indicates
0520:                         * that the write() call hit an IOException, probably out of
0521:                         * disk space, and attempted to rewrite all commit records as
0522:                         * abort records.  Since the abort records are already
0523:                         * rewritten (or at least attempted to be rewritten), there is
0524:                         * no reason to have abort attempt to write an abort record
0525:                         * again.  See [11271].
0526:                         */
0527:                        abortInternal(flushSyncBehavior == TXN_SYNC,
0528:                                !(t instanceof  DatabaseException));
0529:                        Tracer.trace(envImpl, "Txn", "commit",
0530:                                "Commit of transaction " + id + " failed", t);
0531:                    } catch (Error e) {
0532:                        envImpl.invalidate(e);
0533:                        throw e;
0534:                    } catch (Exception abortT2) {
0535:                        throw new DatabaseException(
0536:                                "Failed while attempting to commit transaction "
0537:                                        + id
0538:                                        + ". The attempt to abort and clean up also failed. "
0539:                                        + "The original exception seen from commit = "
0540:                                        + t.getMessage()
0541:                                        + " The exception from the cleanup = "
0542:                                        + abortT2.getMessage(), t);
0543:                    }
0544:
0545:                    /* Now throw an exception that shows the commit problem. */
0546:                    throw new DatabaseException(
0547:                            "Failed while attempting to commit transaction "
0548:                                    + id
0549:                                    + ", aborted instead. Original exception = "
0550:                                    + t.getMessage(), t);
0551:                }
0552:            }
0553:
0554:            /**
0555:             * Count the abortLSN as obsolete.  Do not count if a slot with a deleted
0556:             * LN was reused (abortKnownDeleted), to avoid double counting.  And count
0557:             * each abortLSN only once.
0558:             */
0559:            private void countWriteAbortLSN(WriteLockInfo info,
0560:                    Set alreadyCountedLsnSet) throws DatabaseException {
0561:
0562:                if (info.abortLsn != DbLsn.NULL_LSN && !info.abortKnownDeleted) {
0563:                    Long longLsn = new Long(info.abortLsn);
0564:                    if (!alreadyCountedLsnSet.contains(longLsn)) {
0565:                        envImpl.getLogManager().countObsoleteNode(
0566:                                info.abortLsn, null, info.abortLogSize);
0567:                        alreadyCountedLsnSet.add(longLsn);
0568:                    }
0569:                }
0570:            }
0571:
0572:            /**
0573:             * Abort this transaction. Steps are:
0574:             * 1. Release LN read locks.
0575:             * 2. Write a txn abort entry to the log. This is only for log
0576:             *    file cleaning optimization and there's no need to guarantee a
0577:             *    flush to disk.
0578:             * 3. Find the last LN log entry written for this txn, and use that
0579:             *    to traverse the log looking for nodes to undo. For each node,
0580:             *    use the same undo logic as recovery to rollback the transaction. Note
0581:             *    that we walk the log in order to undo in reverse order of the
0582:             *    actual operations. For example, suppose the txn did this:
0583:             *       delete K1/D1 (in LN 10)
0584:             *       create K1/D1 (in LN 20)
0585:             *    If we process LN10 before LN 20, we'd inadvertently create a
0586:             *    duplicate tree of "K1", which would be fatal for the mapping tree.
0587:             * 4. Release the write lock for this LN.
0588:             */
0589:            public long abort(boolean forceFlush) throws DatabaseException {
0590:
0591:                return abortInternal(forceFlush, true);
0592:            }
0593:
0594:            private long abortInternal(boolean forceFlush,
0595:                    boolean writeAbortRecord) throws DatabaseException {
0596:
0597:                try {
0598:                    int numReadLocks;
0599:                    int numWriteLocks;
0600:                    long abortLsn;
0601:
0602:                    synchronized (this ) {
0603:                        checkState(true);
0604:
0605:                        /* Log the abort. */
0606:                        SingleItemEntry abortEntry = new SingleItemEntry(
0607:                                LogEntryType.LOG_TXN_ABORT, new TxnAbort(id,
0608:                                        lastLoggedLsn));
0609:                        abortLsn = DbLsn.NULL_LSN;
0610:                        if (writeInfo != null) {
0611:                            if (writeAbortRecord) {
0612:                                if (forceFlush) {
0613:                                    abortLsn = envImpl.getLogManager()
0614:                                            .logForceFlush(abortEntry, true);
0615:                                } else {
0616:                                    abortLsn = envImpl.getLogManager().log(
0617:                                            abortEntry);
0618:                                }
0619:                            }
0620:                        }
0621:
0622:                        /* Undo the changes. */
0623:                        undo();
0624:
0625:                        /*
0626:                         * Release all read locks after the undo (since the undo may
0627:                         * need to read in mapLNs).
0628:                         */
0629:                        numReadLocks = (readLocks == null) ? 0
0630:                                : clearReadLocks();
0631:
0632:                        /*
0633:                         * Set database state for deletes before releasing any write
0634:                         * locks.
0635:                         */
0636:                        setDeletedDatabaseState(false);
0637:
0638:                        /* Throw away write lock collection. */
0639:                        numWriteLocks = (writeInfo == null) ? 0
0640:                                : clearWriteLocks();
0641:
0642:                        /*
0643:                         * Let the delete related info (binreferences and dbs) get
0644:                         * gc'ed. Don't explicitly iterate and clear -- that's far less
0645:                         * efficient, gives GC wrong input.
0646:                         */
0647:                        deleteInfo = null;
0648:                    }
0649:
0650:                    /*
0651:                     * Purge any databaseImpls not needed as a result of the abort.  Be
0652:                     * sure to do this outside the synchronization block, to avoid
0653:                     * conflict w/checkpointer.
0654:                     */
0655:                    cleanupDatabaseImpls(false);
0656:
0657:                    synchronized (this ) {
0658:                        boolean openCursors = checkCursorsForClose();
0659:                        Tracer.trace(Level.FINE, envImpl, "Abort:id = " + id
0660:                                + " numWriteLocks= " + numWriteLocks
0661:                                + " numReadLocks= " + numReadLocks
0662:                                + " openCursors= " + openCursors);
0663:                        if (openCursors) {
0664:                            throw new DatabaseException("Transaction " + id
0665:                                    + " detected open cursors while aborting");
0666:                        }
0667:                        /* Unload any db handles protected by this txn. */
0668:                        if (handleToHandleLockMap != null) {
0669:                            Iterator handleIter = handleToHandleLockMap
0670:                                    .keySet().iterator();
0671:                            while (handleIter.hasNext()) {
0672:                                Database handle = (Database) handleIter.next();
0673:                                DbInternal.dbInvalidate(handle);
0674:                            }
0675:                        }
0676:
0677:                        return abortLsn;
0678:                    }
0679:                } finally {
0680:
0681:                    /*
0682:                     * Unregister this txn, must be done outside synchronization block
0683:                     * to avoid conflict w/checkpointer.
0684:                     */
0685:                    close(false);
0686:                }
0687:            }
0688:
0689:            /**
0690:             * Rollback the changes to this txn's write locked nodes.
0691:             */
0692:            private void undo() throws DatabaseException {
0693:
0694:                Long nodeId = null;
0695:                long undoLsn = lastLoggedLsn;
0696:                LogManager logManager = envImpl.getLogManager();
0697:
0698:                try {
0699:                    Set alreadyUndone = new HashSet();
0700:                    TreeLocation location = new TreeLocation();
0701:                    while (undoLsn != DbLsn.NULL_LSN) {
0702:
0703:                        LNLogEntry undoEntry = (LNLogEntry) logManager
0704:                                .getLogEntry(undoLsn);
0705:                        LN undoLN = undoEntry.getLN();
0706:                        nodeId = new Long(undoLN.getNodeId());
0707:
0708:                        /*
0709:                         * Only process this if this is the first time we've seen this
0710:                         * node. All log entries for a given node have the same
0711:                         * abortLsn, so we don't need to undo it multiple times.
0712:                         */
0713:                        if (!alreadyUndone.contains(nodeId)) {
0714:                            alreadyUndone.add(nodeId);
0715:                            DatabaseId dbId = undoEntry.getDbId();
0716:                            DatabaseImpl db = (DatabaseImpl) undoDatabases
0717:                                    .get(dbId);
0718:                            undoLN.postFetchInit(db, undoLsn);
0719:                            long abortLsn = undoEntry.getAbortLsn();
0720:                            boolean abortKnownDeleted = undoEntry
0721:                                    .getAbortKnownDeleted();
0722:                            try {
0723:                                RecoveryManager.undo(Level.FINER, db, location,
0724:                                        undoLN, undoEntry.getKey(), undoEntry
0725:                                                .getDupKey(), undoLsn,
0726:                                        abortLsn, abortKnownDeleted, null,
0727:                                        false);
0728:                            } finally {
0729:                                if (location.bin != null) {
0730:                                    location.bin.releaseLatchIfOwner();
0731:                                }
0732:                            }
0733:
0734:                            /*
0735:                             * The LN undone is counted as obsolete if it is not a
0736:                             * deleted LN.  Deleted LNs are counted as obsolete when
0737:                             * they are logged.
0738:                             */
0739:                            if (!undoLN.isDeleted()) {
0740:                                logManager.countObsoleteNode(undoLsn, null, // type
0741:                                        undoLN.getLastLoggedSize());
0742:                            }
0743:                        }
0744:
0745:                        /* Move on to the previous log entry for this txn. */
0746:                        undoLsn = undoEntry.getUserTxn().getLastLsn();
0747:                    }
0748:                } catch (RuntimeException e) {
0749:                    throw new DatabaseException("Txn undo for node=" + nodeId
0750:                            + " LSN=" + DbLsn.getNoFormatString(undoLsn), e);
0751:                } catch (DatabaseException e) {
0752:                    Tracer.trace(envImpl, "Txn", "undo", "for node=" + nodeId
0753:                            + " LSN=" + DbLsn.getNoFormatString(undoLsn), e);
0754:                    throw e;
0755:                }
0756:            }
0757:
0758:            private int clearWriteLocks() throws DatabaseException {
0759:
0760:                int numWriteLocks = writeInfo.size();
0761:
0762:                /* Release all write locks, clear lock collection. */
0763:                Iterator iter = writeInfo.entrySet().iterator();
0764:                while (iter.hasNext()) {
0765:                    Map.Entry entry = (Map.Entry) iter.next();
0766:                    Long nodeId = (Long) entry.getKey();
0767:                    lockManager.release(nodeId.longValue(), this );
0768:                }
0769:                writeInfo = null;
0770:                return numWriteLocks;
0771:            }
0772:
0773:            private int clearReadLocks() throws DatabaseException {
0774:
0775:                int numReadLocks = 0;
0776:                if (readLocks != null) {
0777:                    numReadLocks = readLocks.size();
0778:                    Iterator iter = readLocks.iterator();
0779:                    while (iter.hasNext()) {
0780:                        Long rLock = (Long) iter.next();
0781:                        lockManager.release(rLock.longValue(), this );
0782:                    }
0783:                    readLocks = null;
0784:                }
0785:                return numReadLocks;
0786:            }
0787:
0788:            /**
0789:             * Called by the recovery manager when logging a transaction aware object.
0790:             * This method is synchronized by the caller, by being called within the
0791:             * log latch. Record the last LSN for this transaction, to create the
0792:             * transaction chain, and also record the LSN in the write info for abort
0793:             * logic.
0794:             */
0795:            public void addLogInfo(long lastLsn) throws DatabaseException {
0796:
0797:                /* Save the last LSN  for maintaining the transaction LSN chain. */
0798:                lastLoggedLsn = lastLsn;
0799:
0800:                /* Save handle to LSN for aborts. */
0801:                synchronized (this ) {
0802:
0803:                    /*
0804:                     * If this is the first LSN, save it for calculating the first LSN
0805:                     * of any active txn, for checkpointing.
0806:                     */
0807:                    if (firstLoggedLsn == DbLsn.NULL_LSN) {
0808:                        firstLoggedLsn = lastLsn;
0809:                    }
0810:                }
0811:            }
0812:
0813:            /**
0814:             * @return first logged LSN, to aid recovery rollback.
0815:             */
0816:            long getFirstActiveLsn() throws DatabaseException {
0817:
0818:                synchronized (this ) {
0819:                    return firstLoggedLsn;
0820:                }
0821:            }
0822:
0823:            /**
0824:             * @param dbImpl databaseImpl to remove
0825:             * @param deleteAtCommit true if this databaseImpl should be cleaned on
0826:             *    commit, false if it should be cleaned on abort.
0827:             * @param mb environment memory budget.
0828:             */
0829:            public void markDeleteAtTxnEnd(DatabaseImpl dbImpl,
0830:                    boolean deleteAtCommit) throws DatabaseException {
0831:
0832:                synchronized (this ) {
0833:                    int delta = 0;
0834:                    if (deletedDatabases == null) {
0835:                        deletedDatabases = new HashSet();
0836:                        delta += MemoryBudget.HASHSET_OVERHEAD;
0837:                    }
0838:
0839:                    deletedDatabases.add(new DatabaseCleanupInfo(dbImpl,
0840:                            deleteAtCommit));
0841:                    delta += MemoryBudget.HASHSET_ENTRY_OVERHEAD
0842:                            + MemoryBudget.OBJECT_OVERHEAD;
0843:                    updateMemoryUsage(delta);
0844:
0845:                    /* releaseDb will be called by cleanupDatabaseImpls. */
0846:                }
0847:            }
0848:
0849:            /*
0850:             * Leftover databaseImpls that are a by-product of database operations like
0851:             * removeDatabase(), truncateDatabase() will be deleted after the write
0852:             * locks are released. However, do set the database state appropriately
0853:             * before the locks are released.
0854:             */
0855:            private void setDeletedDatabaseState(boolean isCommit)
0856:                    throws DatabaseException {
0857:
0858:                if (deletedDatabases != null) {
0859:                    Iterator iter = deletedDatabases.iterator();
0860:                    while (iter.hasNext()) {
0861:                        DatabaseCleanupInfo info = (DatabaseCleanupInfo) iter
0862:                                .next();
0863:                        if (info.deleteAtCommit == isCommit) {
0864:                            info.dbImpl.startDeleteProcessing();
0865:                        }
0866:                    }
0867:                }
0868:            }
0869:
0870:            /**
0871:             * Cleanup leftover databaseImpls that are a by-product of database
0872:             * operations like removeDatabase(), truncateDatabase().
0873:             *
0874:             * This method must be called outside the synchronization on this txn,
0875:             * because it calls releaseDeletedINs, which gets the TxnManager's
0876:             * allTxns latch. The checkpointer also gets the allTxns latch, and within
0877:             * that latch, needs to synchronize on individual txns, so we must avoid a
0878:             * latching hiearchy conflict.
0879:             */
0880:            private void cleanupDatabaseImpls(boolean isCommit)
0881:                    throws DatabaseException {
0882:
0883:                if (deletedDatabases != null) {
0884:                    /* Make a copy of the deleted databases while synchronized. */
0885:                    DatabaseCleanupInfo[] infoArray;
0886:                    synchronized (this ) {
0887:                        infoArray = new DatabaseCleanupInfo[deletedDatabases
0888:                                .size()];
0889:                        deletedDatabases.toArray(infoArray);
0890:                    }
0891:                    for (int i = 0; i < infoArray.length; i += 1) {
0892:                        DatabaseCleanupInfo info = infoArray[i];
0893:                        if (info.deleteAtCommit == isCommit) {
0894:                            /* releaseDb will be called by releaseDeletedINs. */
0895:                            info.dbImpl.releaseDeletedINs();
0896:                        } else {
0897:                            envImpl.releaseDb(info.dbImpl);
0898:                        }
0899:                    }
0900:                    deletedDatabases = null;
0901:                }
0902:            }
0903:
0904:            /**
0905:             * Add lock to the appropriate queue.
0906:             */
0907:            void addLock(Long nodeId, LockType type, LockGrantType grantStatus)
0908:                    throws DatabaseException {
0909:
0910:                synchronized (this ) {
0911:                    int delta = 0;
0912:                    if (type.isWriteLock()) {
0913:                        if (writeInfo == null) {
0914:                            writeInfo = new HashMap();
0915:                            undoDatabases = new HashMap();
0916:                            delta += MemoryBudget.TWOHASHMAPS_OVERHEAD;
0917:                        }
0918:
0919:                        writeInfo.put(nodeId, new WriteLockInfo());
0920:                        delta += WRITE_LOCK_OVERHEAD;
0921:
0922:                        if ((grantStatus == LockGrantType.PROMOTION)
0923:                                || (grantStatus == LockGrantType.WAIT_PROMOTION)) {
0924:                            readLocks.remove(nodeId);
0925:                            delta -= READ_LOCK_OVERHEAD;
0926:                        }
0927:                        updateMemoryUsage(delta);
0928:                    } else {
0929:                        addReadLock(nodeId);
0930:                    }
0931:                }
0932:            }
0933:
0934:            private void addReadLock(Long nodeId) {
0935:                int delta = 0;
0936:                if (readLocks == null) {
0937:                    readLocks = new HashSet();
0938:                    delta = MemoryBudget.HASHSET_OVERHEAD;
0939:                }
0940:
0941:                readLocks.add(nodeId);
0942:                delta += READ_LOCK_OVERHEAD;
0943:                updateMemoryUsage(delta);
0944:            }
0945:
0946:            /**
0947:             * Remove the lock from the set owned by this transaction. If specified to
0948:             * LockManager.release, the lock manager will call this when its releasing
0949:             * a lock. Usually done because the transaction doesn't need to really keep
0950:             * the lock, i.e for a deleted record.
0951:             */
0952:            void removeLock(long nodeId) throws DatabaseException {
0953:
0954:                /*
0955:                 * We could optimize by passing the lock type so we know which
0956:                 * collection to look in. Be careful of demoted locks, which have
0957:                 * shifted collection.
0958:                 *
0959:                 * Don't bother updating memory utilization here -- we'll update at
0960:                 * transaction end.
0961:                 */
0962:                synchronized (this ) {
0963:                    if ((readLocks != null)
0964:                            && readLocks.remove(new Long(nodeId))) {
0965:                        updateMemoryUsage(0 - READ_LOCK_OVERHEAD);
0966:                    } else if ((writeInfo != null)
0967:                            && (writeInfo.remove(new Long(nodeId)) != null)) {
0968:                        updateMemoryUsage(0 - WRITE_LOCK_OVERHEAD);
0969:                    }
0970:                }
0971:            }
0972:
0973:            /**
0974:             * A lock is being demoted. Move it from the write collection into the read
0975:             * collection.
0976:             */
0977:            void moveWriteToReadLock(long nodeId, Lock lock) {
0978:
0979:                boolean found = false;
0980:                synchronized (this ) {
0981:                    if ((writeInfo != null)
0982:                            && (writeInfo.remove(new Long(nodeId)) != null)) {
0983:                        found = true;
0984:                        updateMemoryUsage(0 - WRITE_LOCK_OVERHEAD);
0985:                    }
0986:
0987:                    assert found : "Couldn't find lock for Node " + nodeId
0988:                            + " in writeInfo Map.";
0989:                    addReadLock(new Long(nodeId));
0990:                }
0991:            }
0992:
0993:            private void updateMemoryUsage(int delta) {
0994:                inMemorySize += delta;
0995:                accumulatedDelta += delta;
0996:                if (accumulatedDelta > ACCUMULATED_LIMIT
0997:                        || accumulatedDelta < -ACCUMULATED_LIMIT) {
0998:                    envImpl.getMemoryBudget().updateMiscMemoryUsage(
0999:                            accumulatedDelta);
1000:                    accumulatedDelta = 0;
1001:                }
1002:            }
1003:
1004:            int getAccumulatedDelta() {
1005:                return accumulatedDelta;
1006:            }
1007:
1008:            /**
1009:             * @return true if this transaction created this node. We know that this
1010:             * is true if the node is write locked and has a null abort LSN.
1011:             */
1012:            public boolean createdNode(long nodeId) throws DatabaseException {
1013:
1014:                boolean created = false;
1015:                synchronized (this ) {
1016:                    if (writeInfo != null) {
1017:                        WriteLockInfo info = (WriteLockInfo) writeInfo
1018:                                .get(new Long(nodeId));
1019:                        if (info != null) {
1020:                            created = info.createdThisTxn;
1021:                        }
1022:                    }
1023:                }
1024:                return created;
1025:            }
1026:
1027:            /**
1028:             * @return the abortLsn for this node.
1029:             */
1030:            public long getAbortLsn(long nodeId) throws DatabaseException {
1031:
1032:                WriteLockInfo info = null;
1033:                synchronized (this ) {
1034:                    if (writeInfo != null) {
1035:                        info = (WriteLockInfo) writeInfo.get(new Long(nodeId));
1036:                    }
1037:                }
1038:
1039:                if (info == null) {
1040:                    return DbLsn.NULL_LSN;
1041:                } else {
1042:                    return info.abortLsn;
1043:                }
1044:            }
1045:
1046:            /**
1047:             * @return the WriteLockInfo for this node.
1048:             */
1049:            public WriteLockInfo getWriteLockInfo(long nodeId)
1050:                    throws DatabaseException {
1051:
1052:                WriteLockInfo info = WriteLockInfo.basicWriteLockInfo;
1053:                synchronized (this ) {
1054:                    if (writeInfo != null) {
1055:                        info = (WriteLockInfo) writeInfo.get(new Long(nodeId));
1056:                    }
1057:                }
1058:
1059:                return info;
1060:            }
1061:
1062:            /**
1063:             * Is always transactional.
1064:             */
1065:            public boolean isTransactional() {
1066:                return true;
1067:            }
1068:
1069:            /**
1070:             * Is serializable isolation if so configured.
1071:             */
1072:            public boolean isSerializableIsolation() {
1073:                return serializableIsolation;
1074:            }
1075:
1076:            /**
1077:             * Is read-committed isolation if so configured.
1078:             */
1079:            public boolean isReadCommittedIsolation() {
1080:                return readCommittedIsolation;
1081:            }
1082:
1083:            /**
1084:             * This is a transactional locker.
1085:             */
1086:            public Txn getTxnLocker() {
1087:                return this ;
1088:            }
1089:
1090:            /**
1091:             * Returns 'this', since this locker holds no non-transactional locks.
1092:             */
1093:            public Locker newNonTxnLocker() throws DatabaseException {
1094:
1095:                return this ;
1096:            }
1097:
1098:            /**
1099:             * This locker holds no non-transactional locks.
1100:             */
1101:            public void releaseNonTxnLocks() throws DatabaseException {
1102:            }
1103:
1104:            /**
1105:             * Created transactions do nothing at the end of the operation.
1106:             */
1107:            public void operationEnd() throws DatabaseException {
1108:            }
1109:
1110:            /**
1111:             * Created transactions do nothing at the end of the operation.
1112:             */
1113:            public void operationEnd(boolean operationOK)
1114:                    throws DatabaseException {
1115:            }
1116:
1117:            /**
1118:             * Created transactions don't transfer locks until commit.
1119:             */
1120:            public void setHandleLockOwner(boolean ignore /*operationOK*/,
1121:                    Database dbHandle, boolean dbIsClosing)
1122:                    throws DatabaseException {
1123:
1124:                if (dbIsClosing) {
1125:
1126:                    /*
1127:                     * If the Database handle is closing, take it out of the both the
1128:                     * handle lock map and the handle map. We don't need to do any
1129:                     * transfers at commit time, and we don't need to do any
1130:                     * invalidations at abort time.
1131:                     */
1132:                    Long handleLockId = (Long) handleToHandleLockMap
1133:                            .get(dbHandle);
1134:                    if (handleLockId != null) {
1135:                        Set dbHandleSet = (Set) handleLockToHandleMap
1136:                                .get(handleLockId);
1137:                        boolean removed = dbHandleSet.remove(dbHandle);
1138:                        assert removed : "Can't find " + dbHandle
1139:                                + " from dbHandleSet";
1140:                        if (dbHandleSet.size() == 0) {
1141:                            Object foo = handleLockToHandleMap
1142:                                    .remove(handleLockId);
1143:                            assert (foo != null) : "Can't find " + handleLockId
1144:                                    + " from handleLockIdtoHandleMap.";
1145:                        }
1146:                    }
1147:
1148:                    unregisterHandle(dbHandle);
1149:
1150:                } else {
1151:
1152:                    /*
1153:                     * If the db is still open, make sure the db knows this txn is its
1154:                     * handle lock protector and that this txn knows it owns this db
1155:                     * handle.
1156:                     */
1157:                    if (dbHandle != null) {
1158:                        DbInternal.dbSetHandleLocker(dbHandle, this );
1159:                    }
1160:                }
1161:            }
1162:
1163:            /**
1164:             * Cursors operating under this transaction are added to the collection.
1165:             */
1166:            public void registerCursor(CursorImpl cursor)
1167:                    throws DatabaseException {
1168:
1169:                synchronized (this ) {
1170:                    /* Add to the head of the list. */
1171:                    cursor.setLockerNext(cursorSet);
1172:                    if (cursorSet != null) {
1173:                        cursorSet.setLockerPrev(cursor);
1174:                    }
1175:                    cursorSet = cursor;
1176:                }
1177:            }
1178:
1179:            /**
1180:             * Remove a cursor from the collection.
1181:             */
1182:            public void unRegisterCursor(CursorImpl cursor)
1183:                    throws DatabaseException {
1184:
1185:                synchronized (this ) {
1186:                    CursorImpl prev = cursor.getLockerPrev();
1187:                    CursorImpl next = cursor.getLockerNext();
1188:                    if (prev == null) {
1189:                        cursorSet = next;
1190:                    } else {
1191:                        prev.setLockerNext(next);
1192:                    }
1193:
1194:                    if (next != null) {
1195:                        next.setLockerPrev(prev);
1196:                    }
1197:                    cursor.setLockerPrev(null);
1198:                    cursor.setLockerNext(null);
1199:                }
1200:            }
1201:
1202:            /**
1203:             * @return true if this txn is willing to give up the handle lock to
1204:             * another txn before this txn ends.
1205:             */
1206:            public boolean isHandleLockTransferrable() {
1207:                return false;
1208:            }
1209:
1210:            /**
1211:             * Check if all cursors associated with the txn are closed. If not, those
1212:             * open cursors will be forcibly closed.
1213:             * @return true if open cursors exist
1214:             */
1215:            private boolean checkCursorsForClose() throws DatabaseException {
1216:
1217:                CursorImpl c = cursorSet;
1218:                while (c != null) {
1219:                    if (!c.isClosed()) {
1220:                        return true;
1221:                    }
1222:                    c = c.getLockerNext();
1223:                }
1224:
1225:                return false;
1226:            }
1227:
1228:            /**
1229:             * stats
1230:             */
1231:            public LockStats collectStats(LockStats stats)
1232:                    throws DatabaseException {
1233:
1234:                synchronized (this ) {
1235:                    int nReadLocks = (readLocks == null) ? 0 : readLocks.size();
1236:                    stats.setNReadLocks(stats.getNReadLocks() + nReadLocks);
1237:                    int nWriteLocks = (writeInfo == null) ? 0 : writeInfo
1238:                            .size();
1239:                    stats.setNWriteLocks(stats.getNWriteLocks() + nWriteLocks);
1240:                }
1241:
1242:                return stats;
1243:            }
1244:
1245:            /**
1246:             * Set the state of a transaction to ONLY_ABORTABLE.
1247:             */
1248:            public void setOnlyAbortable() {
1249:                txnState &= ~STATE_BITS;
1250:                txnState |= ONLY_ABORTABLE;
1251:            }
1252:
1253:            /**
1254:             * Get the state of a transaction's ONLY_ABORTABLE.
1255:             */
1256:            public boolean getOnlyAbortable() {
1257:                return (txnState & ONLY_ABORTABLE) != 0;
1258:            }
1259:
1260:            /**
1261:             * Throw an exception if the transaction is not open.
1262:             *
1263:             * If calledByAbort is true, it means we're being called
1264:             * from abort().
1265:             *
1266:             * Caller must invoke with "this" synchronized.
1267:             */
1268:            protected void checkState(boolean calledByAbort)
1269:                    throws DatabaseException {
1270:
1271:                boolean ok = false;
1272:                boolean onlyAbortable = false;
1273:                byte state = (byte) (txnState & STATE_BITS);
1274:                ok = (state == USABLE);
1275:                onlyAbortable = (state == ONLY_ABORTABLE);
1276:
1277:                if (!calledByAbort && onlyAbortable) {
1278:
1279:                    /*
1280:                     * It's ok for FindBugs to whine about id not being synchronized.
1281:                     */
1282:                    throw new DatabaseException("Transaction " + id
1283:                            + " must be aborted.");
1284:                }
1285:
1286:                if (ok || (calledByAbort && onlyAbortable)) {
1287:                    return;
1288:                }
1289:
1290:                /*
1291:                 * It's ok for FindBugs to whine about id not being synchronized.
1292:                 */
1293:                throw new DatabaseException("Transaction " + id
1294:                        + " has been closed.");
1295:            }
1296:
1297:            /**
1298:             */
1299:            private void close(boolean isCommit) throws DatabaseException {
1300:
1301:                synchronized (this ) {
1302:                    txnState &= ~STATE_BITS;
1303:                    txnState |= CLOSED;
1304:                }
1305:
1306:                /*
1307:                 * UnregisterTxn must be called outside the synchronization on this
1308:                 * txn, because it gets the TxnManager's allTxns latch. The
1309:                 * checkpointer also gets the allTxns latch, and within that latch,
1310:                 * needs to synchronize on individual txns, so we must avoid a latching
1311:                 * hiearchy conflict.
1312:                 */
1313:                envImpl.getTxnManager().unRegisterTxn(this , isCommit);
1314:            }
1315:
1316:            /*
1317:             * Log support
1318:             */
1319:
1320:            /**
1321:             * @see Loggable#getLogSize
1322:             */
1323:            public int getLogSize() {
1324:                return LogUtils.LONG_BYTES + // id
1325:                        LogUtils.LONG_BYTES; // lastLoggedLsn
1326:            }
1327:
1328:            /**
1329:             * @see Loggable#writeToLog
1330:             */
1331:            /*
1332:             * It's ok for FindBugs to whine about id not being synchronized.
1333:             */
1334:            public void writeToLog(ByteBuffer logBuffer) {
1335:                LogUtils.writeLong(logBuffer, id);
1336:                LogUtils.writeLong(logBuffer, lastLoggedLsn);
1337:            }
1338:
1339:            /**
1340:             * @see Loggable#readFromLog
1341:             *
1342:             * It's ok for FindBugs to whine about id not being synchronized.
1343:             */
1344:            public void readFromLog(ByteBuffer logBuffer, byte entryTypeVersion) {
1345:                id = LogUtils.readLong(logBuffer);
1346:                lastLoggedLsn = LogUtils.readLong(logBuffer);
1347:            }
1348:
1349:            /**
1350:             * @see Loggable#dumpLog
1351:             */
1352:            public void dumpLog(StringBuffer sb, boolean verbose) {
1353:                sb.append("<txn id=\"");
1354:                sb.append(super .toString());
1355:                sb.append("\">");
1356:                sb.append(DbLsn.toString(lastLoggedLsn));
1357:                sb.append("</txn>");
1358:            }
1359:
1360:            /**
1361:             * @see Loggable#getTransactionId
1362:             */
1363:            public long getTransactionId() {
1364:                return getId();
1365:            }
1366:
1367:            /**
1368:             * Transfer a single handle lock to the set of corresponding handles at
1369:             * commit time.
1370:             */
1371:            private void transferHandleLockToHandleSet(Long handleLockId,
1372:                    Set dbHandleSet) throws DatabaseException {
1373:
1374:                /* Create a set of destination transactions */
1375:                int numHandles = dbHandleSet.size();
1376:                Database[] dbHandles = new Database[numHandles];
1377:                dbHandles = (Database[]) dbHandleSet.toArray(dbHandles);
1378:                Locker[] destTxns = new Locker[numHandles];
1379:                for (int i = 0; i < numHandles; i++) {
1380:                    destTxns[i] = new BasicLocker(envImpl);
1381:                }
1382:
1383:                /* Move this lock to the destination txns. */
1384:                long nodeId = handleLockId.longValue();
1385:                lockManager.transferMultiple(nodeId, this , destTxns);
1386:
1387:                for (int i = 0; i < numHandles; i++) {
1388:
1389:                    /*
1390:                     * Make this handle and its handle protector txn remember each
1391:                     * other.
1392:                     */
1393:                    destTxns[i].addToHandleMaps(handleLockId, dbHandles[i]);
1394:                    DbInternal.dbSetHandleLocker(dbHandles[i], destTxns[i]);
1395:                }
1396:            }
1397:
1398:            /**
1399:             * Send trace messages to the java.util.logger. Don't rely on the logger
1400:             * alone to conditionalize whether we send this message, we don't even want
1401:             * to construct the message if the level is not enabled.  The string
1402:             * construction can be numerous enough to show up on a performance profile.
1403:             */
1404:            private void traceCommit(int numWriteLocks, int numReadLocks) {
1405:                Logger logger = envImpl.getLogger();
1406:                if (logger.isLoggable(Level.FINE)) {
1407:                    StringBuffer sb = new StringBuffer();
1408:                    sb.append(" Commit:id = ").append(id);
1409:                    sb.append(" numWriteLocks=").append(numWriteLocks);
1410:                    sb.append(" numReadLocks = ").append(numReadLocks);
1411:                    Tracer.trace(Level.FINE, envImpl, sb.toString());
1412:                }
1413:            }
1414:
1415:            int getInMemorySize() {
1416:                return inMemorySize;
1417:            }
1418:
1419:            /**
1420:             * Store information about a DatabaseImpl that will have to be
1421:             * purged at transaction commit or abort. This handles cleanup after
1422:             * operations like Environment.truncateDatabase,
1423:             * Environment.removeDatabase. Cleanup like this is done outside the
1424:             * usual transaction commit or node undo processing, because
1425:             * the mapping tree is always AutoTxn'ed to avoid deadlock and is
1426:             * essentially  non-transactional
1427:             */
1428:            private static class DatabaseCleanupInfo {
1429:                DatabaseImpl dbImpl;
1430:
1431:                /* if true, clean on commit. If false, clean on abort. */
1432:                boolean deleteAtCommit;
1433:
1434:                DatabaseCleanupInfo(DatabaseImpl dbImpl, boolean deleteAtCommit) {
1435:                    this.dbImpl = dbImpl;
1436:                    this.deleteAtCommit = deleteAtCommit;
1437:                }
1438:            }
1439:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.