1 8 9 package com.sleepycat.je.cleaner; 10 11 import java.io.IOException ; 12 import java.util.Arrays ; 13 import java.util.Collections ; 14 import java.util.Comparator ; 15 import java.util.Iterator ; 16 import java.util.Set ; 17 import java.util.logging.Level ; 18 import java.util.logging.Logger ; 19 20 import com.sleepycat.je.DatabaseException; 21 import com.sleepycat.je.EnvironmentStats; 22 import com.sleepycat.je.StatsConfig; 23 import com.sleepycat.je.cleaner.FileSelector.CheckpointStartCleanerState; 24 import com.sleepycat.je.config.EnvironmentParams; 25 import com.sleepycat.je.dbi.DatabaseId; 26 import com.sleepycat.je.dbi.DatabaseImpl; 27 import com.sleepycat.je.dbi.DbConfigManager; 28 import com.sleepycat.je.dbi.DbTree; 29 import com.sleepycat.je.dbi.EnvConfigObserver; 30 import com.sleepycat.je.dbi.EnvironmentImpl; 31 import com.sleepycat.je.log.FileManager; 32 import com.sleepycat.je.tree.BIN; 33 import com.sleepycat.je.tree.ChildReference; 34 import com.sleepycat.je.tree.DIN; 35 import com.sleepycat.je.tree.LN; 36 import com.sleepycat.je.tree.Node; 37 import com.sleepycat.je.tree.Tree; 38 import com.sleepycat.je.tree.TreeLocation; 39 import com.sleepycat.je.txn.BasicLocker; 40 import com.sleepycat.je.txn.LockGrantType; 41 import com.sleepycat.je.txn.LockResult; 42 import com.sleepycat.je.txn.LockType; 43 import com.sleepycat.je.utilint.DaemonRunner; 44 import com.sleepycat.je.utilint.DbLsn; 45 import com.sleepycat.je.utilint.PropUtil; 46 import com.sleepycat.je.utilint.Tracer; 47 48 54 public class Cleaner implements DaemonRunner, EnvConfigObserver { 55 56 static final String CLEAN_IN = "CleanIN:"; 57 static final String CLEAN_LN = "CleanLN:"; 58 static final String CLEAN_MIGRATE_LN = "CleanMigrateLN:"; 59 static final String CLEAN_PENDING_LN = "CleanPendingLN:"; 60 61 67 static final boolean PROACTIVE_MIGRATION = true; 68 69 81 static final boolean UPDATE_GENERATION = false; 82 83 91 static final boolean DO_CRITICAL_EVICTION = true; 92 93 99 int nBacklogFiles = 0; 100 int nCleanerRuns = 0; 101 int nCleanerDeletions = 0; 102 int nINsObsolete = 0; 103 int nINsCleaned = 0; 104 int nINsDead = 0; 105 int nINsMigrated = 0; 106 int nLNsObsolete = 0; 107 int nLNsCleaned = 0; 108 int nLNsDead = 0; 109 int nLNsLocked = 0; 110 int nLNsMigrated = 0; 111 int nLNsMarked = 0; 112 int nLNQueueHits = 0; 113 int nPendingLNsProcessed = 0; 114 int nMarkedLNsProcessed = 0; 115 int nToBeCleanedLNsProcessed = 0; 116 int nClusterLNsProcessed = 0; 117 int nPendingLNsLocked = 0; 118 int nEntriesRead = 0; 119 long nRepeatIteratorReads = 0; 120 121 125 long lockTimeout; 126 int readBufferSize; 127 int lookAheadCacheSize; 128 int nDeadlockRetries; 129 boolean expunge; 130 boolean clusterResident; 131 boolean clusterAll; 132 int maxBatchFiles; 133 Level detailedTraceLevel; 134 long cleanerBytesInterval; 135 boolean trackDetail; 136 boolean fetchObsoleteSize; 137 138 143 Set mustBeCleanedFiles = Collections.EMPTY_SET; 144 145 150 Set lowUtilizationFiles = Collections.EMPTY_SET; 151 152 private String name; 153 private EnvironmentImpl env; 154 private UtilizationProfile profile; 155 private UtilizationTracker tracker; 156 private FileSelector fileSelector; 157 private FileProcessor[] threads; 158 159 163 private Object deleteFileLock; 164 private boolean deleteProhibited; 166 public Cleaner(EnvironmentImpl env, String name) 167 throws DatabaseException { 168 169 this.env = env; 170 this.name = name; 171 tracker = new UtilizationTracker(env, this); 172 profile = new UtilizationProfile(env, tracker); 173 fileSelector = new FileSelector(); 174 threads = new FileProcessor[0]; 175 deleteFileLock = new Object (); 176 177 182 trackDetail = env.getConfigManager().getBoolean 183 (EnvironmentParams.CLEANER_TRACK_DETAIL); 184 185 186 envConfigUpdate(env.getConfigManager()); 187 env.addConfigObserver(this); 188 } 189 190 193 public void envConfigUpdate(DbConfigManager cm) 194 throws DatabaseException { 195 196 lockTimeout = PropUtil.microsToMillis(cm.getLong 197 (EnvironmentParams.CLEANER_LOCK_TIMEOUT)); 198 199 readBufferSize = cm.getInt(EnvironmentParams.CLEANER_READ_SIZE); 200 if (readBufferSize <= 0) { 201 readBufferSize = cm.getInt 202 (EnvironmentParams.LOG_ITERATOR_READ_SIZE); 203 } 204 205 lookAheadCacheSize = cm.getInt 206 (EnvironmentParams.CLEANER_LOOK_AHEAD_CACHE_SIZE); 207 208 nDeadlockRetries = cm.getInt(EnvironmentParams.CLEANER_DEADLOCK_RETRY); 209 210 expunge = cm.getBoolean(EnvironmentParams.CLEANER_REMOVE); 211 212 clusterResident = cm.getBoolean(EnvironmentParams.CLEANER_CLUSTER); 213 214 clusterAll = cm.getBoolean(EnvironmentParams.CLEANER_CLUSTER_ALL); 215 216 maxBatchFiles = cm.getInt(EnvironmentParams.CLEANER_MAX_BATCH_FILES); 217 218 detailedTraceLevel = Tracer.parseLevel 219 (env, EnvironmentParams.JE_LOGGING_LEVEL_CLEANER); 220 221 if (clusterResident && clusterAll) { 222 throw new IllegalArgumentException 223 ("Both " + EnvironmentParams.CLEANER_CLUSTER + 224 " and " + EnvironmentParams.CLEANER_CLUSTER_ALL + 225 " may not be set to true."); 226 } 227 228 int nThreads = cm.getInt(EnvironmentParams.CLEANER_THREADS); 229 assert nThreads > 0; 230 231 if (nThreads != threads.length) { 232 233 234 for (int i = nThreads; i < threads.length; i += 1) { 235 if (threads[i] != null) { 236 threads[i].shutdown(); 237 threads[i] = null; 238 } 239 } 240 241 242 FileProcessor[] newThreads = new FileProcessor[nThreads]; 243 for (int i = 0; i < nThreads && i < threads.length; i += 1) { 244 newThreads[i] = threads[i]; 245 } 246 247 248 threads = newThreads; 249 250 251 for (int i = 0; i < nThreads; i += 1) { 252 if (threads[i] == null) { 253 threads[i] = new FileProcessor 254 (name + '-' + (i + 1), 255 env, this, profile, fileSelector); 256 } 257 } 258 } 259 260 cleanerBytesInterval = cm.getLong 261 (EnvironmentParams.CLEANER_BYTES_INTERVAL); 262 if (cleanerBytesInterval == 0) { 263 cleanerBytesInterval = cm.getLong 264 (EnvironmentParams.LOG_FILE_MAX) / 4; 265 } 266 267 fetchObsoleteSize = cm.getBoolean 268 (EnvironmentParams.CLEANER_FETCH_OBSOLETE_SIZE); 269 } 270 271 public UtilizationTracker getUtilizationTracker() { 272 return tracker; 273 } 274 275 public UtilizationProfile getUtilizationProfile() { 276 return profile; 277 } 278 279 public boolean getFetchObsoleteSize() { 280 return fetchObsoleteSize; 281 } 282 283 289 290 public void runOrPause(boolean run) { 291 if (!env.isNoLocking()) { 292 for (int i = 0; i < threads.length; i += 1) { 293 FileProcessor processor = threads[i]; 294 if (processor != null) { 295 296 305 if (run) { 306 processor.addSentinalWorkObject(); 307 } 308 processor.runOrPause(run); 309 } 310 } 311 } 312 } 313 314 public void wakeup() { 315 for (int i = 0; i < threads.length; i += 1) { 316 if (threads[i] != null) { 317 threads[i].wakeup(); 318 } 319 } 320 } 321 322 public void requestShutdown() { 323 for (int i = 0; i < threads.length; i += 1) { 324 if (threads[i] != null) { 325 threads[i].requestShutdown(); 326 } 327 } 328 } 329 330 public void shutdown() { 331 for (int i = 0; i < threads.length; i += 1) { 332 if (threads[i] != null) { 333 threads[i].shutdown(); 334 threads[i].clearEnv(); 335 threads[i] = null; 336 } 337 } 338 } 339 340 public int getNWakeupRequests() { 341 int count = 0; 342 for (int i = 0; i < threads.length; i += 1) { 343 if (threads[i] != null) { 344 count += threads[i].getNWakeupRequests(); 345 } 346 } 347 return count; 348 } 349 350 private boolean areThreadsRunning() { 351 for (int i = 0; i < threads.length; i += 1) { 352 if (threads[i] != null) { 353 return threads[i].isRunning(); 354 } 355 } 356 return false; 357 } 358 359 372 public int doClean(boolean cleanMultipleFiles, boolean forceCleaning) 373 throws DatabaseException { 374 375 FileProcessor processor = new FileProcessor 376 ("", env, this, profile, fileSelector); 377 return processor.doClean 378 (false , cleanMultipleFiles, forceCleaning); 379 } 380 381 384 public void loadStats(StatsConfig config, EnvironmentStats stat) 385 throws DatabaseException { 386 387 stat.setCleanerBacklog(nBacklogFiles); 388 stat.setNCleanerRuns(nCleanerRuns); 389 stat.setNCleanerDeletions(nCleanerDeletions); 390 stat.setNINsObsolete(nINsObsolete); 391 stat.setNINsCleaned(nINsCleaned); 392 stat.setNINsDead(nINsDead); 393 stat.setNINsMigrated(nINsMigrated); 394 stat.setNLNsObsolete(nLNsObsolete); 395 stat.setNLNsCleaned(nLNsCleaned); 396 stat.setNLNsDead(nLNsDead); 397 stat.setNLNsLocked(nLNsLocked); 398 stat.setNLNsMigrated(nLNsMigrated); 399 stat.setNLNsMarked(nLNsMarked); 400 stat.setNLNQueueHits(nLNQueueHits); 401 stat.setNPendingLNsProcessed(nPendingLNsProcessed); 402 stat.setNMarkedLNsProcessed(nMarkedLNsProcessed); 403 stat.setNToBeCleanedLNsProcessed(nToBeCleanedLNsProcessed); 404 stat.setNClusterLNsProcessed(nClusterLNsProcessed); 405 stat.setNPendingLNsLocked(nPendingLNsLocked); 406 stat.setNCleanerEntriesRead(nEntriesRead); 407 stat.setNRepeatIteratorReads(nRepeatIteratorReads); 408 409 if (config.getClear()) { 410 nCleanerRuns = 0; 411 nCleanerDeletions = 0; 412 nINsObsolete = 0; 413 nINsCleaned = 0; 414 nINsDead = 0; 415 nINsMigrated = 0; 416 nLNsObsolete = 0; 417 nLNsCleaned = 0; 418 nLNsDead = 0; 419 nLNsLocked = 0; 420 nLNsMigrated = 0; 421 nLNsMarked = 0; 422 nLNQueueHits = 0; 423 nPendingLNsProcessed = 0; 424 nMarkedLNsProcessed = 0; 425 nToBeCleanedLNsProcessed = 0; 426 nClusterLNsProcessed = 0; 427 nPendingLNsLocked = 0; 428 nEntriesRead = 0; 429 nRepeatIteratorReads = 0; 430 } 431 } 432 433 457 void deleteSafeToDeleteFiles() 458 throws DatabaseException { 459 460 464 synchronized (deleteFileLock) { 465 if (deleteProhibited) { 466 return; 467 } 468 469 Set safeFiles = fileSelector.copySafeToDeleteFiles(); 470 if (safeFiles == null) { 471 return; 472 } 473 474 478 env.checkIfInvalid(); 479 480 483 if (env.mayNotWrite()) { 484 return; 485 } 486 487 491 if (!env.getFileManager().lockEnvironment(false, true)) { 492 Tracer.trace 493 (Level.SEVERE, env, "Cleaner has " + safeFiles.size() + 494 " files not deleted because of read-only processes."); 495 return; 496 } 497 498 try { 499 for (Iterator i = safeFiles.iterator(); i.hasNext();) { 500 Long fileNum = (Long ) i.next(); 501 long fileNumValue = fileNum.longValue(); 502 boolean deleted = false; 503 try { 504 if (expunge) { 505 env.getFileManager().deleteFile(fileNumValue); 506 } else { 507 env.getFileManager().renameFile 508 (fileNumValue, FileManager.DEL_SUFFIX); 509 } 510 deleted = true; 511 } catch (DatabaseException e) { 512 traceFileNotDeleted(e, fileNumValue); 513 } catch (IOException e) { 514 traceFileNotDeleted(e, fileNumValue); 515 } 516 517 529 if (deleted) { 530 Tracer.trace 531 (Level.SEVERE, env, 532 "Cleaner deleted file 0x" + 533 Long.toHexString(fileNumValue)); 534 535 543 try { 544 profile.removeFile(fileNum); 545 } finally { 546 fileSelector.removeDeletedFile(fileNum); 547 } 548 } 549 nCleanerDeletions++; 550 } 551 } finally { 552 env.getFileManager().releaseExclusiveLock(); 553 } 554 } 555 } 556 557 public void setDeleteProhibited() { 558 559 synchronized (deleteFileLock) { 560 deleteProhibited = true; 561 } 562 } 563 564 public void clearDeleteProhibited() { 565 synchronized (deleteFileLock) { 566 deleteProhibited = false; 567 } 568 } 569 570 private void traceFileNotDeleted(Exception e, long fileNum) { 571 Tracer.trace 572 (env, "Cleaner", "deleteSafeToDeleteFiles", 573 "Log file 0x" + Long.toHexString(fileNum) + " could not be " + 574 (expunge ? "deleted" : "renamed") + 575 ". This operation will be retried at the next checkpoint.", 576 e); 577 } 578 579 587 public CheckpointStartCleanerState getFilesAtCheckpointStart() 588 throws DatabaseException { 589 590 591 processPending(); 592 593 return fileSelector.getFilesAtCheckpointStart(); 594 } 595 596 600 public void updateFilesAtCheckpointEnd(CheckpointStartCleanerState info) 601 throws DatabaseException { 602 603 fileSelector.updateFilesAtCheckpointEnd(info); 604 deleteSafeToDeleteFiles(); 605 } 606 607 611 public void updateReadOnlyFileCollections() { 612 mustBeCleanedFiles = fileSelector.getMustBeCleanedFiles(); 613 lowUtilizationFiles = fileSelector.getLowUtilizationFiles(); 614 nBacklogFiles = fileSelector.getBacklog(); 615 } 616 617 621 void processPending() 622 throws DatabaseException { 623 624 DbTree dbMapTree = env.getDbMapTree(); 625 626 LNInfo[] pendingLNs = fileSelector.getPendingLNs(); 627 if (pendingLNs != null) { 628 TreeLocation location = new TreeLocation(); 629 630 for (int i = 0; i < pendingLNs.length; i += 1) { 631 LNInfo info = pendingLNs[i]; 632 633 DatabaseId dbId = info.getDbId(); 634 DatabaseImpl db = dbMapTree.getDb(dbId, lockTimeout); 635 636 byte[] key = info.getKey(); 637 byte[] dupKey = info.getDupKey(); 638 LN ln = info.getLN(); 639 640 641 if (DO_CRITICAL_EVICTION) { 642 env.getEvictor().doCriticalEviction(true); } 644 645 processPendingLN 646 (ln, db, key, dupKey, location); 647 648 649 env.sleepAfterBackgroundIO(); 650 } 651 } 652 653 DatabaseId[] pendingDBs = fileSelector.getPendingDBs(); 654 if (pendingDBs != null) { 655 for (int i = 0; i < pendingDBs.length; i += 1) { 656 DatabaseId dbId = pendingDBs[i]; 657 DatabaseImpl db = dbMapTree.getDb(dbId, lockTimeout); 658 if (db == null || db.isDeleteFinished()) { 659 fileSelector.removePendingDB(dbId); 660 } 661 } 662 } 663 } 664 665 669 private void processPendingLN(LN ln, 670 DatabaseImpl db, 671 byte[] key, 672 byte[] dupKey, 673 TreeLocation location) 674 throws DatabaseException { 675 676 boolean parentFound = false; boolean processedHere = true; boolean lockDenied = false; boolean obsolete = false; boolean completed = false; 682 BasicLocker locker = null; 683 BIN bin = null; 684 DIN parentDIN = null; 685 try { 686 nPendingLNsProcessed++; 687 688 693 if (db == null || db.isDeleted()) { 694 addPendingDB(db); 695 nLNsDead++; 696 obsolete = true; 697 completed = true; 698 return; 699 } 700 701 Tree tree = db.getTree(); 702 assert tree != null; 703 704 705 706 locker = new BasicLocker(env); 707 LockResult lockRet = locker.nonBlockingLock 708 (ln.getNodeId(), LockType.READ, db); 709 if (lockRet.getLockGrant() == LockGrantType.DENIED) { 710 711 nPendingLNsLocked++; 712 lockDenied = true; 713 completed = true; 714 return; 715 } 716 717 724 parentFound = tree.getParentBINForChildLN 725 (location, key, dupKey, ln, 726 false, true, true, UPDATE_GENERATION); 730 bin = location.bin; 731 int index = location.index; 732 733 if (!parentFound) { 734 nLNsDead++; 735 obsolete = true; 736 completed = true; 737 return; 738 } 739 740 if (ln.containsDuplicates()) { 741 742 parentDIN = (DIN) bin.fetchTarget(index); 743 parentDIN.latch(UPDATE_GENERATION); 744 ChildReference dclRef = parentDIN.getDupCountLNRef(); 745 processedHere = false; 746 migrateDupCountLN 747 (db, dclRef.getLsn(), parentDIN, dclRef, 748 true, true, ln.getNodeId(), CLEAN_PENDING_LN); 752 } else { 753 754 processedHere = false; 755 migrateLN 756 (db, bin.getLsn(index), bin, index, 757 true, true, ln.getNodeId(), true, CLEAN_PENDING_LN); 762 } 763 completed = true; 764 } catch (DatabaseException DBE) { 765 DBE.printStackTrace(); 766 Tracer.trace(env, "com.sleepycat.je.cleaner.Cleaner", "processLN", 767 "Exception thrown: ", DBE); 768 throw DBE; 769 } finally { 770 if (parentDIN != null) { 771 parentDIN.releaseLatchIfOwner(); 772 } 773 774 if (bin != null) { 775 bin.releaseLatchIfOwner(); 776 } 777 778 if (locker != null) { 779 locker.operationEnd(); 780 } 781 782 786 if (processedHere) { 787 if (completed && !lockDenied) { 788 fileSelector.removePendingLN(ln.getNodeId()); 789 } 790 trace(detailedTraceLevel, CLEAN_PENDING_LN, ln, DbLsn.NULL_LSN, 791 completed, obsolete, false ); 792 } 793 } 794 } 795 796 801 public boolean isEvictable(BIN bin, int index) { 802 803 if (bin.getDirty()) { 804 805 if (bin.getMigrate(index)) { 806 return false; 807 } 808 809 long lsn = bin.getLsn(index); 810 if (lsn == DbLsn.NULL_LSN) { 811 812 816 return true; 817 } 818 819 boolean isResident = (bin.getTarget(index) != null); 820 Long fileNum = new Long (DbLsn.getFileNumber(lsn)); 821 822 if ((PROACTIVE_MIGRATION || isResident) && 823 mustBeCleanedFiles.contains(fileNum)) { 824 return false; 825 } 826 827 if ((clusterAll || (clusterResident && isResident)) && 828 lowUtilizationFiles.contains(fileNum)) { 829 return false; 830 } 831 } 832 833 return true; 834 } 835 836 852 public void lazyMigrateLNs(final BIN bin, 853 boolean proactiveMigration, 854 boolean backgroundIO) 855 throws DatabaseException { 856 857 DatabaseImpl db = bin.getDatabase(); 858 859 boolean isBinInDupDb = db.getSortedDuplicates() && 860 !bin.containsDuplicates(); 861 862 866 Integer [] sortedIndices = null; 867 int nSortedIndices = 0; 868 int nEntries = bin.getNEntries(); 869 870 for (int index = 0; index < nEntries; index += 1) { 871 872 boolean migrateFlag = bin.getMigrate(index); 873 boolean isResident = (bin.getTarget(index) != null); 874 long childLsn = bin.getLsn(index); 875 876 if (childLsn != DbLsn.NULL_LSN) { 877 878 879 if (shouldMigrateLN 880 (migrateFlag, isResident, proactiveMigration, isBinInDupDb, 881 childLsn)) { 882 883 if (isResident) { 884 migrateLN 885 (db, childLsn, bin, index, 886 migrateFlag, false, 0, backgroundIO, 890 CLEAN_MIGRATE_LN); 891 } else { 892 if (sortedIndices == null) { 893 sortedIndices = new Integer [nEntries]; 894 } 895 sortedIndices[nSortedIndices++] = new Integer (index); 896 } 897 } 898 } 899 } 900 901 if (sortedIndices != null) { 902 Arrays.sort(sortedIndices, 0, nSortedIndices, new Comparator () { 903 public int compare(Object o1, Object o2) { 904 int i1 = ((Integer ) o1).intValue(); 905 int i2 = ((Integer ) o2).intValue(); 906 return DbLsn.compareTo(bin.getLsn(i1), bin.getLsn(i2)); 907 } 908 }); 909 for (int i = 0; i < nSortedIndices; i += 1) { 910 int index = sortedIndices[i].intValue(); 911 long childLsn = bin.getLsn(index); 912 boolean migrateFlag = bin.getMigrate(index); 913 migrateLN 914 (db, childLsn, bin, index, 915 migrateFlag, false, 0, backgroundIO, 919 CLEAN_MIGRATE_LN); 920 } 921 } 922 } 923 924 942 public void lazyMigrateDupCountLN(DIN din, 943 ChildReference dclRef, 944 boolean proactiveMigration) 945 throws DatabaseException { 946 947 DatabaseImpl db = din.getDatabase(); 948 949 boolean migrateFlag = dclRef.getMigrate(); 950 boolean isResident = (dclRef.getTarget() != null); 951 boolean isBinInDupDb = false; 952 long childLsn = dclRef.getLsn(); 953 954 if (shouldMigrateLN 955 (migrateFlag, isResident, proactiveMigration, isBinInDupDb, 956 childLsn)) { 957 958 migrateDupCountLN 959 (db, childLsn, din, dclRef, 960 migrateFlag, false, 0, CLEAN_MIGRATE_LN); 964 } 965 } 966 967 984 private boolean shouldMigrateLN(boolean migrateFlag, 985 boolean isResident, 986 boolean proactiveMigration, 987 boolean isBinInDupDb, 988 long childLsn) { 989 boolean doMigration = false; 990 991 if (migrateFlag) { 992 993 998 doMigration = true; 999 nMarkedLNsProcessed++; 1000 1001 } else if (!proactiveMigration || isBinInDupDb || env.isClosing()) { 1002 1003 1017 1018 } else { 1019 1020 Long fileNum = new Long (DbLsn.getFileNumber(childLsn)); 1021 1022 if ((PROACTIVE_MIGRATION || isResident) && 1023 mustBeCleanedFiles.contains(fileNum)) { 1024 1025 1026 doMigration = true; 1027 nToBeCleanedLNsProcessed++; 1028 1029 } else if ((clusterAll || (clusterResident && isResident)) && 1030 lowUtilizationFiles.contains(fileNum)) { 1031 1032 1033 doMigration = true; 1034 nClusterLNsProcessed++; 1035 } 1036 } 1037 1038 return doMigration; 1039 } 1040 1041 1045 private void migrateLN(DatabaseImpl db, 1046 long lsn, 1047 BIN bin, 1048 int index, 1049 boolean wasCleaned, 1050 boolean isPending, 1051 long lockedPendingNodeId, 1052 boolean backgroundIO, 1053 String cleanAction) 1054 throws DatabaseException { 1055 1056 1057 boolean obsolete = false; boolean migrated = false; boolean lockDenied = false; boolean completed = false; boolean clearTarget = false; 1063 1067 BasicLocker locker = null; 1068 LN ln = null; 1069 1070 try { 1071 if (lsn == DbLsn.NULL_LSN) { 1072 1073 completed = true; 1074 return; 1075 } 1076 1077 1081 if (!bin.isEntryKnownDeleted(index)) { 1082 ln = (LN) bin.getTarget(index); 1083 if (ln == null) { 1084 1085 ln = (LN) bin.fetchTarget(index); 1086 clearTarget = !db.getId().equals(DbTree.ID_DB_ID); 1087 } 1088 } 1089 1090 1091 if (ln == null) { 1092 if (wasCleaned) { 1093 nLNsDead++; 1094 } 1095 obsolete = true; 1096 completed = true; 1097 return; 1098 } 1099 1100 1106 if (lockedPendingNodeId != ln.getNodeId()) { 1107 locker = new BasicLocker(env); 1108 LockResult lockRet = locker.nonBlockingLock 1109 (ln.getNodeId(), LockType.READ, db); 1110 if (lockRet.getLockGrant() == LockGrantType.DENIED) { 1111 1112 1116 if (wasCleaned) { 1117 nLNsLocked++; 1118 } 1119 lockDenied = true; 1120 completed = true; 1121 return; 1122 } 1123 } 1124 1125 1126 if (ln.isDeleted()) { 1127 bin.setKnownDeletedLeaveTarget(index); 1128 if (wasCleaned) { 1129 nLNsDead++; 1130 } 1131 obsolete = true; 1132 completed = true; 1133 return; 1134 } 1135 1136 1149 if (bin.getMigrate(index)) { 1150 Long fileNum = new Long (DbLsn.getFileNumber(lsn)); 1151 if (!fileSelector.isFileCleaningInProgress(fileNum)) { 1152 obsolete = true; 1153 completed = true; 1154 if (wasCleaned) { 1155 nLNsDead++; 1156 } 1157 return; 1158 } 1159 } 1160 1161 1162 byte[] key = getLNMainKey(bin, index); 1163 long newLNLsn = ln.log 1164 (env, db.getId(), key, lsn, ln.getTotalLastLoggedSize(key), 1165 locker, backgroundIO); 1166 bin.updateEntry(index, newLNLsn); 1167 nLNsMigrated++; 1168 migrated = true; 1169 completed = true; 1170 return; 1171 } finally { 1172 if (isPending) { 1173 if (completed && !lockDenied) { 1174 fileSelector.removePendingLN(lockedPendingNodeId); 1175 } 1176 } else { 1177 1178 1185 if (bin.getMigrate(index) && (!completed || lockDenied)) { 1186 1187 byte[] key = getLNMainKey(bin, index); 1188 byte[] dupKey = getLNDupKey(bin, index, ln); 1189 fileSelector.addPendingLN(ln, db.getId(), key, dupKey); 1190 1191 1192 if (!areThreadsRunning()) { 1193 env.getUtilizationTracker().activateCleaner(); 1194 } 1195 1196 1200 clearTarget = false; 1201 } 1202 } 1203 1204 1209 bin.setMigrate(index, false); 1210 1211 1216 if (clearTarget) { 1217 bin.updateEntry(index, null); 1218 } 1219 1220 if (locker != null) { 1221 locker.operationEnd(); 1222 } 1223 1224 trace(detailedTraceLevel, cleanAction, ln, lsn, 1225 completed, obsolete, migrated); 1226 } 1227 } 1228 1229 1233 private void migrateDupCountLN(DatabaseImpl db, 1234 long lsn, 1235 DIN parentDIN, 1236 ChildReference dclRef, 1237 boolean wasCleaned, 1238 boolean isPending, 1239 long lockedPendingNodeId, 1240 String cleanAction) 1241 throws DatabaseException { 1242 1243 1244 boolean obsolete = false; boolean migrated = false; boolean lockDenied = false; boolean completed = false; boolean clearTarget = false; 1250 1254 BasicLocker locker = null; 1255 LN ln = null; 1256 1257 try { 1258 if (lsn == DbLsn.NULL_LSN) { 1259 1260 completed = true; 1261 return; 1262 } 1263 1264 1268 ln = (LN) dclRef.getTarget(); 1269 if (ln == null) { 1270 ln = (LN) dclRef.fetchTarget(db, parentDIN); 1271 assert ln != null; 1272 clearTarget = !db.getId().equals(DbTree.ID_DB_ID); 1273 } 1274 1275 1279 if (lockedPendingNodeId != ln.getNodeId()) { 1280 locker = new BasicLocker(env); 1281 LockResult lockRet = locker.nonBlockingLock 1282 (ln.getNodeId(), LockType.READ, db); 1283 if (lockRet.getLockGrant() == LockGrantType.DENIED) { 1284 1285 1289 if (wasCleaned) { 1290 nLNsLocked++; 1291 } 1292 lockDenied = true; 1293 completed = true; 1294 return; 1295 } 1296 } 1297 1298 1303 Long fileNum = new Long (DbLsn.getFileNumber(lsn)); 1304 if (!fileSelector.isFileCleaningInProgress(fileNum)) { 1305 obsolete = true; 1306 completed = true; 1307 if (wasCleaned) { 1308 nLNsDead++; 1309 } 1310 return; 1311 } 1312 1313 1314 byte[] key = parentDIN.getDupKey(); 1315 long newLNLsn = ln.log 1316 (env, db.getId(), key, lsn, ln.getTotalLastLoggedSize(key), 1317 locker, 1318 false); parentDIN.updateDupCountLNRef(newLNLsn); 1320 nLNsMigrated++; 1321 migrated = true; 1322 completed = true; 1323 return; 1324 } finally { 1325 if (isPending) { 1326 if (completed && !lockDenied) { 1327 fileSelector.removePendingLN(lockedPendingNodeId); 1328 } 1329 } else { 1330 1331 1338 if (dclRef.getMigrate() && (!completed || lockDenied)) { 1339 1340 byte[] key = parentDIN.getDupKey(); 1341 byte[] dupKey = null; 1342 fileSelector.addPendingLN(ln, db.getId(), key, dupKey); 1343 1344 1345 if (!areThreadsRunning()) { 1346 env.getUtilizationTracker().activateCleaner(); 1347 } 1348 1349 1353 clearTarget = false; 1354 } 1355 } 1356 1357 1362 dclRef.setMigrate(false); 1363 1364 1369 if (clearTarget) { 1370 parentDIN.updateDupCountLN(null); 1371 } 1372 1373 if (locker != null) { 1374 locker.operationEnd(); 1375 } 1376 1377 trace(detailedTraceLevel, cleanAction, ln, lsn, 1378 completed, obsolete, migrated); 1379 } 1380 } 1381 1382 1385 private byte[] getLNMainKey(BIN bin, int index) 1386 throws DatabaseException { 1387 1388 if (bin.containsDuplicates()) { 1389 return bin.getDupKey(); 1390 } else { 1391 return bin.getKey(index); 1392 } 1393 } 1394 1395 1398 private byte[] getLNDupKey(BIN bin, int index, LN ln) 1399 throws DatabaseException { 1400 1401 DatabaseImpl db = bin.getDatabase(); 1402 1403 if (!db.getSortedDuplicates() || ln.containsDuplicates()) { 1404 1405 1409 return null; 1410 1411 } else if (bin.containsDuplicates()) { 1412 1413 1414 return bin.getKey(index); 1415 1416 } else { 1417 1418 1423 return ln.getData(); 1424 } 1425 } 1426 1427 1431 void addPendingDB(DatabaseImpl db) { 1432 if (db != null && db.isDeleted() && !db.isDeleteFinished()) { 1433 DatabaseId id = db.getId(); 1434 if (fileSelector.addPendingDB(id)) { 1435 Tracer.trace 1436 (detailedTraceLevel, env, "CleanAddPendingDB " + id); 1437 } 1438 } 1439 } 1440 1441 1446 void trace(Level level, 1447 String action, 1448 Node node, 1449 long logLsn, 1450 boolean completed, 1451 boolean obsolete, 1452 boolean dirtiedMigrated) { 1453 1454 Logger logger = env.getLogger(); 1455 if (logger.isLoggable(level)) { 1456 StringBuffer sb = new StringBuffer (); 1457 sb.append(action); 1458 if (node != null) { 1459 sb.append(" node="); 1460 sb.append(node.getNodeId()); 1461 } 1462 sb.append(" logLsn="); 1463 sb.append(DbLsn.getNoFormatString(logLsn)); 1464 sb.append(" complete=").append(completed); 1465 sb.append(" obsolete=").append(obsolete); 1466 sb.append(" dirtiedOrMigrated=").append(dirtiedMigrated); 1467 1468 logger.log(level, sb.toString()); 1469 } 1470 } 1471} 1472 | Popular Tags |