blob: f8208099aca5be1c514f6b9bebb7c6bc852b605b [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.dbi.MemoryBudget;
/**
* Delta file summary info for a tracked file. Tracked files are managed by
* the UtilizationTracker.
*
* <p>The methods in this class for reading obsolete offsets may be used by
* multiple threads without synchronization even while another thread is adding
* offsets. This is possible because elements are never deleted from the
* lists. The thread adding obsolete offsets does so under the log write
* latch to prevent multiple threads from adding concurrently.</p>
*/
public class TrackedFileSummary extends FileSummary {
private BaseUtilizationTracker tracker;
private long fileNum;
private OffsetList obsoleteOffsets;
private int memSize;
private boolean trackDetail;
private boolean allowFlush = true;
/**
* Creates an empty tracked summary.
*/
TrackedFileSummary(BaseUtilizationTracker tracker,
long fileNum,
boolean trackDetail) {
this.tracker = tracker;
this.fileNum = fileNum;
this.trackDetail = trackDetail;
}
/**
* Returns whether this summary is allowed or prohibited from being flushed
* or evicted during cleaning. By default, flushing is allowed.
*/
public boolean getAllowFlush() {
return allowFlush;
}
/**
* Allows or prohibits this summary from being flushed or evicted during
* cleaning. By default, flushing is allowed.
*/
void setAllowFlush(boolean allowFlush) {
this.allowFlush = allowFlush;
}
/**
* Returns the file number being tracked.
*/
public long getFileNumber() {
return fileNum;
}
/**
* Return the total memory size for this object. We only bother to budget
* obsolete detail, not the overhead for this object, for two reasons:
* 1) The number of these objects is very small, and 2) unit tests disable
* detail tracking as a way to prevent budget adjustments here.
*/
int getMemorySize() {
return memSize;
}
/**
* Overrides reset for a tracked file, and is called when a FileSummaryLN
* is written to the log.
*
* <p>Must be called under the log write latch.</p>
*/
@Override
public void reset() {
assert tracker != null;
obsoleteOffsets = null;
tracker.resetFile(this);
if (memSize > 0) {
updateMemoryBudget(0 - memSize);
}
super.reset();
}
/**
* Tracks the given offset as obsolete or non-obsolete.
*
* <p>Must be called under the log write latch.</p>
*/
void trackObsolete(long offset, boolean checkDupOffsets) {
if (!trackDetail) {
return;
}
int adjustMem = 0;
if (obsoleteOffsets == null) {
obsoleteOffsets = new OffsetList();
adjustMem += MemoryBudget.TFS_LIST_INITIAL_OVERHEAD;
}
if (obsoleteOffsets.add(offset, checkDupOffsets)) {
adjustMem += MemoryBudget.TFS_LIST_SEGMENT_OVERHEAD;
}
if (adjustMem != 0) {
updateMemoryBudget(adjustMem);
}
}
/**
* Adds the obsolete offsets as well as the totals of the given object.
*/
void addTrackedSummary(TrackedFileSummary other) {
/* Add the totals. */
add(other);
/*
* Add the offsets and the memory used [#15505] by the other tracker.
* The memory budget has already been updated for the offsets to be
* added, so we only need to account for a possible difference of one
* segment when we merge them.
*/
memSize += other.memSize;
if (other.obsoleteOffsets != null) {
if (obsoleteOffsets != null) {
/* Merge the other offsets into our list. */
if (obsoleteOffsets.merge(other.obsoleteOffsets)) {
/* There is one segment less as a result of the merge. */
updateMemoryBudget
(- MemoryBudget.TFS_LIST_SEGMENT_OVERHEAD);
}
} else {
/* Adopt the other's offsets as our own. */
obsoleteOffsets = other.obsoleteOffsets;
}
}
}
/**
* Returns obsolete offsets as an array of longs, or null if none.
*/
public long[] getObsoleteOffsets() {
if (obsoleteOffsets != null) {
return obsoleteOffsets.toArray();
} else {
return null;
}
}
/**
* Returns whether the given offset is present in the tracked offsets.
* This does not indicate whether the offset is obsolete in general, but
* only if it is known to be obsolete in this version of the tracked
* information.
*/
boolean containsObsoleteOffset(long offset) {
if (obsoleteOffsets != null) {
return obsoleteOffsets.contains(offset);
} else {
return false;
}
}
private void updateMemoryBudget(int delta) {
assert tracker != null;
memSize += delta;
tracker.env.getMemoryBudget().updateAdminMemoryUsage(delta);
}
/**
* Update memory budgets when this tracker is closed and will never be
* accessed again.
*/
void close() {
assert tracker != null;
tracker.env.getMemoryBudget().updateAdminMemoryUsage(0-memSize);
tracker = null;
memSize = 0;
}
}