/** * Evict a single LN if allowed. The amount of memory freed is returned and must be subtracted * from the memory budget by the caller. */ private long evictInternal(int index, Cleaner cleaner) throws DatabaseException { Node n = getTarget(index); if (n instanceof LN) { LN ln = (LN) n; /* * Don't evict MapLNs for open databases (LN.isEvictable) [#13415]. * And don't strip LNs that the cleaner will be migrating * (Cleaner.isEvictable). */ if (ln.isEvictable() && cleaner.isEvictable(this, index)) { boolean force = getDatabase().isDeferredWriteMode() && getLsn(index) == DbLsn.NULL_LSN; /* Log target if necessary. */ logDirtyLN(index, (LN) n, force); /* Clear target. */ setTarget(index, null); ln.releaseMemoryBudget(); return n.getMemorySizeIncludedByParent(); } } return 0; }
public int invokeCleaner() throws DatabaseException { if (cleaner != null) { return cleaner.doClean( true, // cleanMultipleFiles false); // forceCleaning } else { return 0; } }
/** * Note that the IN may or may not be latched when this method is called. Returning the wrong * answer is OK in that case (it will be called again later when latched), but an exception should * not occur. */ @Override int getChildEvictionType() { Cleaner cleaner = getDatabase().getDbEnvironment().getCleaner(); for (int i = 0; i < getNEntries(); i++) { Node node = getTarget(i); if (node != null) { if (node instanceof LN) { LN ln = (LN) node; /* * If the LN is not evictable, we may neither strip the LN * nor evict the node. isEvictableInexact is used here as * a fast check, to avoid the overhead of acquiring a * handle lock while selecting an IN for eviction. See * evictInternal which will call LN.isEvictable to acquire * an handle lock and guarantee that another thread cannot * open the MapLN. [#13415] */ if (!ln.isEvictableInexact()) { return MAY_NOT_EVICT; } /* * If the cleaner allows eviction, then this LN may be * stripped. */ if (cleaner.isEvictable(this, i)) { return MAY_EVICT_LNS; } } else { return MAY_NOT_EVICT; } } } return MAY_EVICT_NODE; }
/** Returns the UtilizationProfile. */ public UtilizationProfile getUtilizationProfile() { return cleaner.getUtilizationProfile(); }
/** Returns the UtilizationTracker. */ public UtilizationTracker getUtilizationTracker() { return cleaner.getUtilizationTracker(); }
/** Helper for doCheckpoint. Same args only this is called with the evictor locked out. */ private synchronized void doCheckpointInternal( CheckpointConfig config, boolean allowDeltas, boolean flushAll, boolean deleteAllCleanedFiles, String invokingSource) throws DatabaseException { if (!isRunnable(config)) { return; } /* * If there are cleaned files to be deleted, flush an extra level to * write out the parents of cleaned nodes. This ensures that the * no node will contain the LSN of a cleaned files. */ boolean flushExtraLevel = false; Set cleanedFiles = null; Cleaner cleaner = envImpl.getCleaner(); if (cleaner != null) { cleanedFiles = cleaner.getCleanedFiles(deleteAllCleanedFiles); if (cleanedFiles != null) { flushExtraLevel = true; } } lastCheckpointMillis = System.currentTimeMillis(); resetPerRunCounters(); LogManager logManager = envImpl.getLogManager(); /* Get the next checkpoint id. */ checkpointId++; nCheckpoints++; boolean success = false; boolean traced = false; try { /* Log the checkpoint start. */ CheckpointStart startEntry = new CheckpointStart(checkpointId, invokingSource); DbLsn checkpointStart = logManager.log(startEntry); /* * Remember the first active lsn -- before this position in the * log, there are no active transactions at this point in time. */ DbLsn firstActiveLsn = envImpl.getTxnManager().getFirstActiveLsn(); if (firstActiveLsn != null && checkpointStart.compareTo(firstActiveLsn) < 0) { firstActiveLsn = checkpointStart; } /* Flush IN nodes. */ flushDirtyNodes(flushAll, allowDeltas, flushExtraLevel); /* * Flush utilization info AFTER flushing IN nodes to reduce the * inaccuracies caused by the sequence FileSummaryLN-LN-BIN. */ flushUtilizationInfo(); /* Log the checkpoint end. */ if (firstActiveLsn == null) { firstActiveLsn = checkpointStart; } CheckpointEnd endEntry = new CheckpointEnd( invokingSource, checkpointStart, envImpl.getRootLsn(), firstActiveLsn, Node.getLastId(), envImpl.getDbMapTree().getLastDbId(), envImpl.getTxnManager().getLastTxnId(), checkpointId); /* * Log checkpoint end and update state kept about the last * checkpoint location. Send a trace message *before* the * checkpoint end log entry. This is done so that the normal * trace message doesn't affect the time-based isRunnable() * calculation, which only issues a checkpoint if a log record * has been written since the last checkpoint. */ trace(envImpl, invokingSource, true); traced = true; /* * Always flush to ensure that cleaned files are not referenced, * and to ensure that this checkpoint is not wasted if we crash. */ lastCheckpointEnd = logManager.logForceFlush(endEntry); lastFirstActiveLsn = firstActiveLsn; lastCheckpointStart = checkpointStart; success = true; if (cleaner != null && cleanedFiles != null) { cleaner.deleteCleanedFiles(cleanedFiles); } } catch (DatabaseException e) { Tracer.trace(envImpl, "Checkpointer", "doCheckpoint", "checkpointId=" + checkpointId, e); throw e; } finally { if (!traced) { trace(envImpl, invokingSource, success); } } }