blob: d3da1ada8b03281d586c76adeda01ba1ffe5d369 [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.je.cleaner;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.dbi.MemoryBudget;
import com.sleepycat.je.log.LogEntryType;
/**
* Tracks changes to the utilization profile since the last checkpoint. This
* is the "global" tracker for an environment that tracks changes as they
* occur in live operations. Other "local" tracker classes are used to count
* utilization locally and then later transfer the information to the global
* tracker, this tracker.
*
* <p>All changes to this object occur must under the log write latch. It is
* possible to read tracked info without holding the latch. This is done by
* the cleaner when selecting a file and by the checkpointer when determining
* what FileSummaryLNs need to be written. To read tracked info outside the
* log write latch, call getTrackedFile or getTrackedFiles.</p>
*/
public class UtilizationTracker extends BaseUtilizationTracker {
/**
* Constructor used by the cleaner constructor, prior to setting the
* cleaner field of the environment.
*/
UtilizationTracker(EnvironmentImpl env, Cleaner cleaner) {
super(env, cleaner);
}
@Override
public EnvironmentImpl getEnvironment() {
return env;
}
/**
* Evicts tracked detail if the budget for the tracker is exceeded. Evicts
* only one file summary LN at most to keep eviction batches small.
* Returns the number of bytes freed.
*
* <p>When flushFileSummary is called, the TrackedFileSummary is cleared
* via its reset method, which is called by FileSummaryLN.writeToLog. This
* is how memory is subtracted from the budget.</p>
*/
public long evictMemory()
throws DatabaseException {
/* If not tracking detail, there is nothing to evict. */
if (!cleaner.trackDetail) {
return 0;
}
/*
* Do not start eviction until after recovery, since the
* UtilizationProfile will not be initialized properly. UP
* initialization requires that all LNs have been replayed.
*/
if (!env.isValid()) {
return 0;
}
/*
* In a read-only env, we cannot free memory by flushing a
* FileSummaryLN. Normally utilization information is not accumulated
* in a read-only env, but this may ocur during recovery.
*/
if (env.isReadOnly()) {
return 0;
}
MemoryBudget mb = env.getMemoryBudget();
long totalEvicted = 0;
long totalBytes = 0;
int largestBytes = 0;
TrackedFileSummary bestFile = null;
final int ONE_MB = 1024 * 1024;
for (TrackedFileSummary tfs : getTrackedFiles()) {
int mem = tfs.getMemorySize();
if (mem >= ONE_MB) {
env.getUtilizationProfile().flushFileSummary(tfs);
totalEvicted += mem;
continue;
}
totalBytes += mem;
if (mem > largestBytes && tfs.getAllowFlush()) {
largestBytes = mem;
bestFile = tfs;
}
}
if (bestFile != null && totalBytes > mb.getTrackerBudget()) {
env.getUtilizationProfile().flushFileSummary(bestFile);
totalEvicted += largestBytes;
}
return totalEvicted;
}
/**
* Counts the addition of all new log entries including LNs.
*
* <p>Must be called under the log write latch.</p>
*/
public void countNewLogEntry(long lsn,
LogEntryType type,
int size) {
countNew(lsn, type, size);
}
/**
* Counts a node that has become obsolete and tracks the LSN offset, if
* non-zero, to avoid a lookup during cleaning.
*
* <p>A zero LSN offset is used as a special value when obsolete offset
* tracking is not desired. [#15365] The file header entry (at offset
* zero) is never counted as obsolete, it is assumed to be obsolete by the
* cleaner.</p>
*
* <p>This method should only be called for LNs and INs (i.e, only for
* nodes). If type is null we assume it is an LN.</p>
*
* <p>Must be called under the log write latch.</p>
*/
public void countObsoleteNode(long lsn,
LogEntryType type,
int size) {
countObsolete
(lsn, type, size,
true, // trackOffset
true); // checkDupOffsets
}
/**
* Counts as countObsoleteNode does, but since the LSN may be inexact, does
* not track the obsolete LSN offset.
*
* <p>This method should only be called for LNs and INs (i.e, only for
* nodes). If type is null we assume it is an LN.</p>
*
* <p>Must be called under the log write latch.</p>
*/
public void countObsoleteNodeInexact(long lsn,
LogEntryType type,
int size) {
countObsolete
(lsn, type, size,
false, // trackOffset
false); // checkDupOffsets
}
/**
* Counts as countObsoleteNode does, tracks the obsolete LSN offset, but
* does not fire an assert if the offset has already been counted. Use
* this method when the same LSN offset may be counted twice in certain
* circumstances.
*
* <p>This method should only be called for LNs and INs (i.e, only for
* nodes). If type is null we assume it is an LN.</p>
*
* <p>Must be called under the log write latch.</p>
*/
public void countObsoleteNodeDupsAllowed(long lsn,
LogEntryType type,
int size) {
countObsolete
(lsn, type, size,
true, // trackOffset
false); // checkDupOffsets
}
/**
* Returns a tracked summary for the given file which will not be flushed.
*/
public TrackedFileSummary getUnflushableTrackedSummary(long fileNum) {
TrackedFileSummary file = getFileSummary(fileNum);
file.setAllowFlush(false);
return file;
}
}