Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*-
   * See the file LICENSE for redistribution information.
   *
   * Copyright (c) 2000, 2010 Oracle and/or its affiliates.  All rights reserved.
   *
   */
  
  package com.sleepycat.collections;
  
Represents a Berkeley DB database and adds support for indices, bindings and key ranges.

This class defines a view and takes care of reading and updating indices, calling bindings, constraining access to a key range, etc.

Author(s):
Mark Hayes
 
 final class DataView implements Cloneable {
 
     Database db;
     KeyRange range;
     CursorConfig cursorConfig;      // Used for all operations via this view
     boolean writeAllowed;           // Read-write view
     boolean ordered;                // Not a HASH Db
     boolean keyRangesAllowed;       // BTREE only
     boolean recNumAllowed;          // QUEUE, RECNO, or BTREE-RECNUM Db
     boolean recNumAccess;           // recNumAllowed && using a rec num binding
     boolean btreeRecNumDb;          // BTREE-RECNUM Db
     boolean btreeRecNumAccess;      // recNumAccess && BTREE-RECNUM Db
     boolean recNumRenumber;         // RECNO-RENUM Db
     boolean keysRenumbered;         // recNumRenumber || btreeRecNumAccess
     boolean dupsAllowed;            // Dups configured
     boolean dupsOrdered;            // Sorted dups configured
     boolean transactional;          // Db is transactional
     boolean readUncommittedAllowed// Read-uncommited is optional in DB-CORE
 
     /*
      * If duplicatesView is called, dupsView will be true and dupsKey will be
      * the secondary key used as the "single key" range.  dupRange will be set
      * as the range of the primary key values if subRange is subsequently
      * called, to further narrow the view.
      */
     boolean dupsView;
     KeyRange dupsRange;

    
Creates a view for a given database and bindings. The initial key range of the view will be open.
 
     DataView(Database databaseEntryBinding keyBinding,
              EntryBinding valueBindingEntityBinding entityBinding,
              boolean writeAllowedPrimaryKeyAssigner keyAssigner)
         throws IllegalArgumentException {
 
         if (database == null) {
             throw new IllegalArgumentException("database is null");
         }
          = database;
         try {
              =
                 CurrentTransaction.getInstanceInternal(.getEnvironment());
             DatabaseConfig dbConfig;
             if ( instanceof SecondaryDatabase) {
                  = (SecondaryDatabasedatabase;
                 SecondaryConfig secConfig = .getSecondaryConfig();
                  = secConfig.getKeyCreator();
                 dbConfig = secConfig;
             } else {
                 dbConfig = .getConfig();
             }
              = !DbCompat.isTypeHash(dbConfig);
             = DbCompat.isTypeBtree(dbConfig);
             = DbCompat.isTypeQueue(dbConfig) ||
                            DbCompat.isTypeRecno(dbConfig) ||
                            DbCompat.getBtreeRecordNumbers(dbConfig);
             = DbCompat.getRenumbering(dbConfig);
             = DbCompat.getSortedDuplicates(dbConfig) ||
                          DbCompat.getUnsortedDuplicates(dbConfig);
             = DbCompat.getSortedDuplicates(dbConfig);
             = .isTxnMode() &&
                            dbConfig.getTransactional();
             = DbCompat.getReadUncommitted(dbConfig);
             =  && DbCompat.isTypeBtree(dbConfig);
             = new KeyRange(dbConfig.getBtreeComparator());
        } catch (DatabaseException e) {
            throw RuntimeExceptionWrapper.wrapIfNeeded(e);
        }
        this. = writeAllowed;
        this. = keyBinding;
        this. = valueBinding;
        this. = entityBinding;
        this. = keyAssigner;
         = .;
        if (valueBinding != null && entityBinding != null)
            throw new IllegalArgumentException
                ("both valueBinding and entityBinding are non-null");
        if (keyBinding instanceof com.sleepycat.bind.RecordNumberBinding) {
            if (!) {
                throw new IllegalArgumentException
                    ("RecordNumberBinding requires DB_BTREE/DB_RECNUM, " +
                     "DB_RECNO, or DB_QUEUE");
            }
             = true;
            if () {
                 = true;
            }
        }
    }

    
Clones the view.
    private DataView cloneView() {
        try {
            return (DataViewsuper.clone();
        } catch (CloneNotSupportedException willNeverOccur) {
            throw DbCompat.unexpectedState();
        }
    }

    
Return a new key-set view derived from this view by setting the entity and value binding to null.

Returns:
the derived view.
    DataView keySetView() {
        if ( == null) {
            throw new UnsupportedOperationException("Must have keyBinding");
        }
        DataView view = cloneView();
        view.valueBinding = null;
        view.entityBinding = null;
        return view;
    }

    
Return a new value-set view derived from this view by setting the key binding to null.

Returns:
the derived view.
        if ( == null &&  == null) {
            throw new UnsupportedOperationException
                ("Must have valueBinding or entityBinding");
        }
        DataView view = cloneView();
        view.keyBinding = null;
        return view;
    }

    
Return a new value-set view for single key range.

Parameters:
singleKey the single key value.
Returns:
the derived view.
Throws:
com.sleepycat.je.DatabaseException if a database problem occurs.
com.sleepycat.util.keyrange.KeyRangeException if the specified range is not within the current range.
    DataView valueSetView(Object singleKey)
        throws DatabaseExceptionKeyRangeException {
        /*
         * Must do subRange before valueSetView since the latter clears the
         * key binding needed for the former.
         */
        KeyRange singleKeyRange = subRange(singleKey);
        DataView view = valueSetView();
        view.range = singleKeyRange;
        return view;
    }

    
Return a new value-set view for key range, optionally changing the key binding.
    DataView subView(Object beginKeyboolean beginInclusive,
                     Object endKeyboolean endInclusive,
                     EntryBinding keyBinding)
        throws DatabaseExceptionKeyRangeException {
        DataView view = cloneView();
        view.setRange(beginKeybeginInclusiveendKeyendInclusive);
        if (keyBinding != nullview.keyBinding = keyBinding;
        return view;
    }

    
Return a new duplicates view for a given secondary key.
    DataView duplicatesView(Object secondaryKey,
                            EntryBinding primaryKeyBinding)
        throws DatabaseExceptionKeyRangeException {
        if (!isSecondary()) {
            throw new UnsupportedOperationException
                ("Only allowed for maps on secondary databases");
        }
        if () {
            throw DbCompat.unexpectedState();
        }
        DataView view = cloneView();
        view.range = subRange(view.rangesecondaryKey);
        view.dupsKey = view.range.getSingleKey();
        view.dupsView = true;
        view.keyBinding = primaryKeyBinding;
        return view;
    }

    
Returns a new view with a specified cursor configuration.
        DataView view = cloneView();
        view.cursorConfig = (config != null) ?
            DbCompat.cloneCursorConfig(config) : .;
        return view;
    }

    
Returns the current transaction for the view or null if the environment is non-transactional.
        return  ?  : null;
    }

    
Sets this view's range to a subrange with the given parameters.
    private void setRange(Object beginKeyboolean beginInclusive,
                          Object endKeyboolean endInclusive)
        throws DatabaseExceptionKeyRangeException {
        if ((beginKey != null || endKey != null) && !) {
            throw new UnsupportedOperationException
                ("Key ranges allowed only for BTREE databases");
        }
        KeyRange useRange = useSubRange();
        useRange = subRange
            (useRangebeginKeybeginInclusiveendKeyendInclusive);
        if () {
             = useRange;
        } else {
             = useRange;
        }
    }

    
Returns the key thang for a single key range, or null if a single key range is not used.
        return .getSingleKey();
    }

    
Returns the environment for the database.
    final Environment getEnv() {
        return .getEnvironment();
    }

    
Returns whether this is a view on a secondary database rather than directly on a primary database.
    final boolean isSecondary() {
        return ( != null);
    }

    
Returns whether no records are present in the view. Auto-commit must be performed by the caller.
    boolean isEmpty()
        throws DatabaseException {
        DataCursor cursor = new DataCursor(thisfalse);
        try {
            return cursor.getFirst(false) != .;
        } finally {
            cursor.close();
        }
    }

    
Appends a value and returns the new key. If a key assigner is used it assigns the key, otherwise a QUEUE or RECNO database is required. Auto-commit must be performed by the caller.
                           Object[] retPrimaryKey,
                           Object[] retValue)
        throws DatabaseException {
        /*
         * Flags will be NOOVERWRITE if used with assigner, or APPEND
         * otherwise.
         * Requires: if value param, value or entity binding
         * Requires: if retPrimaryKey, primary key binding (no index).
         * Requires: if retValue, value or entity binding
         */
        DatabaseEntry keyThang = new DatabaseEntry();
        DatabaseEntry valueThang = new DatabaseEntry();
        useValue(valuevalueThangnull);
        OperationStatus status;
        if ( != null) {
            .assignKey(keyThang);
            if (!.check(keyThang)) {
                throw new IllegalArgumentException
                    ("assigned key out of range");
            }
            DataCursor cursor = new DataCursor(thistrue);
            try {
                status = cursor.getCursor().putNoOverwrite(keyThang,
                                                           valueThang);
            } finally {
                cursor.close();
            }
        } else {
            /* Assume QUEUE/RECNO access method. */
            if (.isCDBCursorOpen()) {
                throw new IllegalStateException
                    ("cannot open CDB write cursor when read cursor is open");
            }
            status = DbCompat.append(useTransaction(),
                                     keyThangvalueThang);
            if (status == . && !.check(keyThang)) {
                .delete(useTransaction(), keyThang);
                throw new IllegalArgumentException
                    ("appended record number out of range");
            }
        }
        if (status == .) {
            returnPrimaryKeyAndValue(keyThangvalueThang,
                                     retPrimaryKeyretValue);
        }
        return status;
    }

    
Returns the current transaction if the database is transaction, or null if the database is not transactional or there is no current transaction.
        return  ?  .getTransaction() : null;
    }

    
Deletes all records in the current range. Auto-commit must be performed by the caller.
    void clear()
        throws DatabaseException {
        DataCursor cursor = new DataCursor(thistrue);
        try {
            OperationStatus status = .;
            while (status == .) {
                if () {
                    status = cursor.getFirst(true);
                } else {
                    status = cursor.getNext(true);
                }
                if (status == .) {
                    cursor.delete();
                }
            }
        } finally {
            cursor.close();
        }
    }

    
Returns a cursor for this view that reads only records having the specified index key values.
    DataCursor join(DataView[] indexViewsObject[] indexKeys,
                    JoinConfig joinConfig)
        throws DatabaseException {
        DataCursor joinCursor = null;
        DataCursor[] indexCursors = new DataCursor[indexViews.length];
        try {
            for (int i = 0; i < indexViews.lengthi += 1) {
                indexCursors[i] = new DataCursor(indexViews[i], false);
                indexCursors[i].getSearchKey(indexKeys[i], nullfalse);
            }
            joinCursor = new DataCursor(thisindexCursorsjoinConfigtrue);
            return joinCursor;
        } finally {
            if (joinCursor == null) {
                // An exception is being thrown, so close cursors we opened.
                for (int i = 0; i < indexCursors.lengthi += 1) {
                    if (indexCursors[i] != null) {
                        try { indexCursors[i].close(); }
                        catch (Exception e) {
                            /* FindBugs, this is ok. */
                        }
                    }
                }
            }
        }
    }

    
Returns a cursor for this view that reads only records having the index key values at the specified cursors.
    DataCursor join(DataCursor[] indexCursorsJoinConfig joinConfig)
        throws DatabaseException {
        return new DataCursor(thisindexCursorsjoinConfigfalse);
    }

    
Returns primary key and value if return parameters are non-null.
    private void returnPrimaryKeyAndValue(DatabaseEntry keyThang,
                                          DatabaseEntry valueThang,
                                          Object[] retPrimaryKey,
                                          Object[] retValue) {
        // Requires: if retPrimaryKey, primary key binding (no index).
        // Requires: if retValue, value or entity binding
        if (retPrimaryKey != null) {
            if ( == null) {
                throw new IllegalArgumentException
                    ("returning key requires primary key binding");
            } else if (isSecondary()) {
                throw new IllegalArgumentException
                    ("returning key requires unindexed view");
            } else {
                retPrimaryKey[0] = .entryToObject(keyThang);
            }
        }
        if (retValue != null) {
            retValue[0] = makeValue(keyThangvalueThang);
        }
    }

    
Populates the key entry and returns whether the key is within range.
    boolean useKey(Object keyObject valueDatabaseEntry keyThang,
                   KeyRange checkRange)
        throws DatabaseException {
        if (key != null) {
            if ( == null) {
                throw new IllegalArgumentException
                    ("non-null key with null key binding");
            }
            .objectToEntry(keykeyThang);
        } else {
            if (value == null) {
                throw new IllegalArgumentException("null key and null value");
            }
            if ( == null) {
                throw new IllegalStateException
                    ("EntityBinding required to derive key from value");
            }
            if (! && isSecondary()) {
                DatabaseEntry primaryKeyThang = new DatabaseEntry();
                .objectToKey(valueprimaryKeyThang);
                DatabaseEntry valueThang = new DatabaseEntry();
                .objectToData(valuevalueThang);
                .createSecondaryKey(primaryKeyThang,
                                                 valueThangkeyThang);
            } else {
                .objectToKey(valuekeyThang);
            }
        }
        if ( && DbCompat.getRecordNumber(keyThang) <= 0) {
            return false;
        }
        if (checkRange != null && !checkRange.check(keyThang)) {
            return false;
        }
        return true;
    }

    
Returns whether data keys can be derived from the value/entity binding of this view, which determines whether a value/entity object alone is sufficient for operations that require keys.
    final boolean canDeriveKeyFromValue() {
        return ( != null);
    }

    
Populates the value entry and throws an exception if the primary key would be changed via an entity binding.
    void useValue(Object valueDatabaseEntry valueThang,
                  DatabaseEntry checkKeyThang) {
        if ( != null) {
            /* Allow binding to handle null value. */
            .objectToEntry(valuevalueThang);
        } else if ( != null) {
            if (value == null) {
                throw new IllegalArgumentException
                    ("null value with entity binding");
            }
            .objectToData(valuevalueThang);
            if (checkKeyThang != null) {
                DatabaseEntry thang = new DatabaseEntry();
                .objectToKey(valuethang);
                if (!KeyRange.equalBytes(thangcheckKeyThang)) {
                    throw new IllegalArgumentException
                        ("cannot change primary key");
                }
            }
        } else {
            if (value != null) {
                throw new IllegalArgumentException
                    ("non-null value with null value/entity binding");
            }
            valueThang.setData(.);
            valueThang.setOffset(0);
            valueThang.setSize(0);
        }
    }

    
Converts a key entry to a key object.
    Object makeKey(DatabaseEntry keyThangDatabaseEntry priKeyThang) {
        if ( == null) {
            throw new UnsupportedOperationException();
        } else {
            DatabaseEntry thang =  ? priKeyThang : keyThang;
            if (thang.getSize() == 0) {
                return null;
            } else {
                return .entryToObject(thang);
            }
        }
    }

    
Converts a key-value entry pair to a value object.
    Object makeValue(DatabaseEntry primaryKeyThangDatabaseEntry valueThang) {
        Object value;
        if ( != null) {
            value = .entryToObject(valueThang);
        } else if ( != null) {
            value = .entryToObject(primaryKeyThang,
                                                    valueThang);
        } else {
            throw new UnsupportedOperationException
                ("Requires valueBinding or entityBinding");
        }
        return value;
    }

    
Intersects the given key and the current range.
    KeyRange subRange(KeyRange useRangeObject singleKey)
        throws DatabaseExceptionKeyRangeException {
        return useRange.subRange(makeRangeKey(singleKey));
    }

    
Intersects the given range and the current range.
    KeyRange subRange(KeyRange useRange,
                      Object beginKeyboolean beginInclusive,
                      Object endKeyboolean endInclusive)
        throws DatabaseExceptionKeyRangeException {
        if (beginKey == endKey && beginInclusive && endInclusive) {
            return subRange(useRangebeginKey);
        }
        if (!) {
            throw new UnsupportedOperationException
                ("Cannot use key ranges on an unsorted database");
        }
        DatabaseEntry beginThang =
            (beginKey != null) ? makeRangeKey(beginKey) : null;
        DatabaseEntry endThang =
            (endKey != null) ? makeRangeKey(endKey) : null;
        return useRange.subRange(beginThangbeginInclusive,
                                 endThangendInclusive);
    }

    
Returns the range to use for sub-ranges. Returns range if this is not a dupsView, or the dupsRange if this is a dupsView, creating dupsRange if necessary.
        throws DatabaseException {
        if () {
            synchronized (this) {
                if ( == null) {
                    DatabaseConfig config =
                        .getPrimaryDatabase().getConfig();
                     = new KeyRange(config.getBtreeComparator());
                }
            }
            return ;
        } else {
            return ;
        }
    }

    
Given a key object, make a key entry that can be used in a range.
    private DatabaseEntry makeRangeKey(Object key)
        throws DatabaseException {
        DatabaseEntry thang = new DatabaseEntry();
        if ( != null) {
            useKey(keynullthangnull);
        } else {
            useKey(nullkeythangnull);
        }
        return thang;
    }
New to GrepCode? Check out our FAQ X