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 cursor and adds support for indices, bindings and key ranges.

This class operates on 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 DataCursor implements Cloneable {

    
Repositioned exactly to the key/data pair given.
 
     static final int REPOS_EXACT = 0;
    
Repositioned on a record following the key/data pair given.
 
     static final int REPOS_NEXT = 1;
    
Repositioned failed, no records on or after the key/data pair given.
 
     static final int REPOS_EOF = 2;
 
     private RangeCursor cursor;
     private JoinCursor joinCursor;
     private DataView view;
     private KeyRange range;
     private boolean writeAllowed;
     private boolean readUncommitted;
     private DatabaseEntry keyThang;
     private DatabaseEntry valueThang;
     private DatabaseEntry primaryKeyThang;
     private DatabaseEntry otherThang;
     private DataCursor[] indexCursorsToClose;

    
Creates a cursor for a given view.
 
     DataCursor(DataView viewboolean writeAllowed)
         throws DatabaseException {
 
         init(viewwriteAllowednullnull);
     }

    
Creates a cursor for a given view.
 
     DataCursor(DataView viewboolean writeAllowedCursorConfig config)
         throws DatabaseException {
 
         init(viewwriteAllowedconfignull);
     }

    
Creates a cursor for a given view and single key range. Used by unit tests.
 
     DataCursor(DataView viewboolean writeAllowedObject singleKey)
         throws DatabaseException {
 
         init(viewwriteAllowednullview.subRange(view.rangesingleKey));
     }

    
Creates a cursor for a given view and key range. Used by unit tests.
 
     DataCursor(DataView viewboolean writeAllowed,
                Object beginKeyboolean beginInclusive,
                Object endKeyboolean endInclusive)
         throws DatabaseException {
 
         init(viewwriteAllowednull,
              view.subRange
                 (view.rangebeginKeybeginInclusiveendKeyendInclusive));
     }

    
Creates a join cursor.
 
     DataCursor(DataView viewDataCursor[] indexCursors,
                JoinConfig joinConfigboolean closeIndexCursors)
         throws DatabaseException {
        if (view.isSecondary()) {
            throw new IllegalArgumentException(
                "The primary collection in a join must not be a secondary " +
                "database");
        }
        Cursor[] cursors = new Cursor[indexCursors.length];
        for (int i = 0; i < cursors.lengthi += 1) {
            cursors[i] = indexCursors[i]..getCursor();
        }
         = view.db.join(cursorsjoinConfig);
        init(viewfalsenullnull);
        if (closeIndexCursors) {
             = indexCursors;
        }
    }

    
Clones a cursor preserving the current position.
        throws DatabaseException {
        checkNoJoinCursor();
        DataCursor o;
        try {
            o = (DataCursorsuper.clone();
        } catch (CloneNotSupportedException neverHappens) {
            return null;
        }
        o.initThangs();
        KeyRange.copy(o.keyThang);
        KeyRange.copy(o.valueThang);
        if ( != ) {
            KeyRange.copy(o.primaryKeyThang);
        }
        o.cursor = .dup(true);
        return o;
    }

    
Returns the internal range cursor.
        return ;
    }

    
Constructor helper.
    private void init(DataView view,
                      boolean writeAllowed,
                      CursorConfig config,
                      KeyRange range)
        throws DatabaseException {
        if (config == null) {
            config = view.cursorConfig;
        }
        this. = view;
        this. = writeAllowed && view.writeAllowed;
        this. = (range != null) ? range : view.range;
         = config.getReadUncommitted() ||
                          view.currentTxn.isReadUncommitted();
        initThangs();
        if ( == null) {
             = new MyRangeCursor
                (this.configviewthis.);
        }
    }

    
Constructor helper.
    private void initThangs() {
         = new DatabaseEntry();
         = .isSecondary() ? (new DatabaseEntry())
                                             : ;
         = new DatabaseEntry();
    }

    
Set entries from given byte arrays.
    private void setThangs(byte[] keyBytes,
                           byte[] priKeyBytes,
                           byte[] valueBytes) {
        .setData(KeyRange.copyBytes(keyBytes));
        if ( != ) {
            .setData(KeyRange.copyBytes(priKeyBytes));
        }
        .setData(KeyRange.copyBytes(valueBytes));
    }

    
Closes the associated cursor.
    void close()
        throws DatabaseException {
        if ( != null) {
            JoinCursor toClose = ;
             = null;
            toClose.close();
        }
        if ( != null) {
            Cursor toClose = .getCursor();
             = null;
            ..closeCursor(toClose);
        }
        if ( != null) {
            DataCursor[] toClose = ;
             = null;
            for (int i = 0; i < toClose.lengthi += 1) {
                toClose[i].close();
            }
        }
    }

    
Repositions to a given raw key/data pair, or just past it if that record has been deleted.

Returns:
REPOS_EXACT, REPOS_NEXT or REPOS_EOF.
    int repositionRange(byte[] keyBytes,
                        byte[] priKeyBytes,
                        byte[] valueBytes,
                        boolean lockForWrite)
        throws DatabaseException {
        LockMode lockMode = getLockMode(lockForWrite);
        OperationStatus status = null;
        /* Use the given key/data byte arrays. */
        setThangs(keyBytespriKeyBytesvalueBytes);
        /* Position on or after the given key/data pair. */
        if (.) {
            status = .getSearchBothRange(,
                                               lockMode);
        }
        if (status != .) {
            status = .getSearchKeyRange(,
                                              lockMode);
        }
        /* Return the result of the operation. */
        if (status == .) {
            if (!KeyRange.equalBytes(keyBytes, 0, keyBytes.length,
                                     .getData(),
                                     .getOffset(),
                                     .getSize())) {
                return ;
            }
            if (.) {
                DatabaseEntry thang = .isSecondary() ? 
                                                         : ;
                byte[] bytes = .isSecondary() ? priKeyBytes
                                                  : valueBytes;
                if (!KeyRange.equalBytes(bytes, 0, bytes.length,
                                         thang.getData(),
                                         thang.getOffset(),
                                         thang.getSize())) {
                    return ;
                }
            }
            return ;
        } else {
            return ;
        }
    }

    
Repositions to a given raw key/data pair.

Returns:
whether the search succeeded.
Throws:
java.lang.IllegalStateException when the database has unordered keys or unordered duplicates.
    boolean repositionExact(byte[] keyBytes,
                            byte[] priKeyBytes,
                            byte[] valueBytes,
                            boolean lockForWrite)
        throws DatabaseException {
        LockMode lockMode = getLockMode(lockForWrite);
        OperationStatus status = null;
        /* Use the given key/data byte arrays. */
        setThangs(keyBytespriKeyBytesvalueBytes);
        /* Position on the given key/data pair. */
        if (.) {
            /* getSearchBoth doesn't work with recno-renumber databases. */
            status = .getSearchKey(,
                                         lockMode);
        } else {
            status = .getSearchBoth(,
                                          lockMode);
        }
        return (status == .);
    }

    
Returns the view for this cursor.
    DataView getView() {
        return ;
    }

    
Returns the range for this cursor.
    KeyRange getRange() {
        return ;
    }

    
Returns whether write is allowed for this cursor, as specified to the constructor.
    boolean isWriteAllowed() {
        return ;
    }

    
Returns the key object for the last record read.
    Object getCurrentKey() {
        return .makeKey();
    }

    
Returns the value object for the last record read.
        return .makeValue();
    }

    
Returns the internal key entry.
        return ;
    }

    
Returns the internal primary key entry, which is the same object as the key entry if the cursor is not for a secondary database.
        return ;
    }

    
Returns the internal value entry.
        return ;
    }

    
Returns whether record number access is allowed.
    boolean hasRecNumAccess() {
        return .;
    }

    
Returns the record number for the last record read.
        throws DatabaseException {
        if (.) {
            /* BTREE-RECNO access. */
            if ( == null) {
                 = new DatabaseEntry();
            }
            DbCompat.getCurrentRecordNumber(.getCursor(), ,
                                            getLockMode(false));
            return DbCompat.getRecordNumber();
        } else {
            /* QUEUE or RECNO database. */
            return DbCompat.getRecordNumber();
        }
    }

    
Binding version of Cursor.getCurrent(), no join cursor allowed.
    OperationStatus getCurrent(boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
                                 getLockMode(lockForWrite));
    }

    
Binding version of Cursor.getFirst(), join cursor is allowed.
    OperationStatus getFirst(boolean lockForWrite)
        throws DatabaseException {
        LockMode lockMode = getLockMode(lockForWrite);
        if ( != null) {
            return .getNext(lockMode);
        } else {
            return .getFirst(,
                                   lockMode);
        }
    }

    
Binding version of Cursor.getNext(), join cursor is allowed.
    OperationStatus getNext(boolean lockForWrite)
        throws DatabaseException {
        LockMode lockMode = getLockMode(lockForWrite);
        if ( != null) {
            return .getNext(lockMode);
        } else {
            return .getNext(,
                                  lockMode);
        }
    }

    
Binding version of Cursor.getNext(), join cursor is allowed.
    OperationStatus getNextNoDup(boolean lockForWrite)
        throws DatabaseException {
        LockMode lockMode = getLockMode(lockForWrite);
        if ( != null) {
            return .getNext(lockMode);
        } else if (.) {
            return .getNext
                (lockMode);
        } else {
            return .getNextNoDup
                (lockMode);
        }
    }

    
Binding version of Cursor.getNextDup(), no join cursor allowed.
    OperationStatus getNextDup(boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        if (.) {
            return null;
        } else {
            return .getNextDup
                (,
                 getLockMode(lockForWrite));
        }
    }

    
Binding version of Cursor.getLast(), no join cursor allowed.
    OperationStatus getLast(boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        return .getLast(,
                              getLockMode(lockForWrite));
    }

    
Binding version of Cursor.getPrev(), no join cursor allowed.
    OperationStatus getPrev(boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        return .getPrev(,
                              getLockMode(lockForWrite));
    }

    
Binding version of Cursor.getPrevNoDup(), no join cursor allowed.
    OperationStatus getPrevNoDup(boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        LockMode lockMode = getLockMode(lockForWrite);
        if (.) {
            return null;
        } else if (.) {
            return .getPrev
                (lockMode);
        } else {
            return .getPrevNoDup
                (lockMode);
        }
    }

    
Binding version of Cursor.getPrevDup(), no join cursor allowed.
    OperationStatus getPrevDup(boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        if (.) {
            return null;
        } else {
            return .getPrevDup
                (,
                 getLockMode(lockForWrite));
        }
    }

    
Binding version of Cursor.getSearchKey(), no join cursor allowed. Searches by record number in a BTREE-RECNO db with RECNO access.
                                 boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        if (.) {
            if (.useKey(keyvalue.)) {
                KeyRange.copy(.);
                return .getSearchBoth
                    (,
                     getLockMode(lockForWrite));
            }
        } else {
            if (.useKey(keyvalue)) {
                return doGetSearchKey(lockForWrite);
            }
        }
        return .;
    }

    
Pass-thru version of Cursor.getSearchKey(). Searches by record number in a BTREE-RECNO db with RECNO access.
    private OperationStatus doGetSearchKey(boolean lockForWrite)
        throws DatabaseException {
        LockMode lockMode = getLockMode(lockForWrite);
        if (.) {
            return .getSearchRecordNumber(,
                                                lockMode);
        } else {
            return .getSearchKey(,
                                       lockMode);
        }
    }

    
Binding version of Cursor.getSearchKeyRange(), no join cursor allowed.
                                      boolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        LockMode lockMode = getLockMode(lockForWrite);
        if (.) {
            if (.useKey(keyvalue.)) {
                KeyRange.copy(.);
                return .getSearchBothRange
                    (lockMode);
            }
        } else {
            if (.useKey(keyvalue)) {
                return .getSearchKeyRange
                    (lockMode);
            }
        }
        return .;
    }

    
Find the given key and value using getSearchBoth if possible or a sequential scan otherwise, no join cursor allowed.
    OperationStatus findBoth(Object keyObject valueboolean lockForWrite)
        throws DatabaseException {
        checkNoJoinCursor();
        LockMode lockMode = getLockMode(lockForWrite);
        .useValue(valuenull);
        if (.) {
            if (.useKey(keyvalue.)) {
                KeyRange.copy(.);
                if ( == null) {
                     = new DatabaseEntry();
                }
                OperationStatus status = .getSearchBoth
                    (lockMode);
                if (status == . &&
                    KeyRange.equalBytes()) {
                    return status;
                }
            }
        } else if (.useKey(keyvalue)) {
            if (.isSecondary()) {
                if ( == null) {
                     = new DatabaseEntry();
                }
                OperationStatus status = .getSearchKey(,
                                                             ,
                                                             ,
                                                             lockMode);
                while (status == .) {
                    if (KeyRange.equalBytes()) {
                        return status;
                    }
                    status = .getNextDup(,
                                               lockMode);
                }
                /* if status != SUCCESS set range cursor to invalid? */
            } else {
                return .getSearchBoth(null,
                                            lockMode);
            }
        }
        return .;
    }

    
Find the given value using getSearchBoth if possible or a sequential scan otherwise, no join cursor allowed.
    OperationStatus findValue(Object valueboolean findFirst)
        throws DatabaseException {
        checkNoJoinCursor();
        if (. != null && !.isSecondary() &&
            (findFirst || !.)) {
            return findBoth(nullvaluefalse);
        } else {
            if ( == null) {
                 = new DatabaseEntry();
            }
            .useValue(valuenull);
            OperationStatus status = findFirst ? getFirst(false)
                                               : getLast(false);
            while (status == .) {
                if (KeyRange.equalBytes()) {
                    break;
                }
                status = findFirst ? getNext(false) : getPrev(false);
            }
            return status;
        }
    }

    
Calls Cursor.count(), no join cursor allowed.
    int count()
        throws DatabaseException {
        checkNoJoinCursor();
        if (.) {
            return 1;
        } else {
            return .count();
        }
    }

    
Binding version of Cursor.putCurrent().
        throws DatabaseException {
        checkWriteAllowed(false);
        .useValue(value);
        /*
         * Workaround for a DB core problem: With HASH type a put() with
         * different data is allowed.
         */
        boolean hashWorkaround = (. && !.);
        if (hashWorkaround) {
            if ( == null) {
                 = new DatabaseEntry();
            }
                              .);
            if (KeyRange.equalBytes()) {
                return .;
            } else {
                throw new IllegalArgumentException(
                  "Current data differs from put data with sorted duplicates");
            }
        }
        return .putCurrent();
    }

    
Binding version of Cursor.putAfter().
        throws DatabaseException {
        checkWriteAllowed(false);
        .useValue(valuenull); /* why no key check? */
        return .putAfter();
    }

    
Binding version of Cursor.putBefore().
        throws DatabaseException {
        checkWriteAllowed(false);
        .useValue(value);
        return .putBefore();
    }

    
Binding version of Cursor.put(), optionally returning the old value and optionally using the current key instead of the key parameter.
    OperationStatus put(Object keyObject valueObject[] oldValue,
                        boolean useCurrentKey)
        throws DatabaseException {
        initForPut(keyvalueoldValueuseCurrentKey);
        return .put();
    }

    
Binding version of Cursor.putNoOverwrite(), optionally using the current key instead of the key parameter.
                                   boolean useCurrentKey)
        throws DatabaseException {
        initForPut(keyvaluenulluseCurrentKey);
        return .putNoOverwrite();
    }

    
Binding version of Cursor.putNoDupData(), optionally returning the old value and optionally using the current key instead of the key parameter.
    OperationStatus putNoDupData(Object keyObject valueObject[] oldValue,
                                 boolean useCurrentKey)
        throws DatabaseException {
        initForPut(keyvalueoldValueuseCurrentKey);
        if (.) {
            return .putNoDupData();
        } else {
            if (.) {
                /* Unordered duplicates. */
                OperationStatus status =
                        .getSearchBoth(,
                                             ,
                                             getLockMode(false));
                if (status == .) {
                    return .;
                } else {
                    return .put();
                }
            } else {
                /* No duplicates. */
                return .putNoOverwrite();
            }
        }
    }

    
Do setup for a put() operation.
    private void initForPut(Object keyObject valueObject[] oldValue,
                            boolean useCurrentKey)
        throws DatabaseException {
        checkWriteAllowed(false);
        if (!useCurrentKey && !.useKey(keyvalue)) {
            throw new IllegalArgumentException("key out of range");
        }
        if (oldValue != null) {
            oldValue[0] = null;
            if (!.) {
                OperationStatus status = doGetSearchKey(true);
                if (status == .) {
                    oldValue[0] = getCurrentValue();
                }
            }
        }
        .useValue(value);
    }

    
Sets the key entry to the begin key of a single key range, so the next time a putXxx() method is called that key will be used.
    void useRangeKey() {
        if (!.isSingleKey()) {
            throw DbCompat.unexpectedState();
        }
        KeyRange.copy(.getSingleKey(), );
    }

    
Perform an arbitrary database 'delete' operation.
        throws DatabaseException {
        checkWriteAllowed(true);
        return .delete();
    }

    
Returns the lock mode to use for a getXxx() operation.
    LockMode getLockMode(boolean lockForWrite) {
        /* Read-uncommmitted takes precedence over write-locking. */
        if () {
            return .;
        } else if (lockForWrite) {
            return ..getWriteLockMode();
        } else {
            return .;
        }
    }

    
Throws an exception if a join cursor is in use.
    private void checkNoJoinCursor() {
        if ( != null) {
            throw new UnsupportedOperationException
                ("Not allowed with a join cursor");
        }
    }

    
Throws an exception if write is not allowed or if a join cursor is in use.
    private void checkWriteAllowed(boolean allowSecondary) {
        checkNoJoinCursor();
        if (! || (!allowSecondary && .isSecondary())) {
            throw new UnsupportedOperationException
                ("Writing is not allowed");
        }
    }
New to GrepCode? Check out our FAQ X