Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

DataCursor.java

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2000-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: DataCursor.java,v 12.3 2005/08/01 20:25:18 mark Exp $
00008  */
00009 
00010 package com.sleepycat.collections;
00011 
00012 import com.sleepycat.compat.DbCompat;
00013 import com.sleepycat.db.Cursor;
00014 import com.sleepycat.db.DatabaseEntry;
00015 import com.sleepycat.db.DatabaseException;
00016 import com.sleepycat.db.JoinConfig;
00017 import com.sleepycat.db.JoinCursor;
00018 import com.sleepycat.db.LockMode;
00019 import com.sleepycat.db.OperationStatus;
00020 
00030 final class DataCursor implements Cloneable {
00031 
00032     private RangeCursor cursor;
00033     private JoinCursor joinCursor;
00034     private DataView view;
00035     private KeyRange range;
00036     private boolean writeAllowed;
00037     private boolean readUncommitted;
00038     private DatabaseEntry keyThang;
00039     private DatabaseEntry valueThang;
00040     private DatabaseEntry primaryKeyThang;
00041     private DatabaseEntry otherThang;
00042     private DataCursor[] indexCursorsToClose;
00043 
00047     DataCursor(DataView view, boolean writeAllowed)
00048         throws DatabaseException {
00049 
00050         init(view, writeAllowed, null);
00051     }
00052 
00056     DataCursor(DataView view, boolean writeAllowed, Object singleKey)
00057         throws DatabaseException {
00058 
00059         init(view, writeAllowed, view.subRange(singleKey));
00060     }
00061 
00065     DataCursor(DataView view, boolean writeAllowed,
00066                Object beginKey, boolean beginInclusive,
00067                Object endKey, boolean endInclusive)
00068         throws DatabaseException {
00069 
00070         init(view, writeAllowed,
00071              view.subRange(beginKey, beginInclusive, endKey, endInclusive));
00072     }
00073 
00077     DataCursor(DataView view, DataCursor[] indexCursors,
00078                JoinConfig joinConfig, boolean closeIndexCursors)
00079         throws DatabaseException {
00080 
00081         if (view.isSecondary()) {
00082             throw new IllegalArgumentException(
00083                 "The primary collection in a join must not be a secondary " +
00084                 "database");
00085         }
00086         Cursor[] cursors = new Cursor[indexCursors.length];
00087         for (int i = 0; i < cursors.length; i += 1) {
00088             cursors[i] = indexCursors[i].cursor.getCursor();
00089         }
00090         joinCursor = view.db.join(cursors, joinConfig);
00091         init(view, false, null);
00092         if (closeIndexCursors) {
00093             indexCursorsToClose = indexCursors;
00094         }
00095     }
00096 
00100     DataCursor cloneCursor()
00101         throws DatabaseException {
00102 
00103         checkNoJoinCursor();
00104 
00105         DataCursor o;
00106         try {
00107             o = (DataCursor) super.clone();
00108         } catch (CloneNotSupportedException neverHappens) {
00109             return null;
00110         }
00111 
00112         o.initThangs();
00113         KeyRange.copy(keyThang, o.keyThang);
00114         KeyRange.copy(valueThang, o.valueThang);
00115         if (primaryKeyThang != keyThang) {
00116             KeyRange.copy(primaryKeyThang, o.primaryKeyThang);
00117         }
00118 
00119         o.cursor = cursor.dup(true);
00120         return o;
00121     }
00122 
00126     RangeCursor getCursor() {
00127         return cursor;
00128     }
00129 
00133     private void init(DataView view, boolean writeAllowed, KeyRange range)
00134         throws DatabaseException {
00135 
00136         this.view = view;
00137         this.writeAllowed = writeAllowed && view.writeAllowed;
00138         this.range = (range != null) ? range : view.range;
00139         readUncommitted = view.cursorConfig.getReadUncommitted() ||
00140             view.currentTxn.isReadUncommitted();
00141         initThangs();
00142 
00143         if (joinCursor == null) {
00144             cursor = new RangeCursor(view, this.range, this.writeAllowed);
00145         }
00146     }
00147 
00151     private void initThangs()
00152         throws DatabaseException {
00153 
00154         keyThang = new DatabaseEntry();
00155         primaryKeyThang = view.isSecondary() ? (new DatabaseEntry())
00156                                              : keyThang;
00157         valueThang = new DatabaseEntry();
00158     }
00159 
00163     void close()
00164         throws DatabaseException {
00165 
00166         if (joinCursor != null) {
00167             JoinCursor toClose = joinCursor;
00168             joinCursor = null;
00169             toClose.close();
00170         }
00171         if (cursor != null) {
00172             Cursor toClose = cursor.getCursor();
00173             cursor = null;
00174             view.currentTxn.closeCursor(toClose );
00175         }
00176         if (indexCursorsToClose != null) {
00177             DataCursor[] toClose = indexCursorsToClose;
00178             indexCursorsToClose = null;
00179             for (int i = 0; i < toClose.length; i += 1) {
00180                 toClose[i].close();
00181             }
00182         }
00183     }
00184 
00188     DataView getView() {
00189 
00190         return view;
00191     }
00192 
00196     KeyRange getRange() {
00197 
00198         return range;
00199     }
00200 
00205     boolean isWriteAllowed() {
00206 
00207         return writeAllowed;
00208     }
00209 
00213     Object getCurrentKey()
00214         throws DatabaseException {
00215 
00216         if (view.keyBinding == null) {
00217             throw new UnsupportedOperationException();
00218         }
00219         return view.makeKey(keyThang);
00220     }
00221 
00225     Object getCurrentValue()
00226         throws DatabaseException {
00227 
00228         return view.makeValue(primaryKeyThang, valueThang);
00229     }
00230 
00234     boolean hasRecNumAccess() {
00235 
00236         return view.recNumAccess;
00237     }
00238 
00242     int getCurrentRecordNumber()
00243         throws DatabaseException {
00244 
00245         if (view.btreeRecNumDb) {
00246             /* BTREE-RECNO access. */
00247             if (otherThang == null) {
00248                 otherThang = new DatabaseEntry();
00249             }
00250             DbCompat.getCurrentRecordNumber(cursor.getCursor(), otherThang,
00251                                             getLockMode(false));
00252             return DbCompat.getRecordNumber(otherThang);
00253         } else {
00254             /* QUEUE or RECNO database. */
00255             return DbCompat.getRecordNumber(keyThang);
00256         }
00257     }
00258     
00262     OperationStatus getCurrent(boolean lockForWrite)
00263         throws DatabaseException {
00264 
00265         checkNoJoinCursor();
00266         return cursor.getCurrent(keyThang, primaryKeyThang, valueThang,
00267                                  getLockMode(lockForWrite));
00268     }
00269     
00273     OperationStatus getFirst(boolean lockForWrite)
00274         throws DatabaseException {
00275 
00276         LockMode lockMode = getLockMode(lockForWrite);
00277         if (joinCursor != null) {
00278             return joinCursor.getNext(keyThang, valueThang, lockMode);
00279         } else {
00280             return cursor.getFirst(keyThang, primaryKeyThang, valueThang,
00281                                    lockMode);
00282         }
00283     }
00284     
00288     OperationStatus getNext(boolean lockForWrite)
00289         throws DatabaseException {
00290 
00291         LockMode lockMode = getLockMode(lockForWrite);
00292         if (joinCursor != null) {
00293             return joinCursor.getNext(keyThang, valueThang, lockMode);
00294         } else {
00295             return cursor.getNext(keyThang, primaryKeyThang, valueThang,
00296                                   lockMode);
00297         }
00298     }
00299     
00303     OperationStatus getNextNoDup(boolean lockForWrite)
00304         throws DatabaseException {
00305 
00306         LockMode lockMode = getLockMode(lockForWrite);
00307         if (joinCursor != null) {
00308             return joinCursor.getNext(keyThang, valueThang, lockMode);
00309         } else {
00310             return cursor.getNextNoDup(keyThang, primaryKeyThang, valueThang,
00311                                        lockMode);
00312         }
00313     }
00314     
00318     OperationStatus getNextDup(boolean lockForWrite)
00319         throws DatabaseException {
00320 
00321         checkNoJoinCursor();
00322         return cursor.getNextDup(keyThang, primaryKeyThang, valueThang,
00323                                  getLockMode(lockForWrite));
00324     }
00325     
00329     OperationStatus getLast(boolean lockForWrite)
00330         throws DatabaseException {
00331 
00332         checkNoJoinCursor();
00333         return cursor.getLast(keyThang, primaryKeyThang, valueThang,
00334                               getLockMode(lockForWrite));
00335     }
00336     
00340     OperationStatus getPrev(boolean lockForWrite)
00341         throws DatabaseException {
00342 
00343         checkNoJoinCursor();
00344         return cursor.getPrev(keyThang, primaryKeyThang, valueThang,
00345                               getLockMode(lockForWrite));
00346     }
00347     
00351     OperationStatus getPrevNoDup(boolean lockForWrite)
00352         throws DatabaseException {
00353 
00354         checkNoJoinCursor();
00355         return cursor.getPrevNoDup(keyThang, primaryKeyThang, valueThang,
00356                                    getLockMode(lockForWrite));
00357     }
00358     
00362     OperationStatus getPrevDup(boolean lockForWrite)
00363         throws DatabaseException {
00364 
00365         checkNoJoinCursor();
00366         return cursor.getPrevDup(keyThang, primaryKeyThang, valueThang,
00367                                  getLockMode(lockForWrite));
00368     }
00369     
00374     OperationStatus getSearchKey(Object key, Object value,
00375                                  boolean lockForWrite)
00376         throws DatabaseException {
00377 
00378         checkNoJoinCursor();
00379         if (view.useKey(key, value, keyThang, range)) {
00380             return doGetSearchKey(lockForWrite);
00381         } else {
00382             return OperationStatus.NOTFOUND;
00383         }
00384     }
00385     
00390     private OperationStatus doGetSearchKey(boolean lockForWrite)
00391         throws DatabaseException {
00392 
00393         LockMode lockMode = getLockMode(lockForWrite);
00394         if (view.btreeRecNumAccess) {
00395             return cursor.getSearchRecordNumber(keyThang, primaryKeyThang,
00396                                                 valueThang, lockMode);
00397         } else {
00398             return cursor.getSearchKey(keyThang, primaryKeyThang,
00399                                        valueThang, lockMode);
00400         }
00401     }
00402     
00406     OperationStatus getSearchKeyRange(Object key, Object value,
00407                                       boolean lockForWrite)
00408         throws DatabaseException {
00409 
00410         checkNoJoinCursor();
00411         if (view.useKey(key, value, keyThang, range)) {
00412             return cursor.getSearchKeyRange(keyThang, primaryKeyThang,
00413                                             valueThang,
00414                                             getLockMode(lockForWrite));
00415         } else {
00416             return OperationStatus.NOTFOUND;
00417         }
00418     }
00419     
00425     OperationStatus getSearchBoth(Object key, Object value,
00426                                   boolean lockForWrite)
00427         throws DatabaseException {
00428 
00429         checkNoJoinCursor();
00430         LockMode lockMode = getLockMode(lockForWrite);
00431         view.useValue(value, valueThang, null);
00432         if (view.useKey(key, value, keyThang, range)) {
00433             if (view.isSecondary()) {
00434                 if (otherThang == null) {
00435                     otherThang = new DatabaseEntry();
00436                 }
00437                 OperationStatus status = cursor.getSearchKey(keyThang,
00438                                                              primaryKeyThang,
00439                                                              otherThang,
00440                                                              lockMode);
00441                 while (status == OperationStatus.SUCCESS) {
00442                     if (KeyRange.equalBytes(otherThang, valueThang)) {
00443                         break;
00444                     }
00445                     status = cursor.getNextDup(keyThang, primaryKeyThang,
00446                                                otherThang, lockMode);
00447                 }
00448                 /* if status != SUCCESS set range cursor to invalid? */
00449                 return status;
00450             } else {
00451                 return cursor.getSearchBoth(keyThang, null, valueThang,
00452                                             lockMode);
00453             }
00454         } else {
00455             return OperationStatus.NOTFOUND;
00456         }
00457     }
00458 
00463     OperationStatus find(Object value, boolean findFirst)
00464         throws DatabaseException {
00465 
00466         checkNoJoinCursor();
00467 
00468         if (view.entityBinding != null && !view.isSecondary() &&
00469             (findFirst || !view.dupsAllowed)) {
00470             return getSearchBoth(null, value, false);
00471         } else {
00472             if (otherThang == null) {
00473                 otherThang = new DatabaseEntry();
00474             }
00475             view.useValue(value, otherThang, null);
00476             OperationStatus status = findFirst ? getFirst(false)
00477                                                : getLast(false);
00478             while (status == OperationStatus.SUCCESS) {
00479                 if (KeyRange.equalBytes(valueThang, otherThang)) {
00480                     break;
00481                 }
00482                 status = findFirst ? getNext(false) : getPrev(false);
00483             }
00484             return status;
00485         }
00486     }
00487 
00491     int count()
00492         throws DatabaseException {
00493 
00494         checkNoJoinCursor();
00495         return cursor.count();
00496     }
00497 
00501     OperationStatus putCurrent(Object value)
00502         throws DatabaseException {
00503 
00504         checkWriteAllowed(false);
00505         view.useValue(value, valueThang, keyThang);
00506         
00507         /*
00508          * Workaround for a DB core problem: With HASH type a put() with
00509          * different data is allowed.
00510          */
00511         boolean hashWorkaround = (view.dupsOrdered && !view.ordered);
00512         if (hashWorkaround) {
00513             if (otherThang == null) {
00514                 otherThang = new DatabaseEntry();
00515             }
00516             cursor.getCurrent(keyThang, primaryKeyThang, otherThang,
00517                               LockMode.DEFAULT);
00518             if (KeyRange.equalBytes(valueThang, otherThang)) {
00519                 return OperationStatus.SUCCESS;
00520             } else {
00521                 throw new IllegalArgumentException(
00522                   "Current data differs from put data with sorted duplicates");
00523             }
00524         }
00525 
00526         return cursor.putCurrent(valueThang);
00527     }
00528 
00532     OperationStatus putAfter(Object value)
00533         throws DatabaseException {
00534 
00535         checkWriteAllowed(false);
00536         view.useValue(value, valueThang, null); /* why no key check? */
00537         return cursor.putAfter(new DatabaseEntry(), valueThang);
00538     }
00539 
00543     OperationStatus putBefore(Object value)
00544         throws DatabaseException {
00545 
00546         checkWriteAllowed(false);
00547         view.useValue(value, valueThang, keyThang);
00548         return cursor.putBefore(new DatabaseEntry(), valueThang);
00549     }
00550 
00555     OperationStatus put(Object key, Object value, Object[] oldValue,
00556                         boolean useCurrentKey)
00557         throws DatabaseException {
00558 
00559         initForPut(key, value, oldValue, useCurrentKey);
00560         return cursor.put(keyThang, valueThang);
00561     }
00562 
00567     OperationStatus putNoOverwrite(Object key, Object value,
00568                                    boolean useCurrentKey)
00569         throws DatabaseException {
00570 
00571         initForPut(key, value, null, useCurrentKey);
00572         return cursor.putNoOverwrite(keyThang, valueThang);
00573     }
00574 
00579     OperationStatus putNoDupData(Object key, Object value, Object[] oldValue,
00580                                  boolean useCurrentKey)
00581         throws DatabaseException {
00582 
00583         initForPut(key, value, oldValue, useCurrentKey);
00584         if (view.dupsOrdered) {
00585             return cursor.putNoDupData(keyThang, valueThang);
00586         } else {
00587             if (view.dupsAllowed) {
00588                 /* Unordered duplicates. */
00589                 OperationStatus status =
00590                         cursor.getSearchBoth(keyThang, primaryKeyThang,
00591                                              valueThang,
00592                                              getLockMode(false));
00593                 if (status == OperationStatus.SUCCESS) {
00594                     return OperationStatus.KEYEXIST;
00595                 } else {
00596                     return cursor.put(keyThang, valueThang);
00597                 }
00598             } else {
00599                 /* No duplicates. */
00600                 return cursor.putNoOverwrite(keyThang, valueThang);
00601             }
00602         }
00603     }
00604 
00608     private void initForPut(Object key, Object value, Object[] oldValue,
00609                             boolean useCurrentKey)
00610         throws DatabaseException {
00611 
00612         checkWriteAllowed(false);
00613         if (!useCurrentKey && !view.useKey(key, value, keyThang, range)) {
00614             throw new IllegalArgumentException("key out of range");
00615         }
00616         if (oldValue != null) {
00617             oldValue[0] = null;
00618             if (!view.dupsAllowed) {
00619                 OperationStatus status = doGetSearchKey(true);
00620                 if (status == OperationStatus.SUCCESS) {
00621                     oldValue[0] = getCurrentValue();
00622                 }
00623             }
00624         }
00625         view.useValue(value, valueThang, keyThang);
00626     }
00627 
00632     void useRangeKey() {
00633         if (!range.singleKey) {
00634             throw new IllegalStateException();
00635         }
00636         KeyRange.copy(range.beginKey, keyThang);
00637     }
00638 
00642     OperationStatus delete()
00643         throws DatabaseException {
00644 
00645         checkWriteAllowed(true);
00646         return cursor.delete();
00647     }
00648 
00652     LockMode getLockMode(boolean lockForWrite) {
00653 
00654         /* Read-uncommmitted takes precedence over write-locking. */
00655 
00656         if (lockForWrite && !readUncommitted) {
00657             return view.currentTxn.getWriteLockMode();
00658         } else {
00659             return LockMode.DEFAULT;
00660         }
00661     }
00662 
00666     private void checkNoJoinCursor() {
00667 
00668         if (joinCursor != null) {
00669             throw new UnsupportedOperationException
00670                 ("Not allowed with a join cursor");
00671         }
00672     }
00673 
00678     private void checkWriteAllowed(boolean allowSecondary) {
00679 
00680         checkNoJoinCursor();
00681 
00682         if (!writeAllowed || (!allowSecondary && view.isSecondary())) {
00683             throw new UnsupportedOperationException
00684                 ("Writing is not allowed");
00685         }
00686     }
00687 }

Generated on Sun Dec 25 12:14:31 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2