KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > collections > DataCursor


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2000,2006 Oracle. All rights reserved.
5  *
6  * $Id: DataCursor.java,v 1.60 2006/10/30 21:14:10 bostic Exp $
7  */

8
9 package com.sleepycat.collections;
10
11 import com.sleepycat.compat.DbCompat;
12 import com.sleepycat.je.Cursor;
13 import com.sleepycat.je.CursorConfig;
14 import com.sleepycat.je.DatabaseEntry;
15 import com.sleepycat.je.DatabaseException;
16 import com.sleepycat.je.JoinConfig;
17 import com.sleepycat.je.JoinCursor;
18 import com.sleepycat.je.LockMode;
19 import com.sleepycat.je.OperationStatus;
20 import com.sleepycat.util.keyrange.KeyRange;
21 import com.sleepycat.util.keyrange.RangeCursor;
22
23 /**
24  * Represents a Berkeley DB cursor and adds support for indices, bindings and
25  * key ranges.
26  *
27  * <p>This class operates on a view and takes care of reading and updating
28  * indices, calling bindings, constraining access to a key range, etc.</p>
29  *
30  * @author Mark Hayes
31  */

32 final class DataCursor implements Cloneable JavaDoc {
33
34     /** Repositioned exactly to the key/data pair given. */
35     static final int REPOS_EXACT = 0;
36     /** Repositioned on a record following the key/data pair given. */
37     static final int REPOS_NEXT = 1;
38     /** Repositioned failed, no records on or after the key/data pair given. */
39     static final int REPOS_EOF = 2;
40
41     private RangeCursor cursor;
42     private JoinCursor joinCursor;
43     private DataView view;
44     private KeyRange range;
45     private boolean writeAllowed;
46     private boolean readUncommitted;
47     private DatabaseEntry keyThang;
48     private DatabaseEntry valueThang;
49     private DatabaseEntry primaryKeyThang;
50     private DatabaseEntry otherThang;
51     private DataCursor[] indexCursorsToClose;
52
53     /**
54      * Creates a cursor for a given view.
55      */

56     DataCursor(DataView view, boolean writeAllowed)
57         throws DatabaseException {
58
59         init(view, writeAllowed, null, null);
60     }
61
62     /**
63      * Creates a cursor for a given view.
64      */

65     DataCursor(DataView view, boolean writeAllowed, CursorConfig config)
66         throws DatabaseException {
67
68         init(view, writeAllowed, config, null);
69     }
70
71     /**
72      * Creates a cursor for a given view and single key range.
73      * Used by unit tests.
74      */

75     DataCursor(DataView view, boolean writeAllowed, Object JavaDoc singleKey)
76         throws DatabaseException {
77
78         init(view, writeAllowed, null, view.subRange(view.range, singleKey));
79     }
80
81     /**
82      * Creates a cursor for a given view and key range.
83      * Used by unit tests.
84      */

85     DataCursor(DataView view, boolean writeAllowed,
86                Object JavaDoc beginKey, boolean beginInclusive,
87                Object JavaDoc endKey, boolean endInclusive)
88         throws DatabaseException {
89
90         init(view, writeAllowed, null,
91              view.subRange
92                 (view.range, beginKey, beginInclusive, endKey, endInclusive));
93     }
94
95     /**
96      * Creates a join cursor.
97      */

98     DataCursor(DataView view, DataCursor[] indexCursors,
99                JoinConfig joinConfig, boolean closeIndexCursors)
100         throws DatabaseException {
101
102         if (view.isSecondary()) {
103             throw new IllegalArgumentException JavaDoc(
104                 "The primary collection in a join must not be a secondary " +
105                 "database");
106         }
107         Cursor[] cursors = new Cursor[indexCursors.length];
108         for (int i = 0; i < cursors.length; i += 1) {
109             cursors[i] = indexCursors[i].cursor.getCursor();
110         }
111         joinCursor = view.db.join(cursors, joinConfig);
112         init(view, false, null, null);
113         if (closeIndexCursors) {
114             indexCursorsToClose = indexCursors;
115         }
116     }
117
118     /**
119      * Clones a cursor preserving the current position.
120      */

121     DataCursor cloneCursor()
122         throws DatabaseException {
123
124         checkNoJoinCursor();
125
126         DataCursor o;
127         try {
128             o = (DataCursor) super.clone();
129         } catch (CloneNotSupportedException JavaDoc neverHappens) {
130             return null;
131         }
132
133         o.initThangs();
134         KeyRange.copy(keyThang, o.keyThang);
135         KeyRange.copy(valueThang, o.valueThang);
136         if (primaryKeyThang != keyThang) {
137             KeyRange.copy(primaryKeyThang, o.primaryKeyThang);
138         }
139
140         o.cursor = cursor.dup(true);
141         return o;
142     }
143
144     /**
145      * Returns the internal range cursor.
146      */

147     RangeCursor getCursor() {
148         return cursor;
149     }
150
151     /**
152      * Constructor helper.
153      */

154     private void init(DataView view,
155                       boolean writeAllowed,
156                       CursorConfig config,
157                       KeyRange range)
158         throws DatabaseException {
159
160         if (config == null) {
161             config = view.cursorConfig;
162         }
163         this.view = view;
164         this.writeAllowed = writeAllowed && view.writeAllowed;
165         this.range = (range != null) ? range : view.range;
166         readUncommitted = config.getReadUncommitted() ||
167                           view.currentTxn.isReadUncommitted();
168         initThangs();
169
170         if (joinCursor == null) {
171             cursor = new MyRangeCursor
172                 (this.range, config, view, this.writeAllowed);
173         }
174     }
175
176     /**
177      * Constructor helper.
178      */

179     private void initThangs()
180         throws DatabaseException {
181
182         keyThang = new DatabaseEntry();
183         primaryKeyThang = view.isSecondary() ? (new DatabaseEntry())
184                                              : keyThang;
185         valueThang = new DatabaseEntry();
186     }
187
188     /**
189      * Set entries from given byte arrays.
190      */

191     private void setThangs(byte[] keyBytes,
192                            byte[] priKeyBytes,
193                            byte[] valueBytes) {
194
195         keyThang.setData(KeyRange.copyBytes(keyBytes));
196
197         if (keyThang != primaryKeyThang) {
198             primaryKeyThang.setData(KeyRange.copyBytes(priKeyBytes));
199         }
200
201         valueThang.setData(KeyRange.copyBytes(valueBytes));
202     }
203
204     /**
205      * Closes the associated cursor.
206      */

207     void close()
208         throws DatabaseException {
209
210         if (joinCursor != null) {
211             JoinCursor toClose = joinCursor;
212             joinCursor = null;
213             toClose.close();
214         }
215         if (cursor != null) {
216             Cursor toClose = cursor.getCursor();
217             cursor = null;
218             view.currentTxn.closeCursor(toClose );
219         }
220         if (indexCursorsToClose != null) {
221             DataCursor[] toClose = indexCursorsToClose;
222             indexCursorsToClose = null;
223             for (int i = 0; i < toClose.length; i += 1) {
224                 toClose[i].close();
225             }
226         }
227     }
228
229     /**
230      * Repositions to a given raw key/data pair, or just past it if that record
231      * has been deleted.
232      *
233      * @return REPOS_EXACT, REPOS_NEXT or REPOS_EOF.
234      */

235     int repositionRange(byte[] keyBytes,
236                         byte[] priKeyBytes,
237                         byte[] valueBytes,
238                         boolean lockForWrite)
239         throws DatabaseException {
240
241         LockMode lockMode = getLockMode(lockForWrite);
242         OperationStatus status = null;
243
244         /* Use the given key/data byte arrays. */
245         setThangs(keyBytes, priKeyBytes, valueBytes);
246
247         /* Position on or after the given key/data pair. */
248         if (view.dupsAllowed) {
249             status = cursor.getSearchBothRange(keyThang, primaryKeyThang,
250                                                valueThang, lockMode);
251         }
252         if (status != OperationStatus.SUCCESS) {
253             status = cursor.getSearchKeyRange(keyThang, primaryKeyThang,
254                                               valueThang, lockMode);
255         }
256
257         /* Return the result of the operation. */
258         if (status == OperationStatus.SUCCESS) {
259             if (!KeyRange.equalBytes(keyBytes, 0, keyBytes.length,
260                                      keyThang.getData(),
261                                      keyThang.getOffset(),
262                                      keyThang.getSize())) {
263                 return REPOS_NEXT;
264             }
265             if (view.dupsAllowed) {
266                 DatabaseEntry thang = view.isSecondary() ? primaryKeyThang
267                                                          : valueThang;
268                 byte[] bytes = view.isSecondary() ? priKeyBytes
269                                                   : valueBytes;
270                 if (!KeyRange.equalBytes(bytes, 0, bytes.length,
271                                          thang.getData(),
272                                          thang.getOffset(),
273                                          thang.getSize())) {
274                     return REPOS_NEXT;
275                 }
276             }
277             return REPOS_EXACT;
278         } else {
279             return REPOS_EOF;
280         }
281     }
282
283     /**
284      * Repositions to a given raw key/data pair.
285      *
286      * @throws IllegalStateException when the database has unordered keys or
287      * unordered duplicates.
288      *
289      * @return whether the search succeeded.
290      */

291     boolean repositionExact(byte[] keyBytes,
292                             byte[] priKeyBytes,
293                             byte[] valueBytes,
294                             boolean lockForWrite)
295         throws DatabaseException {
296
297         LockMode lockMode = getLockMode(lockForWrite);
298         OperationStatus status = null;
299
300         /* Use the given key/data byte arrays. */
301         setThangs(keyBytes, priKeyBytes, valueBytes);
302
303         /* Position on the given key/data pair. */
304         if (view.recNumRenumber) {
305             /* getSearchBoth doesn't work with recno-renumber databases. */
306             status = cursor.getSearchKey(keyThang, primaryKeyThang,
307                                          valueThang, lockMode);
308         } else {
309             status = cursor.getSearchBoth(keyThang, primaryKeyThang,
310                                           valueThang, lockMode);
311         }
312         
313         return (status == OperationStatus.SUCCESS);
314     }
315
316     /**
317      * Returns the view for this cursor.
318      */

319     DataView getView() {
320
321         return view;
322     }
323
324     /**
325      * Returns the range for this cursor.
326      */

327     KeyRange getRange() {
328
329         return range;
330     }
331
332     /**
333      * Returns whether write is allowed for this cursor, as specified to the
334      * constructor.
335      */

336     boolean isWriteAllowed() {
337
338         return writeAllowed;
339     }
340
341     /**
342      * Returns the key object for the last record read.
343      */

344     Object JavaDoc getCurrentKey()
345         throws DatabaseException {
346
347         return view.makeKey(keyThang, primaryKeyThang);
348     }
349
350     /**
351      * Returns the value object for the last record read.
352      */

353     Object JavaDoc getCurrentValue()
354         throws DatabaseException {
355
356         return view.makeValue(primaryKeyThang, valueThang);
357     }
358
359     /**
360      * Returns the internal key entry.
361      */

362     DatabaseEntry getKeyThang() {
363         return keyThang;
364     }
365
366     /**
367      * Returns the internal primary key entry, which is the same object as the
368      * key entry if the cursor is not for a secondary database.
369      */

370     DatabaseEntry getPrimaryKeyThang() {
371         return primaryKeyThang;
372     }
373
374     /**
375      * Returns the internal value entry.
376      */

377     DatabaseEntry getValueThang() {
378         return valueThang;
379     }
380
381     /**
382      * Returns whether record number access is allowed.
383      */

384     boolean hasRecNumAccess() {
385
386         return view.recNumAccess;
387     }
388
389     /**
390      * Returns the record number for the last record read.
391      */

392     int getCurrentRecordNumber()
393         throws DatabaseException {
394
395         if (view.btreeRecNumDb) {
396             /* BTREE-RECNO access. */
397             if (otherThang == null) {
398                 otherThang = new DatabaseEntry();
399             }
400             DbCompat.getCurrentRecordNumber(cursor.getCursor(), otherThang,
401                                             getLockMode(false));
402             return DbCompat.getRecordNumber(otherThang);
403         } else {
404             /* QUEUE or RECNO database. */
405             return DbCompat.getRecordNumber(keyThang);
406         }
407     }
408     
409     /**
410      * Binding version of Cursor.getCurrent(), no join cursor allowed.
411      */

412     OperationStatus getCurrent(boolean lockForWrite)
413         throws DatabaseException {
414
415         checkNoJoinCursor();
416         return cursor.getCurrent(keyThang, primaryKeyThang, valueThang,
417                                  getLockMode(lockForWrite));
418     }
419     
420     /**
421      * Binding version of Cursor.getFirst(), join cursor is allowed.
422      */

423     OperationStatus getFirst(boolean lockForWrite)
424         throws DatabaseException {
425
426         LockMode lockMode = getLockMode(lockForWrite);
427         if (joinCursor != null) {
428             return joinCursor.getNext(keyThang, valueThang, lockMode);
429         } else {
430             return cursor.getFirst(keyThang, primaryKeyThang, valueThang,
431                                    lockMode);
432         }
433     }
434     
435     /**
436      * Binding version of Cursor.getNext(), join cursor is allowed.
437      */

438     OperationStatus getNext(boolean lockForWrite)
439         throws DatabaseException {
440
441         LockMode lockMode = getLockMode(lockForWrite);
442         if (joinCursor != null) {
443             return joinCursor.getNext(keyThang, valueThang, lockMode);
444         } else {
445             return cursor.getNext(keyThang, primaryKeyThang, valueThang,
446                                   lockMode);
447         }
448     }
449     
450     /**
451      * Binding version of Cursor.getNext(), join cursor is allowed.
452      */

453     OperationStatus getNextNoDup(boolean lockForWrite)
454         throws DatabaseException {
455
456         LockMode lockMode = getLockMode(lockForWrite);
457         if (joinCursor != null) {
458             return joinCursor.getNext(keyThang, valueThang, lockMode);
459         } else if (view.dupsView) {
460             return cursor.getNext
461                 (keyThang, primaryKeyThang, valueThang, lockMode);
462         } else {
463             return cursor.getNextNoDup
464                 (keyThang, primaryKeyThang, valueThang, lockMode);
465         }
466     }
467     
468     /**
469      * Binding version of Cursor.getNextDup(), no join cursor allowed.
470      */

471     OperationStatus getNextDup(boolean lockForWrite)
472         throws DatabaseException {
473
474         checkNoJoinCursor();
475         if (view.dupsView) {
476             return null;
477         } else {
478             return cursor.getNextDup
479                 (keyThang, primaryKeyThang, valueThang,
480                  getLockMode(lockForWrite));
481         }
482     }
483     
484     /**
485      * Binding version of Cursor.getLast(), no join cursor allowed.
486      */

487     OperationStatus getLast(boolean lockForWrite)
488         throws DatabaseException {
489
490         checkNoJoinCursor();
491         return cursor.getLast(keyThang, primaryKeyThang, valueThang,
492                               getLockMode(lockForWrite));
493     }
494     
495     /**
496      * Binding version of Cursor.getPrev(), no join cursor allowed.
497      */

498     OperationStatus getPrev(boolean lockForWrite)
499         throws DatabaseException {
500
501         checkNoJoinCursor();
502         return cursor.getPrev(keyThang, primaryKeyThang, valueThang,
503                               getLockMode(lockForWrite));
504     }
505     
506     /**
507      * Binding version of Cursor.getPrevNoDup(), no join cursor allowed.
508      */

509     OperationStatus getPrevNoDup(boolean lockForWrite)
510         throws DatabaseException {
511
512         checkNoJoinCursor();
513         LockMode lockMode = getLockMode(lockForWrite);
514         if (view.dupsView) {
515             return null;
516         } else if (view.dupsView) {
517             return cursor.getPrev
518                 (keyThang, primaryKeyThang, valueThang, lockMode);
519         } else {
520             return cursor.getPrevNoDup
521                 (keyThang, primaryKeyThang, valueThang, lockMode);
522         }
523     }
524     
525     /**
526      * Binding version of Cursor.getPrevDup(), no join cursor allowed.
527      */

528     OperationStatus getPrevDup(boolean lockForWrite)
529         throws DatabaseException {
530
531         checkNoJoinCursor();
532         if (view.dupsView) {
533             return null;
534         } else {
535             return cursor.getPrevDup
536                 (keyThang, primaryKeyThang, valueThang,
537                  getLockMode(lockForWrite));
538         }
539     }
540     
541     /**
542      * Binding version of Cursor.getSearchKey(), no join cursor allowed.
543      * Searches by record number in a BTREE-RECNO db with RECNO access.
544      */

545     OperationStatus getSearchKey(Object JavaDoc key, Object JavaDoc value,
546                                  boolean lockForWrite)
547         throws DatabaseException {
548
549         checkNoJoinCursor();
550         if (view.dupsView) {
551             if (view.useKey(key, value, primaryKeyThang, view.dupsRange)) {
552                 KeyRange.copy(view.dupsKey, keyThang);
553                 return cursor.getSearchBoth
554                     (keyThang, primaryKeyThang, valueThang,
555                      getLockMode(lockForWrite));
556             }
557         } else {
558             if (view.useKey(key, value, keyThang, range)) {
559                 return doGetSearchKey(lockForWrite);
560             }
561         }
562         return OperationStatus.NOTFOUND;
563     }
564     
565     /**
566      * Pass-thru version of Cursor.getSearchKey().
567      * Searches by record number in a BTREE-RECNO db with RECNO access.
568      */

569     private OperationStatus doGetSearchKey(boolean lockForWrite)
570         throws DatabaseException {
571
572         LockMode lockMode = getLockMode(lockForWrite);
573         if (view.btreeRecNumAccess) {
574             return cursor.getSearchRecordNumber(keyThang, primaryKeyThang,
575                                                 valueThang, lockMode);
576         } else {
577             return cursor.getSearchKey(keyThang, primaryKeyThang,
578                                        valueThang, lockMode);
579         }
580     }
581     
582     /**
583      * Binding version of Cursor.getSearchKeyRange(), no join cursor allowed.
584      */

585     OperationStatus getSearchKeyRange(Object JavaDoc key, Object JavaDoc value,
586                                       boolean lockForWrite)
587         throws DatabaseException {
588
589         checkNoJoinCursor();
590         LockMode lockMode = getLockMode(lockForWrite);
591         if (view.dupsView) {
592             if (view.useKey(key, value, primaryKeyThang, view.dupsRange)) {
593                 KeyRange.copy(view.dupsKey, keyThang);
594                 return cursor.getSearchBothRange
595                     (keyThang, primaryKeyThang, valueThang, lockMode);
596             }
597         } else {
598             if (view.useKey(key, value, keyThang, range)) {
599                 return cursor.getSearchKeyRange
600                     (keyThang, primaryKeyThang, valueThang, lockMode);
601             }
602         }
603         return OperationStatus.NOTFOUND;
604     }
605
606     /**
607      * Find the given key and value using getSearchBoth if possible or a
608      * sequential scan otherwise, no join cursor allowed.
609      */

610     OperationStatus findBoth(Object JavaDoc key, Object JavaDoc value, boolean lockForWrite)
611         throws DatabaseException {
612
613         checkNoJoinCursor();
614         LockMode lockMode = getLockMode(lockForWrite);
615         view.useValue(value, valueThang, null);
616         if (view.dupsView) {
617             if (view.useKey(key, value, primaryKeyThang, view.dupsRange)) {
618                 KeyRange.copy(view.dupsKey, keyThang);
619                 if (otherThang == null) {
620                     otherThang = new DatabaseEntry();
621                 }
622                 OperationStatus status = cursor.getSearchBoth
623                     (keyThang, primaryKeyThang, otherThang, lockMode);
624                 if (status == OperationStatus.SUCCESS &&
625                     KeyRange.equalBytes(otherThang, valueThang)) {
626                     return status;
627                 }
628             }
629         } else if (view.useKey(key, value, keyThang, range)) {
630             if (view.isSecondary()) {
631                 if (otherThang == null) {
632                     otherThang = new DatabaseEntry();
633                 }
634                 OperationStatus status = cursor.getSearchKey(keyThang,
635                                                              primaryKeyThang,
636                                                              otherThang,
637                                                              lockMode);
638                 while (status == OperationStatus.SUCCESS) {
639                     if (KeyRange.equalBytes(otherThang, valueThang)) {
640                         return status;
641                     }
642                     status = cursor.getNextDup(keyThang, primaryKeyThang,
643                                                otherThang, lockMode);
644                 }
645                 /* if status != SUCCESS set range cursor to invalid? */
646             } else {
647                 return cursor.getSearchBoth(keyThang, null, valueThang,
648                                             lockMode);
649             }
650         }
651         return OperationStatus.NOTFOUND;
652     }
653
654     /**
655      * Find the given value using getSearchBoth if possible or a sequential
656      * scan otherwise, no join cursor allowed.
657      */

658     OperationStatus findValue(Object JavaDoc value, boolean findFirst)
659         throws DatabaseException {
660
661         checkNoJoinCursor();
662
663         if (view.entityBinding != null && !view.isSecondary() &&
664             (findFirst || !view.dupsAllowed)) {
665             return findBoth(null, value, false);
666         } else {
667             if (otherThang == null) {
668                 otherThang = new DatabaseEntry();
669             }
670             view.useValue(value, otherThang, null);
671             OperationStatus status = findFirst ? getFirst(false)
672                                                : getLast(false);
673             while (status == OperationStatus.SUCCESS) {
674                 if (KeyRange.equalBytes(valueThang, otherThang)) {
675                     break;
676                 }
677                 status = findFirst ? getNext(false) : getPrev(false);
678             }
679             return status;
680         }
681     }
682
683     /**
684      * Calls Cursor.count(), no join cursor allowed.
685      */

686     int count()
687         throws DatabaseException {
688
689         checkNoJoinCursor();
690         if (view.dupsView) {
691             return 1;
692         } else {
693             return cursor.count();
694         }
695     }
696
697     /**
698      * Binding version of Cursor.putCurrent().
699      */

700     OperationStatus putCurrent(Object JavaDoc value)
701         throws DatabaseException {
702
703         checkWriteAllowed(false);
704         view.useValue(value, valueThang, keyThang);
705         
706         /*
707          * Workaround for a DB core problem: With HASH type a put() with
708          * different data is allowed.
709          */

710         boolean hashWorkaround = (view.dupsOrdered && !view.ordered);
711         if (hashWorkaround) {
712             if (otherThang == null) {
713                 otherThang = new DatabaseEntry();
714             }
715             cursor.getCurrent(keyThang, primaryKeyThang, otherThang,
716                               LockMode.DEFAULT);
717             if (KeyRange.equalBytes(valueThang, otherThang)) {
718                 return OperationStatus.SUCCESS;
719             } else {
720                 throw new IllegalArgumentException JavaDoc(
721                   "Current data differs from put data with sorted duplicates");
722             }
723         }
724
725         return cursor.putCurrent(valueThang);
726     }
727
728     /**
729      * Binding version of Cursor.putAfter().
730      */

731     OperationStatus putAfter(Object JavaDoc value)
732         throws DatabaseException {
733
734         checkWriteAllowed(false);
735         view.useValue(value, valueThang, null); /* why no key check? */
736         return cursor.putAfter(keyThang, valueThang);
737     }
738
739     /**
740      * Binding version of Cursor.putBefore().
741      */

742     OperationStatus putBefore(Object JavaDoc value)
743         throws DatabaseException {
744
745         checkWriteAllowed(false);
746         view.useValue(value, valueThang, keyThang);
747         return cursor.putBefore(keyThang, valueThang);
748     }
749
750     /**
751      * Binding version of Cursor.put(), optionally returning the old value and
752      * optionally using the current key instead of the key parameter.
753      */

754     OperationStatus put(Object JavaDoc key, Object JavaDoc value, Object JavaDoc[] oldValue,
755                         boolean useCurrentKey)
756         throws DatabaseException {
757
758         initForPut(key, value, oldValue, useCurrentKey);
759         return cursor.put(keyThang, valueThang);
760     }
761
762     /**
763      * Binding version of Cursor.putNoOverwrite(), optionally using the current
764      * key instead of the key parameter.
765      */

766     OperationStatus putNoOverwrite(Object JavaDoc key, Object JavaDoc value,
767                                    boolean useCurrentKey)
768         throws DatabaseException {
769
770         initForPut(key, value, null, useCurrentKey);
771         return cursor.putNoOverwrite(keyThang, valueThang);
772     }
773
774     /**
775      * Binding version of Cursor.putNoDupData(), optionally returning the old
776      * value and optionally using the current key instead of the key parameter.
777      */

778     OperationStatus putNoDupData(Object JavaDoc key, Object JavaDoc value, Object JavaDoc[] oldValue,
779                                  boolean useCurrentKey)
780         throws DatabaseException {
781
782         initForPut(key, value, oldValue, useCurrentKey);
783         if (view.dupsOrdered) {
784             return cursor.putNoDupData(keyThang, valueThang);
785         } else {
786             if (view.dupsAllowed) {
787                 /* Unordered duplicates. */
788                 OperationStatus status =
789                         cursor.getSearchBoth(keyThang, primaryKeyThang,
790                                              valueThang,
791                                              getLockMode(false));
792                 if (status == OperationStatus.SUCCESS) {
793                     return OperationStatus.KEYEXIST;
794                 } else {
795                     return cursor.put(keyThang, valueThang);
796                 }
797             } else {
798                 /* No duplicates. */
799                 return cursor.putNoOverwrite(keyThang, valueThang);
800             }
801         }
802     }
803
804     /**
805      * Do setup for a put() operation.
806      */

807     private void initForPut(Object JavaDoc key, Object JavaDoc value, Object JavaDoc[] oldValue,
808                             boolean useCurrentKey)
809         throws DatabaseException {
810
811         checkWriteAllowed(false);
812         if (!useCurrentKey && !view.useKey(key, value, keyThang, range)) {
813             throw new IllegalArgumentException JavaDoc("key out of range");
814         }
815         if (oldValue != null) {
816             oldValue[0] = null;
817             if (!view.dupsAllowed) {
818                 OperationStatus status = doGetSearchKey(true);
819                 if (status == OperationStatus.SUCCESS) {
820                     oldValue[0] = getCurrentValue();
821                 }
822             }
823         }
824         view.useValue(value, valueThang, keyThang);
825     }
826
827     /**
828      * Sets the key entry to the begin key of a single key range, so the next
829      * time a putXxx() method is called that key will be used.
830      */

831     void useRangeKey() {
832         if (!range.isSingleKey()) {
833             throw new IllegalStateException JavaDoc();
834         }
835         KeyRange.copy(range.getSingleKey(), keyThang);
836     }
837
838     /**
839      * Perform an arbitrary database 'delete' operation.
840      */

841     OperationStatus delete()
842         throws DatabaseException {
843
844         checkWriteAllowed(true);
845         return cursor.delete();
846     }
847
848     /**
849      * Returns the lock mode to use for a getXxx() operation.
850      */

851     LockMode getLockMode(boolean lockForWrite) {
852
853         /* Read-uncommmitted takes precedence over write-locking. */
854
855         if (readUncommitted) {
856             return LockMode.READ_UNCOMMITTED;
857         } else if (lockForWrite) {
858             return view.currentTxn.getWriteLockMode();
859         } else {
860             return LockMode.DEFAULT;
861         }
862     }
863
864     /**
865      * Throws an exception if a join cursor is in use.
866      */

867     private void checkNoJoinCursor() {
868
869         if (joinCursor != null) {
870             throw new UnsupportedOperationException JavaDoc
871                 ("Not allowed with a join cursor");
872         }
873     }
874
875     /**
876      * Throws an exception if write is not allowed or if a join cursor is in
877      * use.
878      */

879     private void checkWriteAllowed(boolean allowSecondary) {
880
881         checkNoJoinCursor();
882
883         if (!writeAllowed || (!allowSecondary && view.isSecondary())) {
884             throw new UnsupportedOperationException JavaDoc
885                 ("Writing is not allowed");
886         }
887     }
888 }
889
Popular Tags