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

com.sleepycat.je.cleaner.DbCache 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.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.dbi.DatabaseId;
import com.sleepycat.je.dbi.DatabaseImpl;
import com.sleepycat.je.dbi.EnvironmentImpl;

import org.checkerframework.checker.nullness.qual.NonNull;

class DbCache implements Iterable> {

    private final EnvironmentImpl envImpl;
    private final Cleaner cleaner;
    private final long timoutMs;
    private long lastClearTime;
    private int lookups;
    private final Map cache = new HashMap<>();

    DbCache(final EnvironmentImpl envImpl, final Cleaner cleaner) {
        this.envImpl = envImpl;
        this.cleaner = cleaner;

        timoutMs = envImpl.getConfigManager().getDuration(
            EnvironmentParams.ENV_DB_CACHE_TIMEOUT);

        lastClearTime = System.currentTimeMillis();
    }

    /**
     * Used to cache DatabaseImpl and some relatively static info about it.
     * The static info can be used for determining obsolescence without doing
     * an expensive DbTree lookup.This reduces the negative performance impact
     * of periodically clearing the cache via {@link #releaseDbImpls}. The
     * static info can be obtained with a single DbTree lookup per DB for each
     * file cleaned.
     */
    static class DbInfo {

        /**
         * The dbImpl field is non-null if it is cached, but set to null
         * periodically by calling {@link #releaseDbImpls}.
         */
        DatabaseImpl dbImpl;

        /*
         * The following fields are available even when dbImpl is null. When
         * the cache is cleared, dbImpl is set to null but these fields are
         * left in place. For the most part they can be used for determining
         * obsolescence even when they are stale, with some caveats below.
         */

        /**
         * The following fields are truly immutable.
         */
        boolean dups;
        boolean internal;
        boolean isLNImmediatelyObsolete;

        /**
         * The name field can change, but in all cases the old name can be
         * used, either as debug output or to pass to the extinction filter.
         */
        String name;

        /**
         * If true, the deleted field is immutable and dbImpl will be null.
         * If false, the deleting field can be used to determine whether a
         * deletion is in progress. If both fields are false, the current
         * dbImpl must be consulted to determine whether the DB is deleted.
         * @see #getDbImpl
         */
        boolean deleted;

        /**
         * If true, the DB will definitely be deleted, so the only possible
         * state transition is from [deleting=true,deleted=false] to
         * [deleting=false,deleted=true].
         * @see #getDbImpl
         */
        boolean deleting;
    }

    /**
     * Returns the possibly-stale info for a given DB ID. Does not call
     * DbTree.getDb if the DB ID has been previously cached.
     *
     * DbInfo.dbImpl is not guaranteed to be non-null even if DbInfo.deleted
     * is false. If DbInfo.dbImpl is null, the DB has been released and may be
     * deleted by another thread.
     */
    DbInfo getDbInfo(final DatabaseId dbId) {
        final DbInfo info = cache.get(dbId);
        if (info != null) {
            return info;
        }
        return getDbImpl(dbId);
    }

    /**
     * Returns the up-to-date info for a given DB ID, returning a non-null
     * DbInfo.dbImpl when the DB is not deleted or deleting.
     *
     * If the DB was previously found to be deleted or deleting, this method
     * does not call DbTree.getDb again (this case is optimized).
     */
    DbInfo getDbImpl(final DatabaseId id) {
        DbInfo info = cache.get(id);
        if (info == null) {
            info = new DbInfo();
            cache.put(id, info);
        }
        if (info.dbImpl == null && !info.deleted && !info.deleting) {
            final DatabaseImpl db =
                envImpl.getDbTree().getDb(id, cleaner.lockTimeout);
            if (db == null) {
                info.deleted = true;
            } else {
                info.dbImpl = db;
                info.dups = db.getSortedDuplicates();
                info.internal = db.getDbType().isInternal();
                info.isLNImmediatelyObsolete = db.isLNImmediatelyObsolete();
                info.name = db.getName();
                info.deleting = db.isDeleting();
            }
            lookups++;
        }
        return info;
    }

    /**
     * Returns an iterator over the cached entries.
     */
    @Override
    @NonNull
    public Iterator> iterator() {
        return cache.entrySet().iterator();
    }

    /**
     * Returns the number of calls to DbTree.getDb during the cleaner run.
     */
    int getLookups() {
        return lookups;
    }

    /**
     * Releases all non-null DbInfo.dbImpl objects in the cache and sets this
     * field to null.
     */
    void releaseDbImpls() {
        for (final DbInfo info : cache.values()) {
            releaseDbImpl(info);
        }
    }

    /**
     * Releases DbInfo.dbImpl if non-null and sets this field to null.
     */
    void releaseDbImpl(final DbInfo info) {
        if (info.dbImpl != null) {
            envImpl.getDbTree().releaseDb(info.dbImpl);
            info.dbImpl = null;
        }
    }

    /**
     * Release cached dbImpls periodically to prevent starving other threads
     * that need exclusive access to the MapLN (for example,
     * DbTree.deleteMapLN). [#21015]
     */
    void clearCachePeriodically() {

        final long now = System.currentTimeMillis();

        if (now >= lastClearTime + timoutMs) {
            releaseDbImpls();
            lastClearTime = now;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy