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

com.sleepycat.persist.SubIndex 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.persist;

import java.util.Map;
import java.util.SortedMap;

import com.sleepycat.bind.EntityBinding;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.collections.StoredSortedMap;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.compat.DbCompat.OpResult;
import com.sleepycat.compat.DbCompat.OpWriteOptions;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
/*  */
import com.sleepycat.je.DbInternal;
/*  */
import com.sleepycat.je.Environment;
/*  */
import com.sleepycat.je.Get;
/*  */
import com.sleepycat.je.LockMode;
/*  */
import com.sleepycat.je.OperationResult;
/*  */
import com.sleepycat.je.OperationStatus;
/*  */
import com.sleepycat.je.ReadOptions;
/*  */
import com.sleepycat.je.SecondaryCursor;
import com.sleepycat.je.SecondaryDatabase;
import com.sleepycat.je.Transaction;
/*  */
import com.sleepycat.je.WriteOptions;
/*  */
import com.sleepycat.util.keyrange.KeyRange;
import com.sleepycat.util.keyrange.RangeCursor;

/**
 * The EntityIndex returned by SecondaryIndex.subIndex.  A SubIndex, in JE
 * internal terms, is a duplicates btree for a single key in the main btree.
 * From the user's viewpoint, the keys are primary keys.  This class implements
 * that viewpoint.  In general, getSearchBoth and getSearchBothRange are used
 * where in a normal index getSearchKey and getSearchRange would be used.  The
 * main tree key is always implied, not passed as a parameter.
 *
 * @author Mark Hayes
 */
class SubIndex implements EntityIndex {

    private SecondaryIndex secIndex;
    private SecondaryDatabase db;
    private boolean transactional;
    private boolean sortedDups;
    private boolean locking;
    private boolean concurrentDB;
    private DatabaseEntry keyEntry;
    private Object keyObject;
    private KeyRange singleKeyRange;
    private EntryBinding pkeyBinding;
    private KeyRange emptyPKeyRange;
    private EntityBinding entityBinding;
    private ValueAdapter keyAdapter;
    private ValueAdapter entityAdapter;
    private SortedMap map;

     SubIndex(SecondaryIndex secIndex,
                  EntityBinding entityBinding,
                  SK key)
        throws DatabaseException {

        this.secIndex = secIndex;
        db = secIndex.getDatabase();
        transactional = secIndex.transactional;
        sortedDups = secIndex.sortedDups;
        locking =
            DbCompat.getInitializeLocking(db.getEnvironment().getConfig());
        Environment env = db.getEnvironment();
        concurrentDB = DbCompat.getInitializeCDB(env.getConfig());
        keyObject = key;
        keyEntry = new DatabaseEntry();
        secIndex.keyBinding.objectToEntry(key, keyEntry);
        singleKeyRange = secIndex.emptyRange.subRange(keyEntry);

        PrimaryIndex priIndex = secIndex.getPrimaryIndex();
        pkeyBinding = priIndex.keyBinding;
        emptyPKeyRange = priIndex.emptyRange;
        this.entityBinding = entityBinding;

        keyAdapter = new PrimaryKeyValueAdapter
            (priIndex.keyClass, priIndex.keyBinding);
        entityAdapter = secIndex.entityAdapter;
    }

    public Database getDatabase() {
        return db;
    }

    public boolean contains(PK key)
        throws DatabaseException {

        return contains(null, key, null);
    }

    public boolean contains(Transaction txn, PK key, LockMode lockMode)
        throws DatabaseException {

        DatabaseEntry pkeyEntry = new DatabaseEntry();
        DatabaseEntry dataEntry = BasicIndex.NO_RETURN_ENTRY;
        pkeyBinding.objectToEntry(key, pkeyEntry);

        OperationStatus status =
            db.getSearchBoth(txn, keyEntry, pkeyEntry, dataEntry, lockMode);
        return (status == OperationStatus.SUCCESS);
    }

    public E get(PK key)
        throws DatabaseException {

        return get(null, key, null);
    }

    public E get(Transaction txn, PK key, LockMode lockMode)
        throws DatabaseException {

        /*  */
        if (DbCompat.IS_JE) {
            EntityResult result = get(
                txn, key, Get.SEARCH, DbInternal.getReadOptions(lockMode));
            return result != null ? result.value() : null;
        }
        /*  */

        DatabaseEntry pkeyEntry = new DatabaseEntry();
        DatabaseEntry dataEntry = new DatabaseEntry();
        pkeyBinding.objectToEntry(key, pkeyEntry);

        OperationStatus status =
            db.getSearchBoth(txn, keyEntry, pkeyEntry, dataEntry, lockMode);

        if (status == OperationStatus.SUCCESS) {
            return (E) entityBinding.entryToObject(pkeyEntry, dataEntry);
        } else {
            return null;
        }
    }

    /*  */
    public EntityResult get(Transaction txn,
                               PK key,
                               Get getType,
                               ReadOptions options)
        throws DatabaseException {

        BasicIndex.checkGetType(getType);

        DatabaseEntry pkeyEntry = new DatabaseEntry();
        DatabaseEntry dataEntry = new DatabaseEntry();
        pkeyBinding.objectToEntry(key, pkeyEntry);

        OperationResult result = db.get(
            txn, keyEntry, pkeyEntry, dataEntry, Get.SEARCH_BOTH, options);

        if (result != null) {
            return new EntityResult<>(
                (E) entityBinding.entryToObject(pkeyEntry, dataEntry),
                result);
        } else {
            return null;
        }
    }
    /*  */

    public long count()
        throws DatabaseException {

        CursorConfig cursorConfig = locking ?
            CursorConfig.READ_UNCOMMITTED : null;
        EntityCursor cursor = keys(null, cursorConfig);
        try {
            if (cursor.next() != null) {
                return cursor.count();
            } else {
                return 0;
            }
        } finally {
            cursor.close();
        }
    }

    /*  */

    public long count(long memoryLimit)
        throws DatabaseException {

        return count();
    }

    /*  */

    public boolean delete(PK key)
        throws DatabaseException {

        return delete(null, key);
    }

    public boolean delete(Transaction txn, PK key)
        throws DatabaseException {

        return deleteInternal(txn, key, OpWriteOptions.EMPTY).isSuccess();
    }

    /*  */
    public OperationResult delete(Transaction txn,
                                  PK key,
                                  WriteOptions options)
        throws DatabaseException {

        return deleteInternal(txn, key, OpWriteOptions.make(options)).jeResult;
    }
    /*  */

    private OpResult deleteInternal(Transaction txn,
                                    PK key,
                                    OpWriteOptions options)
        throws DatabaseException {

        DatabaseEntry pkeyEntry = new DatabaseEntry();
        DatabaseEntry dataEntry = BasicIndex.NO_RETURN_ENTRY;
        pkeyBinding.objectToEntry(key, pkeyEntry);

        boolean autoCommit = false;
        Environment env = db.getEnvironment();
        if (transactional &&
            txn == null &&
            DbCompat.getThreadTransaction(env) == null) {
            txn = env.beginTransaction
                (null, secIndex.getAutoCommitTransactionConfig());
            autoCommit = true;
        }

        boolean failed = true;
        CursorConfig cursorConfig = null;
        if (concurrentDB) {
            cursorConfig = new CursorConfig();
            DbCompat.setWriteCursor(cursorConfig, true);
        } 
        SecondaryCursor cursor = db.openSecondaryCursor(txn, cursorConfig);
        try {
            /*  */
            if (DbCompat.IS_JE) {
                ReadOptions readOptions;
                if (options.jeOptions != null &&
                    options.jeOptions.getCacheMode() != null) {
                    readOptions = new ReadOptions();
                    readOptions.setLockMode(LockMode.RMW);
                    readOptions.setCacheMode(options.jeOptions.getCacheMode());
                } else {
                    readOptions = LockMode.RMW.toReadOptions();
                }
                OperationResult result = cursor.get(
                    keyEntry, pkeyEntry, dataEntry, Get.SEARCH_BOTH,
                    readOptions);
                if (result != null) {
                    result = cursor.delete(options.jeOptions);
                }
                failed = false;
                return OpResult.make(result);
            }
            /*  */
            OperationStatus status = cursor.getSearchBoth
                (keyEntry, pkeyEntry, dataEntry,
                 locking ? LockMode.RMW : null);
            if (status == OperationStatus.SUCCESS) {
                status = cursor.delete();
            }
            failed = false;
            return OpResult.make(status);
        } finally {
            cursor.close();
            if (autoCommit) {
                if (failed) {
                    txn.abort();
                } else {
                    txn.commit();
                }
            }
        }
    }

    public EntityCursor keys()
        throws DatabaseException {

        return keys(null, null);
    }

    public EntityCursor keys(Transaction txn, CursorConfig config)
        throws DatabaseException {

        return cursor(txn, null, keyAdapter, config);
    }

    public EntityCursor entities()
        throws DatabaseException {

        return cursor(null, null, entityAdapter, null);
    }

    public EntityCursor entities(Transaction txn,
                                    CursorConfig config)
        throws DatabaseException {

        return cursor(txn, null, entityAdapter, config);
    }

    public EntityCursor keys(PK fromKey,
                                 boolean fromInclusive,
                                 PK toKey,
                                 boolean toInclusive)
        throws DatabaseException {

        return cursor(null, fromKey, fromInclusive, toKey, toInclusive,
                      keyAdapter, null);
    }

    public EntityCursor keys(Transaction txn,
                                 PK fromKey,
                                 boolean fromInclusive,
                                 PK toKey,
                                 boolean toInclusive,
                                 CursorConfig config)
        throws DatabaseException {

        return cursor(txn, fromKey, fromInclusive, toKey, toInclusive,
                      keyAdapter, config);
    }

    public EntityCursor entities(PK fromKey,
                                    boolean fromInclusive,
                                    PK toKey,
                                    boolean toInclusive)
        throws DatabaseException {

        return cursor(null, fromKey, fromInclusive, toKey, toInclusive,
                      entityAdapter, null);
    }

    public EntityCursor entities(Transaction txn,
                                    PK fromKey,
                                    boolean fromInclusive,
                                    PK toKey,
                                    boolean toInclusive,
                                    CursorConfig config)
        throws DatabaseException {

        return cursor(txn, fromKey, fromInclusive, toKey, toInclusive,
                      entityAdapter, config);
    }

    private  EntityCursor cursor(Transaction txn,
                                       PK fromKey,
                                       boolean fromInclusive,
                                       PK toKey,
                                       boolean toInclusive,
                                       ValueAdapter adapter,
                                       CursorConfig config)
        throws DatabaseException {

        DatabaseEntry fromEntry = null;
        if (fromKey != null) {
            fromEntry = new DatabaseEntry();
            pkeyBinding.objectToEntry(fromKey, fromEntry);
        }
        DatabaseEntry toEntry = null;
        if (toKey != null) {
            toEntry = new DatabaseEntry();
            pkeyBinding.objectToEntry(toKey, toEntry);
        }
        KeyRange pkeyRange = emptyPKeyRange.subRange
            (fromEntry, fromInclusive, toEntry, toInclusive);
        return cursor(txn, pkeyRange, adapter, config);
    }

    private  EntityCursor cursor(Transaction txn,
                                       KeyRange pkeyRange,
                                       ValueAdapter adapter,
                                       CursorConfig config)
        throws DatabaseException {

        Cursor cursor = db.openCursor(txn, config);
        RangeCursor rangeCursor =
            new RangeCursor(singleKeyRange, pkeyRange, sortedDups, cursor);
        return new SubIndexCursor(rangeCursor, adapter);
    }

    public Map map() {
        return sortedMap();
    }

    public synchronized SortedMap sortedMap() {
        if (map == null) {
            map = (SortedMap) ((StoredSortedMap) secIndex.sortedMap()).
                duplicatesMap(keyObject, pkeyBinding);
        }
        return map;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy