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

oracle.kv.impl.api.ops.PutIfAbsentHandler Maven / Gradle / Ivy

Go to download

NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.

The newest version!
/*-
 * Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle NoSQL
 * Database made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle NoSQL Database for a copy of the license and
 * additional information.
 */

package oracle.kv.impl.api.ops;

import static com.sleepycat.je.Put.NO_OVERWRITE;
import static oracle.kv.impl.api.ops.OperationHandler.CURSOR_DEFAULT;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Get;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationResult;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.WriteOptions;

import oracle.kv.ReturnValueVersion.Choice;
import oracle.kv.Version;
import oracle.kv.impl.api.ops.InternalOperation.OpCode;
import oracle.kv.impl.rep.migration.MigrationStreamHandle;
import oracle.kv.impl.topo.PartitionId;
import oracle.kv.impl.util.TxnUtil;

/**
 * Server handler for {@link PutIfAbsent}.
 *
 * Throughput calculation
 * +---------------------------------------------------------------------------+
 * |    Op         | Choice | # |          Read        |       Write           |
 * |---------------+--------+---+----------------------+-----------------------|
 * |               |        | P |        MIN_READ      |           0           |
 * |               |  NONE  |---+----------------------+-----------------------|
 * |               |        | A |        MIN_READ      |    new record size    |
 * |               +--------+---+----------------------+-----------------------|
 * |               |        | P |        MIN_READ      |           0           |
 * | PutIfAbsent   | VERSION|---+----------------------+-----------------------|
 * |               |        | A |        MIN_READ      |    new record size    |
 * |               +--------+---+----------------------+-----------------------|
 * |               |        | P |    old record size   |           0           |
 * |               |  VALUE |---+----------------------+-----------------------|
 * |               |        | A |        MIN_READ      |    new record size    |
 * +---------------------------------------------------------------------------+
 *      # = Target record is present (P) or absent (A)
 */
class PutIfAbsentHandler extends BasicPutHandler {

    PutIfAbsentHandler(OperationHandler handler) {
        super(handler, OpCode.PUT_IF_ABSENT, PutIfAbsent.class);
    }

    @Override
    Result execute(PutIfAbsent op, Transaction txn, PartitionId partitionId) {

        verifyDataAccess(op);

        ResultValueVersion prevVal = null;
        long expTime = 0L;
        Version version = null;

        byte[] keyBytes = op.getKeyBytes();
        byte[] valueBytes = op.getValueBytes();

        assert (keyBytes != null) && (valueBytes != null);

        final DatabaseEntry keyEntry = new DatabaseEntry(keyBytes);
        final DatabaseEntry dataEntry = valueDatabaseEntry(valueBytes);

        OperationResult opres;
        WriteOptions jeOptions = makeOption(op.getTTL(), op.getUpdateTTL());

        final Database db = getRepNode().getPartitionDB(partitionId);

        final Cursor cursor = db.openCursor(txn, CURSOR_DEFAULT);

        try {
            while (true) {
                opres = putEntry(cursor, keyEntry, dataEntry,
                                 NO_OVERWRITE, jeOptions);

                if (opres != null) {
                    op.addReadBytes(MIN_READ);
                    op.addWriteBytes(getStorageSize(cursor),
                                     getNIndexWrites(cursor));

                    version = getVersion(cursor);
                    expTime = opres.getExpirationTime();

                    MigrationStreamHandle.get().addPut(keyEntry,
                                                       dataEntry,
                                                       version.getVLSN(),
                                                       expTime);
                } else {
                    final Choice choice = op.getReturnValueVersionChoice();

                    if (choice == Choice.NONE) {
                        op.addReadBytes(MIN_READ);

                    } else {
                        final DatabaseEntry prevData =
                            (choice.needValue() ?
                             new DatabaseEntry() : NO_DATA);

                        opres = cursor.get(keyEntry, prevData, Get.SEARCH,
                                           LockMode.DEFAULT.toReadOptions());

                        if (opres == null) {
                            /* Another thread deleted the record. Continue. */
                            continue;
                        }

                        prevVal = getBeforeUpdateInfo(choice, cursor,
                                                      prevData, opres);

                        /* Charge for the above search */
                        if (choice.needValue()) {
                            op.addReadBytes(getStorageSize(cursor));
                        } else {
                            op.addReadBytes(MIN_READ);
                        }

                        reserializeResultValue(op, prevVal);
                    }
                }

                return new Result.PutResult(getOpCode(),
                                            op.getReadKB(),
                                            op.getWriteKB(),
                                            prevVal,
                                            version,
                                            expTime,
                                            false /*wasUpdate*/);
            }
        } finally {
            TxnUtil.close(cursor);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy