1 8 9 package com.sleepycat.je.dbi; 10 11 import java.io.ByteArrayInputStream ; 12 import java.io.ByteArrayOutputStream ; 13 import java.io.IOException ; 14 import java.io.ObjectInputStream ; 15 import java.io.ObjectOutputStream ; 16 import java.io.PrintStream ; 17 import java.nio.ByteBuffer ; 18 import java.util.Collections ; 19 import java.util.Comparator ; 20 import java.util.HashMap ; 21 import java.util.HashSet ; 22 import java.util.Iterator ; 23 import java.util.Map ; 24 import java.util.Set ; 25 26 import com.sleepycat.je.BtreeStats; 27 import com.sleepycat.je.Cursor; 28 import com.sleepycat.je.Database; 29 import com.sleepycat.je.DatabaseConfig; 30 import com.sleepycat.je.DatabaseEntry; 31 import com.sleepycat.je.DatabaseException; 32 import com.sleepycat.je.DatabaseStats; 33 import com.sleepycat.je.DbInternal; 34 import com.sleepycat.je.LockMode; 35 import com.sleepycat.je.OperationStatus; 36 import com.sleepycat.je.PreloadConfig; 37 import com.sleepycat.je.PreloadStats; 38 import com.sleepycat.je.PreloadStatus; 39 import com.sleepycat.je.SecondaryDatabase; 40 import com.sleepycat.je.StatsConfig; 41 import com.sleepycat.je.VerifyConfig; 42 import com.sleepycat.je.cleaner.UtilizationTracker; 43 import com.sleepycat.je.config.EnvironmentParams; 44 import com.sleepycat.je.dbi.SortedLSNTreeWalker.ExceptionPredicate; 45 import com.sleepycat.je.dbi.SortedLSNTreeWalker.TreeNodeProcessor; 46 import com.sleepycat.je.latch.LatchSupport; 47 import com.sleepycat.je.log.LogEntryType; 48 import com.sleepycat.je.log.LogException; 49 import com.sleepycat.je.log.LogFileNotFoundException; 50 import com.sleepycat.je.log.LogReadable; 51 import com.sleepycat.je.log.LogUtils; 52 import com.sleepycat.je.log.LogWritable; 53 import com.sleepycat.je.recovery.Checkpointer; 54 import com.sleepycat.je.tree.BIN; 55 import com.sleepycat.je.tree.ChildReference; 56 import com.sleepycat.je.tree.DBIN; 57 import com.sleepycat.je.tree.DIN; 58 import com.sleepycat.je.tree.DupCountLN; 59 import com.sleepycat.je.tree.IN; 60 import com.sleepycat.je.tree.LN; 61 import com.sleepycat.je.tree.Node; 62 import com.sleepycat.je.tree.Tree; 63 import com.sleepycat.je.tree.TreeUtils; 64 import com.sleepycat.je.tree.TreeWalkerStatsAccumulator; 65 import com.sleepycat.je.tree.WithRootLatched; 66 import com.sleepycat.je.txn.Locker; 67 import com.sleepycat.je.txn.ThreadLocker; 68 import com.sleepycat.je.utilint.CmdUtil; 69 import com.sleepycat.je.utilint.DbLsn; 70 import com.sleepycat.je.utilint.TestHook; 71 72 75 public class DatabaseImpl 76 implements LogWritable, LogReadable, Cloneable { 77 78 82 private static final short NOT_DELETED = 1; 83 private static final short DELETED_CLEANUP_INLIST_HARVEST = 2; 84 private static final short DELETED_CLEANUP_LOG_HARVEST = 3; 85 private static final short DELETED = 4; 86 87 private DatabaseId id; private Tree tree; 89 private EnvironmentImpl envImpl; private boolean duplicatesAllowed; private boolean transactional; private boolean deferredWrite; private Set referringHandles; private BtreeStats stats; private long eofNodeId; private short deleteState; 98 101 private Comparator btreeComparator = null; 102 private Comparator duplicateComparator = null; 103 private byte[] btreeComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY; 104 private byte[] duplicateComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY; 105 private boolean btreeComparatorByClassName = false; 106 private boolean duplicateComparatorByClassName = false; 107 108 111 private int binDeltaPercent; 112 private int binMaxDeltas; 113 private int maxMainTreeEntriesPerNode; 114 private int maxDupTreeEntriesPerNode; 115 116 121 private String debugDatabaseName; 122 123 124 private TestHook pendingDeletedHook; 125 126 129 public DatabaseImpl(String dbName, 130 DatabaseId id, 131 EnvironmentImpl envImpl, 132 DatabaseConfig dbConfig) 133 throws DatabaseException { 134 135 this.id = id; 136 this.envImpl = envImpl; 137 setBtreeComparator(dbConfig.getBtreeComparator(), 138 dbConfig.getBtreeComparatorByClassName()); 139 setDuplicateComparator(dbConfig.getDuplicateComparator(), 140 dbConfig.getDuplicateComparatorByClassName()); 141 duplicatesAllowed = dbConfig.getSortedDuplicates(); 142 transactional = dbConfig.getTransactional(); 143 deferredWrite = dbConfig.getDeferredWrite(); 144 maxMainTreeEntriesPerNode = dbConfig.getNodeMaxEntries(); 145 maxDupTreeEntriesPerNode = dbConfig.getNodeMaxDupTreeEntries(); 146 147 initDefaultSettings(); 148 149 deleteState = NOT_DELETED; 150 151 155 tree = new Tree(this); 156 referringHandles = Collections.synchronizedSet(new HashSet ()); 157 158 eofNodeId = Node.getNextNodeId(); 159 160 161 debugDatabaseName = dbName; 162 } 163 164 169 public DatabaseImpl() 170 throws DatabaseException { 171 172 id = new DatabaseId(); 173 envImpl = null; 174 175 deleteState = NOT_DELETED; 176 177 tree = new Tree(); 178 referringHandles = Collections.synchronizedSet(new HashSet ()); 179 180 181 182 eofNodeId = Node.getNextNodeId(); 183 } 184 185 public void setDebugDatabaseName(String debugName) { 186 debugDatabaseName = debugName; 187 } 188 189 public String getDebugName() { 190 return debugDatabaseName; 191 } 192 193 194 public void setPendingDeletedHook(TestHook hook) { 195 pendingDeletedHook = hook; 196 } 197 198 203 private void initDefaultSettings() 204 throws DatabaseException { 205 206 DbConfigManager configMgr = envImpl.getConfigManager(); 207 208 binDeltaPercent = 209 configMgr.getInt(EnvironmentParams.BIN_DELTA_PERCENT); 210 binMaxDeltas = 211 configMgr.getInt(EnvironmentParams.BIN_MAX_DELTAS); 212 213 if (maxMainTreeEntriesPerNode == 0) { 214 maxMainTreeEntriesPerNode = 215 configMgr.getInt(EnvironmentParams.NODE_MAX); 216 } 217 218 if (maxDupTreeEntriesPerNode == 0) { 219 maxDupTreeEntriesPerNode = 220 configMgr.getInt(EnvironmentParams.NODE_MAX_DUPTREE); 221 } 222 } 223 224 228 public Object clone() 229 throws CloneNotSupportedException { 230 231 return super.clone(); 232 } 233 234 237 public Tree getTree() { 238 return tree; 239 } 240 241 void setTree(Tree tree) { 242 this.tree = tree; 243 } 244 245 248 public DatabaseId getId() { 249 return id; 250 } 251 252 void setId(DatabaseId id) { 253 this.id = id; 254 } 255 256 public long getEofNodeId() { 257 return eofNodeId; 258 } 259 260 263 public boolean isTransactional() { 264 return transactional; 265 } 266 267 270 public void setTransactional(boolean transactional) { 271 this.transactional = transactional; 272 } 273 274 277 public boolean isDeferredWrite() { 278 return deferredWrite; 279 } 280 281 284 public void setDeferredWrite(boolean deferredWrite) { 285 this.deferredWrite = deferredWrite; 286 } 287 288 291 public boolean getSortedDuplicates() { 292 return duplicatesAllowed; 293 } 294 295 public int getNodeMaxEntries() { 296 return maxMainTreeEntriesPerNode; 297 } 298 299 public int getNodeMaxDupTreeEntries() { 300 return maxDupTreeEntriesPerNode; 301 } 302 303 311 public int getAdditionalMemorySize() { 312 313 int val = 0; 314 315 322 if (btreeComparator != null) { 323 val += 2 * MemoryBudget.byteArraySize 324 (btreeComparatorBytes.length); 325 } 326 if (duplicateComparator != null) { 327 val += 2 * MemoryBudget.byteArraySize 328 (duplicateComparatorBytes.length); 329 } 330 return val; 331 } 332 333 338 public void setDuplicateComparator(Comparator comparator, 339 boolean byClassName) 340 throws DatabaseException { 341 342 duplicateComparator = comparator; 343 duplicateComparatorBytes = 344 comparatorToBytes(comparator, byClassName, "Duplicate"); 345 duplicateComparatorByClassName = byClassName; 346 } 347 348 353 public void setBtreeComparator(Comparator comparator, 354 boolean byClassName) 355 throws DatabaseException { 356 357 btreeComparator = comparator; 358 btreeComparatorBytes = 359 comparatorToBytes(comparator, byClassName, "Btree"); 360 btreeComparatorByClassName = byClassName; 361 } 362 363 366 public Comparator getBtreeComparator() { 367 return btreeComparator; 368 } 369 370 373 public Comparator getDuplicateComparator() { 374 return duplicateComparator; 375 } 376 377 381 public boolean getBtreeComparatorByClass() { 382 return btreeComparatorByClassName; 383 } 384 385 389 public boolean getDuplicateComparatorByClass() { 390 return duplicateComparatorByClassName; 391 } 392 393 397 public void setEnvironmentImpl(EnvironmentImpl envImpl) 398 throws DatabaseException { 399 400 this.envImpl = envImpl; 401 initDefaultSettings(); 402 tree.setDatabase(this); 403 } 404 405 408 public EnvironmentImpl getDbEnvironment() { 409 return envImpl; 410 } 411 412 415 public boolean hasOpenHandles() { 416 return referringHandles.size() > 0; 417 } 418 419 422 public void addReferringHandle(Database db) { 423 referringHandles.add(db); 424 } 425 426 429 public void removeReferringHandle(Database db) { 430 referringHandles.remove(db); 431 } 432 433 436 synchronized int getReferringHandleCount() { 437 return referringHandles.size(); 438 } 439 440 443 public synchronized void sync(boolean flushLog) 444 throws DatabaseException { 445 446 if (!isDeferredWrite()) { 447 throw new DatabaseException("Database.sync() is only supported " + 448 "for deferred-write databases"); 449 } 450 451 if (tree.rootExists()) { 452 Checkpointer.syncDatabase(envImpl, this, flushLog); 453 } 454 } 455 456 461 public Database findPrimaryDatabase() 462 throws DatabaseException { 463 464 for (Iterator i = referringHandles.iterator(); i.hasNext();) { 465 Object obj = i.next(); 466 if (obj instanceof SecondaryDatabase) { 467 return ((SecondaryDatabase) obj).getPrimaryDatabase(); 468 } 469 } 470 return null; 471 } 472 473 public String getName() 474 throws DatabaseException { 475 476 return envImpl.getDbMapTree().getDbName(id); 477 } 478 479 483 public boolean isDeleted() { 484 return !(deleteState == NOT_DELETED); 485 } 486 487 490 public boolean isDeleteFinished() { 491 return (deleteState == DELETED); 492 } 493 494 498 public void startDeleteProcessing() { 499 assert (deleteState == NOT_DELETED); 500 501 deleteState = DELETED_CLEANUP_INLIST_HARVEST; 502 } 503 504 508 void finishedINListHarvest() { 509 assert (deleteState == DELETED_CLEANUP_INLIST_HARVEST); 510 511 deleteState = DELETED_CLEANUP_LOG_HARVEST; 512 } 513 514 526 public void deleteAndReleaseINs() 527 throws DatabaseException { 528 529 startDeleteProcessing(); 530 releaseDeletedINs(); 531 } 532 533 public void releaseDeletedINs() 534 throws DatabaseException { 535 536 if (pendingDeletedHook != null) { 537 pendingDeletedHook.doHook(); 538 } 539 540 try { 541 542 546 long rootLsn = tree.getRootLsn(); 547 if (rootLsn == DbLsn.NULL_LSN) { 548 549 554 envImpl.getDbMapTree().deleteMapLN(id); 555 556 } else { 557 558 UtilizationTracker snapshot = new UtilizationTracker(envImpl); 559 560 565 snapshot.countObsoleteNodeInexact 566 (rootLsn, LogEntryType.LOG_IN, 0); 567 568 569 boolean fetchLNSize = 570 envImpl.getCleaner().getFetchObsoleteSize(); 571 572 573 ObsoleteProcessor obsoleteProcessor = 574 new ObsoleteProcessor(snapshot); 575 SortedLSNTreeWalker walker = new ObsoleteTreeWalker 576 (this, rootLsn, fetchLNSize, obsoleteProcessor); 577 578 587 envImpl.getDbMapTree().deleteMapLN(id); 588 589 593 walker.walk(); 594 595 600 envImpl.getUtilizationProfile().countAndLogSummaries 601 (snapshot.getTrackedFiles()); 602 } 603 } finally { 604 deleteState = DELETED; 605 } 606 } 607 608 public void checkIsDeleted(String operation) 609 throws DatabaseException { 610 611 if (isDeleted()) { 612 throw new DatabaseException 613 ("Attempt to " + operation + " a deleted database"); 614 } 615 } 616 617 private static class ObsoleteTreeWalker extends SortedLSNTreeWalker { 618 619 private ObsoleteTreeWalker(DatabaseImpl dbImpl, 620 long rootLsn, 621 boolean fetchLNSize, 622 TreeNodeProcessor callback) 623 throws DatabaseException { 624 625 super(dbImpl, 626 true, true, rootLsn, 629 callback, 630 null, 631 null); 632 633 accumulateLNs = fetchLNSize; 634 } 635 } 636 637 638 private static class ObsoleteProcessor implements TreeNodeProcessor { 639 640 private UtilizationTracker tracker; 641 642 ObsoleteProcessor(UtilizationTracker tracker) { 643 this.tracker = tracker; 644 } 645 646 public void processLSN(long childLsn, 647 LogEntryType childType, 648 Node node, 649 byte[] lnKey) 650 throws DatabaseException { 651 652 assert childLsn != DbLsn.NULL_LSN; 653 654 655 int size = 0; 656 if (lnKey != null && node instanceof LN) { 657 size = ((LN) node).getTotalLastLoggedSize(lnKey); 658 } 659 660 tracker.countObsoleteNodeInexact(childLsn, childType, size); 661 } 662 663 public void processDupCount(long ignore) { 664 } 665 } 666 667 public DatabaseStats stat(StatsConfig config) 668 throws DatabaseException { 669 670 if (stats == null) { 671 672 676 stats = new BtreeStats(); 677 } 678 679 if (!config.getFast()) { 680 if (tree == null) { 681 return new BtreeStats(); 682 } 683 684 PrintStream out = config.getShowProgressStream(); 685 if (out == null) { 686 out = System.err; 687 } 688 689 StatsAccumulator statsAcc = 690 new StatsAccumulator(out, 691 config.getShowProgressInterval(), 692 getEmptyStats()); 693 walkDatabaseTree(statsAcc, out, true); 694 statsAcc.copyToStats(stats); 695 } 696 697 return stats; 698 } 699 700 705 public boolean verify(VerifyConfig config, DatabaseStats emptyStats) 706 throws DatabaseException { 707 708 if (tree == null) { 709 return true; 710 } 711 712 PrintStream out = config.getShowProgressStream(); 713 if (out == null) { 714 out = System.err; 715 } 716 717 StatsAccumulator statsAcc = 718 new StatsAccumulator(out, 719 config.getShowProgressInterval(), 720 emptyStats) { 721 void verifyNode(Node node) { 722 723 try { 724 node.verify(null); 725 } catch (DatabaseException INE) { 726 progressStream.println(INE); 727 } 728 } 729 }; 730 boolean ok = walkDatabaseTree(statsAcc, out, config.getPrintInfo()); 731 statsAcc.copyToStats(emptyStats); 732 return ok; 733 } 734 735 736 public DatabaseStats getEmptyStats() { 737 return new BtreeStats(); 738 } 739 740 743 private boolean walkDatabaseTree(TreeWalkerStatsAccumulator statsAcc, 744 PrintStream out, 745 boolean verbose) 746 throws DatabaseException { 747 748 boolean ok = true; 749 Locker locker = new ThreadLocker(envImpl); 750 Cursor cursor = null; 751 CursorImpl impl = null; 752 try { 753 EnvironmentImpl.incThreadLocalReferenceCount(); 754 cursor = DbInternal.newCursor(this, locker, null); 755 impl = DbInternal.getCursorImpl(cursor); 756 tree.setTreeStatsAccumulator(statsAcc); 757 758 762 impl.setTreeStatsAccumulator(statsAcc); 763 DatabaseEntry foundData = new DatabaseEntry(); 764 DatabaseEntry key = new DatabaseEntry(); 765 OperationStatus status = DbInternal.position 766 (cursor, key, foundData, LockMode.READ_UNCOMMITTED, true); 767 while (status == OperationStatus.SUCCESS) { 768 try { 769 status = DbInternal.retrieveNext 770 (cursor, key, foundData, LockMode.READ_UNCOMMITTED, 771 GetMode.NEXT); 772 } catch (DatabaseException DBE) { 773 ok = false; 774 if (DbInternal.advanceCursor(cursor, key, foundData)) { 775 if (verbose) { 776 out.println("Error encountered (continuing):"); 777 out.println(DBE); 778 printErrorRecord(out, key, foundData); 779 } 780 } else { 781 throw DBE; 782 } 783 } 784 } 785 } finally { 786 if (impl != null) { 787 impl.setTreeStatsAccumulator(null); 788 } 789 tree.setTreeStatsAccumulator(null); 790 EnvironmentImpl.decThreadLocalReferenceCount(); 791 if (cursor != null) { 792 cursor.close(); 793 } 794 } 795 796 return ok; 797 } 798 799 804 private void printErrorRecord(PrintStream out, 805 DatabaseEntry key, 806 DatabaseEntry data) { 807 808 byte[] bytes = key.getData(); 809 StringBuffer sb = new StringBuffer ("Error Key "); 810 if (bytes == null) { 811 sb.append("UNKNOWN"); 812 } else { 813 CmdUtil.formatEntry(sb, bytes, false); 814 sb.append(' '); 815 CmdUtil.formatEntry(sb, bytes, true); 816 } 817 out.println(sb); 818 819 bytes = data.getData(); 820 sb = new StringBuffer ("Error Data "); 821 if (bytes == null) { 822 sb.append("UNKNOWN"); 823 } else { 824 CmdUtil.formatEntry(sb, bytes, false); 825 sb.append(' '); 826 CmdUtil.formatEntry(sb, bytes, true); 827 } 828 out.println(sb); 829 } 830 831 static class StatsAccumulator implements TreeWalkerStatsAccumulator { 832 private Set inNodeIdsSeen = new HashSet (); 833 private Set binNodeIdsSeen = new HashSet (); 834 private Set dinNodeIdsSeen = new HashSet (); 835 private Set dbinNodeIdsSeen = new HashSet (); 836 private Set dupCountLNsSeen = new HashSet (); 837 private long[] insSeenByLevel = null; 838 private long[] binsSeenByLevel = null; 839 private long[] dinsSeenByLevel = null; 840 private long[] dbinsSeenByLevel = null; 841 private long lnCount = 0; 842 private long deletedLNCount = 0; 843 private int mainTreeMaxDepth = 0; 844 private int duplicateTreeMaxDepth = 0; 845 private DatabaseStats useStats; 846 847 PrintStream progressStream; 848 int progressInterval; 849 850 851 private static final int MAX_LEVELS = 100; 852 853 StatsAccumulator(PrintStream progressStream, 854 int progressInterval, 855 DatabaseStats useStats) { 856 857 this.progressStream = progressStream; 858 this.progressInterval = progressInterval; 859 860 insSeenByLevel = new long[MAX_LEVELS]; 861 binsSeenByLevel = new long[MAX_LEVELS]; 862 dinsSeenByLevel = new long[MAX_LEVELS]; 863 dbinsSeenByLevel = new long[MAX_LEVELS]; 864 865 this.useStats = useStats; 866 } 867 868 void verifyNode(Node node) { 869 870 } 871 872 public void processIN(IN node, Long nid, int level) { 873 if (inNodeIdsSeen.add(nid)) { 874 tallyLevel(level, insSeenByLevel); 875 verifyNode(node); 876 } 877 } 878 879 public void processBIN(BIN node, Long nid, int level) { 880 if (binNodeIdsSeen.add(nid)) { 881 tallyLevel(level, binsSeenByLevel); 882 verifyNode(node); 883 } 884 } 885 886 public void processDIN(DIN node, Long nid, int level) { 887 if (dinNodeIdsSeen.add(nid)) { 888 tallyLevel(level, dinsSeenByLevel); 889 verifyNode(node); 890 } 891 } 892 893 public void processDBIN(DBIN node, Long nid, int level) { 894 if (dbinNodeIdsSeen.add(nid)) { 895 tallyLevel(level, dbinsSeenByLevel); 896 verifyNode(node); 897 } 898 } 899 900 public void processDupCountLN(DupCountLN node, Long nid) { 901 dupCountLNsSeen.add(nid); 902 verifyNode(node); 903 } 904 905 private void tallyLevel(int levelArg, long[] nodesSeenByLevel) { 906 int level = levelArg; 907 if (level >= IN.DBMAP_LEVEL) { 908 return; 909 } 910 if (level >= IN.MAIN_LEVEL) { 911 level &= ~IN.MAIN_LEVEL; 912 if (level > mainTreeMaxDepth) { 913 mainTreeMaxDepth = level; 914 } 915 } else { 916 if (level > duplicateTreeMaxDepth) { 917 duplicateTreeMaxDepth = level; 918 } 919 } 920 921 nodesSeenByLevel[level]++; 922 } 923 924 public void incrementLNCount() { 925 lnCount++; 926 if (progressInterval != 0) { 927 if ((lnCount % progressInterval) == 0) { 928 copyToStats(useStats); 929 progressStream.println(useStats); 930 } 931 } 932 } 933 934 public void incrementDeletedLNCount() { 935 deletedLNCount++; 936 } 937 938 Set getINNodeIdsSeen() { 939 return inNodeIdsSeen; 940 } 941 942 Set getBINNodeIdsSeen() { 943 return binNodeIdsSeen; 944 } 945 946 Set getDINNodeIdsSeen() { 947 return dinNodeIdsSeen; 948 } 949 950 Set getDBINNodeIdsSeen() { 951 return dbinNodeIdsSeen; 952 } 953 954 long[] getINsByLevel() { 955 return insSeenByLevel; 956 } 957 958 long[] getBINsByLevel() { 959 return binsSeenByLevel; 960 } 961 962 long[] getDINsByLevel() { 963 return dinsSeenByLevel; 964 } 965 966 long[] getDBINsByLevel() { 967 return dbinsSeenByLevel; 968 } 969 970 long getLNCount() { 971 return lnCount; 972 } 973 974 Set getDupCountLNCount() { 975 return dupCountLNsSeen; 976 } 977 978 long getDeletedLNCount() { 979 return deletedLNCount; 980 } 981 982 int getMainTreeMaxDepth() { 983 return mainTreeMaxDepth; 984 } 985 986 int getDuplicateTreeMaxDepth() { 987 return duplicateTreeMaxDepth; 988 } 989 990 private void copyToStats(DatabaseStats stats) { 991 BtreeStats bStats = (BtreeStats) stats; 992 bStats.setInternalNodeCount(getINNodeIdsSeen().size()); 993 bStats.setBottomInternalNodeCount 994 (getBINNodeIdsSeen().size()); 995 bStats.setDuplicateInternalNodeCount 996 (getDINNodeIdsSeen().size()); 997 bStats.setDuplicateBottomInternalNodeCount 998 (getDBINNodeIdsSeen().size()); 999 bStats.setLeafNodeCount(getLNCount()); 1000 bStats.setDeletedLeafNodeCount(getDeletedLNCount()); 1001 bStats.setDupCountLeafNodeCount 1002 (getDupCountLNCount().size()); 1003 bStats.setMainTreeMaxDepth(getMainTreeMaxDepth()); 1004 bStats.setDuplicateTreeMaxDepth(getDuplicateTreeMaxDepth()); 1005 bStats.setINsByLevel(getINsByLevel()); 1006 bStats.setBINsByLevel(getBINsByLevel()); 1007 bStats.setDINsByLevel(getDINsByLevel()); 1008 bStats.setDBINsByLevel(getDBINsByLevel()); 1009 } 1010 } 1011 1012 1015 1016 1020 private static class HaltPreloadException extends RuntimeException { 1021 1022 private PreloadStatus status; 1023 1024 HaltPreloadException(PreloadStatus status) { 1025 super(status.toString()); 1026 this.status = status; 1027 } 1028 1029 PreloadStatus getStatus() { 1030 return status; 1031 } 1032 } 1033 1034 private static final HaltPreloadException 1035 TIME_EXCEEDED_PRELOAD_EXCEPTION = 1036 new HaltPreloadException(PreloadStatus.EXCEEDED_TIME); 1037 1038 private static final HaltPreloadException 1039 MEMORY_EXCEEDED_PRELOAD_EXCEPTION = 1040 new HaltPreloadException(PreloadStatus.FILLED_CACHE); 1041 1042 1045 private static class PreloadProcessor implements TreeNodeProcessor { 1046 1047 private EnvironmentImpl envImpl; 1048 private long maxBytes; 1049 private long targetTime; 1050 private PreloadStats stats; 1051 1052 PreloadProcessor(EnvironmentImpl envImpl, 1053 long maxBytes, 1054 long targetTime, 1055 PreloadStats stats) { 1056 this.envImpl = envImpl; 1057 this.maxBytes = maxBytes; 1058 this.targetTime = targetTime; 1059 this.stats = stats; 1060 } 1061 1062 1065 public void processLSN(long childLsn, 1066 LogEntryType childType, 1067 Node ignore, 1068 byte[] ignore2) 1069 throws DatabaseException { 1070 1071 assert childLsn != DbLsn.NULL_LSN; 1072 1073 1077 if (System.currentTimeMillis() > targetTime) { 1078 throw TIME_EXCEEDED_PRELOAD_EXCEPTION; 1079 } 1080 1081 if (envImpl.getMemoryBudget().getCacheMemoryUsage() > maxBytes) { 1082 throw MEMORY_EXCEEDED_PRELOAD_EXCEPTION; 1083 } 1084 1085 1086 if (childType.equals(LogEntryType.LOG_DUPCOUNTLN_TRANSACTIONAL) || 1087 childType.equals(LogEntryType.LOG_DUPCOUNTLN)) { 1088 stats.nDupCountLNsLoaded++; 1089 } else if (childType.equals(LogEntryType.LOG_LN_TRANSACTIONAL) || 1090 childType.equals(LogEntryType.LOG_LN)) { 1091 stats.nLNsLoaded++; 1092 } else if (childType.equals(LogEntryType.LOG_DBIN)) { 1093 stats.nDBINsLoaded++; 1094 } else if (childType.equals(LogEntryType.LOG_BIN)) { 1095 stats.nBINsLoaded++; 1096 } else if (childType.equals(LogEntryType.LOG_DIN)) { 1097 stats.nDINsLoaded++; 1098 } else if (childType.equals(LogEntryType.LOG_IN)) { 1099 stats.nINsLoaded++; 1100 } 1101 } 1102 1103 public void processDupCount(long ignore) { 1104 } 1105 } 1106 1107 1113 private static class PreloadLSNTreeWalker extends SortedLSNTreeWalker { 1114 1115 1116 private Map lsnINMap = new HashMap (); 1117 1118 1119 private static class INEntry { 1120 INEntry(IN in, int index) { 1121 this.in = in; 1122 this.index = index; 1123 } 1124 1125 IN in; 1126 int index; 1127 } 1128 1129 PreloadLSNTreeWalker(DatabaseImpl db, 1130 TreeNodeProcessor callback, 1131 PreloadConfig conf) 1132 throws DatabaseException { 1133 1134 super(db, false, false, db.tree.getRootLsn(), callback, 1135 null, null); 1136 accumulateLNs = conf.getLoadLNs(); 1137 } 1138 1139 private final class PreloadWithRootLatched 1140 implements WithRootLatched { 1141 1142 public IN doWork(ChildReference root) 1143 throws DatabaseException { 1144 1145 walkInternal(); 1146 return null; 1147 } 1148 } 1149 1150 public void walk() 1151 throws DatabaseException { 1152 1153 WithRootLatched preloadWRL = new PreloadWithRootLatched(); 1154 dbImpl.getTree().withRootLatchedExclusive(preloadWRL); 1155 } 1156 1157 1161 protected IN getRootIN(long rootLsn) 1162 throws DatabaseException { 1163 1164 return dbImpl.getTree().getRootIN(false); 1165 } 1166 1167 1170 protected void releaseRootIN(IN root) 1171 throws DatabaseException { 1172 1173 root.releaseLatch(); 1174 } 1175 1176 1179 protected void addToLsnINMap(Long lsn, IN in, int index) { 1180 assert in.getDatabase() != null; 1181 lsnINMap.put(lsn, new INEntry(in, index)); 1182 } 1183 1184 1192 protected Node fetchLSN(long lsn, DatabaseEntry lnKeyEntry) 1193 throws DatabaseException { 1194 1195 INEntry inEntry = (INEntry) lsnINMap.remove(new Long (lsn)); 1196 assert (inEntry != null); 1197 IN in = inEntry.in; 1198 in.latch(); 1199 try { 1200 int index = inEntry.index; 1201 if (in.isEntryKnownDeleted(index) || 1202 in.getLsn(index) != lsn) { 1203 return null; 1204 } 1205 return in.fetchTarget(index); 1206 } finally { 1207 in.releaseLatch(); 1208 } 1209 } 1210 } 1211 1212 1215 public PreloadStats preload(PreloadConfig config) 1216 throws DatabaseException { 1217 1218 try { 1219 long maxBytes = config.getMaxBytes(); 1220 long maxMillisecs = config.getMaxMillisecs(); 1221 long targetTime = Long.MAX_VALUE; 1222 if (maxMillisecs > 0) { 1223 targetTime = System.currentTimeMillis() + maxMillisecs; 1224 } 1225 1226 long cacheBudget = envImpl.getMemoryBudget().getCacheBudget(); 1227 if (maxBytes == 0) { 1228 maxBytes = cacheBudget; 1229 } else if (maxBytes > cacheBudget) { 1230 throw new IllegalArgumentException 1231 ("maxBytes parameter to Database.preload() was " + 1232 "specified as " + 1233 maxBytes + " bytes \nbut the cache is only " + 1234 cacheBudget + " bytes."); 1235 } 1236 1237 PreloadStats ret = new PreloadStats(); 1238 PreloadProcessor callback = 1239 new PreloadProcessor(envImpl, maxBytes, targetTime, ret); 1240 SortedLSNTreeWalker walker = 1241 new PreloadLSNTreeWalker(this, callback, config); 1242 try { 1243 walker.walk(); 1244 } catch (HaltPreloadException HPE) { 1245 ret.status = HPE.getStatus(); 1246 } 1247 1248 assert LatchSupport.countLatchesHeld() == 0; 1249 return ret; 1250 } catch (Error E) { 1251 envImpl.invalidate(E); 1252 throw E; 1253 } 1254 } 1255 1256 1259 private static class CountProcessor implements TreeNodeProcessor { 1260 1261 private EnvironmentImpl envImpl; 1262 1263 private PreloadStats stats; 1264 1265 CountProcessor(EnvironmentImpl envImpl, 1266 PreloadStats stats) { 1267 this.envImpl = envImpl; 1268 this.stats = stats; 1269 } 1270 1271 1274 public void processLSN(long childLsn, 1275 LogEntryType childType, 1276 Node ignore, 1277 byte[] ignore2) 1278 throws DatabaseException { 1279 1280 1281 if (childType.equals(LogEntryType.LOG_DUPCOUNTLN_TRANSACTIONAL) || 1282 childType.equals(LogEntryType.LOG_DUPCOUNTLN)) { 1283 1284 long dupCount = 0; 1285 DupCountLN dcl = (DupCountLN) 1286 envImpl.getLogManager().get(childLsn); 1287 dupCount = dcl.getDupCount(); 1288 stats.nLNsLoaded += dupCount; 1289 } else if (childType.equals(LogEntryType.LOG_LN_TRANSACTIONAL) || 1290 childType.equals(LogEntryType.LOG_LN)) { 1291 stats.nLNsLoaded++; 1292 } 1293 } 1294 1295 1296 public void processDupCount(long count) { 1297 stats.nLNsLoaded += count; 1298 } 1299 } 1300 1301 private static class CountExceptionPredicate 1302 implements ExceptionPredicate { 1303 1304 1308 public boolean ignoreException(Exception e) { 1309 if (e instanceof LogFileNotFoundException) { 1310 return true; 1311 } 1312 return false; 1313 } 1314 } 1315 1316 1319 public long count() 1320 throws DatabaseException { 1321 1322 try { 1323 PreloadStats ret = new PreloadStats(); 1324 1325 CountProcessor callback = new CountProcessor(envImpl, ret); 1326 ExceptionPredicate excPredicate = new CountExceptionPredicate(); 1327 SortedLSNTreeWalker walker = 1328 new SortedLSNTreeWalker(this, false, false, 1329 tree.getRootLsn(), callback, null, 1330 excPredicate); 1331 1332 walker.setProcessDupTree(false); 1333 if (deferredWrite) { 1334 walker.setPassNullLSNNodes(true); 1335 } 1336 walker.walk(); 1337 1338 assert LatchSupport.countLatchesHeld() == 0; 1339 return ret.nLNsLoaded; 1340 } catch (Error E) { 1341 envImpl.invalidate(E); 1342 throw E; 1343 } 1344 } 1345 1346 1349 public String dumpString(int nSpaces) { 1350 StringBuffer sb = new StringBuffer (); 1351 sb.append(TreeUtils.indent(nSpaces)); 1352 sb.append("<database id=\"" ); 1353 sb.append(id.toString()); 1354 sb.append("\""); 1355 if (btreeComparator != null) { 1356 sb.append(" btc=\""); 1357 sb.append(getComparatorClassName(btreeComparator)); 1358 sb.append("\""); 1359 } 1360 if (duplicateComparator != null) { 1361 sb.append(" dupc=\""); 1362 sb.append(getComparatorClassName(duplicateComparator)); 1363 sb.append("\""); 1364 } 1365 sb.append("/>"); 1366 return sb.toString(); 1367 } 1368 1369 1372 1373 1379 public int getLastLoggedSize() { 1380 return getLogSizeInternal(true); 1381 } 1382 1383 1386 public int getLogSize() { 1387 return getLogSizeInternal(false); 1388 } 1389 1390 private int getLogSizeInternal(boolean lastLogged) { 1391 return 1392 id.getLogSize() + 1393 (lastLogged ? tree.getLastLoggedSize() : tree.getLogSize()) + 1394 LogUtils.getBooleanLogSize() + 1395 LogUtils.getByteArrayLogSize(btreeComparatorBytes) + 1396 LogUtils.getByteArrayLogSize(duplicateComparatorBytes) + 1397 (LogUtils.getIntLogSize() * 2); 1398 } 1399 1400 1403 public void writeToLog(ByteBuffer logBuffer) { 1404 id.writeToLog(logBuffer); 1405 tree.writeToLog(logBuffer); 1406 LogUtils.writeBoolean(logBuffer, duplicatesAllowed); 1407 LogUtils.writeByteArray(logBuffer, btreeComparatorBytes); 1408 LogUtils.writeByteArray(logBuffer, duplicateComparatorBytes); 1409 LogUtils.writeInt(logBuffer, maxMainTreeEntriesPerNode); 1410 LogUtils.writeInt(logBuffer, maxDupTreeEntriesPerNode); 1411 } 1412 1413 1416 public void readFromLog(ByteBuffer itemBuffer, byte entryTypeVersion) 1417 throws LogException { 1418 1419 id.readFromLog(itemBuffer, entryTypeVersion); 1420 tree.readFromLog(itemBuffer, entryTypeVersion); 1421 duplicatesAllowed = LogUtils.readBoolean(itemBuffer); 1422 1423 if (entryTypeVersion >= 2) { 1424 btreeComparatorBytes = LogUtils.readByteArray(itemBuffer); 1425 duplicateComparatorBytes = LogUtils.readByteArray(itemBuffer); 1426 } else { 1427 String btreeClassName = LogUtils.readString(itemBuffer); 1428 String dupClassName = LogUtils.readString(itemBuffer); 1429 if (btreeClassName.length() == 0) { 1430 btreeComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY; 1431 } else { 1432 btreeComparatorBytes = 1433 objectToBytes(btreeClassName, "Btree"); 1434 } 1435 if (dupClassName.length() == 0) { 1436 duplicateComparatorBytes = LogUtils.ZERO_LENGTH_BYTE_ARRAY; 1437 } else { 1438 duplicateComparatorBytes = 1439 objectToBytes(dupClassName, "Duplicate"); 1440 } 1441 } 1442 1443 1444 if (!EnvironmentImpl.getNoComparators()) { 1445 try { 1446 if (btreeComparatorBytes.length != 0) { 1447 Object obj = bytesToObject 1448 (btreeComparatorBytes, "Btree"); 1449 if (obj instanceof String ) { 1450 Class cls = Class.forName((String ) obj); 1451 btreeComparator = 1452 instantiateComparator(cls, "Btree"); 1453 btreeComparatorByClassName = true; 1454 } else if (obj instanceof Comparator ) { 1455 btreeComparator = (Comparator ) obj; 1456 btreeComparatorByClassName = false; 1457 } else { 1458 assert false : obj.getClass().getName(); 1459 } 1460 } else { 1461 btreeComparator = null; 1462 btreeComparatorByClassName = false; 1463 } 1464 if (duplicateComparatorBytes.length != 0) { 1465 Object obj = bytesToObject 1466 (duplicateComparatorBytes, "Duplicate"); 1467 if (obj instanceof String ) { 1468 Class cls = Class.forName((String ) obj); 1469 duplicateComparator = 1470 instantiateComparator(cls, "Duplicate"); 1471 duplicateComparatorByClassName = true; 1472 } else if (obj instanceof Comparator ) { 1473 duplicateComparator = (Comparator ) obj; 1474 duplicateComparatorByClassName = false; 1475 } else { 1476 assert false : obj.getClass().getName(); 1477 } 1478 } else { 1479 duplicateComparator = null; 1480 duplicateComparatorByClassName = false; 1481 } 1482 } catch (ClassNotFoundException CNFE) { 1483 throw new LogException("couldn't instantiate class comparator", 1484 CNFE); 1485 } 1486 } 1487 1488 if (entryTypeVersion >= 1) { 1489 maxMainTreeEntriesPerNode = LogUtils.readInt(itemBuffer); 1490 maxDupTreeEntriesPerNode = LogUtils.readInt(itemBuffer); 1491 } 1492 } 1493 1494 1497 public void dumpLog(StringBuffer sb, boolean verbose) { 1498 sb.append("<database>"); 1499 id.dumpLog(sb, verbose); 1500 tree.dumpLog(sb, verbose); 1501 sb.append("<dupsort v=\"").append(duplicatesAllowed); 1502 sb.append("\"/>"); 1503 sb.append("<btcf name=\""); 1504 sb.append(getComparatorClassName(btreeComparator)); 1505 sb.append("\"/>"); 1506 sb.append("<dupcf name=\""); 1507 sb.append(getComparatorClassName(duplicateComparator)); 1508 sb.append("\"/>"); 1509 sb.append("</database>"); 1510 } 1511 1512 1515 public boolean logEntryIsTransactional() { 1516 return false; 1517 } 1518 1519 1522 public long getTransactionId() { 1523 return 0; 1524 } 1525 1526 1529 private static String getComparatorClassName(Comparator comparator) { 1530 if (comparator != null) { 1531 return comparator.getClass().getName(); 1532 } else { 1533 return ""; 1534 } 1535 } 1536 1537 1541 public static Comparator instantiateComparator(Class comparator, 1542 String comparatorType) 1543 throws LogException { 1544 1545 if (comparator == null) { 1546 return null; 1547 } 1548 1549 try { 1550 return (Comparator ) comparator.newInstance(); 1551 } catch (InstantiationException IE) { 1552 throw new LogException 1553 ("Exception while trying to load " + comparatorType + 1554 " Comparator class: " + IE); 1555 } catch (IllegalAccessException IAE) { 1556 throw new LogException 1557 ("Exception while trying to load " + comparatorType + 1558 " Comparator class: " + IAE); 1559 } 1560 } 1561 1562 1565 public static Comparator instantiateComparator(Comparator comparator, 1566 String comparatorType) 1567 throws DatabaseException { 1568 1569 if (comparator == null) { 1570 return null; 1571 } 1572 1573 return (Comparator ) bytesToObject 1574 (objectToBytes(comparator, comparatorType), comparatorType); 1575 } 1576 1577 1583 private static byte[] comparatorToBytes(Comparator comparator, 1584 boolean byClassName, 1585 String comparatorType) 1586 throws DatabaseException { 1587 1588 if (comparator == null) { 1589 return LogUtils.ZERO_LENGTH_BYTE_ARRAY; 1590 } else { 1591 Object obj; 1592 if (byClassName) { 1593 obj = comparator.getClass().getName(); 1594 } else { 1595 obj = comparator; 1596 } 1597 return objectToBytes(obj, comparatorType); 1598 } 1599 } 1600 1601 1605 public static byte[] objectToBytes(Object obj, 1606 String comparatorType) 1607 throws LogException { 1608 1609 try { 1610 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 1611 ObjectOutputStream oos = new ObjectOutputStream (baos); 1612 oos.writeObject(obj); 1613 return baos.toByteArray(); 1614 } catch (IOException e) { 1615 throw new LogException 1616 ("Exception while trying to load " + comparatorType + 1617 ": " + e); 1618 } 1619 } 1620 1621 1625 private static Object bytesToObject(byte[] bytes, 1626 String comparatorType) 1627 throws LogException { 1628 1629 try { 1630 ByteArrayInputStream bais = new ByteArrayInputStream (bytes); 1631 ObjectInputStream ois = new ObjectInputStream (bais); 1632 return ois.readObject(); 1633 } catch (IOException e) { 1634 throw new LogException 1635 ("Exception while trying to load " + comparatorType + 1636 ": " + e); 1637 } catch (ClassNotFoundException e) { 1638 throw new LogException 1639 ("Exception while trying to load " + comparatorType + 1640 ": " + e); 1641 } 1642 } 1643 1644 public int getBinDeltaPercent() { 1645 return binDeltaPercent; 1646 } 1647 1648 public int getBinMaxDeltas() { 1649 return binMaxDeltas; 1650 } 1651} 1652 | Popular Tags |