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

com.sleepycat.je.dbi.DbCleanup 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.dbi;

import com.sleepycat.je.utilint.TestHook;

/**
 * Store information about a DatabaseImpl that will have to be deleted or
 * updated at transaction commit or abort. This handles cleanup after
 * operations like Environment.truncateDatabase, removeDatabase and
 * renameDatabase. Cleanup like this is done outside the usual transaction
 * commit or node undo processing, because the mapping tree is always
 * auto-committed to avoid deadlock and is essentially non-transactional.
 */
public class DbCleanup {

    public enum Action {DELETE, RENAME}

    private final DatabaseImpl dbImpl;
    private final Action action;
    private final boolean atCommit;
    private final String newName;

    DbCleanup(final DatabaseImpl dbImpl,
              final Action action,
              final boolean atCommit) {
        this(dbImpl, action, atCommit, null);
    }

    DbCleanup(final DatabaseImpl dbImpl,
              final Action action,
              final boolean atCommit,
              final String newName) {

        assert (action == Action.RENAME) == (newName != null);

        this.dbImpl = dbImpl;
        this.action = action;
        this.atCommit = atCommit;
        this.newName = newName;
    }

    public static TestHook modifyDbRootHook;

    /**
     * Make sure that a set of DbCleanup only has one entry per
     * databaseImpl/action tuple.
     */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof DbCleanup)) {
            return false;
        }

        final DbCleanup other = (DbCleanup) obj;

        return dbImpl.equals(other.dbImpl) &&
            action == other.action &&
            atCommit == other.atCommit;
    }

    @Override
    public int hashCode() {
        return dbImpl.hashCode();
    }

    /**
     * Do any preparation needed for a cleanup task _before_ the txn's write
     * locks have been released.
     */
    public static void setState(final DbCleanup cleanup,
                                final boolean isCommit) {

        final DatabaseImpl dbImpl = cleanup.dbImpl;

        switch (cleanup.action) {
        case RENAME:
            if (cleanup.atCommit == isCommit) {
                dbImpl.setNameAndType(cleanup.newName);
            }
            break;
        case DELETE:
            if (cleanup.atCommit == isCommit) {
                dbImpl.setDeleteStarted();
            }
            break;
        }
    }

    /**
     * Perform and complete the cleanup task _after_ the txn's write locks
     * have been released.
     */
    public static void execute(final EnvironmentImpl envImpl,
                               final DbCleanup[] cleanupArray,
                               final boolean isCommit) {

        final DbTree dbTree = envImpl.getDbTree();

        for (final DbCleanup cleanup : cleanupArray) {

            final DatabaseImpl dbImpl = cleanup.dbImpl;

            switch (cleanup.action) {
            case RENAME:
                /*
                 * We do not even attempt to support updates (renaming) along
                 * with truncate or remove for the same DB in the same txn.
                 */
                try {
                    if (cleanup.atCommit == isCommit) {

                        if (modifyDbRootHook != null) {
                            modifyDbRootHook.doHook();
                        }

                        dbTree.modifyDbRoot(dbImpl);
                    }
                } finally {
                    dbTree.releaseDb(dbImpl);
                }
                break;
            case DELETE:
                if (cleanup.atCommit == isCommit) {
                    /*
                     * If dbCleanupSet contains same databases with different
                     * atCommit, first release the database, then delete it.
                     * [#19636]
                     */
                    if (checkRepeatedDeletedDB(cleanupArray, cleanup)) {
                        dbTree.releaseDb(dbImpl);
                    }

                    /* releaseDb will be called by startDbExtinction. */
                    envImpl.getExtinctionScanner().startDbExtinction(dbImpl);

                } else {
                    /*
                     * If dbCleanupSet contains same databases with different
                     * atCommit, do nothing. [#19636]
                     */
                    if (!checkRepeatedDeletedDB(cleanupArray, cleanup)) {
                        dbTree.releaseDb(dbImpl);
                    }
                }
                break;
            }
        }
    }

    private static boolean checkRepeatedDeletedDB(final DbCleanup[] array,
                                                  final DbCleanup cleanup) {
        for (final DbCleanup element : array) {
            if (element.action == Action.DELETE &&
                element.dbImpl.getId().equals(cleanup.dbImpl.getId()) &&
                element.atCommit != cleanup.atCommit){
                return true;
            }
        }
        return false;
    }

    /**
     * Process cleanup task when a non-transactional DB operation is complete
     * (meaning that the NameLN was logged).
     */
    public static void setStateAndExecute(final EnvironmentImpl envImpl,
                                          final DbCleanup cleanup) {

        final DbTree dbTree = envImpl.getDbTree();
        final DatabaseImpl dbImpl = cleanup.dbImpl;

        switch (cleanup.action) {
        case RENAME:
            try {
                if (cleanup.atCommit) {
                    dbImpl.setNameAndType(cleanup.newName);

                    if (modifyDbRootHook != null) {
                        modifyDbRootHook.doHook();
                    }

                    dbTree.modifyDbRoot(cleanup.dbImpl);
                }
            } finally {
                dbTree.releaseDb(dbImpl);
            }
            break;
        case DELETE:
            if (cleanup.atCommit) {
                /* releaseDb will be called by startDbExtinction. */
                dbImpl.setDeleteStarted();
                envImpl.getExtinctionScanner().startDbExtinction(dbImpl);
            } else {
                dbTree.releaseDb(dbImpl);
            }
            break;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy