📄 datacursor.java
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2000-2006 * Oracle Corporation. All rights reserved. * * $Id: DataCursor.java,v 12.7 2006/09/08 20:32:13 bostic Exp $ */package com.sleepycat.collections;import com.sleepycat.compat.DbCompat;import com.sleepycat.db.Cursor;import com.sleepycat.db.CursorConfig;import com.sleepycat.db.DatabaseEntry;import com.sleepycat.db.DatabaseException;import com.sleepycat.db.JoinConfig;import com.sleepycat.db.JoinCursor;import com.sleepycat.db.LockMode;import com.sleepycat.db.OperationStatus;import com.sleepycat.util.keyrange.KeyRange;import com.sleepycat.util.keyrange.RangeCursor;/** * Represents a Berkeley DB cursor and adds support for indices, bindings and * key ranges. * * <p>This class operates on a view and takes care of reading and updating * indices, calling bindings, constraining access to a key range, etc.</p> * * @author 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 view, boolean writeAllowed) throws DatabaseException { init(view, writeAllowed, null, null); } /** * Creates a cursor for a given view. */ DataCursor(DataView view, boolean writeAllowed, CursorConfig config) throws DatabaseException { init(view, writeAllowed, config, null); } /** * Creates a cursor for a given view and single key range. * Used by unit tests. */ DataCursor(DataView view, boolean writeAllowed, Object singleKey) throws DatabaseException { init(view, writeAllowed, null, view.subRange(view.range, singleKey)); } /** * Creates a cursor for a given view and key range. * Used by unit tests. */ DataCursor(DataView view, boolean writeAllowed, Object beginKey, boolean beginInclusive, Object endKey, boolean endInclusive) throws DatabaseException { init(view, writeAllowed, null, view.subRange (view.range, beginKey, beginInclusive, endKey, endInclusive)); } /** * Creates a join cursor. */ DataCursor(DataView view, DataCursor[] indexCursors, JoinConfig joinConfig, boolean 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.length; i += 1) { cursors[i] = indexCursors[i].cursor.getCursor(); } joinCursor = view.db.join(cursors, joinConfig); init(view, false, null, null); if (closeIndexCursors) { indexCursorsToClose = indexCursors; } } /** * Clones a cursor preserving the current position. */ DataCursor cloneCursor() throws DatabaseException { checkNoJoinCursor(); DataCursor o; try { o = (DataCursor) super.clone(); } catch (CloneNotSupportedException neverHappens) { return null; } o.initThangs(); KeyRange.copy(keyThang, o.keyThang); KeyRange.copy(valueThang, o.valueThang); if (primaryKeyThang != keyThang) { KeyRange.copy(primaryKeyThang, o.primaryKeyThang); } o.cursor = cursor.dup(true); return o; } /** * Returns the internal range cursor. */ RangeCursor getCursor() { return cursor; } /** * Constructor helper. */ private void init(DataView view, boolean writeAllowed, CursorConfig config, KeyRange range) throws DatabaseException { if (config == null) { config = view.cursorConfig; } this.view = view; this.writeAllowed = writeAllowed && view.writeAllowed; this.range = (range != null) ? range : view.range; readUncommitted = config.getReadUncommitted() || view.currentTxn.isReadUncommitted(); initThangs(); if (joinCursor == null) { cursor = new MyRangeCursor (this.range, config, view, this.writeAllowed); } } /** * Constructor helper. */ private void initThangs() throws DatabaseException { keyThang = new DatabaseEntry(); primaryKeyThang = view.isSecondary() ? (new DatabaseEntry()) : keyThang; valueThang = new DatabaseEntry(); } /** * Set entries from given byte arrays. */ private void setThangs(byte[] keyBytes, byte[] priKeyBytes, byte[] valueBytes) { keyThang.setData(KeyRange.copyBytes(keyBytes)); if (keyThang != primaryKeyThang) { primaryKeyThang.setData(KeyRange.copyBytes(priKeyBytes)); } valueThang.setData(KeyRange.copyBytes(valueBytes)); } /** * Closes the associated cursor. */ void close() throws DatabaseException { if (joinCursor != null) { JoinCursor toClose = joinCursor; joinCursor = null; toClose.close(); } if (cursor != null) { Cursor toClose = cursor.getCursor(); cursor = null; view.currentTxn.closeCursor(toClose ); } if (indexCursorsToClose != null) { DataCursor[] toClose = indexCursorsToClose; indexCursorsToClose = null; for (int i = 0; i < toClose.length; i += 1) { toClose[i].close(); } } } /** * Repositions to a given raw key/data pair, or just past it if that record * has been deleted. * * @return 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(keyBytes, priKeyBytes, valueBytes); /* Position on or after the given key/data pair. */ if (view.dupsAllowed) { status = cursor.getSearchBothRange(keyThang, primaryKeyThang, valueThang, lockMode); } if (status != OperationStatus.SUCCESS) { status = cursor.getSearchKeyRange(keyThang, primaryKeyThang, valueThang, lockMode); } /* Return the result of the operation. */ if (status == OperationStatus.SUCCESS) { if (!KeyRange.equalBytes(keyBytes, 0, keyBytes.length, keyThang.getData(), keyThang.getOffset(), keyThang.getSize())) { return REPOS_NEXT; } if (view.dupsAllowed) { DatabaseEntry thang = view.isSecondary() ? primaryKeyThang : valueThang; byte[] bytes = view.isSecondary() ? priKeyBytes : valueBytes; if (!KeyRange.equalBytes(bytes, 0, bytes.length, thang.getData(), thang.getOffset(), thang.getSize())) { return REPOS_NEXT; } } return REPOS_EXACT; } else { return REPOS_EOF; } } /** * Repositions to a given raw key/data pair. * * @throws IllegalStateException when the database has unordered keys or * unordered duplicates. * * @return whether the search succeeded. */ 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(keyBytes, priKeyBytes, valueBytes); /* Position on the given key/data pair. */ if (view.recNumRenumber) { /* getSearchBoth doesn't work with recno-renumber databases. */ status = cursor.getSearchKey(keyThang, primaryKeyThang, valueThang, lockMode); } else { status = cursor.getSearchBoth(keyThang, primaryKeyThang, valueThang, lockMode); } return (status == OperationStatus.SUCCESS); } /** * Returns the view for this cursor. */ DataView getView() { return view; } /** * Returns the range for this cursor. */ KeyRange getRange() { return range; } /** * Returns whether write is allowed for this cursor, as specified to the * constructor. */ boolean isWriteAllowed() { return writeAllowed; } /** * Returns the key object for the last record read. */ Object getCurrentKey() throws DatabaseException { return view.makeKey(keyThang, primaryKeyThang); } /** * Returns the value object for the last record read. */ Object getCurrentValue() throws DatabaseException { return view.makeValue(primaryKeyThang, valueThang); } /** * Returns the internal key entry. */ DatabaseEntry getKeyThang() { return keyThang; } /** * Returns the internal primary key entry, which is the same object as the * key entry if the cursor is not for a secondary database. */ DatabaseEntry getPrimaryKeyThang() { return primaryKeyThang; } /** * Returns the internal value entry. */ DatabaseEntry getValueThang() { return valueThang; } /** * Returns whether record number access is allowed. */ boolean hasRecNumAccess() { return view.recNumAccess; } /** * Returns the record number for the last record read. */ int getCurrentRecordNumber() throws DatabaseException { if (view.btreeRecNumDb) { /* BTREE-RECNO access. */ if (otherThang == null) { otherThang = new DatabaseEntry(); } DbCompat.getCurrentRecordNumber(cursor.getCursor(), otherThang, getLockMode(false)); return DbCompat.getRecordNumber(otherThang); } else { /* QUEUE or RECNO database. */ return DbCompat.getRecordNumber(keyThang); } } /** * Binding version of Cursor.getCurrent(), no join cursor allowed. */ OperationStatus getCurrent(boolean lockForWrite) throws DatabaseException { checkNoJoinCursor(); return cursor.getCurrent(keyThang, primaryKeyThang, valueThang, getLockMode(lockForWrite)); } /** * Binding version of Cursor.getFirst(), join cursor is allowed. */ OperationStatus getFirst(boolean lockForWrite) throws DatabaseException { LockMode lockMode = getLockMode(lockForWrite); if (joinCursor != null) { return joinCursor.getNext(keyThang, valueThang, lockMode); } else { return cursor.getFirst(keyThang, primaryKeyThang, valueThang, lockMode); } } /** * Binding version of Cursor.getNext(), join cursor is allowed. */ OperationStatus getNext(boolean lockForWrite) throws DatabaseException { LockMode lockMode = getLockMode(lockForWrite); if (joinCursor != null) { return joinCursor.getNext(keyThang, valueThang, lockMode); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -