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

com.sleepycat.je.log.entry.NameLNLogEntry 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.log.entry;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import com.sleepycat.je.dbi.DatabaseId;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.dbi.ReplicatedDatabaseConfig;
import com.sleepycat.je.log.DbOpReplicationContext;
import com.sleepycat.je.log.LogEntryHeader;
import com.sleepycat.je.log.LogEntryType;
import com.sleepycat.je.log.ReplicationContext;
import com.sleepycat.je.log.VersionedWriteLoggable;
import com.sleepycat.je.tree.NameLN;
import com.sleepycat.je.txn.Txn;
import com.sleepycat.je.utilint.VLSN;

/**
 * NameLNLogEntry contains all the regular LNLogEntry fields and additional
 * information about the database operation which instigated the logging of
 * this NameLN. This additional information is used to support replication of
 * database operations in a replication group.
 *
 * Database operations pose a special problem for replication because unlike
 * data record put and get calls, they can result in multiple log entries that
 * are not all members of a single transaction.  Create and truncate are the
 * problem operations because they end up logging new MapLNs, and our
 * implementation does not treat MapLNs as transactional.  Database operations
 * challenge two replication assumptions: (a) that all logical operations can
 * be repeated on the client node based on the contents of a single log entry,
 * and (b) that non-txnal log entries like MapLNs need not be replicated.
 *
 * Specifically, here's what is logged for database operations.
 *
 * create:
 *
 *  1. new NameLN_TX
 *  2. new MapLN, which has the database config info.
 *  3. txn commit of autocommit or user txn.
 *
 * rename:
 *
 *  1. deleted NameLN_TX
 *  2. new NameLN_TX
 *  3. txn commit from autocommit or user txn
 *
 * truncate:
 *
 *  1. new MapLN w/new id
 *  2. modify the existing NameLN with new id (old database is deleted by
 *     usual commit-time processing)
 *  3. txn commit from autocommit or user txn
 *
 * delete
 *
 *  1. deleted NameLN_TX (old database gets deleted by usual commit-time
 *     processing)
 *  2. txn commit from autocommit or user txn
 *
 * Extra information is needed for create and truncate, which both log
 * information within the MapLN. Rename and delete only log NameLNs, so they
 * can be replicated on the client using the normal replication messages.  The
 * extra fields which follow the usual LNLogEntry fields are:
 *
 * operationType - the type of database operation. In a single node system,
 *                 this is local information implicit in the code path.
 * databaseConfig (optional) - For creates, database configuration info
 * databaseId (optional)- For truncates, the old db id, so we know which
 *                        MapLN to delete.
 */
public class NameLNLogEntry extends LNLogEntry {

    /**
     * The log version of the most recent format change for this entry,
     * including the superclass and any changes to the format of referenced
     * loggables.
     *
     * @see #getLastFormatChange
     */
    private static final int LAST_FORMAT_CHANGE = 12;

    /*
     * operationType, truncateOldDbId and replicatedCreateConfig are
     * logged as part of the entry.
     */
    private DbOperationType operationType;
    private DatabaseId truncateOldDbId;
    private ReplicatedDatabaseConfig replicatedCreateConfig;

    /**
     * Constructor to read an entry.
     */
    public NameLNLogEntry() {
        super(com.sleepycat.je.tree.NameLN.class);
    }

    /**
     * Constructor to write this entry.
     */
    public NameLNLogEntry(
        LogEntryType entryType,
        DatabaseId dbId,
        Txn txn,
        long abortLsn,
        boolean abortKD,
        byte[] key,
        NameLN nameLN,
        int priorSize,
        long priorLsn,
        ReplicationContext repContext) {

        super(
            entryType, dbId, txn,
            abortLsn, abortKD,
            null/*abortKey*/, null/*abortData*/,
            VLSN.NULL_VLSN_SEQUENCE/*abortVLSN*/,
            0 /*abortExpiration*/, false /*abortExpirationInHours*/,
            key, nameLN, false/*newEmbeddedLN*/,
            0 /*expiration*/, false /*expirationInHours*/,
            priorSize, priorLsn);

        ReplicationContext operationContext = repContext;

        operationType = repContext.getDbOperationType();
        if (DbOperationType.isWriteConfigType(operationType)) {
            replicatedCreateConfig =
                ((DbOpReplicationContext) operationContext).getCreateConfig();
        }

        if (operationType == DbOperationType.TRUNCATE) {
            truncateOldDbId =
              ((DbOpReplicationContext) operationContext).getTruncateOldDbId();
        }
    }

    /**
     * Extends its super class to read in database operation information.
     */
    @Override
    public void readEntry(EnvironmentImpl envImpl,
                          LogEntryHeader header,
                          ByteBuffer entryBuffer) {

        readBaseLNEntry(envImpl, header, entryBuffer,
                        false /*keyIsLastSerializedField*/);

        /*
         * The NameLNLogEntry was introduced in version 6. Before, a LNLogEntry
         * was used for NameLNs, and there is no extra information in the log
         * entry.
         */
        int version = header.getVersion();
        if (version >= 6) {
            operationType = DbOperationType.readTypeFromLog(entryBuffer,
                                                            version);
            if (DbOperationType.isWriteConfigType(operationType)) {
                replicatedCreateConfig = new ReplicatedDatabaseConfig();
                replicatedCreateConfig.readFromLog(entryBuffer, version);
            }

            if (operationType == DbOperationType.TRUNCATE) {
                truncateOldDbId = new DatabaseId();
                truncateOldDbId.readFromLog(entryBuffer, version);
            }
        } else {
            operationType = DbOperationType.NONE;
        }
    }

    /**
     * Extends its super class to dump database operation information.
     */
    @Override
    public StringBuilder dumpEntry(StringBuilder sb, boolean verbose) {

        super.dumpEntry(sb, verbose);

        operationType.dumpLog(sb, verbose);
        if (replicatedCreateConfig != null ) {
            replicatedCreateConfig.dumpLog(sb, verbose);
        }
        if (truncateOldDbId != null) {
            truncateOldDbId.dumpLog(sb, verbose);
        }

        return sb;
    }

    @Override
    public int getLastFormatChange() {
        return Math.max(LAST_FORMAT_CHANGE, super.getLastFormatChange());
    }

    @Override
    public Collection getEmbeddedLoggables() {
        final Collection list =
            new ArrayList<>(super.getEmbeddedLoggables());
        list.addAll(Arrays.asList(
            new NameLN(), DbOperationType.NONE,
            new ReplicatedDatabaseConfig()));
        return list;
    }

    @Override
    public int getSize(final int logVersion, final boolean forReplication) {

        int size = getBaseLNEntrySize(
            logVersion, false /*keyIsLastSerializedField*/,
            forReplication);

        size += operationType.getLogSize(logVersion, forReplication);

        if (DbOperationType.isWriteConfigType(operationType)) {
            size += replicatedCreateConfig.getLogSize(
                logVersion, forReplication);
        }

        if (operationType == DbOperationType.TRUNCATE) {
            size += truncateOldDbId.getLogSize(logVersion, forReplication);
        }
        return size;
    }

    @Override
    public void writeEntry(final ByteBuffer destBuffer,
                           final int logVersion,
                           final boolean forReplication) {

        writeBaseLNEntry(
            destBuffer, logVersion,
            false /*keyIsLastSerializedField*/, forReplication);

        operationType.writeToLog(destBuffer, logVersion, forReplication);

        if (DbOperationType.isWriteConfigType(operationType)) {
            replicatedCreateConfig.writeToLog(
                destBuffer, logVersion, forReplication);
        }

        if (operationType == DbOperationType.TRUNCATE) {
            truncateOldDbId.writeToLog(destBuffer, logVersion, forReplication);
        }
    }

    @Override
    public boolean logicalEquals(LogEntry other) {

        if (!super.logicalEquals(other))
            return false;

        NameLNLogEntry otherEntry = (NameLNLogEntry) other;
        if (!operationType.logicalEquals(otherEntry.operationType)) {
            return false;
        }

        if ((truncateOldDbId != null) &&
            (!truncateOldDbId.logicalEquals(otherEntry.truncateOldDbId))) {
                return false;
        }

        if (replicatedCreateConfig != null) {
            if (!replicatedCreateConfig.logicalEquals
                (otherEntry.replicatedCreateConfig))
                return false;
        }
        return true;
    }

    public DbOperationType getOperationType() {
        return operationType;
    }

    public ReplicatedDatabaseConfig getReplicatedCreateConfig() {
        return replicatedCreateConfig;
    }

    public DatabaseId getTruncateOldDbId() {
        return truncateOldDbId;
    }

    @Override
    public void dumpRep(StringBuilder sb) {
        super.dumpRep(sb);
        sb.append(" dbop=").append(operationType);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy