1 8 9 package com.sleepycat.je.tree; 10 11 import java.nio.ByteBuffer ; 12 import java.util.ArrayList ; 13 import java.util.List ; 14 import java.util.ListIterator ; 15 import java.util.logging.Level ; 16 import java.util.logging.Logger ; 17 18 import com.sleepycat.je.DatabaseException; 19 import com.sleepycat.je.cleaner.UtilizationTracker; 20 import com.sleepycat.je.config.EnvironmentParams; 21 import com.sleepycat.je.dbi.CursorImpl; 22 import com.sleepycat.je.dbi.DatabaseImpl; 23 import com.sleepycat.je.dbi.DbConfigManager; 24 import com.sleepycat.je.dbi.DbTree; 25 import com.sleepycat.je.dbi.EnvironmentImpl; 26 import com.sleepycat.je.dbi.INList; 27 import com.sleepycat.je.latch.LatchSupport; 28 import com.sleepycat.je.latch.SharedLatch; 29 import com.sleepycat.je.log.LogManager; 30 import com.sleepycat.je.log.LogReadable; 31 import com.sleepycat.je.log.LogUtils; 32 import com.sleepycat.je.log.LogWritable; 33 import com.sleepycat.je.recovery.RecoveryManager; 34 import com.sleepycat.je.txn.BasicLocker; 35 import com.sleepycat.je.txn.LockGrantType; 36 import com.sleepycat.je.txn.LockResult; 37 import com.sleepycat.je.txn.LockType; 38 import com.sleepycat.je.txn.Locker; 39 import com.sleepycat.je.txn.WriteLockInfo; 40 import com.sleepycat.je.utilint.DbLsn; 41 import com.sleepycat.je.utilint.TestHook; 42 import com.sleepycat.je.utilint.TestHookExecute; 43 import com.sleepycat.je.utilint.Tracer; 44 45 74 public final class Tree implements LogWritable, LogReadable { 75 76 77 private static final String TRACE_ROOT_SPLIT = "RootSplit:"; 78 private static final String TRACE_DUP_ROOT_SPLIT = "DupRootSplit:"; 79 private static final String TRACE_MUTATE = "Mut:"; 80 private static final String TRACE_INSERT = "Ins:"; 81 private static final String TRACE_INSERT_DUPLICATE = "InsD:"; 82 83 private DatabaseImpl database; 84 private ChildReference root; 85 private int maxMainTreeEntriesPerNode; 86 private int maxDupTreeEntriesPerNode; 87 private boolean purgeRoot; 88 89 94 private boolean rootLastLogged; 95 96 100 private SharedLatch rootLatch; 101 102 private TreeStats treeStats; 103 104 private ThreadLocal treeStatsAccumulatorTL = new ThreadLocal (); 105 106 111 private static SplitRequiredException splitRequiredException = 112 new SplitRequiredException(); 113 114 119 public static class SearchType { 120 121 public static final SearchType NORMAL = new SearchType(); 122 public static final SearchType LEFT = new SearchType(); 123 public static final SearchType RIGHT = new SearchType(); 124 125 126 private SearchType() { 127 } 128 } 129 130 131 private TestHook waitHook; private TestHook searchHook; private TestHook ckptHook; 135 138 public Tree(DatabaseImpl database) 139 throws DatabaseException { 140 141 init(database); 142 setDatabase(database); 143 } 144 145 148 public Tree() 149 throws DatabaseException { 150 151 init(null); 152 maxMainTreeEntriesPerNode = 0; 153 maxDupTreeEntriesPerNode = 0; 154 } 155 156 159 private void init(DatabaseImpl database) { 160 rootLatch = 161 LatchSupport.makeSharedLatch 162 ("RootLatch", 163 (database != null) ? database.getDbEnvironment() : null); 164 treeStats = new TreeStats(); 165 this.root = null; 166 this.database = database; 167 } 168 169 173 public void setDatabase(DatabaseImpl database) 174 throws DatabaseException { 175 176 this.database = database; 177 maxMainTreeEntriesPerNode = database.getNodeMaxEntries(); 178 maxDupTreeEntriesPerNode = database.getNodeMaxDupTreeEntries(); 179 DbConfigManager configManager = 180 database.getDbEnvironment().getConfigManager(); 181 purgeRoot = configManager.getBoolean 182 (EnvironmentParams.COMPRESSOR_PURGE_ROOT); 183 } 184 185 188 public DatabaseImpl getDatabase() { 189 return database; 190 } 191 192 195 public void setRoot(ChildReference newRoot, boolean notLatched) { 196 assert (notLatched || rootLatch.isWriteLockedByCurrentThread()); 197 root = newRoot; 198 } 199 200 public ChildReference makeRootChildReference(Node target, 201 byte[] key, 202 long lsn) { 203 return new RootChildReference(target, key, lsn); 204 } 205 206 private ChildReference makeRootChildReference() { 207 return new RootChildReference(); 208 } 209 210 217 public boolean rootExists() { 218 if (root == null) { 219 return false; 220 } 221 222 if ((root.getTarget() == null) && 223 (root.getLsn() == DbLsn.NULL_LSN)) { 224 return false; 225 } 226 227 return true; 228 } 229 230 234 private class RootChildReference extends ChildReference { 235 236 private RootChildReference() { 237 super(); 238 } 239 240 private RootChildReference(Node target, byte[] key, long lsn) { 241 super(target, key, lsn); 242 } 243 244 245 private RootChildReference(Node target, 246 byte[] key, 247 long lsn, 248 byte existingState) { 249 super(target, key, lsn, existingState); 250 } 251 252 253 public Node fetchTarget(DatabaseImpl database, IN in) 254 throws DatabaseException { 255 256 if (getTarget() == null && 257 !rootLatch.isWriteLockedByCurrentThread()) { 258 rootLatch.release(); 259 rootLatch.acquireExclusive(); 260 } 261 262 return super.fetchTarget(database, in); 263 } 264 265 public void setTarget(Node target) { 266 assert rootLatch.isWriteLockedByCurrentThread(); 267 super.setTarget(target); 268 } 269 270 public void clearTarget() { 271 assert rootLatch.isWriteLockedByCurrentThread(); 272 super.clearTarget(); 273 } 274 275 public void setLsn(long lsn) { 276 assert rootLatch.isWriteLockedByCurrentThread(); 277 super.setLsn(lsn); 278 } 279 280 void updateLsnAfterOptionaLog(DatabaseImpl dbImpl, long lsn) { 281 assert rootLatch.isWriteLockedByCurrentThread(); 282 super.updateLsnAfterOptionalLog(dbImpl, lsn); 283 } 284 } 285 286 290 public long getRootLsn() { 291 if (root == null) { 292 return DbLsn.NULL_LSN; 293 } else { 294 return root.getLsn(); 295 } 296 } 297 298 301 TreeStats getTreeStats() { 302 return treeStats; 303 } 304 305 private TreeWalkerStatsAccumulator getTreeStatsAccumulator() { 306 if (EnvironmentImpl.getThreadLocalReferenceCount() > 0) { 307 return (TreeWalkerStatsAccumulator) treeStatsAccumulatorTL.get(); 308 } else { 309 return null; 310 } 311 } 312 313 public void setTreeStatsAccumulator(TreeWalkerStatsAccumulator tSA) { 314 treeStatsAccumulatorTL.set(tSA); 315 } 316 317 public IN withRootLatchedExclusive(WithRootLatched wrl) 318 throws DatabaseException { 319 320 try { 321 rootLatch.acquireExclusive(); 322 return wrl.doWork(root); 323 } finally { 324 rootLatch.release(); 325 } 326 } 327 328 public IN withRootLatchedShared(WithRootLatched wrl) 329 throws DatabaseException { 330 331 try { 332 rootLatch.acquireShared(); 333 return wrl.doWork(root); 334 } finally { 335 rootLatch.release(); 336 } 337 } 338 339 350 public void delete(byte[] idKey, 351 UtilizationTracker tracker) 352 throws DatabaseException, 353 NodeNotEmptyException, 354 CursorsExistException { 355 356 IN subtreeRootIN = null; 357 358 365 ArrayList nodeLadder = new ArrayList (); 366 367 IN rootIN = null; 368 boolean rootNeedsUpdating = false; 369 rootLatch.acquireExclusive(); 370 try { 371 if (!rootExists()) { 372 373 return; 374 } 375 376 rootIN = (IN) root.fetchTarget(database, null); 377 rootIN.latch(false); 378 379 searchDeletableSubTree(rootIN, idKey, nodeLadder); 380 if (nodeLadder.size() == 0) { 381 382 403 404 if (purgeRoot) { 405 subtreeRootIN = logTreeRemoval(rootIN); 406 if (subtreeRootIN != null) { 407 rootNeedsUpdating = true; 408 } 409 } 410 } else { 411 412 SplitInfo detachPoint = 413 (SplitInfo) nodeLadder.get(nodeLadder.size() - 1); 414 boolean deleteOk = 415 detachPoint.parent.deleteEntry(detachPoint.index, 416 true); 417 assert deleteOk; 418 419 420 rootNeedsUpdating = cascadeUpdates(nodeLadder, null, -1); 421 subtreeRootIN = detachPoint.child; 422 } 423 } finally { 424 releaseNodeLadderLatches(nodeLadder); 425 426 if (rootIN != null) { 427 rootIN.releaseLatch(); 428 } 429 430 rootLatch.release(); 431 } 432 433 434 if (subtreeRootIN != null) { 435 436 EnvironmentImpl envImpl = database.getDbEnvironment(); 437 if (rootNeedsUpdating) { 438 442 DbTree dbTree = envImpl.getDbMapTree(); 443 dbTree.optionalModifyDbRoot(database); 444 RecoveryManager.traceRootDeletion(Level.FINE, database); 445 } 446 447 452 INList inList = envImpl.getInMemoryINs(); 453 accountForSubtreeRemoval(inList, subtreeRootIN, tracker); 454 } 455 } 456 457 private void releaseNodeLadderLatches(ArrayList nodeLadder) 458 throws DatabaseException { 459 460 464 ListIterator iter = nodeLadder.listIterator(nodeLadder.size()); 465 while (iter.hasPrevious()) { 466 SplitInfo info = (SplitInfo) iter.previous(); 467 info.child.releaseLatch(); 468 } 469 } 470 471 476 private IN logTreeRemoval(IN rootIN) 477 throws DatabaseException { 478 479 assert rootLatch.isWriteLockedByCurrentThread(); 480 IN detachedRootIN = null; 481 482 486 if ((rootIN.getNEntries() <= 1) && 487 (rootIN.validateSubtreeBeforeDelete(0))) { 488 489 root = null; 490 491 507 INDeleteInfo info = new INDeleteInfo(rootIN.getNodeId(), 508 rootIN.getIdentifierKey(), 509 database.getId()); 510 info.optionalLog(database.getDbEnvironment().getLogManager(), 511 database); 512 513 514 detachedRootIN = rootIN; 515 } 516 return detachedRootIN; 517 } 518 519 539 private boolean cascadeUpdates(ArrayList nodeLadder, 540 BIN binRoot, 541 int index) 542 throws DatabaseException { 543 544 ListIterator iter = nodeLadder.listIterator(nodeLadder.size()); 545 EnvironmentImpl envImpl = database.getDbEnvironment(); 546 LogManager logManager = envImpl.getLogManager(); 547 548 long newLsn = DbLsn.NULL_LSN; 549 SplitInfo info = null; 550 while (iter.hasPrevious()) { 551 info = (SplitInfo) iter.previous(); 552 553 if (newLsn != DbLsn.NULL_LSN) { 554 info.parent.updateEntry(info.index, newLsn); 555 } 556 newLsn = info.parent.optionalLog(logManager); 557 } 558 559 boolean rootNeedsUpdating = false; 560 if (info != null) { 561 562 if (info.parent.isDbRoot()) { 563 564 assert rootLatch.isWriteLockedByCurrentThread(); 565 root.updateLsnAfterOptionalLog(database, newLsn); 566 rootNeedsUpdating = true; 567 } else if ((binRoot != null) && info.parent.isRoot()) { 568 569 binRoot.updateEntry(index, newLsn); 570 } else { 571 assert false; 572 } 573 } 574 return rootNeedsUpdating; 575 } 576 577 590 public void deleteDup(byte[] idKey, 591 byte[] mainKey, 592 UtilizationTracker tracker) 593 throws DatabaseException, 594 NodeNotEmptyException, 595 CursorsExistException { 596 597 598 IN in = search(mainKey, SearchType.NORMAL, -1, null, 599 false ); 600 601 IN deletedSubtreeRoot = null; 602 try { 603 assert in.isLatchOwnerForWrite(); 604 assert in instanceof BIN; 605 assert in.getNEntries() > 0; 606 607 608 int index = in.findEntry(mainKey, false, true); 609 if (index >= 0) { 610 deletedSubtreeRoot = deleteDupSubtree(idKey, (BIN) in, index); 611 } 612 } finally { 613 in.releaseLatch(); 614 } 615 616 if (deletedSubtreeRoot != null) { 617 EnvironmentImpl envImpl = database.getDbEnvironment(); 618 accountForSubtreeRemoval(envImpl.getInMemoryINs(), 619 deletedSubtreeRoot, tracker); 620 } 621 } 622 623 628 private IN deleteDupSubtree(byte[] idKey, 629 BIN bin, 630 int index) 631 throws DatabaseException, 632 NodeNotEmptyException, 633 CursorsExistException { 634 635 EnvironmentImpl envImpl = database.getDbEnvironment(); 636 boolean dupCountLNLocked = false; 637 DupCountLN dcl = null; 638 BasicLocker locker = new BasicLocker(envImpl); 639 640 641 DIN duplicateRoot = (DIN) bin.fetchTarget(index); 642 duplicateRoot.latch(false); 643 644 ArrayList nodeLadder = new ArrayList (); 645 IN subtreeRootIN = null; 646 647 try { 648 649 653 ChildReference dclRef = duplicateRoot.getDupCountLNRef(); 654 dcl = (DupCountLN) dclRef.fetchTarget(database, duplicateRoot); 655 656 LockResult lockResult = locker.nonBlockingLock(dcl.getNodeId(), 657 LockType.READ, 658 database); 659 if (lockResult.getLockGrant() == LockGrantType.DENIED) { 660 throw CursorsExistException.CURSORS_EXIST; 661 } else { 662 dupCountLNLocked = true; 663 } 664 665 671 searchDeletableSubTree(duplicateRoot, idKey, nodeLadder); 672 673 674 if (nodeLadder.size() == 0) { 675 676 if (bin.nCursors() == 0) { 677 boolean deleteOk = bin.deleteEntry(index, true); 678 assert deleteOk; 679 680 687 INDupDeleteInfo info = 688 new INDupDeleteInfo(duplicateRoot.getNodeId(), 689 duplicateRoot.getMainTreeKey(), 690 duplicateRoot.getDupTreeKey(), 691 database.getId()); 692 info.optionalLog(envImpl.getLogManager(), database); 693 694 subtreeRootIN = duplicateRoot; 695 696 if (bin.getNEntries() == 0) { 697 database.getDbEnvironment(). 698 addToCompressorQueue(bin, null, false); 699 } 700 } else { 701 702 706 throw CursorsExistException.CURSORS_EXIST; 707 } 708 } else { 709 710 711 SplitInfo detachPoint = 712 (SplitInfo) nodeLadder.get(nodeLadder.size() - 1); 713 boolean deleteOk = 714 detachPoint.parent.deleteEntry(detachPoint.index, 715 true); 716 assert deleteOk; 717 718 722 cascadeUpdates(nodeLadder, bin, index); 723 subtreeRootIN = detachPoint.child; 724 } 725 } finally { 726 releaseNodeLadderLatches(nodeLadder); 727 728 729 if (dupCountLNLocked) { 730 locker.releaseLock(dcl.getNodeId()); 731 } 732 733 duplicateRoot.releaseLatch(); 734 } 735 736 return subtreeRootIN; 737 } 738 739 746 public IN getFirstNode() 747 throws DatabaseException { 748 749 return search 750 (null, SearchType.LEFT, -1, null, true ); 751 } 752 753 760 public IN getLastNode() 761 throws DatabaseException { 762 763 return search 764 (null, SearchType.RIGHT, -1, null, true ); 765 } 766 767 773 public DBIN getFirstNode(DIN dupRoot) 774 throws DatabaseException { 775 776 if (dupRoot == null) { 777 throw new IllegalArgumentException 778 ("getFirstNode passed null root"); 779 } 780 781 assert dupRoot.isLatchOwnerForWrite(); 782 783 IN ret = searchSubTree 784 (dupRoot, null, SearchType.LEFT, -1, null, 785 true ); 786 return (DBIN) ret; 787 } 788 789 795 public DBIN getLastNode(DIN dupRoot) 796 throws DatabaseException { 797 798 if (dupRoot == null) { 799 throw new IllegalArgumentException 800 ("getLastNode passed null root"); 801 } 802 803 assert dupRoot.isLatchOwnerForWrite(); 804 805 IN ret = searchSubTree 806 (dupRoot, null, SearchType.RIGHT, -1, null, 807 true ); 808 return (DBIN) ret; 809 } 810 811 814 public SearchResult getParentINForChildIN(IN child, 815 boolean requireExactMatch, 816 boolean updateGeneration) 817 throws DatabaseException { 818 819 return getParentINForChildIN 820 (child, requireExactMatch, updateGeneration, -1, null); 821 } 822 823 847 public SearchResult getParentINForChildIN(IN child, 848 boolean requireExactMatch, 849 boolean updateGeneration, 850 int targetLevel, 851 List trackingList) 852 throws DatabaseException { 853 854 855 if (child == null) { 856 throw new IllegalArgumentException ("getParentNode passed null"); 857 } 858 859 assert child.isLatchOwnerForWrite(); 860 861 864 byte[] mainTreeKey = child.getMainTreeKey(); 865 byte[] dupTreeKey = child.getDupTreeKey(); 866 boolean isRoot = child.isRoot(); 867 child.releaseLatch(); 868 869 return getParentINForChildIN(child.getNodeId(), 870 child.containsDuplicates(), 871 isRoot, 872 mainTreeKey, 873 dupTreeKey, 874 requireExactMatch, 875 updateGeneration, 876 targetLevel, 877 trackingList, 878 true); 879 } 880 881 909 public SearchResult getParentINForChildIN(long targetNodeId, 910 boolean targetContainsDuplicates, 911 boolean targetIsRoot, 912 byte[] targetMainTreeKey, 913 byte[] targetDupTreeKey, 914 boolean requireExactMatch, 915 boolean updateGeneration, 916 int targetLevel, 917 List trackingList, 918 boolean doFetch) 919 throws DatabaseException { 920 921 IN rootIN = getRootINLatchedExclusive(updateGeneration); 922 923 SearchResult result = new SearchResult(); 924 if (rootIN != null) { 925 926 if (trackingList != null) { 927 trackingList.add(new TrackingInfo(root.getLsn(), 928 rootIN.getNodeId())); 929 } 930 931 IN potentialParent = rootIN; 932 933 try { 934 while (result.keepSearching) { 935 936 940 assert TestHookExecute.doHookIfSet(searchHook); 941 942 potentialParent.findParent(SearchType.NORMAL, 943 targetNodeId, 944 targetContainsDuplicates, 945 targetIsRoot, 946 targetMainTreeKey, 947 targetDupTreeKey, 948 result, 949 requireExactMatch, 950 updateGeneration, 951 targetLevel, 952 trackingList, 953 doFetch); 954 potentialParent = result.parent; 955 } 956 } catch (Exception e) { 957 potentialParent.releaseLatchIfOwner(); 958 959 throw new DatabaseException(e); 960 } 961 } 962 return result; 963 } 964 965 1004 public boolean getParentBINForChildLN(TreeLocation location, 1005 byte[] mainKey, 1006 byte[] dupKey, 1007 LN ln, 1008 boolean splitsAllowed, 1009 boolean findDeletedEntries, 1010 boolean searchDupTree, 1011 boolean updateGeneration) 1012 throws DatabaseException { 1013 1014 1018 IN searchResult = null; 1019 try { 1020 if (splitsAllowed) { 1021 searchResult = searchSplitsAllowed 1022 (mainKey, -1, updateGeneration); 1023 } else { 1024 searchResult = search 1025 (mainKey, SearchType.NORMAL, -1, null, updateGeneration); 1026 } 1027 location.bin = (BIN) searchResult; 1028 } catch (Exception e) { 1029 1030 StringBuffer msg = new StringBuffer (); 1031 if (searchResult != null) { 1032 searchResult.releaseLatchIfOwner(); 1033 msg.append("searchResult=" + searchResult.getClass() + 1034 " nodeId=" + searchResult.getNodeId() + 1035 " nEntries=" + searchResult.getNEntries()); 1036 } 1037 throw new DatabaseException(msg.toString(), e); 1038 } 1039 1040 if (location.bin == null) { 1041 return false; 1042 } 1043 1044 1051 boolean exactSearch = false; 1052 boolean indicateIfExact = true; 1053 if (!findDeletedEntries) { 1054 exactSearch = true; 1055 indicateIfExact = false; 1056 } 1057 location.index = 1058 location.bin.findEntry(mainKey, indicateIfExact, exactSearch); 1059 1060 boolean match = false; 1061 if (findDeletedEntries) { 1062 match = (location.index >= 0 && 1063 (location.index & IN.EXACT_MATCH) != 0); 1064 location.index &= ~IN.EXACT_MATCH; 1065 } else { 1066 match = (location.index >= 0); 1067 } 1068 1069 if (match) { 1070 1071 1075 if (!location.bin.isEntryKnownDeleted(location.index)) { 1076 1077 1084 if (database.getSortedDuplicates()) { 1085 1086 Node childNode = location.bin.fetchTarget(location.index); 1087 try { 1088 1089 1092 if (childNode == null) { 1093 1094 } else if (ln.containsDuplicates()) { 1095 1096 return searchDupTreeForDupCountLNParent 1097 (location, mainKey, childNode); 1098 } else { 1099 1100 1105 if (childNode.containsDuplicates()) { 1106 if (dupKey == null) { 1107 1108 1116 return searchDupTreeByNodeId 1117 (location, childNode, ln, 1118 searchDupTree, updateGeneration); 1119 } else { 1120 return searchDupTreeForDBIN 1121 (location, dupKey, (DIN) childNode, 1122 ln, findDeletedEntries, 1123 indicateIfExact, exactSearch, 1124 splitsAllowed, updateGeneration); 1125 } 1126 } 1127 } 1128 } catch (DatabaseException e) { 1129 location.bin.releaseLatchIfOwner(); 1130 throw e; 1131 } 1132 } 1133 } 1134 1135 1136 location.childLsn = location.bin.getLsn(location.index); 1137 return true; 1138 } else { 1139 location.lnKey = mainKey; 1140 return false; 1141 } 1142 } 1143 1144 1151 private boolean searchDupTreeByNodeId(TreeLocation location, 1152 Node childNode, 1153 LN ln, 1154 boolean searchDupTree, 1155 boolean updateGeneration) 1156 throws DatabaseException { 1157 1158 if (searchDupTree) { 1159 BIN oldBIN = location.bin; 1160 if (childNode.matchLNByNodeId 1161 (location, ln.getNodeId())) { 1162 location.index &= ~IN.EXACT_MATCH; 1163 if (oldBIN != null) { 1164 oldBIN.releaseLatch(); 1165 } 1166 location.bin.latch(updateGeneration); 1167 return true; 1168 } else { 1169 return false; 1170 } 1171 } else { 1172 1173 1177 return false; 1178 } 1179 } 1180 1181 1184 private boolean searchDupTreeForDupCountLNParent(TreeLocation location, 1185 byte[] mainKey, 1186 Node childNode) 1187 throws DatabaseException { 1188 location.lnKey = mainKey; 1189 if (childNode instanceof DIN) { 1190 DIN dupRoot = (DIN) childNode; 1191 location.childLsn = dupRoot.getDupCountLNRef().getLsn(); 1192 return true; 1193 } else { 1194 1195 1202 return false; 1203 } 1204 } 1205 1206 1209 private boolean searchDupTreeForDBIN(TreeLocation location, 1210 byte[] dupKey, 1211 DIN dupRoot, 1212 LN ln, 1213 boolean findDeletedEntries, 1214 boolean indicateIfExact, 1215 boolean exactSearch, 1216 boolean splitsAllowed, 1217 boolean updateGeneration) 1218 throws DatabaseException { 1219 1220 assert dupKey != null; 1221 1222 dupRoot.latch(); 1223 1224 try { 1225 1226 if (maybeSplitDuplicateRoot(location.bin, location.index)) { 1227 dupRoot = (DIN) location.bin.fetchTarget(location.index); 1228 } 1229 1230 1234 location.bin.releaseLatch(); 1235 1236 1240 location.lnKey = dupKey; 1241 1242 1243 if (splitsAllowed) { 1244 try { 1245 location.bin = (BIN) searchSubTreeSplitsAllowed 1246 (dupRoot, location.lnKey, ln.getNodeId(), 1247 updateGeneration); 1248 } catch (SplitRequiredException e) { 1249 1250 1255 throw new DatabaseException(e); 1256 } 1257 } else { 1258 location.bin = (BIN) searchSubTree 1259 (dupRoot, location.lnKey, SearchType.NORMAL, 1260 ln.getNodeId(), null, updateGeneration); 1261 } 1262 1263 1264 location.index = location.bin.findEntry 1265 (location.lnKey, indicateIfExact, exactSearch); 1266 boolean match; 1267 if (findDeletedEntries) { 1268 match = (location.index >= 0 && 1269 (location.index & IN.EXACT_MATCH) != 0); 1270 location.index &= ~IN.EXACT_MATCH; 1271 } else { 1272 match = (location.index >= 0); 1273 } 1274 1275 if (match) { 1276 location.childLsn = location.bin.getLsn(location.index); 1277 return true; 1278 } else { 1279 return false; 1280 } 1281 } catch (DatabaseException e) { 1282 dupRoot.releaseLatchIfOwner(); 1283 throw e; 1284 } 1285 } 1286 1287 1288 1299 public BIN getNextBin(BIN bin, boolean traverseWithinDupTree) 1300 throws DatabaseException { 1301 1302 return getNextBinInternal(traverseWithinDupTree, bin, true); 1303 } 1304 1305 1316 public BIN getPrevBin(BIN bin, boolean traverseWithinDupTree) 1317 throws DatabaseException { 1318 1319 return getNextBinInternal(traverseWithinDupTree, bin, false); 1320 } 1321 1322 1325 private BIN getNextBinInternal(boolean traverseWithinDupTree, 1326 BIN bin, 1327 boolean forward) 1328 throws DatabaseException { 1329 1330 1339 byte[] idKey = null; 1340 1341 if (bin.getNEntries() == 0) { 1342 idKey = bin.getIdentifierKey(); 1343 } else if (forward) { 1344 idKey = bin.getKey(bin.getNEntries() - 1); 1345 } else { 1346 idKey = bin.getKey(0); 1347 } 1348 1349 IN next = bin; 1350 boolean nextIsLatched = false; 1351 1352 assert LatchSupport.countLatchesHeld() == 1: 1353 LatchSupport.latchesHeldToString(); 1354 1355 1361 IN parent = null; 1362 IN nextIN = null; 1363 boolean nextINIsLatched = false; 1364 try { 1365 while (true) { 1366 1367 1371 SearchResult result = null; 1372 if (!traverseWithinDupTree) { 1373 1374 nextIsLatched = false; 1375 result = getParentINForChildIN 1376 (next, true , 1377 true ); 1378 if (result.exactParentFound) { 1379 parent = result.parent; 1380 } else { 1381 1382 assert (LatchSupport.countLatchesHeld() == 0): 1383 LatchSupport.latchesHeldToString(); 1384 return null; 1385 } 1386 } else { 1387 1388 if (next.isRoot()) { 1389 1390 next.releaseLatch(); 1391 nextIsLatched = false; 1392 return null; 1393 } else { 1394 result = getParentINForChildIN 1395 (next, true , 1396 true ); 1397 nextIsLatched = false; 1398 if (result.exactParentFound) { 1399 parent = result.parent; 1400 } else { 1401 return null; 1402 } 1403 } 1404 } 1405 1406 assert (LatchSupport.countLatchesHeld() == 1) : 1407 LatchSupport.latchesHeldToString(); 1408 1409 1416 int index = parent.findEntry(idKey, false, false); 1417 boolean moreEntriesThisBin = false; 1418 if (forward) { 1419 index++; 1420 if (index < parent.getNEntries()) { 1421 moreEntriesThisBin = true; 1422 } 1423 } else { 1424 if (index > 0) { 1425 moreEntriesThisBin = true; 1426 } 1427 index--; 1428 } 1429 1430 if (moreEntriesThisBin) { 1431 1432 1437 nextIN = (IN) parent.fetchTarget(index); 1438 nextIN.latch(); 1439 nextINIsLatched = true; 1440 1441 assert (LatchSupport.countLatchesHeld() == 2): 1442 LatchSupport.latchesHeldToString(); 1443 1444 if (nextIN instanceof BIN) { 1445 1446 parent.releaseLatch(); 1447 TreeWalkerStatsAccumulator treeStatsAccumulator = 1448 getTreeStatsAccumulator(); 1449 if (treeStatsAccumulator != null) { 1450 nextIN.accumulateStats(treeStatsAccumulator); 1451 } 1452 1453 return (BIN) nextIN; 1454 } else { 1455 1456 1460 nextINIsLatched = false; 1461 IN ret = searchSubTree(nextIN, null, 1462 (forward ? 1463 SearchType.LEFT : 1464 SearchType.RIGHT), 1465 -1, 1466 null, 1467 true ); 1468 parent.releaseLatch(); 1469 1470 assert LatchSupport.countLatchesHeld() == 1: 1471 LatchSupport.latchesHeldToString(); 1472 1473 if (ret instanceof BIN) { 1474 return (BIN) ret; 1475 } else { 1476 throw new InconsistentNodeException 1477 ("subtree did not have a BIN for leaf"); 1478 } 1479 } 1480 } 1481 next = parent; 1482 nextIsLatched = true; 1483 } 1484 } catch (DatabaseException e) { 1485 if (nextIsLatched) { 1486 next.releaseLatchIfOwner(); 1487 nextIsLatched = false; 1488 } 1489 if (parent != null) { 1490 parent.releaseLatchIfOwner(); 1491 } 1492 if (nextIN != null && 1493 nextINIsLatched) { 1494 nextIN.releaseLatchIfOwner(); 1495 } 1496 throw e; 1497 } 1498 } 1499 1500 1503 private void splitRoot() 1504 throws DatabaseException { 1505 1506 1510 EnvironmentImpl env = database.getDbEnvironment(); 1511 LogManager logManager = env.getLogManager(); 1512 INList inMemoryINs = env.getInMemoryINs(); 1513 1514 IN curRoot = null; 1515 curRoot = (IN) root.fetchTarget(database, null); 1516 curRoot.latch(); 1517 long curRootLsn = 0; 1518 long logLsn = 0; 1519 IN newRoot = null; 1520 try { 1521 1522 1525 byte[] rootIdKey = curRoot.getKey(0); 1526 newRoot = new IN(database, rootIdKey, maxMainTreeEntriesPerNode, 1527 curRoot.getLevel() + 1); 1528 newRoot.latch(); 1529 newRoot.setIsRoot(true); 1530 curRoot.setIsRoot(false); 1531 1532 1538 try { 1539 curRootLsn = 1540 curRoot.optionalLogProvisional(logManager, newRoot); 1541 boolean insertOk = newRoot.insertEntry 1542 (new ChildReference(curRoot, rootIdKey, curRootLsn)); 1543 assert insertOk; 1544 1545 logLsn = newRoot.optionalLog(logManager); 1546 } catch (DatabaseException e) { 1547 1548 curRoot.setIsRoot(true); 1549 throw e; 1550 } 1551 inMemoryINs.add(newRoot); 1552 1553 1558 root.setTarget(newRoot); 1559 root.updateLsnAfterOptionalLog(database, logLsn); 1560 curRoot.split(newRoot, 0, maxMainTreeEntriesPerNode); 1561 root.setLsn(newRoot.getLastFullVersion()); 1562 1563 } finally { 1564 1565 newRoot.releaseLatch(); 1566 curRoot.releaseLatch(); 1567 } 1568 treeStats.nRootSplits++; 1569 traceSplitRoot(Level.FINE, TRACE_ROOT_SPLIT, newRoot, logLsn, 1570 curRoot, curRootLsn); 1571 } 1572 1573 1605 public IN search(byte[] key, 1606 SearchType searchType, 1607 long nid, 1608 BINBoundary binBoundary, 1609 boolean updateGeneration) 1610 throws DatabaseException { 1611 1612 IN rootIN = getRootIN(true ); 1613 1614 if (rootIN != null) { 1615 return searchSubTree 1616 (rootIN, key, searchType, nid, binBoundary, updateGeneration); 1617 } else { 1618 return null; 1619 } 1620 } 1621 1622 1626 public IN searchSplitsAllowed(byte[] key, 1627 long nid, 1628 boolean updateGeneration) 1629 throws DatabaseException { 1630 1631 IN insertTarget = null; 1632 while (insertTarget == null) { 1633 rootLatch.acquireShared(); 1634 boolean rootLatched = true; 1635 boolean rootLatchedExclusive = false; 1636 boolean rootINLatched = false; 1637 boolean success = false; 1638 IN rootIN = null; 1639 try { 1640 while (true) { 1641 if (rootExists()) { 1642 rootIN = (IN) root.fetchTarget(database, null); 1643 1644 1645 if (rootIN.needsSplitting()) { 1646 if (!rootLatchedExclusive) { 1647 rootIN = null; 1648 rootLatch.release(); 1649 rootLatch.acquireExclusive(); 1650 rootLatchedExclusive = true; 1651 continue; 1652 } 1653 splitRoot(); 1654 1655 1661 rootLatch.release(); 1662 rootLatched = false; 1663 EnvironmentImpl env = database.getDbEnvironment(); 1664 env.getDbMapTree().optionalModifyDbRoot(database); 1665 rootLatched = true; 1666 rootLatch.acquireExclusive(); 1667 rootIN = (IN) root.fetchTarget(database, null); 1668 } 1669 rootIN.latch(); 1670 rootINLatched = true; 1671 } 1672 break; 1673 } 1674 success = true; 1675 } finally { 1676 if (!success && rootINLatched) { 1677 rootIN.releaseLatch(); 1678 } 1679 if (rootLatched) { 1680 rootLatch.release(); 1681 } 1682 } 1683 1684 1685 if (rootIN == null) { 1686 break; 1687 } 1688 1689 try { 1690 success = false; 1691 insertTarget = 1692 searchSubTreeSplitsAllowed(rootIN, key, nid, 1693 updateGeneration); 1694 success = true; 1695 } catch (SplitRequiredException e) { 1696 1697 success = true; 1698 1699 1704 continue; 1705 } finally { 1706 if (!success) { 1707 rootIN.releaseLatchIfOwner(); 1708 if (insertTarget != null) { 1709 insertTarget.releaseLatchIfOwner(); 1710 } 1711 } 1712 } 1713 } 1714 1715 return insertTarget; 1716 } 1717 1718 1722 private static class RelatchRequiredException extends DatabaseException { 1723 public synchronized Throwable fillInStackTrace() { 1724 return this; 1725 } 1726 } 1727 1728 private static RelatchRequiredException relatchRequiredException = 1729 new RelatchRequiredException(); 1730 1731 1736 public IN searchSubTree(IN parent, 1737 byte[] key, 1738 SearchType searchType, 1739 long nid, 1740 BINBoundary binBoundary, 1741 boolean updateGeneration) 1742 throws DatabaseException { 1743 1744 1748 for (int i = 0; i < 2; i++) { 1749 try { 1750 return searchSubTreeInternal(parent, key, searchType, nid, 1751 binBoundary, updateGeneration); 1752 } catch (RelatchRequiredException RRE) { 1753 parent = getRootINLatchedExclusive(updateGeneration); 1754 } 1755 } 1756 1757 throw new DatabaseException 1758 ("searchSubTreeInternal should have completed in two tries"); 1759 } 1760 1761 1796 public IN searchSubTreeInternal(IN parent, 1797 byte[] key, 1798 SearchType searchType, 1799 long nid, 1800 BINBoundary binBoundary, 1801 boolean updateGeneration) 1802 throws DatabaseException { 1803 1804 1805 if (parent == null) { 1806 return null; 1807 } 1808 1809 if ((searchType == SearchType.LEFT || 1810 searchType == SearchType.RIGHT) && 1811 key != null) { 1812 1813 1817 throw new IllegalArgumentException 1818 ("searchSubTree passed key and left/right search"); 1819 } 1820 1821 assert parent.isLatchOwnerForRead(); 1822 1823 if (parent.getNodeId() == nid) { 1824 parent.releaseLatch(); 1825 return null; 1826 } 1827 1828 if (binBoundary != null) { 1829 binBoundary.isLastBin = true; 1830 binBoundary.isFirstBin = true; 1831 } 1832 1833 int index; 1834 IN child = null; 1835 IN grandParent = null; 1836 boolean childIsLatched = false; 1837 boolean grandParentIsLatched = false; 1838 boolean maintainGrandParentLatches = !parent.isLatchOwnerForWrite(); 1839 1840 TreeWalkerStatsAccumulator treeStatsAccumulator = 1841 getTreeStatsAccumulator(); 1842 1843 try { 1844 do { 1845 if (treeStatsAccumulator != null) { 1846 parent.accumulateStats(treeStatsAccumulator); 1847 } 1848 1849 if (parent.getNEntries() == 0) { 1850 1851 return parent; 1852 } else if (searchType == SearchType.NORMAL) { 1853 1854 index = parent.findEntry(key, false, false); 1855 } else if (searchType == SearchType.LEFT) { 1856 1857 index = 0; 1858 } else if (searchType == SearchType.RIGHT) { 1859 1860 index = parent.getNEntries() - 1; 1861 } else { 1862 throw new IllegalArgumentException 1863 ("Invalid value of searchType: " + searchType); 1864 } 1865 1866 assert index >= 0; 1867 1868 if (binBoundary != null) { 1869 if (index != parent.getNEntries() - 1) { 1870 binBoundary.isLastBin = false; 1871 } 1872 if (index != 0) { 1873 binBoundary.isFirstBin = false; 1874 } 1875 } 1876 1877 1885 if (maintainGrandParentLatches && 1886 parent.getTarget(index) == null && 1887 !parent.isAlwaysLatchedExclusively()) { 1888 1889 if (grandParent == null) { 1890 1891 1895 throw relatchRequiredException; 1896 } else { 1897 1898 parent.releaseLatch(); 1899 parent.latch(); 1900 } 1901 1902 1907 if (grandParent != null) { 1908 grandParent.releaseLatch(); 1909 grandParentIsLatched = false; 1910 grandParent = null; 1911 } 1912 } 1913 child = (IN) parent.fetchTarget(index); 1914 1915 1919 if (grandParent != null) { 1920 grandParent.releaseLatch(); 1921 grandParentIsLatched = false; 1922 } 1923 1924 1925 if (maintainGrandParentLatches) { 1926 child.latchShared(updateGeneration); 1927 } else { 1928 child.latch(updateGeneration); 1929 } 1930 childIsLatched = true; 1931 1932 if (treeStatsAccumulator != null) { 1933 child.accumulateStats(treeStatsAccumulator); 1934 } 1935 1936 1940 if (child.getNodeId() == nid) { 1941 child.releaseLatch(); 1942 childIsLatched = false; 1943 return parent; 1944 } 1945 1946 1947 if (maintainGrandParentLatches) { 1948 grandParent = parent; 1949 grandParentIsLatched = true; 1950 } else { 1951 parent.releaseLatch(); 1952 } 1953 parent = child; 1954 } while (!(parent instanceof BIN)); 1955 1956 return child; 1957 } catch (Throwable t) { 1958 1959 1965 try { 1966 if (child != null && 1967 childIsLatched) { 1968 child.releaseLatchIfOwner(); 1969 } 1970 1971 if (parent != child) { 1972 parent.releaseLatchIfOwner(); 1973 } 1974 } catch (Throwable t2) { 1975 t2.printStackTrace(); 1976 } 1977 1978 if (t instanceof DatabaseException) { 1979 1980 throw (DatabaseException) t; 1981 } else { 1982 throw new DatabaseException(t); 1983 } 1984 } finally { 1985 if (grandParent != null && 1986 grandParentIsLatched) { 1987 grandParent.releaseLatch(); 1988 grandParentIsLatched = false; 1989 } 1990 } 1991 } 1992 1993 2025 public void searchDeletableSubTree(IN parent, 2026 byte[] key, 2027 ArrayList nodeLadder) 2028 throws DatabaseException, 2029 NodeNotEmptyException, 2030 CursorsExistException { 2031 2032 assert (parent!=null); 2033 assert (key!= null); 2034 assert parent.isLatchOwnerForWrite(); 2035 2036 int index; 2037 IN child = null; 2038 2039 2040 IN lowestMultipleEntryIN = null; 2041 2042 do { 2043 if (parent.getNEntries() == 0) { 2044 break; 2045 } 2046 2047 2048 if (parent.getNEntries() > 1) { 2049 lowestMultipleEntryIN = parent; 2050 } 2051 2052 index = parent.findEntry(key, false, false); 2053 assert index >= 0; 2054 2055 2056 child = (IN) parent.fetchTarget(index); 2057 child.latch(false); 2058 nodeLadder.add(new SplitInfo(parent, child, index)); 2059 2060 2061 parent = child; 2062 } while (!(parent instanceof BIN)); 2063 2064 2068 if ((child != null) && (child instanceof BIN)) { 2069 if (child.getNEntries() != 0) { 2070 throw NodeNotEmptyException.NODE_NOT_EMPTY; 2071 } 2072 2073 2077 if (((BIN) child).nCursors() > 0) { 2078 throw CursorsExistException.CURSORS_EXIST; 2079 } 2080 } 2081 2082 if (lowestMultipleEntryIN != null) { 2083 2084 2089 ListIterator iter = nodeLadder.listIterator(nodeLadder.size()); 2090 while (iter.hasPrevious()) { 2091 SplitInfo info = (SplitInfo) iter.previous(); 2092 if (info.parent == lowestMultipleEntryIN) { 2093 break; 2094 } else { 2095 info.child.releaseLatch(); 2096 iter.remove(); 2097 } 2098 } 2099 } else { 2100 2101 2105 releaseNodeLadderLatches(nodeLadder); 2106 nodeLadder.clear(); 2107 } 2108 } 2109 2110 2114 private IN searchSubTreeSplitsAllowed(IN parent, 2115 byte[] key, 2116 long nid, 2117 boolean updateGeneration) 2118 throws DatabaseException, SplitRequiredException { 2119 2120 if (parent != null) { 2121 2122 2127 while (true) { 2128 try { 2129 return searchSubTreeUntilSplit 2130 (parent, key, nid, updateGeneration); 2131 } catch (SplitRequiredException e) { 2132 2133 if (waitHook != null) { 2134 waitHook.doHook(); 2135 } 2136 2137 2144 forceSplit(parent, key); 2145 } 2146 } 2147 } else { 2148 return null; 2149 } 2150 } 2151 2152 2156 private IN searchSubTreeUntilSplit(IN parent, 2157 byte[] key, 2158 long nid, 2159 boolean updateGeneration) 2160 throws DatabaseException, SplitRequiredException { 2161 2162 2163 if (parent == null) { 2164 return null; 2165 } 2166 2167 assert parent.isLatchOwnerForWrite(); 2168 2169 if (parent.getNodeId() == nid) { 2170 parent.releaseLatch(); 2171 return null; 2172 } 2173 2174 int index; 2175 IN child = null; 2176 boolean childIsLatched = false; 2177 boolean success = false; 2178 2179 try { 2180 do { 2181 if (parent.getNEntries() == 0) { 2182 2183 success = true; 2184 return parent; 2185 } else { 2186 2187 index = parent.findEntry(key, false, false); 2188 } 2189 2190 assert index >= 0; 2191 2192 2193 child = (IN) parent.fetchTarget(index); 2194 child.latch(updateGeneration); 2195 childIsLatched = true; 2196 2197 2198 if (child.needsSplitting()) { 2199 child.releaseLatch(); 2200 childIsLatched = false; 2201 parent.releaseLatch(); 2202 success = true; 2203 throw splitRequiredException; 2204 } 2205 2206 2210 if (child.getNodeId() == nid) { 2211 child.releaseLatch(); 2212 childIsLatched = false; 2213 success = true; 2214 return parent; 2215 } 2216 2217 2218 parent.releaseLatch(); 2219 parent = child; 2220 } while (!(parent instanceof BIN)); 2221 2222 success = true; 2223 return parent; 2224 } finally { 2225 if (!success) { 2226 if (child != null && 2227 childIsLatched) { 2228 child.releaseLatchIfOwner(); 2229 } 2230 if (parent != child) { 2231 parent.releaseLatchIfOwner(); 2232 } 2233 } 2234 } 2235 } 2236 2237 2246 private void forceSplit(IN parent, 2247 byte[] key) 2248 throws DatabaseException, SplitRequiredException { 2249 2250 ArrayList nodeLadder = new ArrayList (); 2251 2252 boolean allLeftSideDescent = true; 2253 boolean allRightSideDescent = true; 2254 int index; 2255 IN child = null; 2256 IN originalParent = parent; 2257 ListIterator iter = null; 2258 2259 boolean isRootLatched = false; 2260 boolean success = false; 2261 try { 2262 2263 2268 if (originalParent.isDbRoot()) { 2269 rootLatch.acquireExclusive(); 2270 isRootLatched = true; 2271 } 2272 originalParent.latch(); 2273 2274 2282 if (originalParent.needsSplitting() || !originalParent.isRoot()) { 2283 throw splitRequiredException; 2284 } 2285 2286 2290 do { 2291 if (parent.getNEntries() == 0) { 2292 2293 break; 2294 } else { 2295 2296 index = parent.findEntry(key, false, false); 2297 if (index != 0) { 2298 allLeftSideDescent = false; 2299 } 2300 if (index != (parent.getNEntries() - 1)) { 2301 allRightSideDescent = false; 2302 } 2303 } 2304 2305 assert index >= 0; 2306 2307 2311 child = (IN) parent.getTarget(index); 2312 if (child == null) { 2313 break; 2314 } else { 2315 child.latch(); 2316 nodeLadder.add(new SplitInfo(parent, child, index)); 2317 } 2318 2319 2320 parent = child; 2321 } while (!(parent instanceof BIN)); 2322 2323 boolean startedSplits = false; 2324 LogManager logManager = 2325 database.getDbEnvironment().getLogManager(); 2326 2327 2337 iter = nodeLadder.listIterator(nodeLadder.size()); 2338 long lastParentForSplit = -1; 2339 while (iter.hasPrevious()) { 2340 SplitInfo info = (SplitInfo) iter.previous(); 2341 child = info.child; 2342 parent = info.parent; 2343 index = info.index; 2344 2345 2346 if (child.needsSplitting()) { 2347 int maxEntriesPerNode = (child.containsDuplicates() ? 2348 maxDupTreeEntriesPerNode : 2349 maxMainTreeEntriesPerNode); 2350 if (allLeftSideDescent || allRightSideDescent) { 2351 child.splitSpecial(parent, 2352 index, 2353 maxEntriesPerNode, 2354 key, 2355 allLeftSideDescent); 2356 } else { 2357 child.split(parent, index, maxEntriesPerNode); 2358 } 2359 lastParentForSplit = parent.getNodeId(); 2360 startedSplits = true; 2361 2362 2370 if (parent.isDbRoot()) { 2371 assert isRootLatched; 2372 root.setLsn(parent.getLastFullVersion()); 2373 parent.setDirty(true); 2374 } 2375 } else { 2376 if (startedSplits) { 2377 long newLsn = 0; 2378 2379 2385 if (lastParentForSplit == child.getNodeId()) { 2386 newLsn = child.getLastFullVersion(); 2387 } else { 2388 newLsn = child.optionalLog(logManager); 2389 } 2390 parent.updateEntry(index, newLsn); 2391 } 2392 } 2393 child.releaseLatch(); 2394 child = null; 2395 iter.remove(); 2396 } 2397 2398 success = true; 2399 } finally { 2400 2401 if (!success) { 2402 if (child != null) { 2403 child.releaseLatchIfOwner(); 2404 } 2405 originalParent.releaseLatchIfOwner(); 2406 } 2407 2408 2412 if (nodeLadder.size() > 0) { 2413 iter = nodeLadder.listIterator(nodeLadder.size()); 2414 while (iter.hasPrevious()) { 2415 SplitInfo info = (SplitInfo) iter.previous(); 2416 info.child.releaseLatchIfOwner(); 2417 } 2418 } 2419 2420 if (isRootLatched) { 2421 rootLatch.release(); 2422 } 2423 } 2424 } 2425 2426 2430 public IN getRootIN(boolean updateGeneration) 2431 throws DatabaseException { 2432 2433 return getRootINInternal(updateGeneration, false); 2434 } 2435 2436 2440 public IN getRootINLatchedExclusive(boolean updateGeneration) 2441 throws DatabaseException { 2442 2443 return getRootINInternal(updateGeneration, true); 2444 } 2445 2446 private IN getRootINInternal(boolean updateGeneration, boolean exclusive) 2447 throws DatabaseException { 2448 2449 rootLatch.acquireShared(); 2450 IN rootIN = null; 2451 try { 2452 if (rootExists()) { 2453 rootIN = (IN) root.fetchTarget(database, null); 2454 if (exclusive) { 2455 rootIN.latch(updateGeneration); 2456 } else { 2457 rootIN.latchShared(updateGeneration); 2458 } 2459 } 2460 return rootIN; 2461 } finally { 2462 rootLatch.release(); 2463 } 2464 } 2465 2466 2477 public boolean insert(LN ln, 2478 byte[] key, 2479 boolean allowDuplicates, 2480 CursorImpl cursor, 2481 LockResult lnLock) 2482 throws DatabaseException { 2483 2484 validateInsertArgs(allowDuplicates); 2485 2486 EnvironmentImpl env = database.getDbEnvironment(); 2487 LogManager logManager = env.getLogManager(); 2488 INList inMemoryINs = env.getInMemoryINs(); 2489 2490 2491 BIN bin = null; 2492 try { 2493 bin = findBinForInsert(key, logManager, inMemoryINs, cursor); 2494 assert bin.isLatchOwnerForWrite(); 2495 2496 2497 ChildReference newLNRef = 2498 new ChildReference(ln, key, DbLsn.NULL_LSN); 2499 2500 2507 cursor.setBIN(bin); 2508 2509 int index = bin.insertEntry1(newLNRef); 2510 if ((index & IN.INSERT_SUCCESS) != 0) { 2511 2512 2516 index &= ~IN.INSERT_SUCCESS; 2517 cursor.updateBin(bin, index); 2518 2519 2520 long newLsn = DbLsn.NULL_LSN; 2521 2522 try { 2523 newLsn = ln.optionalLog 2524 (env, database, key, DbLsn.NULL_LSN, 0, 2525 cursor.getLocker()); 2526 } finally { 2527 if ((newLsn == DbLsn.NULL_LSN) && 2528 !database.isDeferredWrite()) { 2529 2530 2540 bin.setKnownDeleted(index); 2541 } 2542 } 2543 lnLock.setAbortLsn(DbLsn.NULL_LSN, true, true); 2544 bin.updateEntry(index, newLsn); 2545 2546 traceInsert(Level.FINER, env, bin, ln, newLsn, index); 2547 return true; 2548 } else { 2549 2550 2554 index &= ~IN.EXACT_MATCH; 2555 cursor.updateBin(bin, index); 2556 2557 LN currentLN = null; 2558 boolean isDup = false; 2559 Node n = bin.fetchTarget(index); 2560 if (n == null || n instanceof LN) { 2561 currentLN = (LN) n; 2562 } else { 2563 isDup = true; 2564 } 2565 2566 2567 boolean isDeleted = false; 2568 LockResult currentLock = null; 2569 2570 if (!isDup) { 2571 if (currentLN == null) { 2572 2573 isDeleted = true; 2574 } else { 2575 currentLock = cursor.lockLNDeletedAllowed 2576 (currentLN, LockType.WRITE); 2577 currentLN = currentLock.getLN(); 2578 2579 bin = cursor.getBIN(); 2580 index = cursor.getIndex(); 2581 if (cursor.getDupBIN() != null) { 2582 2583 2590 cursor.clearDupBIN(true ); 2591 isDup = true; 2592 } else if (bin.isEntryKnownDeleted(index) || 2593 currentLN == null || 2594 currentLN.isDeleted()) { 2595 2596 isDeleted = true; 2597 } 2598 } 2599 } 2600 2601 if (isDeleted) { 2602 2603 2615 long abortLsn = bin.getLsn(index); 2616 boolean abortKnownDeleted = true; 2617 if (currentLN != null && 2618 currentLock.getLockGrant() == LockGrantType.EXISTING) { 2619 long nodeId = currentLN.getNodeId(); 2620 Locker locker = cursor.getLocker(); 2621 WriteLockInfo info = locker.getWriteLockInfo(nodeId); 2622 abortLsn = info.getAbortLsn(); 2623 abortKnownDeleted = info.getAbortKnownDeleted(); 2624 } 2625 lnLock.setAbortLsn(abortLsn, abortKnownDeleted); 2626 2627 2633 long newLsn = ln.optionalLog(env, database, 2634 key, DbLsn.NULL_LSN, 0, 2635 cursor.getLocker()); 2636 2637 bin.updateEntry(index, ln, newLsn, key); 2638 bin.clearKnownDeleted(index); 2639 bin.clearPendingDeleted(index); 2640 2641 traceInsert(Level.FINER, env, bin, ln, newLsn, index); 2642 return true; 2643 } else { 2644 2645 2649 return insertDuplicate 2650 (key, bin, ln, logManager, inMemoryINs, cursor, lnLock, 2651 allowDuplicates); 2652 } 2653 } 2654 } finally { 2655 cursor.releaseBIN(); 2656 } 2657 } 2658 2659 2670 private boolean insertDuplicate(byte[] key, 2671 BIN bin, 2672 LN newLN, 2673 LogManager logManager, 2674 INList inMemoryINs, 2675 CursorImpl cursor, 2676 LockResult lnLock, 2677 boolean allowDuplicates) 2678 throws DatabaseException { 2679 2680 EnvironmentImpl env = database.getDbEnvironment(); 2681 int index = cursor.getIndex(); 2682 boolean successfulInsert = false; 2683 2684 DIN dupRoot = null; 2685 Node n = bin.fetchTarget(index); 2686 long binNid = bin.getNodeId(); 2687 2688 if (n instanceof DIN) { 2689 DBIN dupBin = null; 2690 2691 2695 try { 2696 dupRoot = (DIN) n; 2697 dupRoot.latch(); 2698 2699 2700 LockResult dclLockResult = 2701 cursor.lockDupCountLN(dupRoot, LockType.WRITE); 2702 2703 bin = cursor.getBIN(); 2704 index = cursor.getIndex(); 2705 2706 2711 if (!allowDuplicates) { 2712 DupCountLN dcl = (DupCountLN) dclLockResult.getLN(); 2713 if (dcl.getDupCount() > 0) { 2714 return false; 2715 } 2716 } 2717 2718 2723 maybeSplitDuplicateRoot(bin, index); 2724 dupRoot = (DIN) bin.fetchTarget(index); 2725 2726 2733 byte[] newLNKey = newLN.getData(); 2734 long previousLsn = dupRoot.getLastFullVersion(); 2735 try { 2736 dupBin = (DBIN) searchSubTreeSplitsAllowed 2737 (dupRoot, newLNKey, -1, true ); 2738 } catch (SplitRequiredException e) { 2739 2740 2746 throw new DatabaseException(e) ; 2747 } 2748 2749 long currentLsn = dupRoot.getLastFullVersion(); 2750 if (currentLsn != previousLsn) { 2751 bin.updateEntry(index, currentLsn); 2752 } 2753 2754 2755 cursor.releaseBIN(); 2756 bin = null; 2757 2758 2759 dupRoot = null; 2760 2761 2765 ChildReference newLNRef = 2766 new ChildReference(newLN, newLNKey, DbLsn.NULL_LSN); 2767 2768 int dupIndex = dupBin.insertEntry1(newLNRef); 2769 if ((dupIndex & IN.INSERT_SUCCESS) != 0) { 2770 2771 2775 dupIndex &= ~IN.INSERT_SUCCESS; 2776 cursor.updateDBin(dupBin, dupIndex); 2777 2778 2779 long newLsn = DbLsn.NULL_LSN; 2780 try { 2781 newLsn = newLN.optionalLog 2782 (env, database, key, DbLsn.NULL_LSN, 0, 2783 cursor.getLocker()); 2784 } finally { 2785 if ((newLsn == DbLsn.NULL_LSN) && 2786 (!database.isDeferredWrite())) { 2787 2788 2792 dupBin.setKnownDeleted(dupIndex); 2793 } 2794 } 2795 2796 lnLock.setAbortLsn(DbLsn.NULL_LSN, true, true); 2797 2798 2801 dupBin.updateEntry(dupIndex, newLsn); 2802 2803 traceInsertDuplicate(Level.FINER, 2804 database.getDbEnvironment(), 2805 dupBin, newLN, newLsn, binNid); 2806 successfulInsert = true; 2807 } else { 2808 2809 2814 dupIndex &= ~IN.EXACT_MATCH; 2815 cursor.updateDBin(dupBin, dupIndex); 2816 LN currentLN = (LN) dupBin.fetchTarget(dupIndex); 2817 2818 2819 boolean isDeleted = false; 2820 LockResult currentLock = null; 2821 if (currentLN == null) { 2822 2823 isDeleted = true; 2824 } else { 2825 currentLock = cursor.lockLNDeletedAllowed 2826 (currentLN, LockType.WRITE); 2827 currentLN = currentLock.getLN(); 2828 2829 dupBin = cursor.getDupBIN(); 2830 dupIndex = cursor.getDupIndex(); 2831 if (dupBin.isEntryKnownDeleted(dupIndex) || 2832 currentLN == null || 2833 currentLN.isDeleted()) { 2834 2835 isDeleted = true; 2836 } 2837 } 2838 2839 if (isDeleted) { 2840 2841 long abortLsn = dupBin.getLsn(dupIndex); 2842 boolean abortKnownDeleted = true; 2843 if (currentLN != null && 2844 currentLock.getLockGrant() == 2845 LockGrantType.EXISTING) { 2846 long nodeId = currentLN.getNodeId(); 2847 Locker locker = cursor.getLocker(); 2848 WriteLockInfo info = 2849 locker.getWriteLockInfo(nodeId); 2850 abortLsn = info.getAbortLsn(); 2851 abortKnownDeleted = info.getAbortKnownDeleted(); 2852 } 2853 lnLock.setAbortLsn(abortLsn, abortKnownDeleted); 2854 2855 2861 long newLsn = 2862 newLN.optionalLog(env, database, key, 2863 DbLsn.NULL_LSN, 0, cursor.getLocker()); 2864 2865 dupBin.updateEntry(dupIndex, newLN, newLsn, newLNKey); 2866 dupBin.clearKnownDeleted(dupIndex); 2867 dupBin.clearPendingDeleted(dupIndex); 2868 2869 traceInsertDuplicate(Level.FINER, 2870 database.getDbEnvironment(), 2871 dupBin, newLN, newLsn, binNid); 2872 successfulInsert = true; 2873 } else { 2874 2875 successfulInsert = false; 2876 } 2877 } 2878 2879 2883 dupBin.releaseLatch(); 2884 dupBin = null; 2885 2886 if (successfulInsert) { 2887 cursor.latchBIN(); 2888 dupRoot = 2889 cursor.getLatchedDupRoot(false ); 2890 cursor.releaseBIN(); 2891 dupRoot.incrementDuplicateCount 2892 (dclLockResult, key, cursor.getLocker(), 2893 true ); 2894 } 2895 } finally { 2896 if (dupBin != null) { 2897 dupBin.releaseLatchIfOwner(); 2898 } 2899 2900 if (dupRoot != null) { 2901 dupRoot.releaseLatchIfOwner(); 2902 } 2903 } 2904 } else if (n instanceof LN) { 2905 2906 2910 if (!allowDuplicates) { 2911 return false; 2912 } 2913 2914 2918 try { 2919 lnLock.setAbortLsn(DbLsn.NULL_LSN, true, true); 2920 dupRoot = createDuplicateTree 2921 (key, logManager, inMemoryINs, newLN, cursor); 2922 } finally { 2923 if (dupRoot != null) { 2924 dupRoot.releaseLatch(); 2925 successfulInsert = true; 2926 } else { 2927 successfulInsert = false; 2928 } 2929 } 2930 } else { 2931 throw new InconsistentNodeException 2932 ("neither LN or DIN found in BIN"); 2933 } 2934 2935 return successfulInsert; 2936 } 2937 2938 2947 private boolean maybeSplitDuplicateRoot(BIN bin, 2948 int index) 2949 throws DatabaseException { 2950 2951 DIN curRoot = (DIN) bin.fetchTarget(index); 2952 2953 if (curRoot.needsSplitting()) { 2954 2955 EnvironmentImpl env = database.getDbEnvironment(); 2956 LogManager logManager = env.getLogManager(); 2957 INList inMemoryINs = env.getInMemoryINs(); 2958 2959 2962 byte[] rootIdKey = curRoot.getKey(0); 2963 DIN newRoot = new DIN(database, 2964 rootIdKey, 2965 maxDupTreeEntriesPerNode, 2966 curRoot.getDupKey(), 2967 curRoot.getDupCountLNRef(), 2968 curRoot.getLevel() + 1); 2969 2970 newRoot.latch(); 2971 long curRootLsn = 0; 2972 long logLsn = 0; 2973 try { 2974 newRoot.setIsRoot(true); 2975 curRoot.setDupCountLN(null); 2976 curRoot.setIsRoot(false); 2977 2978 2983 try { 2984 curRootLsn = 2985 curRoot.optionalLogProvisional(logManager, newRoot); 2986 boolean insertOk = newRoot.insertEntry 2987 (new ChildReference(curRoot, rootIdKey, 2988 bin.getLsn(index))); 2989 assert insertOk; 2990 2991 logLsn = newRoot.optionalLog(logManager); 2992 } catch (DatabaseException e) { 2993 2994 2995 curRoot.setIsRoot(true); 2996 throw e; 2997 } 2998 2999 inMemoryINs.add(newRoot); 3000 bin.updateEntry(index, newRoot, logLsn); 3001 curRoot.split(newRoot, 0, maxDupTreeEntriesPerNode); 3002 } finally { 3003 curRoot.releaseLatch(); 3004 } 3005 traceSplitRoot(Level.FINE, TRACE_DUP_ROOT_SPLIT, 3006 newRoot, logLsn, curRoot, curRootLsn); 3007 return true; 3008 } else { 3009 return false; 3010 } 3011 } 3012 3013 3027 private DIN createDuplicateTree(byte[] key, 3028 LogManager logManager, 3029 INList inMemoryINs, 3030 LN newLN, 3031 CursorImpl cursor) 3032 throws DatabaseException { 3033 3034 EnvironmentImpl env = database.getDbEnvironment(); 3035 DIN dupRoot = null; 3036 DBIN dupBin = null; 3037 BIN bin = cursor.getBIN(); 3038 int index = cursor.getIndex(); 3039 3040 3044 LN existingLN = (LN) bin.fetchTarget(index); 3045 boolean existingLNIsDeleted = bin.isEntryKnownDeleted(index) || 3046 existingLN.isDeleted(); 3047 assert existingLN != null; 3048 3049 byte[] existingKey = existingLN.getData(); 3050 byte[] newLNKey = newLN.getData(); 3051 3052 3053 boolean keysEqual = Key.compareKeys 3054 (newLNKey, existingKey, database.getDuplicateComparator()) == 0; 3055 if (keysEqual) { 3056 return null; 3057 } 3058 3059 3085 3086 3087 Locker locker = cursor.getLocker(); 3088 long nodeId = existingLN.getNodeId(); 3089 3090 3095 int startingCount = 3096 (locker.createdNode(nodeId) || 3097 existingLNIsDeleted || 3098 locker.getWriteLockInfo(nodeId).getAbortKnownDeleted()) ? 3099 0 : 1; 3100 3101 DupCountLN dupCountLN = new DupCountLN(startingCount); 3102 long firstDupCountLNLsn = 3103 dupCountLN.optionalLogProvisional(env, database, 3104 key, DbLsn.NULL_LSN, 0); 3105 int firstDupCountLNSize = dupCountLN.getTotalLastLoggedSize(key); 3106 3107 3108 dupRoot = new DIN(database, 3109 existingKey, maxDupTreeEntriesPerNode, 3111 key, new ChildReference 3113 (dupCountLN, key, firstDupCountLNLsn), 3114 2); dupRoot.latch(); 3116 dupRoot.setIsRoot(true); 3117 3118 dupBin = new DBIN(database, 3119 existingKey, maxDupTreeEntriesPerNode, 3121 key, 1); dupBin.latch(); 3124 3125 3129 ChildReference newExistingLNRef = new ChildReference 3130 (existingLN, existingKey, bin.getLsn(index), bin.getState(index)); 3131 3132 boolean insertOk = dupBin.insertEntry(newExistingLNRef); 3133 assert insertOk; 3134 3135 try { 3136 3137 3138 long dbinLsn = dupBin.optionalLogProvisional(logManager, dupRoot); 3139 inMemoryINs.add(dupBin); 3140 3141 3142 dupRoot.setEntry(0, dupBin, dupBin.getKey(0), 3143 dbinLsn, dupBin.getState(0)); 3144 3145 3146 long dinLsn = dupRoot.optionalLog(logManager); 3147 inMemoryINs.add(dupRoot); 3148 3149 3159 LockResult lockResult = locker.lock 3160 (dupCountLN.getNodeId(), LockType.WRITE, false , 3161 database); 3162 lockResult.setAbortLsn(firstDupCountLNLsn, false); 3163 3164 dupCountLN.setDupCount(2); 3165 long dupCountLsn = dupCountLN.optionalLog 3166 (env, database, key, firstDupCountLNLsn, firstDupCountLNSize, 3167 locker); 3168 dupRoot.updateDupCountLNRef(dupCountLsn); 3169 3170 3171 long newLsn = newLN.optionalLog 3172 (env, database, key, DbLsn.NULL_LSN, 0, locker); 3173 int dupIndex = dupBin.insertEntry1 3174 (new ChildReference(newLN, newLNKey, newLsn)); 3175 dupIndex &= ~IN.INSERT_SUCCESS; 3176 cursor.updateDBin(dupBin, dupIndex); 3177 3178 3184 bin.adjustCursorsForMutation(index, dupBin, dupIndex ^ 1, cursor); 3185 dupBin.releaseLatch(); 3186 3187 3192 bin.updateEntry(index, dupRoot, dinLsn); 3193 bin.setMigrate(index, false); 3194 3195 traceMutate(Level.FINE, bin, existingLN, newLN, newLsn, 3196 dupCountLN, dupCountLsn, dupRoot, dinLsn, 3197 dupBin, dbinLsn); 3198 } catch (DatabaseException e) { 3199 3200 3206 dupBin.releaseLatchIfOwner(); 3207 dupRoot.releaseLatchIfOwner(); 3208 throw e; 3209 } 3210 return dupRoot; 3211 } 3212 3213 3218 private void validateInsertArgs(boolean allowDuplicates) 3219 throws DatabaseException { 3220 if (allowDuplicates && !database.getSortedDuplicates()) { 3221 throw new DatabaseException 3222 ("allowDuplicates passed to insert but database doesn't " + 3223 "have allow duplicates set."); 3224 } 3225 } 3226 3227 3232 private BIN findBinForInsert(byte[] key, 3233 LogManager logManager, 3234 INList inMemoryINs, 3235 CursorImpl cursor) 3236 throws DatabaseException { 3237 3238 BIN bin; 3239 3240 3241 bin = cursor.latchBIN(); 3242 if (bin != null) { 3243 if (!bin.needsSplitting() && bin.isKeyInBounds(key)) { 3244 return bin; 3245 } else { 3246 bin.releaseLatch(); 3247 } 3248 } 3249 3250 boolean rootLatchIsHeld = false; 3251 try { 3252 long logLsn; 3253 3254 3258 while (true) { 3259 rootLatchIsHeld = true; 3260 rootLatch.acquireShared(); 3261 if (!rootExists()) { 3262 rootLatch.release(); 3263 rootLatch.acquireExclusive(); 3264 if (rootExists()) { 3265 rootLatch.release(); 3266 rootLatchIsHeld = false; 3267 continue; 3268 } 3269 3270 3280 3281 bin = new BIN(database, key, maxMainTreeEntriesPerNode, 1); 3282 bin.latch(); 3283 logLsn = bin.optionalLogProvisional(logManager, null); 3284 3285 3297 3298 IN rootIN = 3299 new IN(database, key, maxMainTreeEntriesPerNode, 2); 3300 3301 3305 rootIN.latch(); 3306 rootIN.setIsRoot(true); 3307 3308 boolean insertOk = rootIN.insertEntry 3309 (new ChildReference(bin, key, logLsn)); 3310 assert insertOk; 3311 3312 logLsn = rootIN.optionalLog(logManager); 3313 rootIN.setDirty(true); 3314 3315 root = makeRootChildReference(rootIN, 3316 new byte[0], 3317 logLsn); 3318 3319 rootIN.releaseLatch(); 3320 3321 3322 inMemoryINs.add(bin); 3323 inMemoryINs.add(rootIN); 3324 rootLatch.release(); 3325 rootLatchIsHeld = false; 3326 3327 break; 3328 } else { 3329 rootLatch.release(); 3330 rootLatchIsHeld = false; 3331 3332 3341 IN in = searchSplitsAllowed 3342 (key, -1, true ); 3343 if (in == null) { 3344 3345 continue; 3346 } else { 3347 3348 bin = (BIN) in; 3349 break; 3350 } 3351 } 3352 } 3353 } finally { 3354 if (rootLatchIsHeld) { 3355 rootLatch.release(); 3356 } 3357 } 3358 3359 3360 if (ckptHook != null) { 3361 ckptHook.doHook(); 3362 } 3363 3364 return bin; 3365 } 3366 3367 3373 private void accountForSubtreeRemoval(INList inList, 3374 IN subtreeRoot, 3375 UtilizationTracker tracker) 3376 throws DatabaseException { 3377 3378 inList.latchMajor(); 3379 try { 3380 subtreeRoot.accountForSubtreeRemoval(inList, tracker); 3381 } finally { 3382 inList.releaseMajorLatch(); 3383 } 3384 3385 Tracer.trace(Level.FINE, database.getDbEnvironment(), 3386 "SubtreeRemoval: subtreeRoot = " + 3387 subtreeRoot.getNodeId()); 3388 } 3389 3390 3393 3394 3403 public int getLastLoggedSize() { 3404 return getLogSizeInternal(true); 3405 } 3406 3407 3410 public int getLogSize() { 3411 return getLogSizeInternal(false); 3412 } 3413 3414 private int getLogSizeInternal(boolean lastLogged) { 3415 int size = LogUtils.getBooleanLogSize(); 3417 3421 if (lastLogged) { 3422 if (rootLastLogged) { 3423 size += ChildReference.ROOT_LOG_SIZE; 3424 } 3425 } else { 3426 if (root != null) { 3427 size += ChildReference.ROOT_LOG_SIZE; 3428 } 3429 } 3430 return size; 3431 } 3432 3433 3436 public void writeToLog(ByteBuffer logBuffer) { 3437 LogUtils.writeBoolean(logBuffer, (root != null)); 3438 if (root != null) { 3439 root.writeToLog(logBuffer); 3440 rootLastLogged = true; 3441 } else { 3442 rootLastLogged = false; 3443 } 3444 } 3445 3446 3449 public void readFromLog(ByteBuffer itemBuffer, byte entryTypeVersion) { 3450 boolean rootExists = LogUtils.readBoolean(itemBuffer); 3451 if (rootExists) { 3452 root = makeRootChildReference(); 3453 root.readFromLog(itemBuffer, entryTypeVersion); 3454 rootLastLogged = true; 3455 } else { 3456 rootLastLogged = false; 3457 } 3458 } 3459 3460 3463 public void dumpLog(StringBuffer sb, boolean verbose) { 3464 sb.append("<root>"); 3465 if (root != null) { 3466 root.dumpLog(sb, verbose); 3467 } 3468 sb.append("</root>"); 3469 } 3470 3471 3474 public boolean logEntryIsTransactional() { 3475 return false; 3476 } 3477 3478 3481 public long getTransactionId() { 3482 return 0; 3483 } 3484 3485 3489 public void rebuildINList() 3490 throws DatabaseException { 3491 3492 INList inMemoryList = database.getDbEnvironment().getInMemoryINs(); 3493 3494 if (root != null) { 3495 rootLatch.acquireShared(); 3496 try { 3497 Node rootIN = root.getTarget(); 3498 if (rootIN != null) { 3499 rootIN.rebuildINList(inMemoryList); 3500 } 3501 } finally { 3502 rootLatch.release(); 3503 } 3504 } 3505 } 3506 3507 3510 public void dump() 3511 throws DatabaseException { 3512 3513 System.out.println(dumpString(0)); 3514 } 3515 3516 public String dumpString(int nSpaces) 3517 throws DatabaseException { 3518 3519 StringBuffer sb = new StringBuffer (); 3520 sb.append(TreeUtils.indent(nSpaces)); 3521 sb.append("<tree>"); 3522 sb.append('\n'); 3523 if (root != null) { 3524 sb.append(DbLsn.dumpString(root.getLsn(), nSpaces)); 3525 sb.append('\n'); 3526 IN rootIN = (IN) root.getTarget(); 3527 if (rootIN == null) { 3528 sb.append("<in/>"); 3529 } else { 3530 sb.append(rootIN.toString()); 3531 } 3532 sb.append('\n'); 3533 } 3534 sb.append(TreeUtils.indent(nSpaces)); 3535 sb.append("</tree>"); 3536 return sb.toString(); 3537 } 3538 3539 3543 boolean validateDelete(int index) 3544 throws DatabaseException { 3545 3546 rootLatch.acquireShared(); 3547 try { 3548 IN rootIN = (IN) root.fetchTarget(database, null); 3549 return rootIN.validateSubtreeBeforeDelete(index); 3550 } finally { 3551 rootLatch.release(); 3552 } 3553 } 3554 3555 3559 public void validateINList(IN parent) 3560 throws DatabaseException { 3561 3562 if (parent == null) { 3563 parent = (IN) root.getTarget(); 3564 } 3565 if (parent != null) { 3566 INList inList = database.getDbEnvironment().getInMemoryINs(); 3567 if (!inList.getINs().contains(parent)) { 3568 throw new DatabaseException 3569 ("IN " + parent.getNodeId() + " missing from INList"); 3570 } 3571 for (int i = 0;; i += 1) { 3572 try { 3573 Node node = parent.getTarget(i); 3574 if (i >= parent.getNEntries()) { 3575 if (node != null) { 3576 throw new DatabaseException 3577 ("IN " + parent.getNodeId() + 3578 " has stray node " + node.getNodeId() + 3579 " at index " + i); 3580 } 3581 byte[] key = parent.getKey(i); 3582 if (key != null) { 3583 throw new DatabaseException 3584 ("IN " + parent.getNodeId() + 3585 " has stray key " + key + 3586 " at index " + i); 3587 } 3588 } 3589 if (node instanceof IN) { 3590 validateINList((IN) node); 3591 } 3592 } catch (ArrayIndexOutOfBoundsException e) { 3593 break; 3594 } 3595 } 3596 } 3597 } 3598 3599 3600 public void setWaitHook(TestHook hook) { 3601 waitHook = hook; 3602 } 3603 3604 3605 public void setSearchHook(TestHook hook) { 3606 searchHook = hook; 3607 } 3608 3609 3610 public void setCkptHook(TestHook hook) { 3611 ckptHook = hook; 3612 } 3613 3614 3619 private void traceSplitRoot(Level level, 3620 String splitType, 3621 IN newRoot, 3622 long newRootLsn, 3623 IN oldRoot, 3624 long oldRootLsn) { 3625 Logger logger = database.getDbEnvironment().getLogger(); 3626 if (logger.isLoggable(level)) { 3627 StringBuffer sb = new StringBuffer (); 3628 sb.append(splitType); 3629 sb.append(" newRoot=").append(newRoot.getNodeId()); 3630 sb.append(" newRootLsn="). 3631 append(DbLsn.getNoFormatString(newRootLsn)); 3632 sb.append(" oldRoot=").append(oldRoot.getNodeId()); 3633 sb.append(" oldRootLsn="). 3634 append(DbLsn.getNoFormatString(oldRootLsn)); 3635 logger.log(level, sb.toString()); 3636 } 3637 } 3638 3639 3644 private void traceMutate(Level level, 3645 BIN theBin, 3646 LN existingLn, 3647 LN newLn, 3648 long newLsn, 3649 DupCountLN dupCountLN, 3650 long dupRootLsn, 3651 DIN dupRoot, 3652 long ddinLsn, 3653 DBIN dupBin, 3654 long dbinLsn) { 3655 Logger logger = database.getDbEnvironment().getLogger(); 3656 if (logger.isLoggable(level)) { 3657 StringBuffer sb = new StringBuffer (); 3658 sb.append(TRACE_MUTATE); 3659 sb.append(" existingLn="); 3660 sb.append(existingLn.getNodeId()); 3661 sb.append(" newLn="); 3662 sb.append(newLn.getNodeId()); 3663 sb.append(" newLnLsn="); 3664 sb.append(DbLsn.getNoFormatString(newLsn)); 3665 sb.append(" dupCountLN="); 3666 sb.append(dupCountLN.getNodeId()); 3667 sb.append(" dupRootLsn="); 3668 sb.append(DbLsn.getNoFormatString(dupRootLsn)); 3669 sb.append(" rootdin="); 3670 sb.append(dupRoot.getNodeId()); 3671 sb.append(" ddinLsn="); 3672 sb.append(DbLsn.getNoFormatString(ddinLsn)); 3673 sb.append(" dbin="); 3674 sb.append(dupBin.getNodeId()); 3675 sb.append(" dbinLsn="); 3676 sb.append(DbLsn.getNoFormatString(dbinLsn)); 3677 sb.append(" bin="); 3678 sb.append(theBin.getNodeId()); 3679 3680 logger.log(level, sb.toString()); 3681 } 3682 } 3683 3684 3689 private void traceInsert(Level level, 3690 EnvironmentImpl env, 3691 BIN insertingBin, 3692 LN ln, 3693 long lnLsn, 3694 int index) { 3695 Logger logger = env.getLogger(); 3696 if (logger.isLoggable(level)) { 3697 StringBuffer sb = new StringBuffer (); 3698 sb.append(TRACE_INSERT); 3699 sb.append(" bin="); 3700 sb.append(insertingBin.getNodeId()); 3701 sb.append(" ln="); 3702 sb.append(ln.getNodeId()); 3703 sb.append(" lnLsn="); 3704 sb.append(DbLsn.getNoFormatString(lnLsn)); 3705 sb.append(" index="); 3706 sb.append(index); 3707 3708 logger.log(level, sb.toString()); 3709 } 3710 } 3711 3712 3717 private void traceInsertDuplicate(Level level, 3718 EnvironmentImpl env, 3719 BIN insertingDBin, 3720 LN ln, 3721 long lnLsn, 3722 long binNid) { 3723 Logger logger = env.getLogger(); 3724 if (logger.isLoggable(level)) { 3725 StringBuffer sb = new StringBuffer (); 3726 sb.append(TRACE_INSERT_DUPLICATE); 3727 sb.append(" dbin="); 3728 sb.append(insertingDBin.getNodeId()); 3729 sb.append(" bin="); 3730 sb.append(binNid); 3731 sb.append(" ln="); 3732 sb.append(ln.getNodeId()); 3733 sb.append(" lnLsn="); 3734 sb.append(DbLsn.getNoFormatString(lnLsn)); 3735 3736 logger.log(level, sb.toString()); 3737 } 3738 } 3739 3740 private static class SplitInfo { 3741 IN parent; 3742 IN child; 3743 int index; 3744 3745 SplitInfo(IN parent, IN child, int index) { 3746 this.parent = parent; 3747 this.child = child; 3748 this.index = index; 3749 } 3750 } 3751} 3752 | Popular Tags |