Source Code Cross Referenced for DatabaseImpl.java in  » JMX » je » com » sleepycat » je » dbi » 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.dbi 
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: DatabaseImpl.java,v 1.157.2.12 2008/01/07 15:14:09 cwl Exp $
0007:         */
0008:
0009:        package com.sleepycat.je.dbi;
0010:
0011:        import java.io.ByteArrayInputStream;
0012:        import java.io.ByteArrayOutputStream;
0013:        import java.io.IOException;
0014:        import java.io.ObjectInputStream;
0015:        import java.io.ObjectOutputStream;
0016:        import java.io.PrintStream;
0017:        import java.nio.ByteBuffer;
0018:        import java.util.Arrays;
0019:        import java.util.Collections;
0020:        import java.util.Comparator;
0021:        import java.util.HashMap;
0022:        import java.util.HashSet;
0023:        import java.util.Iterator;
0024:        import java.util.Map;
0025:        import java.util.Set;
0026:
0027:        import com.sleepycat.je.BtreeStats;
0028:        import com.sleepycat.je.Cursor;
0029:        import com.sleepycat.je.Database;
0030:        import com.sleepycat.je.DatabaseConfig;
0031:        import com.sleepycat.je.DatabaseEntry;
0032:        import com.sleepycat.je.DatabaseException;
0033:        import com.sleepycat.je.DatabaseStats;
0034:        import com.sleepycat.je.DbInternal;
0035:        import com.sleepycat.je.LockMode;
0036:        import com.sleepycat.je.OperationStatus;
0037:        import com.sleepycat.je.PreloadConfig;
0038:        import com.sleepycat.je.PreloadStats;
0039:        import com.sleepycat.je.PreloadStatus;
0040:        import com.sleepycat.je.SecondaryDatabase;
0041:        import com.sleepycat.je.StatsConfig;
0042:        import com.sleepycat.je.VerifyConfig;
0043:        import com.sleepycat.je.cleaner.UtilizationTracker;
0044:        import com.sleepycat.je.config.EnvironmentParams;
0045:        import com.sleepycat.je.dbi.SortedLSNTreeWalker.ExceptionPredicate;
0046:        import com.sleepycat.je.dbi.SortedLSNTreeWalker.TreeNodeProcessor;
0047:        import com.sleepycat.je.latch.LatchSupport;
0048:        import com.sleepycat.je.log.LogEntryType;
0049:        import com.sleepycat.je.log.LogException;
0050:        import com.sleepycat.je.log.LogFileNotFoundException;
0051:        import com.sleepycat.je.log.LogUtils;
0052:        import com.sleepycat.je.log.Loggable;
0053:        import com.sleepycat.je.recovery.Checkpointer;
0054:        import com.sleepycat.je.tree.BIN;
0055:        import com.sleepycat.je.tree.ChildReference;
0056:        import com.sleepycat.je.tree.DBIN;
0057:        import com.sleepycat.je.tree.DIN;
0058:        import com.sleepycat.je.tree.DupCountLN;
0059:        import com.sleepycat.je.tree.IN;
0060:        import com.sleepycat.je.tree.LN;
0061:        import com.sleepycat.je.tree.Node;
0062:        import com.sleepycat.je.tree.Tree;
0063:        import com.sleepycat.je.tree.TreeUtils;
0064:        import com.sleepycat.je.tree.TreeWalkerStatsAccumulator;
0065:        import com.sleepycat.je.tree.WithRootLatched;
0066:        import com.sleepycat.je.txn.Locker;
0067:        import com.sleepycat.je.txn.ThreadLocker;
0068:        import com.sleepycat.je.utilint.CmdUtil;
0069:        import com.sleepycat.je.utilint.DbLsn;
0070:        import com.sleepycat.je.utilint.TestHook;
0071:
0072:        /**
0073:         * The underlying object for a given database.
0074:         */
0075:        public class DatabaseImpl implements  Loggable, Cloneable {
0076:
0077:            /*
0078:             * Delete processing states. See design note on database deletion and
0079:             * truncation
0080:             */
0081:            private static final short NOT_DELETED = 1;
0082:            private static final short DELETED_CLEANUP_INLIST_HARVEST = 2;
0083:            private static final short DELETED_CLEANUP_LOG_HARVEST = 3;
0084:            private static final short DELETED = 4;
0085:
0086:            private DatabaseId id; // unique id
0087:            private Tree tree;
0088:            private EnvironmentImpl envImpl; // Tree operations find the env this way
0089:            private boolean duplicatesAllowed; // duplicates allowed
0090:            private boolean transactional; // All open handles are transactional
0091:            private boolean deferredWrite; // deferred write mode set
0092:            private Set referringHandles; // Set of open Database handles
0093:            private BtreeStats stats; // most recent btree stats w/ !DB_FAST_STAT
0094:            private long eofNodeId; // Logical EOF node for range locking
0095:            private short deleteState; // one of four delete states.
0096:            private int useCount = 0; // If non-zero, eviction is prohibited
0097:            private Object useCountLock = new Object();
0098:
0099:            /*
0100:             * The user defined Btree and duplicate comparison functions, if specified.
0101:             */
0102:            private Comparator btreeComparator = null;
0103:            private Comparator duplicateComparator = null;
0104:            private byte[] btreeComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY;
0105:            private byte[] duplicateComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY;
0106:            private boolean btreeComparatorByClassName = false;
0107:            private boolean duplicateComparatorByClassName = false;
0108:
0109:            /*
0110:             * Cache some configuration values.
0111:             */
0112:            private int binDeltaPercent;
0113:            private int binMaxDeltas;
0114:            private int maxMainTreeEntriesPerNode;
0115:            private int maxDupTreeEntriesPerNode;
0116:
0117:            /*
0118:             * The debugDatabaseName is used for error messages only, to avoid
0119:             * accessing the db mapping tree in error situations. Currently it's not
0120:             * guaranteed to be transactionally correct, nor is it updated by rename.
0121:             */
0122:            private String debugDatabaseName;
0123:
0124:            /* For unit tests */
0125:            private TestHook pendingDeletedHook;
0126:
0127:            /**
0128:             * Create a database object for a new database.
0129:             */
0130:            public DatabaseImpl(String dbName, DatabaseId id,
0131:                    EnvironmentImpl envImpl, DatabaseConfig dbConfig)
0132:                    throws DatabaseException {
0133:
0134:                this .id = id;
0135:                this .envImpl = envImpl;
0136:                setBtreeComparator(dbConfig.getBtreeComparator(), dbConfig
0137:                        .getBtreeComparatorByClassName());
0138:                setDuplicateComparator(dbConfig.getDuplicateComparator(),
0139:                        dbConfig.getDuplicateComparatorByClassName());
0140:                duplicatesAllowed = dbConfig.getSortedDuplicates();
0141:                transactional = dbConfig.getTransactional();
0142:                deferredWrite = dbConfig.getDeferredWrite();
0143:                maxMainTreeEntriesPerNode = dbConfig.getNodeMaxEntries();
0144:                maxDupTreeEntriesPerNode = dbConfig.getNodeMaxDupTreeEntries();
0145:
0146:                initDefaultSettings();
0147:
0148:                deleteState = NOT_DELETED;
0149:
0150:                /*
0151:                 * The tree needs the env, make sure we assign it before
0152:                 * allocating the tree.
0153:                 */
0154:                tree = new Tree(this );
0155:                referringHandles = Collections.synchronizedSet(new HashSet());
0156:
0157:                eofNodeId = Node.getNextNodeId();
0158:
0159:                /* For error messages only. */
0160:                debugDatabaseName = dbName;
0161:            }
0162:
0163:            /**
0164:             * Create an empty database object for initialization from the log.  Note
0165:             * that the rest of the initialization comes from readFromLog(), except
0166:             * for the debugDatabaseName, which is set by the caller.
0167:             */
0168:            public DatabaseImpl() throws DatabaseException {
0169:
0170:                id = new DatabaseId();
0171:                envImpl = null;
0172:
0173:                deleteState = NOT_DELETED;
0174:
0175:                tree = new Tree();
0176:                referringHandles = Collections.synchronizedSet(new HashSet());
0177:
0178:                /* initDefaultSettings is called after envImpl is set.  */
0179:
0180:                eofNodeId = Node.getNextNodeId();
0181:            }
0182:
0183:            public void setDebugDatabaseName(String debugName) {
0184:                debugDatabaseName = debugName;
0185:            }
0186:
0187:            public String getDebugName() {
0188:                return debugDatabaseName;
0189:            }
0190:
0191:            /* For unit testing only. */
0192:            public void setPendingDeletedHook(TestHook hook) {
0193:                pendingDeletedHook = hook;
0194:            }
0195:
0196:            /**
0197:             * Initialize configuration settings when creating a new instance or after
0198:             * reading an instance from the log.  The envImpl field must be set before
0199:             * calling this method.
0200:             */
0201:            private void initDefaultSettings() throws DatabaseException {
0202:
0203:                DbConfigManager configMgr = envImpl.getConfigManager();
0204:
0205:                binDeltaPercent = configMgr
0206:                        .getInt(EnvironmentParams.BIN_DELTA_PERCENT);
0207:                binMaxDeltas = configMgr
0208:                        .getInt(EnvironmentParams.BIN_MAX_DELTAS);
0209:
0210:                if (maxMainTreeEntriesPerNode == 0) {
0211:                    maxMainTreeEntriesPerNode = configMgr
0212:                            .getInt(EnvironmentParams.NODE_MAX);
0213:                }
0214:
0215:                if (maxDupTreeEntriesPerNode == 0) {
0216:                    maxDupTreeEntriesPerNode = configMgr
0217:                            .getInt(EnvironmentParams.NODE_MAX_DUPTREE);
0218:                }
0219:            }
0220:
0221:            /**
0222:             * Clone.  For the most part, just pass off to the super class for a
0223:             * field-by-field copy.
0224:             */
0225:            public DatabaseImpl cloneDb() throws DatabaseException {
0226:
0227:                try {
0228:                    DatabaseImpl newDb = (DatabaseImpl) clone();
0229:                    /* The cloned DB could have a non-zero use count. [#13415] */
0230:                    newDb.useCount = 0;
0231:                    return newDb;
0232:                } catch (CloneNotSupportedException e) {
0233:                    throw new DatabaseException(e);
0234:                }
0235:            }
0236:
0237:            /**
0238:             * @return the database tree.
0239:             */
0240:            public Tree getTree() {
0241:                return tree;
0242:            }
0243:
0244:            void setTree(Tree tree) {
0245:                this .tree = tree;
0246:            }
0247:
0248:            /**
0249:             * @return the database id.
0250:             */
0251:            public DatabaseId getId() {
0252:                return id;
0253:            }
0254:
0255:            void setId(DatabaseId id) {
0256:                this .id = id;
0257:            }
0258:
0259:            public long getEofNodeId() {
0260:                return eofNodeId;
0261:            }
0262:
0263:            /**
0264:             * @return true if this database is transactional.
0265:             */
0266:            public boolean isTransactional() {
0267:                return transactional;
0268:            }
0269:
0270:            /**
0271:             * Sets the transactional property for the first opened handle.
0272:             */
0273:            public void setTransactional(boolean transactional) {
0274:                this .transactional = transactional;
0275:            }
0276:
0277:            /**
0278:             * @return true if this database is in deferred write mode.
0279:             */
0280:            public boolean isDeferredWrite() {
0281:                return deferredWrite;
0282:            }
0283:
0284:            /*
0285:             * Set the deferred write property for the first opened handle.
0286:             */
0287:            public void setDeferredWrite(boolean deferredWrite) {
0288:                this .deferredWrite = deferredWrite;
0289:            }
0290:
0291:            /**
0292:             * @return true if duplicates are allowed in this database.
0293:             */
0294:            public boolean getSortedDuplicates() {
0295:                return duplicatesAllowed;
0296:            }
0297:
0298:            public int getNodeMaxEntries() {
0299:                return maxMainTreeEntriesPerNode;
0300:            }
0301:
0302:            public int getNodeMaxDupTreeEntries() {
0303:                return maxDupTreeEntriesPerNode;
0304:            }
0305:
0306:            /**
0307:             * Returns the memory size that should be added to MAPLN_OVERHEAD.
0308:             *
0309:             * This is a start at budgeting per-Database memory.  For future reference,
0310:             * other things that could be budgeted are:
0311:             * - debugDatabaseName as it is set
0312:             * - Database handles as they are added/removed in referringHandles
0313:             */
0314:            public int getAdditionalMemorySize() {
0315:
0316:                int val = 0;
0317:
0318:                /*
0319:                 * If the comparator object is non-null we double the size of the
0320:                 * serialized form to account for the approximate size of the user's
0321:                 * comparator object.  This is only an approximation of course, and is
0322:                 * not a very good one if we have serialized the class name, but we
0323:                 * have no way to know the size of the user's object.
0324:                 */
0325:                if (btreeComparator != null) {
0326:                    val += 2 * MemoryBudget
0327:                            .byteArraySize(btreeComparatorBytes.length);
0328:                }
0329:                if (duplicateComparator != null) {
0330:                    val += 2 * MemoryBudget
0331:                            .byteArraySize(duplicateComparatorBytes.length);
0332:                }
0333:                return val;
0334:            }
0335:
0336:            /**
0337:             * Set the duplicate comparison function for this database.
0338:             *
0339:             * @return true if the comparator was actually changed
0340:             *
0341:             * @param duplicateComparator - The Duplicate Comparison function.
0342:             */
0343:            public boolean setDuplicateComparator(Comparator comparator,
0344:                    boolean byClassName) throws DatabaseException {
0345:
0346:                duplicateComparator = comparator;
0347:                byte[] newDuplicateComparatorBytes = comparatorToBytes(
0348:                        comparator, byClassName, "Duplicate");
0349:                boolean ret = Arrays.equals(newDuplicateComparatorBytes,
0350:                        duplicateComparatorBytes);
0351:                duplicateComparatorBytes = newDuplicateComparatorBytes;
0352:                duplicateComparatorByClassName = byClassName;
0353:                return !ret;
0354:            }
0355:
0356:            /**
0357:             * Set the btree comparison function for this database.
0358:             *
0359:             * @return true if the comparator was actually changed
0360:             *
0361:             * @param btreeComparator - The btree Comparison function.
0362:             */
0363:            public boolean setBtreeComparator(Comparator comparator,
0364:                    boolean byClassName) throws DatabaseException {
0365:
0366:                btreeComparator = comparator;
0367:                byte[] newBtreeComparatorBytes = comparatorToBytes(comparator,
0368:                        byClassName, "Btree");
0369:                boolean ret = Arrays.equals(newBtreeComparatorBytes,
0370:                        btreeComparatorBytes);
0371:                btreeComparatorBytes = newBtreeComparatorBytes;
0372:                btreeComparatorByClassName = byClassName;
0373:                return !ret;
0374:            }
0375:
0376:            /**
0377:             * @return the btree Comparator object.
0378:             */
0379:            public Comparator getBtreeComparator() {
0380:                return btreeComparator;
0381:            }
0382:
0383:            /**
0384:             * @return the duplicate Comparator object.
0385:             */
0386:            public Comparator getDuplicateComparator() {
0387:                return duplicateComparator;
0388:            }
0389:
0390:            /**
0391:             * @return whether Comparator is set by class name, not by serializable
0392:             * Comparator object.
0393:             */
0394:            public boolean getBtreeComparatorByClass() {
0395:                return btreeComparatorByClassName;
0396:            }
0397:
0398:            /**
0399:             * @return whether Comparator is set by class name, not by serializable
0400:             * Comparator object.
0401:             */
0402:            public boolean getDuplicateComparatorByClass() {
0403:                return duplicateComparatorByClassName;
0404:            }
0405:
0406:            /**
0407:             * Set the db environment during recovery, after instantiating the database
0408:             * from the log
0409:             */
0410:            public void setEnvironmentImpl(EnvironmentImpl envImpl)
0411:                    throws DatabaseException {
0412:
0413:                this .envImpl = envImpl;
0414:                initDefaultSettings();
0415:                tree.setDatabase(this );
0416:            }
0417:
0418:            /**
0419:             * @return the database environment.
0420:             */
0421:            public EnvironmentImpl getDbEnvironment() {
0422:                return envImpl;
0423:            }
0424:
0425:            /**
0426:             * Returns whether one or more handles are open.
0427:             */
0428:            public boolean hasOpenHandles() {
0429:                return referringHandles.size() > 0;
0430:            }
0431:
0432:            /**
0433:             * Add a referring handle
0434:             */
0435:            public void addReferringHandle(Database db) {
0436:                referringHandles.add(db);
0437:            }
0438:
0439:            /**
0440:             * Decrement the reference count.
0441:             */
0442:            public void removeReferringHandle(Database db) {
0443:                referringHandles.remove(db);
0444:            }
0445:
0446:            /**
0447:             * @return the referring handle count.
0448:             */
0449:            synchronized int getReferringHandleCount() {
0450:                return referringHandles.size();
0451:            }
0452:
0453:            /**
0454:             * Increments the use count of this DB to prevent it from being
0455:             * evicted.  Called by the DbTree.createDb/getDb methods that return a
0456:             * DatabaseImpl.  Must be called while holding a lock on the MapLN. See
0457:             * isInUse. [#13415]
0458:             */
0459:            void incrementUseCount() {
0460:                /* Synchronize to update useCount atomically. */
0461:                synchronized (useCountLock) {
0462:                    useCount += 1;
0463:                }
0464:            }
0465:
0466:            /**
0467:             * Decrements the use count of this DB, allowing it to be evicted if the
0468:             * use count reaches zero.  Called via DbTree.releaseDb to release a
0469:             * DatabaseImpl that was returned by a DbTree.createDb/getDb method. See
0470:             * isInUse. [#13415]
0471:             */
0472:            void decrementUseCount() {
0473:                /* Synchronize to update useCount atomically. */
0474:                synchronized (useCountLock) {
0475:                    assert useCount > 0;
0476:                    useCount -= 1;
0477:                }
0478:            }
0479:
0480:            /**
0481:             * Returns whether this DB is in use and cannot be evicted.  Called by
0482:             * MapLN.isEvictable while holding a write-lock on the MapLN and a latch on
0483:             * its parent BIN. [#13415]
0484:             *
0485:             * When isInUse returns false (while holding a write-lock on the MapLN and
0486:             * a latch on the parent BIN), it guarantees that the database object
0487:             * is not in use and cannot be acquired by another thread (via
0488:             * DbTree.createDb/getDb) until both the MapLN lock and BIN latch are
0489:             * released.  This guarantee is due to the fact that DbTree.createDb/getDb
0490:             * only increment the use count while holding a read-lock on the MapLN.
0491:             * Therefore, it is safe to evict the MapLN when isInUse returns false.
0492:             *
0493:             * When isInUse returns true, it is possible that another thread may
0494:             * decrement the use count at any time, since no locking or latching is
0495:             * performed when calling DbTree.releaseDb (which calls decrementUseCount).
0496:             * Therefore, it is not guaranteed that the MapLN is in use when isInUse
0497:             * returns true.  A true result means: the DB may be in use, so it is not
0498:             * safe to evict it.
0499:             */
0500:            public boolean isInUse() {
0501:                /* Synchronize to read the up-to-date value of useCount. */
0502:                synchronized (useCountLock) {
0503:                    return (useCount > 0);
0504:                }
0505:            }
0506:
0507:            /**
0508:             * Checks whether a database is in use during a remove or truncate database
0509:             * operation.
0510:             */
0511:            boolean isInUseDuringDbRemove() {
0512:                /* Synchronize to read the up-to-date value of useCount. */
0513:                synchronized (useCountLock) {
0514:
0515:                    /*
0516:                     * The use count is at least one here, because remove/truncate has
0517:                     * called getDb but releaseDb has not yet been called.  Normally
0518:                     * the database must be closed in order to remove or truncate it
0519:                     * and referringHandles will be empty.  But when the deprecated
0520:                     * Database.truncate is called, the database is open and the use
0521:                     * count includes the number of open handles.  [#15805]
0522:                     */
0523:                    return useCount > 1 + referringHandles.size();
0524:                }
0525:            }
0526:
0527:            /**
0528:             * Flush all dirty nodes for this database to disk.
0529:             */
0530:            public synchronized void sync(boolean flushLog)
0531:                    throws DatabaseException {
0532:
0533:                if (!isDeferredWrite()) {
0534:                    throw new DatabaseException(
0535:                            "Database.sync() is only supported "
0536:                                    + "for deferred-write databases");
0537:                }
0538:
0539:                if (tree.rootExists()) {
0540:                    Checkpointer.syncDatabase(envImpl, this , flushLog);
0541:                }
0542:            }
0543:
0544:            /**
0545:             * For this secondary database return the primary that it is associated
0546:             * with, or null if not associated with any primary.  Note that not all
0547:             * handles need be associated with a primary.
0548:             */
0549:            public Database findPrimaryDatabase() throws DatabaseException {
0550:
0551:                for (Iterator i = referringHandles.iterator(); i.hasNext();) {
0552:                    Object obj = i.next();
0553:                    if (obj instanceof  SecondaryDatabase) {
0554:                        return ((SecondaryDatabase) obj).getPrimaryDatabase();
0555:                    }
0556:                }
0557:                return null;
0558:            }
0559:
0560:            public String getName() throws DatabaseException {
0561:
0562:                return envImpl.getDbMapTree().getDbName(id);
0563:            }
0564:
0565:            /*
0566:             * @return true if this database is deleted. Delete cleanup
0567:             * may still be in progress.
0568:             */
0569:            public boolean isDeleted() {
0570:                return !(deleteState == NOT_DELETED);
0571:            }
0572:
0573:            /*
0574:             * @return true if this database is deleted and all cleanup is finished.
0575:             */
0576:            public boolean isDeleteFinished() {
0577:                return (deleteState == DELETED);
0578:            }
0579:
0580:            /*
0581:             * The delete cleanup is starting. Set this before releasing any
0582:             * write locks held for a db operation.
0583:             */
0584:            public void startDeleteProcessing() {
0585:                assert (deleteState == NOT_DELETED);
0586:
0587:                deleteState = DELETED_CLEANUP_INLIST_HARVEST;
0588:            }
0589:
0590:            /*
0591:             * Should be called by the SortedLSNTreeWalker when it is finished with
0592:             * the INList.
0593:             */
0594:            void finishedINListHarvest() {
0595:                assert (deleteState == DELETED_CLEANUP_INLIST_HARVEST);
0596:
0597:                deleteState = DELETED_CLEANUP_LOG_HARVEST;
0598:            }
0599:
0600:            /**
0601:             * Purge a DatabaseImpl and corresponding MapLN in the db mapping tree.
0602:             * Purging consists of removing all related INs from the db mapping tree
0603:             * and deleting the related MapLN.
0604:             * Used at the transaction end in these cases:
0605:             *  - purge the deleted database after a commit of
0606:             *           Environment.removeDatabase
0607:             *  - purge the deleted database after a commit of
0608:             *           Environment.truncateDatabase
0609:             *  - purge the newly created database after an abort of
0610:             *           Environment.truncateDatabase
0611:             */
0612:            public void deleteAndReleaseINs() throws DatabaseException {
0613:
0614:                startDeleteProcessing();
0615:                releaseDeletedINs();
0616:            }
0617:
0618:            public void releaseDeletedINs() throws DatabaseException {
0619:
0620:                if (pendingDeletedHook != null) {
0621:                    pendingDeletedHook.doHook();
0622:                }
0623:
0624:                try {
0625:
0626:                    /*
0627:                     * Get the root LSN before deleting the MapLN, as that will null
0628:                     * out the root.
0629:                     */
0630:                    long rootLsn = tree.getRootLsn();
0631:
0632:                    /*
0633:                     * Use a snapshot tracker that is accumulated under the log write
0634:                     * latch when we're doing counting.  Start by recording the LSN of
0635:                     * the root IN as obsolete.  A zero size is passed for the last
0636:                     * parameter because it is too expensive to fetch the node.
0637:                     */
0638:                    UtilizationTracker snapshot = new UtilizationTracker(
0639:                            envImpl);
0640:                    if (rootLsn != DbLsn.NULL_LSN) {
0641:                        snapshot.countObsoleteNodeInexact(rootLsn,
0642:                                LogEntryType.LOG_IN, 0);
0643:                    }
0644:
0645:                    /* Fetch LNs to count LN sizes only if so configured. */
0646:                    boolean fetchLNSize = envImpl.getCleaner()
0647:                            .getFetchObsoleteSize();
0648:
0649:                    /* Use the tree walker to visit every child lsn in the tree. */
0650:                    ObsoleteProcessor obsoleteProcessor = new ObsoleteProcessor(
0651:                            snapshot);
0652:                    SortedLSNTreeWalker walker = new ObsoleteTreeWalker(this ,
0653:                            rootLsn, fetchLNSize, obsoleteProcessor);
0654:
0655:                    /*
0656:                     * Delete MapLN before the walk. Note that the processing of
0657:                     * the naming tree means this MapLN is never actually
0658:                     * accessible from the current tree, but deleting the MapLN
0659:                     * will do two things:
0660:                     * (a) mark it properly obsolete
0661:                     * (b) null out the database tree, leaving the INList the only
0662:                     * reference to the INs.
0663:                     */
0664:                    envImpl.getDbMapTree().deleteMapLN(id);
0665:
0666:                    /*
0667:                     * At this point, it's possible for the evictor to find an IN
0668:                     * for this database on the INList. It should be ignored.
0669:                     */
0670:                    walker.walk();
0671:
0672:                    /*
0673:                     * Count obsolete nodes for a deleted database at transaction
0674:                     * end time.  Write out the modified file summaries for
0675:                     * recovery.
0676:                     */
0677:                    envImpl.getUtilizationProfile().countAndLogSummaries(
0678:                            snapshot.getTrackedFiles());
0679:                } finally {
0680:                    deleteState = DELETED;
0681:                    /* releaseDb to balance getDb called by truncate/remove. */
0682:                    envImpl.releaseDb(this );
0683:                }
0684:            }
0685:
0686:            public void checkIsDeleted(String operation)
0687:                    throws DatabaseException {
0688:
0689:                if (isDeleted()) {
0690:                    throw new DatabaseException("Attempt to " + operation
0691:                            + " a deleted database");
0692:                }
0693:            }
0694:
0695:            private static class ObsoleteTreeWalker extends SortedLSNTreeWalker {
0696:
0697:                private ObsoleteTreeWalker(DatabaseImpl dbImpl, long rootLsn,
0698:                        boolean fetchLNSize, TreeNodeProcessor callback)
0699:                        throws DatabaseException {
0700:
0701:                    super (dbImpl, true, // remove INs from INList
0702:                            true, // set INList finish harvest
0703:                            rootLsn, callback, null, /* savedException */
0704:                            null); /* exception predicate */
0705:
0706:                    accumulateLNs = fetchLNSize;
0707:                }
0708:            }
0709:
0710:            /* Mark each LSN obsolete in the utilization tracker. */
0711:            private static class ObsoleteProcessor implements  TreeNodeProcessor {
0712:
0713:                private UtilizationTracker tracker;
0714:
0715:                ObsoleteProcessor(UtilizationTracker tracker) {
0716:                    this .tracker = tracker;
0717:                }
0718:
0719:                public void processLSN(long childLsn, LogEntryType childType,
0720:                        Node node, byte[] lnKey) throws DatabaseException {
0721:
0722:                    assert childLsn != DbLsn.NULL_LSN;
0723:
0724:                    /*
0725:                     * Count the LN log size if an LN node and key are available.  But
0726:                     * do not count the size if the LN is dirty, since the logged LN is
0727:                     * not available. [#15365]
0728:                     */
0729:                    int size = 0;
0730:                    if (lnKey != null && node instanceof  LN) {
0731:                        LN ln = (LN) node;
0732:                        size = ln.getLastLoggedSize();
0733:                    }
0734:
0735:                    tracker.countObsoleteNodeInexact(childLsn, childType, size);
0736:                }
0737:
0738:                public void processDirtyDeletedLN(long childLsn, LN ln,
0739:                        byte[] lnKey) throws DatabaseException {
0740:
0741:                    assert ln != null;
0742:
0743:                    /*
0744:                     * Do not count the size (pass zero) because the LN is dirty and
0745:                     * the logged LN is not available.
0746:                     */
0747:                    tracker.countObsoleteNodeInexact(childLsn, ln.getLogType(),
0748:                            0);
0749:                }
0750:
0751:                public void processDupCount(long ignore) {
0752:                }
0753:            }
0754:
0755:            public DatabaseStats stat(StatsConfig config)
0756:                    throws DatabaseException {
0757:
0758:                if (stats == null) {
0759:
0760:                    /*
0761:                     * Called first time w/ FAST_STATS so just give them an
0762:                     * empty one.
0763:                     */
0764:                    stats = new BtreeStats();
0765:                }
0766:
0767:                if (!config.getFast()) {
0768:                    if (tree == null) {
0769:                        return new BtreeStats();
0770:                    }
0771:
0772:                    PrintStream out = config.getShowProgressStream();
0773:                    if (out == null) {
0774:                        out = System.err;
0775:                    }
0776:
0777:                    StatsAccumulator statsAcc = new StatsAccumulator(out,
0778:                            config.getShowProgressInterval(), getEmptyStats());
0779:                    walkDatabaseTree(statsAcc, out, true);
0780:                    statsAcc.copyToStats(stats);
0781:                }
0782:
0783:                return stats;
0784:            }
0785:
0786:            /*
0787:             * @param config verify configuration
0788:             * @param emptyStats empty database stats, to be filled by this method
0789:             * @return true if the verify saw no errors.
0790:             */
0791:            public boolean verify(VerifyConfig config, DatabaseStats emptyStats)
0792:                    throws DatabaseException {
0793:
0794:                if (tree == null) {
0795:                    return true;
0796:                }
0797:
0798:                PrintStream out = config.getShowProgressStream();
0799:                if (out == null) {
0800:                    out = System.err;
0801:                }
0802:
0803:                StatsAccumulator statsAcc = new StatsAccumulator(out, config
0804:                        .getShowProgressInterval(), emptyStats) {
0805:                    void verifyNode(Node node) {
0806:
0807:                        try {
0808:                            node.verify(null);
0809:                        } catch (DatabaseException INE) {
0810:                            progressStream.println(INE);
0811:                        }
0812:                    }
0813:                };
0814:                boolean ok = walkDatabaseTree(statsAcc, out, config
0815:                        .getPrintInfo());
0816:                statsAcc.copyToStats(emptyStats);
0817:                return ok;
0818:            }
0819:
0820:            /* @return the right kind of stats object for this database. */
0821:            public DatabaseStats getEmptyStats() {
0822:                return new BtreeStats();
0823:            }
0824:
0825:            /*
0826:             * @return true if no errors.
0827:             */
0828:            private boolean walkDatabaseTree(
0829:                    TreeWalkerStatsAccumulator statsAcc, PrintStream out,
0830:                    boolean verbose) throws DatabaseException {
0831:
0832:                boolean ok = true;
0833:                Locker locker = new ThreadLocker(envImpl);
0834:                Cursor cursor = null;
0835:                CursorImpl impl = null;
0836:                try {
0837:                    EnvironmentImpl.incThreadLocalReferenceCount();
0838:                    cursor = DbInternal.newCursor(this , locker, null);
0839:                    impl = DbInternal.getCursorImpl(cursor);
0840:                    tree.setTreeStatsAccumulator(statsAcc);
0841:
0842:                    /*
0843:                     * This will only be used on the first call for the position()
0844:                     * call.
0845:                     */
0846:                    impl.setTreeStatsAccumulator(statsAcc);
0847:                    DatabaseEntry foundData = new DatabaseEntry();
0848:                    DatabaseEntry key = new DatabaseEntry();
0849:                    OperationStatus status = DbInternal.position(cursor, key,
0850:                            foundData, LockMode.READ_UNCOMMITTED, true);
0851:                    while (status == OperationStatus.SUCCESS) {
0852:                        try {
0853:                            status = DbInternal.retrieveNext(cursor, key,
0854:                                    foundData, LockMode.READ_UNCOMMITTED,
0855:                                    GetMode.NEXT);
0856:                        } catch (DatabaseException DBE) {
0857:                            ok = false;
0858:                            if (DbInternal
0859:                                    .advanceCursor(cursor, key, foundData)) {
0860:                                if (verbose) {
0861:                                    out
0862:                                            .println("Error encountered (continuing):");
0863:                                    out.println(DBE);
0864:                                    printErrorRecord(out, key, foundData);
0865:                                }
0866:                            } else {
0867:                                throw DBE;
0868:                            }
0869:                        }
0870:                    }
0871:                } finally {
0872:                    if (impl != null) {
0873:                        impl.setTreeStatsAccumulator(null);
0874:                    }
0875:                    tree.setTreeStatsAccumulator(null);
0876:                    EnvironmentImpl.decThreadLocalReferenceCount();
0877:                    if (cursor != null) {
0878:                        cursor.close();
0879:                    }
0880:                }
0881:
0882:                return ok;
0883:            }
0884:
0885:            /**
0886:             * Prints the key and data, if available, for a BIN entry that could not be
0887:             * read/verified.  Uses the same format as DbDump and prints both the hex
0888:             * and printable versions of the entries.
0889:             */
0890:            private void printErrorRecord(PrintStream out, DatabaseEntry key,
0891:                    DatabaseEntry data) {
0892:
0893:                byte[] bytes = key.getData();
0894:                StringBuffer sb = new StringBuffer("Error Key ");
0895:                if (bytes == null) {
0896:                    sb.append("UNKNOWN");
0897:                } else {
0898:                    CmdUtil.formatEntry(sb, bytes, false);
0899:                    sb.append(' ');
0900:                    CmdUtil.formatEntry(sb, bytes, true);
0901:                }
0902:                out.println(sb);
0903:
0904:                bytes = data.getData();
0905:                sb = new StringBuffer("Error Data ");
0906:                if (bytes == null) {
0907:                    sb.append("UNKNOWN");
0908:                } else {
0909:                    CmdUtil.formatEntry(sb, bytes, false);
0910:                    sb.append(' ');
0911:                    CmdUtil.formatEntry(sb, bytes, true);
0912:                }
0913:                out.println(sb);
0914:            }
0915:
0916:            static class StatsAccumulator implements  TreeWalkerStatsAccumulator {
0917:                private Set inNodeIdsSeen = new HashSet();
0918:                private Set binNodeIdsSeen = new HashSet();
0919:                private Set dinNodeIdsSeen = new HashSet();
0920:                private Set dbinNodeIdsSeen = new HashSet();
0921:                private Set dupCountLNsSeen = new HashSet();
0922:                private long[] insSeenByLevel = null;
0923:                private long[] binsSeenByLevel = null;
0924:                private long[] dinsSeenByLevel = null;
0925:                private long[] dbinsSeenByLevel = null;
0926:                private long lnCount = 0;
0927:                private long deletedLNCount = 0;
0928:                private int mainTreeMaxDepth = 0;
0929:                private int duplicateTreeMaxDepth = 0;
0930:                private DatabaseStats useStats;
0931:
0932:                PrintStream progressStream;
0933:                int progressInterval;
0934:
0935:                /* The max levels we ever expect to see in a tree. */
0936:                private static final int MAX_LEVELS = 100;
0937:
0938:                StatsAccumulator(PrintStream progressStream,
0939:                        int progressInterval, DatabaseStats useStats) {
0940:
0941:                    this .progressStream = progressStream;
0942:                    this .progressInterval = progressInterval;
0943:
0944:                    insSeenByLevel = new long[MAX_LEVELS];
0945:                    binsSeenByLevel = new long[MAX_LEVELS];
0946:                    dinsSeenByLevel = new long[MAX_LEVELS];
0947:                    dbinsSeenByLevel = new long[MAX_LEVELS];
0948:
0949:                    this .useStats = useStats;
0950:                }
0951:
0952:                void verifyNode(Node node) {
0953:
0954:                }
0955:
0956:                public void processIN(IN node, Long nid, int level) {
0957:                    if (inNodeIdsSeen.add(nid)) {
0958:                        tallyLevel(level, insSeenByLevel);
0959:                        verifyNode(node);
0960:                    }
0961:                }
0962:
0963:                public void processBIN(BIN node, Long nid, int level) {
0964:                    if (binNodeIdsSeen.add(nid)) {
0965:                        tallyLevel(level, binsSeenByLevel);
0966:                        verifyNode(node);
0967:                    }
0968:                }
0969:
0970:                public void processDIN(DIN node, Long nid, int level) {
0971:                    if (dinNodeIdsSeen.add(nid)) {
0972:                        tallyLevel(level, dinsSeenByLevel);
0973:                        verifyNode(node);
0974:                    }
0975:                }
0976:
0977:                public void processDBIN(DBIN node, Long nid, int level) {
0978:                    if (dbinNodeIdsSeen.add(nid)) {
0979:                        tallyLevel(level, dbinsSeenByLevel);
0980:                        verifyNode(node);
0981:                    }
0982:                }
0983:
0984:                public void processDupCountLN(DupCountLN node, Long nid) {
0985:                    dupCountLNsSeen.add(nid);
0986:                    verifyNode(node);
0987:                }
0988:
0989:                private void tallyLevel(int levelArg, long[] nodesSeenByLevel) {
0990:                    int level = levelArg;
0991:                    if (level >= IN.DBMAP_LEVEL) {
0992:                        return;
0993:                    }
0994:                    if (level >= IN.MAIN_LEVEL) {
0995:                        level &= ~IN.MAIN_LEVEL;
0996:                        if (level > mainTreeMaxDepth) {
0997:                            mainTreeMaxDepth = level;
0998:                        }
0999:                    } else {
1000:                        if (level > duplicateTreeMaxDepth) {
1001:                            duplicateTreeMaxDepth = level;
1002:                        }
1003:                    }
1004:
1005:                    nodesSeenByLevel[level]++;
1006:                }
1007:
1008:                public void incrementLNCount() {
1009:                    lnCount++;
1010:                    if (progressInterval != 0) {
1011:                        if ((lnCount % progressInterval) == 0) {
1012:                            copyToStats(useStats);
1013:                            progressStream.println(useStats);
1014:                        }
1015:                    }
1016:                }
1017:
1018:                public void incrementDeletedLNCount() {
1019:                    deletedLNCount++;
1020:                }
1021:
1022:                Set getINNodeIdsSeen() {
1023:                    return inNodeIdsSeen;
1024:                }
1025:
1026:                Set getBINNodeIdsSeen() {
1027:                    return binNodeIdsSeen;
1028:                }
1029:
1030:                Set getDINNodeIdsSeen() {
1031:                    return dinNodeIdsSeen;
1032:                }
1033:
1034:                Set getDBINNodeIdsSeen() {
1035:                    return dbinNodeIdsSeen;
1036:                }
1037:
1038:                long[] getINsByLevel() {
1039:                    return insSeenByLevel;
1040:                }
1041:
1042:                long[] getBINsByLevel() {
1043:                    return binsSeenByLevel;
1044:                }
1045:
1046:                long[] getDINsByLevel() {
1047:                    return dinsSeenByLevel;
1048:                }
1049:
1050:                long[] getDBINsByLevel() {
1051:                    return dbinsSeenByLevel;
1052:                }
1053:
1054:                long getLNCount() {
1055:                    return lnCount;
1056:                }
1057:
1058:                Set getDupCountLNCount() {
1059:                    return dupCountLNsSeen;
1060:                }
1061:
1062:                long getDeletedLNCount() {
1063:                    return deletedLNCount;
1064:                }
1065:
1066:                int getMainTreeMaxDepth() {
1067:                    return mainTreeMaxDepth;
1068:                }
1069:
1070:                int getDuplicateTreeMaxDepth() {
1071:                    return duplicateTreeMaxDepth;
1072:                }
1073:
1074:                private void copyToStats(DatabaseStats stats) {
1075:                    BtreeStats bStats = (BtreeStats) stats;
1076:                    bStats.setInternalNodeCount(getINNodeIdsSeen().size());
1077:                    bStats.setBottomInternalNodeCount(getBINNodeIdsSeen()
1078:                            .size());
1079:                    bStats.setDuplicateInternalNodeCount(getDINNodeIdsSeen()
1080:                            .size());
1081:                    bStats
1082:                            .setDuplicateBottomInternalNodeCount(getDBINNodeIdsSeen()
1083:                                    .size());
1084:                    bStats.setLeafNodeCount(getLNCount());
1085:                    bStats.setDeletedLeafNodeCount(getDeletedLNCount());
1086:                    bStats
1087:                            .setDupCountLeafNodeCount(getDupCountLNCount()
1088:                                    .size());
1089:                    bStats.setMainTreeMaxDepth(getMainTreeMaxDepth());
1090:                    bStats.setDuplicateTreeMaxDepth(getDuplicateTreeMaxDepth());
1091:                    bStats.setINsByLevel(getINsByLevel());
1092:                    bStats.setBINsByLevel(getBINsByLevel());
1093:                    bStats.setDINsByLevel(getDINsByLevel());
1094:                    bStats.setDBINsByLevel(getDBINsByLevel());
1095:                }
1096:            }
1097:
1098:            /**
1099:             * Preload exceptions, classes, callbacks.
1100:             */
1101:
1102:            /**
1103:             * Undeclared exception used to throw through SortedLSNTreeWalker code
1104:             * when preload has either filled the user's max byte or time request.
1105:             */
1106:            private static class HaltPreloadException extends RuntimeException {
1107:
1108:                private PreloadStatus status;
1109:
1110:                HaltPreloadException(PreloadStatus status) {
1111:                    super (status.toString());
1112:                    this .status = status;
1113:                }
1114:
1115:                PreloadStatus getStatus() {
1116:                    return status;
1117:                }
1118:            }
1119:
1120:            private static final HaltPreloadException TIME_EXCEEDED_PRELOAD_EXCEPTION = new HaltPreloadException(
1121:                    PreloadStatus.EXCEEDED_TIME);
1122:
1123:            private static final HaltPreloadException MEMORY_EXCEEDED_PRELOAD_EXCEPTION = new HaltPreloadException(
1124:                    PreloadStatus.FILLED_CACHE);
1125:
1126:            /**
1127:             * The processLSN() code for PreloadLSNTreeWalker.
1128:             */
1129:            private static class PreloadProcessor implements  TreeNodeProcessor {
1130:
1131:                private EnvironmentImpl envImpl;
1132:                private long maxBytes;
1133:                private long targetTime;
1134:                private PreloadStats stats;
1135:
1136:                PreloadProcessor(EnvironmentImpl envImpl, long maxBytes,
1137:                        long targetTime, PreloadStats stats) {
1138:                    this .envImpl = envImpl;
1139:                    this .maxBytes = maxBytes;
1140:                    this .targetTime = targetTime;
1141:                    this .stats = stats;
1142:                }
1143:
1144:                /**
1145:                 * Called for each LSN that the SortedLSNTreeWalker encounters.
1146:                 */
1147:                public void processLSN(long childLsn, LogEntryType childType,
1148:                        Node ignore, byte[] ignore2) throws DatabaseException {
1149:
1150:                    assert childLsn != DbLsn.NULL_LSN;
1151:
1152:                    /*
1153:                     * Check if we've exceeded either the max time or max bytes
1154:                     * allowed for this preload() call.
1155:                     */
1156:                    if (System.currentTimeMillis() > targetTime) {
1157:                        throw TIME_EXCEEDED_PRELOAD_EXCEPTION;
1158:                    }
1159:
1160:                    if (envImpl.getMemoryBudget().getCacheMemoryUsage() > maxBytes) {
1161:                        throw MEMORY_EXCEEDED_PRELOAD_EXCEPTION;
1162:                    }
1163:
1164:                    /* Count entry types to return in the PreloadStats. */
1165:                    if (childType
1166:                            .equals(LogEntryType.LOG_DUPCOUNTLN_TRANSACTIONAL)
1167:                            || childType.equals(LogEntryType.LOG_DUPCOUNTLN)) {
1168:                        stats.nDupCountLNsLoaded++;
1169:                    } else if (childType
1170:                            .equals(LogEntryType.LOG_LN_TRANSACTIONAL)
1171:                            || childType.equals(LogEntryType.LOG_LN)) {
1172:                        stats.nLNsLoaded++;
1173:                    } else if (childType.equals(LogEntryType.LOG_DBIN)) {
1174:                        stats.nDBINsLoaded++;
1175:                    } else if (childType.equals(LogEntryType.LOG_BIN)) {
1176:                        stats.nBINsLoaded++;
1177:                    } else if (childType.equals(LogEntryType.LOG_DIN)) {
1178:                        stats.nDINsLoaded++;
1179:                    } else if (childType.equals(LogEntryType.LOG_IN)) {
1180:                        stats.nINsLoaded++;
1181:                    }
1182:                }
1183:
1184:                public void processDirtyDeletedLN(long childLsn, LN ln,
1185:                        byte[] lnKey) throws DatabaseException {
1186:                }
1187:
1188:                public void processDupCount(long ignore) {
1189:                }
1190:            }
1191:
1192:            /*
1193:             * An extension of SortedLSNTreeWalker that provides an LSN to IN/index
1194:             * map.  When an LSN is processed by the tree walker, the map is used to
1195:             * lookup the parent IN and child entry index of each LSN processed by the
1196:             * tree walker.
1197:             */
1198:            private static class PreloadLSNTreeWalker extends
1199:                    SortedLSNTreeWalker {
1200:
1201:                /* LSN -> INEntry */
1202:                private Map lsnINMap = new HashMap();
1203:
1204:                /* struct to hold IN/entry-index pair. */
1205:                private static class INEntry {
1206:                    INEntry(IN in, int index) {
1207:                        this .in = in;
1208:                        this .index = index;
1209:                    }
1210:
1211:                    IN in;
1212:                    int index;
1213:                }
1214:
1215:                PreloadLSNTreeWalker(DatabaseImpl db,
1216:                        TreeNodeProcessor callback, PreloadConfig conf)
1217:                        throws DatabaseException {
1218:
1219:                    super (db, false, false, db.tree.getRootLsn(), callback,
1220:                            null, null); /* savedException, exception predicate */
1221:                    accumulateLNs = conf.getLoadLNs();
1222:                }
1223:
1224:                private final class PreloadWithRootLatched implements 
1225:                        WithRootLatched {
1226:
1227:                    public IN doWork(ChildReference root)
1228:                            throws DatabaseException {
1229:
1230:                        walkInternal();
1231:                        return null;
1232:                    }
1233:                }
1234:
1235:                public void walk() throws DatabaseException {
1236:
1237:                    WithRootLatched preloadWRL = new PreloadWithRootLatched();
1238:                    dbImpl.getTree().withRootLatchedExclusive(preloadWRL);
1239:                }
1240:
1241:                /*
1242:                 * Method to get the Root IN for this DatabaseImpl's tree.  Latches
1243:                 * the root IN.
1244:                 */
1245:                protected IN getRootIN(long rootLsn) throws DatabaseException {
1246:
1247:                    return dbImpl.getTree().getRootIN(false);
1248:                }
1249:
1250:                /*
1251:                 * Release the latch on the root IN.
1252:                 */
1253:                protected void releaseRootIN(IN root) throws DatabaseException {
1254:
1255:                    root.releaseLatch();
1256:                }
1257:
1258:                /*
1259:                 * Add an LSN -> IN/index entry to the map.
1260:                 */
1261:                protected void addToLsnINMap(Long lsn, IN in, int index) {
1262:                    assert in.getDatabase() != null;
1263:                    lsnINMap.put(lsn, new INEntry(in, index));
1264:                }
1265:
1266:                /*
1267:                 * Process an LSN.  Get & remove its INEntry from the map, then fetch
1268:                 * the target at the INEntry's IN/index pair.  This method will be
1269:                 * called in sorted LSN order.
1270:                 *
1271:                 * We do not bother to set the lnkeyEntry because we never use the
1272:                 * lnKey parameter in the processLSN method.
1273:                 */
1274:                protected Node fetchLSN(long lsn, DatabaseEntry lnKeyEntry)
1275:                        throws DatabaseException {
1276:
1277:                    INEntry inEntry = (INEntry) lsnINMap.remove(new Long(lsn));
1278:                    assert (inEntry != null);
1279:                    IN in = inEntry.in;
1280:                    in.latch();
1281:                    try {
1282:                        int index = inEntry.index;
1283:                        if (index < 0) {
1284:                            /* Negative index signifies a DupCountLN. */
1285:                            DIN din = (DIN) in;
1286:                            return din.getDupCountLN();
1287:                        } else {
1288:                            if (in.isEntryKnownDeleted(index)
1289:                                    || in.getLsn(index) != lsn) {
1290:                                return null;
1291:                            }
1292:                        }
1293:                        return in.fetchTarget(index);
1294:                    } finally {
1295:                        in.releaseLatch();
1296:                    }
1297:                }
1298:            }
1299:
1300:            /**
1301:             * Preload the cache, using up to maxBytes bytes or maxMillsecs msec.
1302:             */
1303:            public PreloadStats preload(PreloadConfig config)
1304:                    throws DatabaseException {
1305:
1306:                try {
1307:                    long maxBytes = config.getMaxBytes();
1308:                    long maxMillisecs = config.getMaxMillisecs();
1309:                    long targetTime = Long.MAX_VALUE;
1310:                    if (maxMillisecs > 0) {
1311:                        targetTime = System.currentTimeMillis() + maxMillisecs;
1312:                    }
1313:
1314:                    long cacheBudget = envImpl.getMemoryBudget()
1315:                            .getCacheBudget();
1316:                    if (maxBytes == 0) {
1317:                        maxBytes = cacheBudget;
1318:                    } else if (maxBytes > cacheBudget) {
1319:                        throw new IllegalArgumentException(
1320:                                "maxBytes parameter to Database.preload() was "
1321:                                        + "specified as " + maxBytes
1322:                                        + " bytes \nbut the cache is only "
1323:                                        + cacheBudget + " bytes.");
1324:                    }
1325:
1326:                    PreloadStats ret = new PreloadStats();
1327:                    PreloadProcessor callback = new PreloadProcessor(envImpl,
1328:                            maxBytes, targetTime, ret);
1329:                    SortedLSNTreeWalker walker = new PreloadLSNTreeWalker(this ,
1330:                            callback, config);
1331:                    try {
1332:                        walker.walk();
1333:                    } catch (HaltPreloadException HPE) {
1334:                        ret.status = HPE.getStatus();
1335:                    }
1336:
1337:                    assert LatchSupport.countLatchesHeld() == 0;
1338:                    return ret;
1339:                } catch (Error E) {
1340:                    envImpl.invalidate(E);
1341:                    throw E;
1342:                }
1343:            }
1344:
1345:            /**
1346:             * The processLSN() code for PreloadLSNTreeWalker.
1347:             */
1348:            private static class CountProcessor implements  TreeNodeProcessor {
1349:
1350:                private EnvironmentImpl envImpl;
1351:                /* Use PreloadStats in case we ever want to count more than LNs. */
1352:                private PreloadStats stats;
1353:
1354:                CountProcessor(EnvironmentImpl envImpl, PreloadStats stats) {
1355:                    this .envImpl = envImpl;
1356:                    this .stats = stats;
1357:                }
1358:
1359:                /**
1360:                 * Called for each LSN that the SortedLSNTreeWalker encounters.
1361:                 */
1362:                public void processLSN(long childLsn, LogEntryType childType,
1363:                        Node ignore, byte[] ignore2) throws DatabaseException {
1364:
1365:                    /* Count entry types to return in the PreloadStats. */
1366:                    if (childType
1367:                            .equals(LogEntryType.LOG_DUPCOUNTLN_TRANSACTIONAL)
1368:                            || childType.equals(LogEntryType.LOG_DUPCOUNTLN)) {
1369:                        /* Don't descend down into the dup tree -- just use the DCL. */
1370:                        long dupCount = 0;
1371:                        DupCountLN dcl = (DupCountLN) envImpl.getLogManager()
1372:                                .get(childLsn);
1373:                        dupCount = dcl.getDupCount();
1374:                        stats.nLNsLoaded += dupCount;
1375:                    } else if (childType
1376:                            .equals(LogEntryType.LOG_LN_TRANSACTIONAL)
1377:                            || childType.equals(LogEntryType.LOG_LN)) {
1378:                        stats.nLNsLoaded++;
1379:                    }
1380:                }
1381:
1382:                public void processDirtyDeletedLN(long childLsn, LN ln,
1383:                        byte[] lnKey) throws DatabaseException {
1384:                }
1385:
1386:                /* Used when processing Deferred Write dbs and there are no LSNs. */
1387:                public void processDupCount(long count) {
1388:                    stats.nLNsLoaded += count;
1389:                }
1390:            }
1391:
1392:            private static class CountExceptionPredicate implements 
1393:                    ExceptionPredicate {
1394:
1395:                /*
1396:                 * Return true if the exception can be ignored.
1397:                 * LogFileNotFoundException is the only one so far.
1398:                 */
1399:                public boolean ignoreException(Exception e) {
1400:                    if (e instanceof  LogFileNotFoundException) {
1401:                        return true;
1402:                    }
1403:                    return false;
1404:                }
1405:            }
1406:
1407:            /**
1408:             * Count entries in the database including dups, but don't dirty the cache.
1409:             */
1410:            public long count() throws DatabaseException {
1411:
1412:                try {
1413:                    PreloadStats ret = new PreloadStats();
1414:
1415:                    CountProcessor callback = new CountProcessor(envImpl, ret);
1416:                    ExceptionPredicate excPredicate = new CountExceptionPredicate();
1417:                    SortedLSNTreeWalker walker = new SortedLSNTreeWalker(this ,
1418:                            false, false, tree.getRootLsn(), callback, null,
1419:                            excPredicate);
1420:                    /* Don't descend down into the dup tree. Use the DupCountLN. */
1421:                    walker.setProcessDupTree(false);
1422:                    if (deferredWrite) {
1423:                        walker.setPassNullLSNNodes(true);
1424:                    }
1425:                    walker.walk();
1426:
1427:                    assert LatchSupport.countLatchesHeld() == 0;
1428:                    return ret.nLNsLoaded;
1429:                } catch (Error E) {
1430:                    envImpl.invalidate(E);
1431:                    throw E;
1432:                }
1433:            }
1434:
1435:            /*
1436:             * Dumping
1437:             */
1438:            public String dumpString(int nSpaces) {
1439:                StringBuffer sb = new StringBuffer();
1440:                sb.append(TreeUtils.indent(nSpaces));
1441:                sb.append("<database id=\"");
1442:                sb.append(id.toString());
1443:                sb.append("\"");
1444:                if (btreeComparator != null) {
1445:                    sb.append(" btc=\"");
1446:                    sb.append(getComparatorClassName(btreeComparator));
1447:                    sb.append("\"");
1448:                }
1449:                if (duplicateComparator != null) {
1450:                    sb.append(" dupc=\"");
1451:                    sb.append(getComparatorClassName(duplicateComparator));
1452:                    sb.append("\"");
1453:                }
1454:                sb.append("/>");
1455:                return sb.toString();
1456:            }
1457:
1458:            /*
1459:             * Logging support
1460:             */
1461:
1462:            /**
1463:             * @see Loggable#getLogSize
1464:             */
1465:            public int getLogSize() {
1466:                return id.getLogSize()
1467:                        + tree.getLogSize()
1468:                        + LogUtils.getBooleanLogSize()
1469:                        + LogUtils.getByteArrayLogSize(btreeComparatorBytes)
1470:                        + LogUtils
1471:                                .getByteArrayLogSize(duplicateComparatorBytes)
1472:                        + (LogUtils.getIntLogSize() * 2);
1473:            }
1474:
1475:            /**
1476:             * @see Loggable#writeToLog
1477:             */
1478:            public void writeToLog(ByteBuffer logBuffer) {
1479:                id.writeToLog(logBuffer);
1480:                tree.writeToLog(logBuffer);
1481:                LogUtils.writeBoolean(logBuffer, duplicatesAllowed);
1482:                LogUtils.writeByteArray(logBuffer, btreeComparatorBytes);
1483:                LogUtils.writeByteArray(logBuffer, duplicateComparatorBytes);
1484:                LogUtils.writeInt(logBuffer, maxMainTreeEntriesPerNode);
1485:                LogUtils.writeInt(logBuffer, maxDupTreeEntriesPerNode);
1486:            }
1487:
1488:            /**
1489:             * @see Loggable#readFromLog
1490:             */
1491:            public void readFromLog(ByteBuffer itemBuffer, byte entryTypeVersion)
1492:                    throws LogException {
1493:
1494:                id.readFromLog(itemBuffer, entryTypeVersion);
1495:                tree.readFromLog(itemBuffer, entryTypeVersion);
1496:                duplicatesAllowed = LogUtils.readBoolean(itemBuffer);
1497:
1498:                if (entryTypeVersion >= 2) {
1499:                    btreeComparatorBytes = LogUtils.readByteArray(itemBuffer);
1500:                    duplicateComparatorBytes = LogUtils
1501:                            .readByteArray(itemBuffer);
1502:                } else {
1503:                    String btreeClassName = LogUtils.readString(itemBuffer);
1504:                    String dupClassName = LogUtils.readString(itemBuffer);
1505:                    if (btreeClassName.length() == 0) {
1506:                        btreeComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY;
1507:                    } else {
1508:                        btreeComparatorBytes = objectToBytes(btreeClassName,
1509:                                "Btree");
1510:                    }
1511:                    if (dupClassName.length() == 0) {
1512:                        duplicateComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY;
1513:                    } else {
1514:                        duplicateComparatorBytes = objectToBytes(dupClassName,
1515:                                "Duplicate");
1516:                    }
1517:                }
1518:
1519:                /* Don't instantiate if comparators are unnecessary (DbPrintLog). */
1520:                if (!EnvironmentImpl.getNoComparators()) {
1521:                    try {
1522:                        if (btreeComparatorBytes.length != 0) {
1523:                            Object obj = bytesToObject(btreeComparatorBytes,
1524:                                    "Btree");
1525:                            if (obj instanceof  String) {
1526:                                Class cls = Class.forName((String) obj);
1527:                                btreeComparator = instantiateComparator(cls,
1528:                                        "Btree");
1529:                                btreeComparatorByClassName = true;
1530:                            } else if (obj instanceof  Comparator) {
1531:                                btreeComparator = (Comparator) obj;
1532:                                btreeComparatorByClassName = false;
1533:                            } else {
1534:                                assert false : obj.getClass().getName();
1535:                            }
1536:                        } else {
1537:                            btreeComparator = null;
1538:                            btreeComparatorByClassName = false;
1539:                        }
1540:                        if (duplicateComparatorBytes.length != 0) {
1541:                            Object obj = bytesToObject(
1542:                                    duplicateComparatorBytes, "Duplicate");
1543:                            if (obj instanceof  String) {
1544:                                Class cls = Class.forName((String) obj);
1545:                                duplicateComparator = instantiateComparator(
1546:                                        cls, "Duplicate");
1547:                                duplicateComparatorByClassName = true;
1548:                            } else if (obj instanceof  Comparator) {
1549:                                duplicateComparator = (Comparator) obj;
1550:                                duplicateComparatorByClassName = false;
1551:                            } else {
1552:                                assert false : obj.getClass().getName();
1553:                            }
1554:                        } else {
1555:                            duplicateComparator = null;
1556:                            duplicateComparatorByClassName = false;
1557:                        }
1558:                    } catch (ClassNotFoundException CNFE) {
1559:                        throw new LogException(
1560:                                "couldn't instantiate class comparator", CNFE);
1561:                    }
1562:                }
1563:
1564:                if (entryTypeVersion >= 1) {
1565:                    maxMainTreeEntriesPerNode = LogUtils.readInt(itemBuffer);
1566:                    maxDupTreeEntriesPerNode = LogUtils.readInt(itemBuffer);
1567:                }
1568:            }
1569:
1570:            /**
1571:             * @see Loggable#dumpLog
1572:             */
1573:            public void dumpLog(StringBuffer sb, boolean verbose) {
1574:                sb.append("<database>");
1575:                id.dumpLog(sb, verbose);
1576:                tree.dumpLog(sb, verbose);
1577:                sb.append("<dupsort v=\"").append(duplicatesAllowed);
1578:                sb.append("\"/>");
1579:                sb.append("<btcf name=\"");
1580:                sb.append(getComparatorClassName(btreeComparator));
1581:                sb.append("\"/>");
1582:                sb.append("<dupcf name=\"");
1583:                sb.append(getComparatorClassName(duplicateComparator));
1584:                sb.append("\"/>");
1585:                sb.append("</database>");
1586:            }
1587:
1588:            /**
1589:             * @see Loggable#getTransactionId
1590:             */
1591:            public long getTransactionId() {
1592:                return 0;
1593:            }
1594:
1595:            /**
1596:             * Used for log dumping.
1597:             */
1598:            private static String getComparatorClassName(Comparator comparator) {
1599:                if (comparator != null) {
1600:                    return comparator.getClass().getName();
1601:                } else {
1602:                    return "";
1603:                }
1604:            }
1605:
1606:            /**
1607:             * Used both to read from the log and to validate a comparator when set in
1608:             * DatabaseConfig.
1609:             */
1610:            public static Comparator instantiateComparator(Class comparator,
1611:                    String comparatorType) throws LogException {
1612:
1613:                if (comparator == null) {
1614:                    return null;
1615:                }
1616:
1617:                try {
1618:                    return (Comparator) comparator.newInstance();
1619:                } catch (InstantiationException IE) {
1620:                    throw new LogException("Exception while trying to load "
1621:                            + comparatorType + " Comparator class: " + IE);
1622:                } catch (IllegalAccessException IAE) {
1623:                    throw new LogException("Exception while trying to load "
1624:                            + comparatorType + " Comparator class: " + IAE);
1625:                }
1626:            }
1627:
1628:            /**
1629:             * Used to validate a comparator when set in DatabaseConfig.
1630:             */
1631:            public static Comparator instantiateComparator(
1632:                    Comparator comparator, String comparatorType)
1633:                    throws DatabaseException {
1634:
1635:                if (comparator == null) {
1636:                    return null;
1637:                }
1638:
1639:                return (Comparator) bytesToObject(objectToBytes(comparator,
1640:                        comparatorType), comparatorType);
1641:            }
1642:
1643:            /**
1644:             * Converts a comparator object to a serialized byte array, converting to
1645:             * a class name String object if byClassName is true.
1646:             *
1647:             * @throws LogException if the object cannot be serialized.
1648:             */
1649:            private static byte[] comparatorToBytes(Comparator comparator,
1650:                    boolean byClassName, String comparatorType)
1651:                    throws DatabaseException {
1652:
1653:                if (comparator == null) {
1654:                    return LogUtils.ZERO_LENGTH_BYTE_ARRAY;
1655:                } else {
1656:                    Object obj;
1657:                    if (byClassName) {
1658:                        obj = comparator.getClass().getName();
1659:                    } else {
1660:                        obj = comparator;
1661:                    }
1662:                    return objectToBytes(obj, comparatorType);
1663:                }
1664:            }
1665:
1666:            /**
1667:             * Converts an arbitrary object to a serialized byte array.  Assumes that
1668:             * the object given is non-null.
1669:             */
1670:            public static byte[] objectToBytes(Object obj, String comparatorType)
1671:                    throws LogException {
1672:
1673:                try {
1674:                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
1675:                    ObjectOutputStream oos = new ObjectOutputStream(baos);
1676:                    oos.writeObject(obj);
1677:                    return baos.toByteArray();
1678:                } catch (IOException e) {
1679:                    throw new LogException("Exception while trying to load "
1680:                            + comparatorType + ": " + e);
1681:                }
1682:            }
1683:
1684:            /**
1685:             * Converts an arbitrary serialized byte array to an object.  Assumes that
1686:             * the byte array given is non-null and has a non-zero length.
1687:             */
1688:            private static Object bytesToObject(byte[] bytes,
1689:                    String comparatorType) throws LogException {
1690:
1691:                try {
1692:                    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
1693:                    ObjectInputStream ois = new ObjectInputStream(bais);
1694:                    return ois.readObject();
1695:                } catch (IOException e) {
1696:                    throw new LogException("Exception while trying to load "
1697:                            + comparatorType + ": " + e);
1698:                } catch (ClassNotFoundException e) {
1699:                    throw new LogException("Exception while trying to load "
1700:                            + comparatorType + ": " + e);
1701:                }
1702:            }
1703:
1704:            public int getBinDeltaPercent() {
1705:                return binDeltaPercent;
1706:            }
1707:
1708:            public int getBinMaxDeltas() {
1709:                return binMaxDeltas;
1710:            }
1711:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.