All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.cleaner.BaseUtilizationTracker Maven / Gradle / Ivy

The newest version!
/*-
 * 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 java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.log.LogEntryType;
import com.sleepycat.je.utilint.DbLsn;

/**
 * Shared implementation for all utilization trackers.  The base implementation
 * keeps track of per-file utilization info only.
 */
public abstract class BaseUtilizationTracker {

    EnvironmentImpl env;
    Cleaner cleaner;
    private long activeFile;

    /**
     * The tracked files are maintained in a volatile field Map that is "copied
     * on write" whenever an element is added or removed.  Add and remove are
     * called only under the log write latch, but get and iteration may be
     * performed at any time because the map is read-only.
     */
    private volatile Map fileSummaries;

    BaseUtilizationTracker(EnvironmentImpl env) {
        this(env, env.getCleaner());
    }

    BaseUtilizationTracker(EnvironmentImpl env, Cleaner cleaner) {
        assert cleaner != null;
        this.env = env;
        this.cleaner = cleaner;
        fileSummaries = Collections.emptyMap();
        activeFile = -1;
    }

    public EnvironmentImpl getEnvironment() {
        return env;
    }

    /**
     * Returns a snapshot of the files being tracked as of the last time a
     * log entry was added.  The summary info returned is the delta since the
     * last checkpoint, not the grand totals, and is approximate since it is
     * changing in real time.  This method may be called without holding the
     * log write latch.
     *
     * 

If files are added or removed from the collection of tracked files in * real time, the returned collection will not be changed since it is a * snapshot. But the objects contained in the collection are live and will * be updated in real time under the log write latch. The collection and * the objects in the collection should not be modified by the caller.

*/ public Collection getTrackedFiles() { return fileSummaries.values(); } /** * Returns one file from the snapshot of tracked files, or null if the * given file number is not in the snapshot array. * * @see #getTrackedFiles */ public TrackedFileSummary getTrackedFile(long fileNum) { return fileSummaries.get(fileNum); } /** * Counts the addition of all new log entries including LNs. * *

For the global tracker, must be called under the log write latch.

*/ final void countNew(long lsn, LogEntryType type, int size) { assert type != null; /* Count in per-file and per-file-per-db summaries. */ long fileNum = DbLsn.getFileNumber(lsn); FileSummary fileSummary = getFileSummary(fileNum); fileSummary.totalCount += 1; fileSummary.totalSize += size; boolean isLN = isLNType(type); if (isLN && fileSummary.maxLNSize < size) { fileSummary.maxLNSize = size; } if (trackObsoleteInfo(type)) { if (isLN) { fileSummary.totalLNCount += 1; fileSummary.totalLNSize += size; } else { fileSummary.totalINCount += 1; fileSummary.totalINSize += size; } } } /** * Counts an obsolete node by incrementing the obsolete count and size. * Tracks the LSN offset if trackOffset is true and the offset is non-zero. * *

For the global tracker, must be called under the log write latch.

*/ final void countObsolete( long lsn, LogEntryType type, int size, boolean trackOffset, boolean checkDupOffsets) { assert trackObsoleteInfo(type); boolean isLN = isLNType(type); long fileNum = DbLsn.getFileNumber(lsn); TrackedFileSummary fileSummary = getFileSummary(fileNum); if (isLN) { fileSummary.obsoleteLNCount += 1; /* The size is optional when tracking obsolete LNs. */ if (size > 0) { fileSummary.obsoleteLNSize += size; fileSummary.obsoleteLNSizeCounted += 1; } } else { fileSummary.obsoleteINCount += 1; /* The size is not allowed when tracking obsolete INs. */ assert size == 0; } if (trackOffset) { long offset = DbLsn.getFileOffset(lsn); if (offset != 0) { fileSummary.trackObsolete(offset, checkDupOffsets); } } } /** * Returns whether file summary information for the given LSN is not * already counted. Outside of recovery, always returns true. For * recovery, is overridden by RecoveryUtilizationTracker and returns * whether the FileSummaryLN for the given file is prior to the given LSN. * . */ boolean isFileUncounted(Long fileNum, long lsn) { return true; } /** * Transfers counts and offsets from this local tracker to the given * (global) UtilizationTracker. * *

When called after recovery has finished, must be called under the log * write latch.

*/ public void transferToUtilizationTracker(UtilizationTracker tracker) throws DatabaseException { /* Add file summary information, including obsolete offsets. */ for (TrackedFileSummary localSummary : getTrackedFiles()) { TrackedFileSummary fileSummary = tracker.getFileSummary(localSummary.getFileNumber()); fileSummary.addTrackedSummary(localSummary); } } /** * Counts all active LSNs in a database as obsolete in the per-file * utilization summaries. This method is called during database * remove/truncate or when replaying those operations during recovery. * *

For the global tracker, must be called under the log write latch.

* * @param dbFileSummaries the map of Long file number to DbFileSummary for * a database that is being deleted. * * @param mapLnLsn is the LSN of the MapLN when recovery is replaying the * truncate/remove, or NULL_LSN when called outside of recovery; obsolete * totals should only be counted when this LSN is prior to the LSN of the * FileSummaryLN for the file being counted. */ public void countObsoleteDb( DbFileSummaryMap dbFileSummaries, long mapLnLsn) { for (Map.Entry entry : dbFileSummaries.entrySet()) { Long fileNum = entry.getKey(); if (isFileUncounted(fileNum, mapLnLsn)) { DbFileSummary dbFileSummary = entry.getValue(); TrackedFileSummary fileSummary = getFileSummary(fileNum); /* * Count as obsolete the currently active amounts in the * database, which are the total amounts minus the previously * counted obsolete amounts. */ int lnObsoleteCount = dbFileSummary.totalLNCount - dbFileSummary.obsoleteLNCount; int lnObsoleteSize = dbFileSummary.totalLNSize - dbFileSummary.obsoleteLNSize; int inObsoleteCount = dbFileSummary.totalINCount - dbFileSummary.obsoleteINCount; fileSummary.obsoleteLNCount += lnObsoleteCount; fileSummary.obsoleteLNSize += lnObsoleteSize; fileSummary.obsoleteINCount += inObsoleteCount; /* * When a DB becomes obsolete, the size of all obsolete LNs can * now be counted accurately because all LN bytes in the DB are * now obsolete. The lnObsoleteSize value calculated above * includes LNs that become obsolete now, plus those that * became obsolete previously but whose size was not counted. * The obsoleteLNSizeCounted field is updated accordingly * below. In other words, DB obsolescence is self-healing with * respect to obsolete LN sizes. [#19144] */ int lnObsoleteSizeCounted = lnObsoleteCount + (dbFileSummary.obsoleteLNCount - dbFileSummary.obsoleteLNSizeCounted); fileSummary.obsoleteLNSizeCounted += lnObsoleteSizeCounted; /* * Do not update the DbFileSummary. It will be flushed when * the MapLN is deleted. If later replayed during recovery, we * will call this method to update the per-file utilization. */ } } } boolean isEmpty() { return fileSummaries.isEmpty(); } /** * Returns a tracked file for the given file number, adding an empty one * if the file is not already being tracked. * *

For the global tracker, must be called under the log write latch.

*/ TrackedFileSummary getFileSummary(long fileNum) { if (activeFile < fileNum) { activeFile = fileNum; } Long fileNumLong = fileNum; TrackedFileSummary file = fileSummaries.get(fileNumLong); if (file == null) { /* Assign fileSummaries field after modifying the new map. */ file = new TrackedFileSummary(this, fileNum, cleaner.trackDetail); Map newFiles = new HashMap<>(fileSummaries); newFiles.put(fileNumLong, file); fileSummaries = newFiles; } return file; } /** * Called after the FileSummaryLN is written to the log during checkpoint. * *

We keep the active file summary in the tracked file map, but we * remove older files to prevent unbounded growth of the map.

* *

Must be called under the log write latch.

*/ void resetFile(TrackedFileSummary fileSummary) { if (fileSummary.getFileNumber() < activeFile && fileSummary.getAllowFlush()) { /* Assign fileSummaries field after modifying the new map. */ Map newFiles = new HashMap<>(fileSummaries); newFiles.remove(fileSummary.getFileNumber()); fileSummaries = newFiles; } } /** * Returns whether obsoleteness is tracked for the given type. Obsoleteness * is tracked for node types and BIN-deltas. A null type is assumed to be * an LN. */ public static boolean trackObsoleteInfo(LogEntryType type) { return type == null || type.isNodeType() || type.equals(LogEntryType.LOG_BIN_DELTA) || type.equals(LogEntryType.LOG_OLD_BIN_DELTA); } /** * Returns whether the given type is an LN; a null type is assumed to be an * LN. */ public static boolean isLNType(LogEntryType type) { return type == null || type.isLNType(); } /** * Update memory budgets when this tracker is closed and will never be * accessed again. */ void close() { for (TrackedFileSummary t: fileSummaries.values()) { t.close(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy