⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rangecursor.java

📁 关于Berkelay数据库的共享源码
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2002-2006 *      Oracle Corporation.  All rights reserved. * * $Id: RangeCursor.java,v 1.3 2006/09/08 20:32:14 bostic Exp $ */package com.sleepycat.util.keyrange;import com.sleepycat.compat.DbCompat;import com.sleepycat.db.Cursor;import com.sleepycat.db.DatabaseEntry;import com.sleepycat.db.DatabaseException;import com.sleepycat.db.LockMode;import com.sleepycat.db.OperationStatus;import com.sleepycat.db.SecondaryCursor;/** * A cursor-like interface that enforces a key range.  The method signatures * are actually those of SecondaryCursor, but the pKey parameter may be null. * It was done this way to avoid doubling the number of methods. * * <p>This is not a fully general implementation of a range cursor and should * not be used directly by applications; however, it may evolve into a * generally useful range cursor some day.</p> * * @author Mark Hayes */public class RangeCursor implements Cloneable {    /**     * The cursor and secondary cursor are the same object.  The secCursor is     * null if the database is not a secondary database.     */    private Cursor cursor;    private SecondaryCursor secCursor;    /**     * The range is always non-null, but may be unbounded meaning that it is     * open and not used.     */    private KeyRange range;    /**     * The pkRange may be non-null only if the range is a single-key range     * and the cursor is a secondary cursor.  It further restricts the range of     * primary keys in a secondary database.     */    private KeyRange pkRange;    /**     * The privXxx entries are used only when the range is bounded.  We read     * into these private entries to avoid modifying the caller's entry     * parameters in the case where we read successfully but the key is out of     * range.  In that case we return NOTFOUND and we want to leave the entry     * parameters unchanged.     */    private DatabaseEntry privKey;    private DatabaseEntry privPKey;    private DatabaseEntry privData;    /**     * The initialized flag is set to true whenever we successfully position     * the cursor.  It is used to implement the getNext/Prev logic for doing a     * getFirst/Last when the cursor is not initialized.  We can't rely on     * Cursor to do that for us, since if we position the underlying cursor     * successfully but the key is out of range, we have no way to set the     * underlying cursor to uninitialized.  A range cursor always starts in the     * uninitialized state.     */    private boolean initialized;    /**     * Creates a range cursor.     */    public RangeCursor(KeyRange range, Cursor cursor)        throws DatabaseException {        this.range = range;        this.cursor = cursor;        init();    }    /**     * Creates a range cursor with a duplicate range.     */    public RangeCursor(KeyRange range, KeyRange pkRange, Cursor cursor)        throws DatabaseException {        if (pkRange != null && !range.singleKey) {            throw new IllegalArgumentException();        }        this.range = range;        this.pkRange = pkRange;        this.cursor = cursor;        init();        if (pkRange != null && secCursor == null) {            throw new IllegalArgumentException();        }    }    /**     * Create a cloned range cursor.  The caller must clone the underlying     * cursor before using this constructor, because cursor open/close is     * handled specially for CDS cursors outside this class.     */    public RangeCursor dup(boolean samePosition)        throws DatabaseException {        try {            RangeCursor c = (RangeCursor) super.clone();            c.cursor = dupCursor(cursor, samePosition);            c.init();            return c;        } catch (CloneNotSupportedException neverHappens) {            return null;        }    }    /**     * Used for opening and duping (cloning).     */    private void init() {        if (cursor instanceof SecondaryCursor) {            secCursor = (SecondaryCursor) cursor;        } else {            secCursor = null;        }        if (range.hasBound()) {            privKey = new DatabaseEntry();            privPKey = new DatabaseEntry();            privData = new DatabaseEntry();        } else {            privKey = null;            privPKey = null;            privData = null;        }    }    /**     * Returns whether the cursor is initialized at a valid position.     */    public boolean isInitialized() {        return initialized;    }    /**     * Returns the underlying cursor.  Used for cloning.     */    public Cursor getCursor() {        return cursor;    }    /**     * When an unbounded range is used, this method is called to use the     * callers entry parameters directly, to avoid the extra step of copying     * between the private entries and the caller's entries.     */    private void setParams(DatabaseEntry key, DatabaseEntry pKey,                           DatabaseEntry data) {        privKey = key;        privPKey = pKey;        privData = data;    }    /**     * Dups the cursor, sets the cursor and secCursor fields to the duped     * cursor, and returns the old cursor.  Always call endOperation in a     * finally clause after calling beginOperation.     *     * <p>If the returned cursor == the cursor field, the cursor is     * uninitialized and was not duped; this case is handled correctly by     * endOperation.</p>     */    private Cursor beginOperation()        throws DatabaseException {        Cursor oldCursor = cursor;        if (initialized) {            cursor = dupCursor(cursor, true);            if (secCursor != null) {                secCursor = (SecondaryCursor) cursor;            }        } else {            return cursor;        }        return oldCursor;    }    /**     * If the operation succeded, leaves the duped cursor in place and closes     * the oldCursor.  If the operation failed, moves the oldCursor back in     * place and closes the duped cursor.  oldCursor may be null if     * beginOperation was not called, in cases where we don't need to dup     * the cursor.  Always call endOperation when a successful operation ends,     * in order to set the initialized field.     */    private void endOperation(Cursor oldCursor, OperationStatus status,                              DatabaseEntry key, DatabaseEntry pKey,                              DatabaseEntry data)        throws DatabaseException {        if (status == OperationStatus.SUCCESS) {            if (oldCursor != null && oldCursor != cursor) {                closeCursor(oldCursor);            }            if (key != null) {                swapData(key, privKey);            }            if (pKey != null && secCursor != null) {                swapData(pKey, privPKey);            }            if (data != null) {                swapData(data, privData);            }            initialized = true;        } else {            if (oldCursor != null && oldCursor != cursor) {                closeCursor(cursor);                cursor = oldCursor;                if (secCursor != null) {                    secCursor = (SecondaryCursor) cursor;                }            }        }    }    /**     * Swaps the contents of the two entries.  Used to return entry data to     * the caller when the operation was successful.     */    private static void swapData(DatabaseEntry e1, DatabaseEntry e2) {        byte[] d1 = e1.getData();        int o1 = e1.getOffset();        int s1 = e1.getSize();        e1.setData(e2.getData(), e2.getOffset(), e2.getSize());        e2.setData(d1, o1, s1);    }    /**     * Shares the same byte array, offset and size between two entries.     * Used when copying the entry data is not necessary because it is known     * that the underlying operation will not modify the entry, for example,     * with getSearchKey.     */    private static void shareData(DatabaseEntry from, DatabaseEntry to) {        if (from != null) {            to.setData(from.getData(), from.getOffset(), from.getSize());        }    }    public OperationStatus getFirst(DatabaseEntry key,                                    DatabaseEntry pKey,                                    DatabaseEntry data,                                    LockMode lockMode)        throws DatabaseException {        OperationStatus status;        if (!range.hasBound()) {            setParams(key, pKey, data);            status = doGetFirst(lockMode);            endOperation(null, status, null, null, null);            return status;        }        if (pkRange != null) {            KeyRange.copy(range.beginKey, privKey);            if (pkRange.singleKey) {                KeyRange.copy(pkRange.beginKey, privPKey);                status = doGetSearchBoth(lockMode);                endOperation(null, status, key, pKey, data);            } else {                status = OperationStatus.NOTFOUND;                Cursor oldCursor = beginOperation();                try {                    if (pkRange.beginKey == null) {                        status = doGetSearchKey(lockMode);                    } else {                        KeyRange.copy(pkRange.beginKey, privPKey);                        status = doGetSearchBothRange(lockMode);                        if (status == OperationStatus.SUCCESS &&                            !pkRange.beginInclusive &&                            pkRange.compare(privPKey, pkRange.beginKey) == 0) {                            status = doGetNextDup(lockMode);                        }                    }                    if (status == OperationStatus.SUCCESS &&                        !pkRange.check(privPKey)) {                        status = OperationStatus.NOTFOUND;                    }                } finally {                    endOperation(oldCursor, status, key, pKey, data);                }            }        } else if (range.singleKey) {            KeyRange.copy(range.beginKey, privKey);            status = doGetSearchKey(lockMode);            endOperation(null, status, key, pKey, data);        } else {            status = OperationStatus.NOTFOUND;            Cursor oldCursor = beginOperation();            try {                if (range.beginKey == null) {                    status = doGetFirst(lockMode);                } else {                    KeyRange.copy(range.beginKey, privKey);                    status = doGetSearchKeyRange(lockMode);                    if (status == OperationStatus.SUCCESS &&                        !range.beginInclusive &&                        range.compare(privKey, range.beginKey) == 0) {                        status = doGetNextNoDup(lockMode);                    }                }                if (status == OperationStatus.SUCCESS &&                    !range.check(privKey)) {                    status = OperationStatus.NOTFOUND;                }            } finally {                endOperation(oldCursor, status, key, pKey, data);            }        }        return status;    }    public OperationStatus getLast(DatabaseEntry key,                                   DatabaseEntry pKey,                                   DatabaseEntry data,                                   LockMode lockMode)        throws DatabaseException {        OperationStatus status = OperationStatus.NOTFOUND;        if (!range.hasBound()) {            setParams(key, pKey, data);            status = doGetLast(lockMode);            endOperation(null, status, null, null, null);            return status;        }        Cursor oldCursor = beginOperation();        try {            if (pkRange != null) {                KeyRange.copy(range.beginKey, privKey);                boolean doLast = false;                if (pkRange.endKey == null) {                    doLast = true;                } else {                    KeyRange.copy(pkRange.endKey, privPKey);                    status = doGetSearchBothRange(lockMode);                    if (status == OperationStatus.SUCCESS) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -