KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > test > PhantomTest


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

8
9 package com.sleepycat.je.test;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.util.Enumeration JavaDoc;
14
15 import junit.framework.Test;
16 import junit.framework.TestCase;
17 import junit.framework.TestSuite;
18
19 import com.sleepycat.bind.tuple.IntegerBinding;
20 import com.sleepycat.je.Cursor;
21 import com.sleepycat.je.CursorConfig;
22 import com.sleepycat.je.Database;
23 import com.sleepycat.je.DatabaseConfig;
24 import com.sleepycat.je.DatabaseEntry;
25 import com.sleepycat.je.DatabaseException;
26 import com.sleepycat.je.DeadlockException;
27 import com.sleepycat.je.Environment;
28 import com.sleepycat.je.EnvironmentConfig;
29 import com.sleepycat.je.LockMode;
30 import com.sleepycat.je.LockStats;
31 import com.sleepycat.je.OperationStatus;
32 import com.sleepycat.je.StatsConfig;
33 import com.sleepycat.je.Transaction;
34 import com.sleepycat.je.TransactionConfig;
35 import com.sleepycat.je.config.EnvironmentParams;
36 import com.sleepycat.je.junit.JUnitThread;
37 import com.sleepycat.je.log.FileManager;
38 import com.sleepycat.je.util.TestUtils;
39
40 /**
41  * Tests phantom prevention (range locking) added in SR [#10477].
42  *
43  * <p>We test that with a serializable txn, range locking will prevent phantoms
44  * from appearing. We also test that phantoms *do* appear for non-serializable
45  * isolation levels. These include read-uncommitted, read-committed and
46  * repeatable-read now.</p>
47  *
48  * <p>Test method names have the suffix _Sucess or _NotFound depending on
49  * whether they're testing a read operation with a SUCCESS or NOTFOUND outcome.
50  * If they're testing duplicates, the _Dup suffix is also added. Finally, a
51  * suffix is added for the isolation level at run time.</p>
52  *
53  * <p>All tests are for the case where the reader txn locks a range and then
54  * the writer txn tries to insert into the locked range. The reverse (where
55  * the writer inserts first) works without range locking because the reader
56  * will block on the inserted key, so we don't test that here.</p>
57  *
58  * <p>We test all read operations with and without duplicates (with duplicates
59  * the test name has _Dup appended) except for the following cases which are
60  * meaningless without duplicates because get{Next,Prev}Dup always return
61  * NOTFOUND when duplicates are not configured:
62  * testGetNextDup_Success, testGetNextDup_NotFound,
63  * testGetPrevDup_Success, testGetPrevDup_NotFound.</p>
64  */

65 public class PhantomTest extends TestCase {
66
67     private static final TransactionConfig READ_UNCOMMITTED_CONFIG
68                                            = new TransactionConfig();
69     private static final TransactionConfig READ_COMMITTED_CONFIG
70                                            = new TransactionConfig();
71     private static final TransactionConfig REPEATABLE_READ_CONFIG
72                                            = new TransactionConfig();
73     private static final TransactionConfig SERIALIZABLE_CONFIG
74                                            = new TransactionConfig();
75     static {
76         READ_UNCOMMITTED_CONFIG.setReadUncommitted(true);
77         READ_COMMITTED_CONFIG.setReadCommitted(true);
78         SERIALIZABLE_CONFIG.setSerializableIsolation(true);
79     }
80     private static final TransactionConfig[] TXN_CONFIGS = {
81         READ_UNCOMMITTED_CONFIG,
82         READ_COMMITTED_CONFIG,
83         REPEATABLE_READ_CONFIG,
84         SERIALIZABLE_CONFIG,
85     };
86
87     private static final String JavaDoc DB_NAME = "PhantomTest";
88
89     public static Test suite() {
90         TestSuite all = new TestSuite();
91         for (int i = 0; i < TXN_CONFIGS.length; i += 1) {
92             TestSuite suite = new TestSuite(PhantomTest.class);
93             Enumeration JavaDoc e = suite.tests();
94             while (e.hasMoreElements()) {
95                 PhantomTest test = (PhantomTest) e.nextElement();
96                 test.init(TXN_CONFIGS[i]);
97                 all.addTest(test);
98             }
99         }
100         return all;
101     }
102
103     private static final int MAX_INSERT_MILLIS = 5000;
104
105     private File JavaDoc envHome;
106     private Environment env;
107     private Database db;
108     private TransactionConfig txnConfig;
109     private JUnitThread writerThread;
110     private boolean txnSerializable;
111     private boolean dups;
112     private boolean insertFinished;
113
114     public PhantomTest() {
115         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
116     }
117
118     private void init(TransactionConfig txnConfig) {
119         this.txnConfig = txnConfig;
120         txnSerializable = (txnConfig == SERIALIZABLE_CONFIG);
121     }
122
123     public void setUp()
124         throws IOException JavaDoc {
125
126         TestUtils.removeLogFiles("Setup", envHome, false);
127         TestUtils.removeFiles("Setup", envHome, FileManager.DEL_SUFFIX);
128     }
129     
130     public void tearDown()
131         throws Exception JavaDoc {
132
133         String JavaDoc txnType;
134         if (txnConfig == SERIALIZABLE_CONFIG) {
135             txnType = "-Serializable";
136         } else if (txnConfig == REPEATABLE_READ_CONFIG) {
137             txnType = "-RepeatableRead";
138         } else if (txnConfig == READ_COMMITTED_CONFIG) {
139             txnType = "-ReadCommitted";
140         } else if (txnConfig == READ_UNCOMMITTED_CONFIG) {
141             txnType = "-ReadUncommitted";
142         } else {
143             throw new IllegalStateException JavaDoc();
144         }
145         setName(getName() + txnType);
146
147         try {
148             if (env != null) {
149                 env.close();
150             }
151         } catch (Throwable JavaDoc e) {
152             System.out.println("tearDown: " + e);
153         }
154                 
155         try {
156             //*
157
TestUtils.removeLogFiles("tearDown", envHome, true);
158             TestUtils.removeFiles("tearDown", envHome, FileManager.DEL_SUFFIX);
159             //*/
160
} catch (Throwable JavaDoc e) {
161             System.out.println("tearDown: " + e);
162         }
163
164         envHome = null;
165         env = null;
166         db = null;
167
168         if (writerThread != null) {
169             while (writerThread.isAlive()) {
170                 writerThread.interrupt();
171                 Thread.yield();
172             }
173             writerThread = null;
174         }
175     }
176
177     /**
178      * Opens the environment and database.
179      */

180     private void openEnv(boolean dups)
181         throws DatabaseException {
182
183         openEnv(dups, null);
184     }
185
186     /**
187      * Opens the environment and database.
188      */

189     private void openEnv(boolean dups, EnvironmentConfig envConfig)
190         throws DatabaseException {
191
192         this.dups = dups;
193         if (envConfig == null) {
194             envConfig = TestUtils.initEnvConfig();
195             /* Control over isolation level is required by this test. */
196             TestUtils.clearIsolationLevel(envConfig);
197         }
198
199         /* Disable the daemons so the don't interfere with stats. */
200         envConfig.setConfigParam
201             (EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false");
202         envConfig.setConfigParam
203             (EnvironmentParams.ENV_RUN_CLEANER.getName(), "false");
204         envConfig.setConfigParam
205             (EnvironmentParams.ENV_RUN_CHECKPOINTER.getName(), "false");
206         envConfig.setConfigParam
207             (EnvironmentParams.ENV_RUN_INCOMPRESSOR.getName(), "false");
208
209         envConfig.setAllowCreate(true);
210         envConfig.setTransactional(true);
211         env = new Environment(envHome, envConfig);
212
213         DatabaseConfig dbConfig = new DatabaseConfig();
214         dbConfig.setAllowCreate(true);
215         dbConfig.setTransactional(true);
216         dbConfig.setSortedDuplicates(dups);
217         db = env.openDatabase(null, DB_NAME, dbConfig);
218     }
219
220     /**
221      * Closes the environment and database.
222      */

223     private void closeEnv()
224         throws DatabaseException {
225
226         if (db != null) {
227             db.close();
228             db = null;
229         }
230         if (env != null) {
231             env.close();
232             env = null;
233         }
234     }
235     
236     public void testGetSearchKey_Success()
237         throws DatabaseException, InterruptedException JavaDoc {
238
239         openEnv(false);
240
241         /* Insert key 2. */
242         insert(2);
243
244         /* getSearchKey returns key 2. */
245         Transaction readerTxn = env.beginTransaction(null, txnConfig);
246         Cursor cursor = db.openCursor(readerTxn, null);
247         assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
248
249         /* Insertions are never blocked. */
250         try {
251             insert(1);
252         } catch (DeadlockException e) {
253             fail();
254         }
255
256         cursor.close();
257         readerTxn.commitNoSync();
258         closeEnv();
259     }
260     
261     public void testGetSearchKey_Success_Dup()
262         throws DatabaseException, InterruptedException JavaDoc {
263
264         openEnv(true);
265
266         /* Insert dups. */
267         insert(1, 2);
268         insert(1, 3);
269
270         /* getSearchKey returns key {1,2}. */
271         Transaction readerTxn = env.beginTransaction(null, txnConfig);
272         Cursor cursor = db.openCursor(readerTxn, null);
273         assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1, 2));
274
275         /* Insertions are never blocked. */
276         try {
277             insert(1, 1);
278         } catch (DeadlockException e) {
279             fail();
280         }
281
282         cursor.close();
283         readerTxn.commitNoSync();
284         closeEnv();
285     }
286     
287     public void testGetSearchKey_NotFound()
288         throws DatabaseException, InterruptedException JavaDoc {
289
290         openEnv(false);
291
292         /* Insert key 1. */
293         insert(1);
294
295         /* getSearchKey for key 2 returns NOTFOUND. */
296         Transaction readerTxn = env.beginTransaction(null, txnConfig);
297         Cursor cursor = db.openCursor(readerTxn, null);
298         assertEquals(OperationStatus.NOTFOUND, searchKey(cursor, 2));
299
300         /* Insert key 2 in a writer thread. */
301         startInsert(2);
302         
303         /*
304          * If serializable, getSearchKey should return NOTFOUND again;
305          * otherwise getSearchKey should see key 2.
306          */

307         if (txnSerializable) {
308             assertEquals(OperationStatus.NOTFOUND, searchKey(cursor, 2));
309         } else {
310             assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
311         }
312
313         /* Close reader to allow writer to finish. */
314         cursor.close();
315         readerTxn.commitNoSync();
316         waitForInsert();
317
318         /* getSearchKey returns key 2. */
319         readerTxn = env.beginTransaction(null, txnConfig);
320         cursor = db.openCursor(readerTxn, null);
321         assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
322         cursor.close();
323         readerTxn.commit();
324
325         closeEnv();
326     }
327     
328     public void testGetSearchKey_NotFound_Dup()
329         throws DatabaseException, InterruptedException JavaDoc {
330
331         openEnv(true);
332
333         /* Insert dups. */
334         insert(2, 1);
335         insert(2, 2);
336
337         /* getSearchKey for {1,1} returns NOTFOUND. */
338         Transaction readerTxn = env.beginTransaction(null, txnConfig);
339         Cursor cursor = db.openCursor(readerTxn, null);
340         assertEquals(OperationStatus.NOTFOUND, searchKey(cursor, 1, 1));
341
342         /* Insert {1,1} in a writer thread. */
343         startInsert(1, 1);
344         
345         /*
346          * If serializable, getSearchKey should return NOTFOUND again;
347          * otherwise getSearchKey should see {1,1}.
348          */

349         if (txnSerializable) {
350             assertEquals(OperationStatus.NOTFOUND, searchKey(cursor, 1, 1));
351         } else {
352             assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1, 1));
353         }
354
355         /* Close reader to allow writer to finish. */
356         cursor.close();
357         readerTxn.commitNoSync();
358         waitForInsert();
359
360         /* getSearchKey returns {1,1}. */
361         readerTxn = env.beginTransaction(null, txnConfig);
362         cursor = db.openCursor(readerTxn, null);
363         assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1, 1));
364         cursor.close();
365         readerTxn.commit();
366
367         closeEnv();
368     }
369     
370     public void testGetSearchBoth_Success()
371         throws DatabaseException, InterruptedException JavaDoc {
372
373         openEnv(false);
374
375         /* Insert key 2. */
376         insert(2);
377
378         /* getSearchBoth returns {2,0}. */
379         Transaction readerTxn = env.beginTransaction(null, txnConfig);
380         Cursor cursor = db.openCursor(readerTxn, null);
381         assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 0));
382
383         /* Insertions are never blocked. */
384         try {
385             insert(1);
386         } catch (DeadlockException e) {
387             fail();
388         }
389
390         cursor.close();
391         readerTxn.commitNoSync();
392         closeEnv();
393     }
394     
395     public void testGetSearchBoth_Success_Dup()
396         throws DatabaseException, InterruptedException JavaDoc {
397
398         openEnv(true);
399
400         /* Insert dups. */
401         insert(1, 1);
402         insert(1, 3);
403
404         /* getSearchBoth returns key {1,3}. */
405         Transaction readerTxn = env.beginTransaction(null, txnConfig);
406         Cursor cursor = db.openCursor(readerTxn, null);
407         assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 3));
408
409         /* Insertions are never blocked. */
410         try {
411             insert(1, 2);
412         } catch (DeadlockException e) {
413             fail();
414         }
415
416         cursor.close();
417         readerTxn.commitNoSync();
418         closeEnv();
419     }
420     
421     public void testGetSearchBoth_NotFound()
422         throws DatabaseException, InterruptedException JavaDoc {
423
424         openEnv(false);
425
426         /* Insert key 1. */
427         insert(1);
428
429         /* getSearchBoth for key 2 returns NOTFOUND. */
430         Transaction readerTxn = env.beginTransaction(null, txnConfig);
431         Cursor cursor = db.openCursor(readerTxn, null);
432         assertEquals(OperationStatus.NOTFOUND, searchBoth(cursor, 2));
433
434         /* Insert key 2 in a writer thread. */
435         startInsert(2);
436         
437         /*
438          * If serializable, getSearchBoth should return NOTFOUND again;
439          * otherwise getSearchBoth should see key 2.
440          */

441         if (txnSerializable) {
442             assertEquals(OperationStatus.NOTFOUND, searchBoth(cursor, 2));
443         } else {
444             assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2));
445         }
446
447         /* Close reader to allow writer to finish. */
448         cursor.close();
449         readerTxn.commitNoSync();
450         waitForInsert();
451
452         /* getSearchBoth returns key 2. */
453         readerTxn = env.beginTransaction(null, txnConfig);
454         cursor = db.openCursor(readerTxn, null);
455         assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2));
456         cursor.close();
457         readerTxn.commit();
458
459         closeEnv();
460     }
461     
462     public void testGetSearchBoth_NotFound_Dup()
463         throws DatabaseException, InterruptedException JavaDoc {
464
465         openEnv(true);
466
467         /* Insert dups. */
468         insert(1, 1);
469         insert(1, 3);
470
471         /* getSearchBoth for {1,2} returns NOTFOUND. */
472         Transaction readerTxn = env.beginTransaction(null, txnConfig);
473         Cursor cursor = db.openCursor(readerTxn, null);
474         assertEquals(OperationStatus.NOTFOUND, searchBoth(cursor, 1, 2));
475
476         /* Insert {1,2} in a writer thread. */
477         startInsert(1, 2);
478         
479         /*
480          * If serializable, getSearchBoth should return NOTFOUND again;
481          * otherwise getSearchBoth should see {1,2}.
482          */

483         if (txnSerializable) {
484             assertEquals(OperationStatus.NOTFOUND, searchBoth(cursor, 1, 2));
485         } else {
486             assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
487         }
488
489         /* Close reader to allow writer to finish. */
490         cursor.close();
491         readerTxn.commitNoSync();
492         waitForInsert();
493
494         /* getSearchBoth returns {1,2}. */
495         readerTxn = env.beginTransaction(null, txnConfig);
496         cursor = db.openCursor(readerTxn, null);
497         assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
498         cursor.close();
499         readerTxn.commit();
500
501         closeEnv();
502     }
503     
504     public void testGetSearchKeyRange_Success()
505         throws DatabaseException, InterruptedException JavaDoc {
506
507         openEnv(false);
508         DatabaseEntry key = new DatabaseEntry();
509         DatabaseEntry data = new DatabaseEntry();
510         OperationStatus status;
511
512         /* Insert key 1 and 3. */
513         insert(1);
514         insert(3);
515
516         /* getSearchKeyRange for key 2 returns key 3. */
517         Transaction readerTxn = env.beginTransaction(null, txnConfig);
518         Cursor cursor = db.openCursor(readerTxn, null);
519         IntegerBinding.intToEntry(2, key);
520         status = cursor.getSearchKeyRange(key, data, null);
521         assertEquals(OperationStatus.SUCCESS, status);
522         assertEquals(3, IntegerBinding.entryToInt(key));
523
524         /* Insert key 2 in a writer thread. */
525         startInsert(2);
526         
527         /*
528          * If serializable, getSearchKeyRange should return key 3 again;
529          * otherwise getSearchKeyRange should see key 2.
530          */

531         IntegerBinding.intToEntry(2, key);
532         status = cursor.getSearchKeyRange(key, data, null);
533         assertEquals(OperationStatus.SUCCESS, status);
534         if (txnSerializable) {
535             assertEquals(3, IntegerBinding.entryToInt(key));
536         } else {
537             assertEquals(2, IntegerBinding.entryToInt(key));
538         }
539
540         /* Close reader to allow writer to finish. */
541         cursor.close();
542         readerTxn.commitNoSync();
543         waitForInsert();
544
545         /* getSearchKeyRange returns key 2. */
546         readerTxn = env.beginTransaction(null, txnConfig);
547         cursor = db.openCursor(readerTxn, null);
548         IntegerBinding.intToEntry(2, key);
549         status = cursor.getSearchKeyRange(key, data, null);
550         assertEquals(OperationStatus.SUCCESS, status);
551         assertEquals(2, IntegerBinding.entryToInt(key));
552         cursor.close();
553         readerTxn.commit();
554
555         closeEnv();
556     }
557     
558     public void testGetSearchKeyRange_Success_Dup()
559         throws DatabaseException, InterruptedException JavaDoc {
560
561         openEnv(true);
562         DatabaseEntry key = new DatabaseEntry();
563         DatabaseEntry data = new DatabaseEntry();
564         OperationStatus status;
565
566         /* Insert dups. */
567         insert(1, 1);
568         insert(1, 2);
569         insert(3, 2);
570         insert(3, 3);
571
572         /* getSearchKeyRange for key 2 returns {3,2}. */
573         Transaction readerTxn = env.beginTransaction(null, txnConfig);
574         Cursor cursor = db.openCursor(readerTxn, null);
575         IntegerBinding.intToEntry(2, key);
576         status = cursor.getSearchKeyRange(key, data, null);
577         assertEquals(3, IntegerBinding.entryToInt(key));
578         assertEquals(2, IntegerBinding.entryToInt(data));
579         assertEquals(OperationStatus.SUCCESS, status);
580
581         /* Insert {3,1} in a writer thread. */
582         startInsert(3, 1);
583         
584         /*
585          * If serializable, getSearchKeyRange should return {3,2} again;
586          * otherwise getSearchKeyRange should see {3,1}.
587          */

588         IntegerBinding.intToEntry(2, key);
589         status = cursor.getSearchKeyRange(key, data, null);
590         assertEquals(OperationStatus.SUCCESS, status);
591         if (txnSerializable) {
592             assertEquals(3, IntegerBinding.entryToInt(key));
593             assertEquals(2, IntegerBinding.entryToInt(data));
594         } else {
595             assertEquals(3, IntegerBinding.entryToInt(key));
596             assertEquals(1, IntegerBinding.entryToInt(data));
597         }
598
599         /* Close reader to allow writer to finish. */
600         cursor.close();
601         readerTxn.commitNoSync();
602         waitForInsert();
603
604         /* getSearchKeyRange returns {3,1}. */
605         readerTxn = env.beginTransaction(null, txnConfig);
606         cursor = db.openCursor(readerTxn, null);
607         IntegerBinding.intToEntry(2, key);
608         status = cursor.getSearchKeyRange(key, data, null);
609         assertEquals(OperationStatus.SUCCESS, status);
610         assertEquals(3, IntegerBinding.entryToInt(key));
611         assertEquals(1, IntegerBinding.entryToInt(data));
612         cursor.close();
613         readerTxn.commit();
614
615         closeEnv();
616     }
617     
618     public void testGetSearchKeyRange_NotFound()
619         throws DatabaseException, InterruptedException JavaDoc {
620
621         openEnv(false);
622         DatabaseEntry key = new DatabaseEntry();
623         DatabaseEntry data = new DatabaseEntry();
624         OperationStatus status;
625
626         /* Insert key 1. */
627         insert(1);
628
629         /* getSearchKeyRange for key 2 returns NOTFOUND. */
630         Transaction readerTxn = env.beginTransaction(null, txnConfig);
631         Cursor cursor = db.openCursor(readerTxn, null);
632         IntegerBinding.intToEntry(2, key);
633         status = cursor.getSearchKeyRange(key, data, null);
634         assertEquals(OperationStatus.NOTFOUND, status);
635
636         /* Insert key 3 in a writer thread. */
637         startInsert(3);
638         
639         /*
640          * If serializable, getSearchKeyRange should return NOTFOUND again;
641          * otherwise getSearchKeyRange should see key 3.
642          */

643         IntegerBinding.intToEntry(2, key);
644         status = cursor.getSearchKeyRange(key, data, null);
645         if (txnSerializable) {
646             assertEquals(OperationStatus.NOTFOUND, status);
647         } else {
648             assertEquals(OperationStatus.SUCCESS, status);
649             assertEquals(3, IntegerBinding.entryToInt(key));
650         }
651
652         /* Close reader to allow writer to finish. */
653         cursor.close();
654         readerTxn.commitNoSync();
655         waitForInsert();
656
657         /* getSearchKeyRange returns key 3. */
658         readerTxn = env.beginTransaction(null, txnConfig);
659         cursor = db.openCursor(readerTxn, null);
660         IntegerBinding.intToEntry(2, key);
661         status = cursor.getSearchKeyRange(key, data, null);
662         assertEquals(OperationStatus.SUCCESS, status);
663         assertEquals(3, IntegerBinding.entryToInt(key));
664         cursor.close();
665         readerTxn.commit();
666
667         closeEnv();
668     }
669     
670     public void testGetSearchKeyRange_NotFound_Dup()
671         throws DatabaseException, InterruptedException JavaDoc {
672
673         openEnv(true);
674         DatabaseEntry key = new DatabaseEntry();
675         DatabaseEntry data = new DatabaseEntry();
676         OperationStatus status;
677
678         /* Insert dups. */
679         insert(1, 1);
680         insert(1, 2);
681
682         /* getSearchKeyRange for key 2 returns NOTFOUND. */
683         Transaction readerTxn = env.beginTransaction(null, txnConfig);
684         Cursor cursor = db.openCursor(readerTxn, null);
685         IntegerBinding.intToEntry(2, key);
686         status = cursor.getSearchKeyRange(key, data, null);
687         assertEquals(OperationStatus.NOTFOUND, status);
688
689         /* Insert {3,1} in a writer thread. */
690         startInsert(3, 1);
691         
692         /*
693          * If serializable, getSearchKeyRange should return NOTFOUND again;
694          * otherwise getSearchKeyRange should see {3,1}.
695          */

696         IntegerBinding.intToEntry(2, key);
697         status = cursor.getSearchKeyRange(key, data, null);
698         if (txnSerializable) {
699             assertEquals(OperationStatus.NOTFOUND, status);
700         } else {
701             assertEquals(OperationStatus.SUCCESS, status);
702             assertEquals(3, IntegerBinding.entryToInt(key));
703             assertEquals(1, IntegerBinding.entryToInt(data));
704         }
705
706         /* Close reader to allow writer to finish. */
707         cursor.close();
708         readerTxn.commitNoSync();
709         waitForInsert();
710
711         /* getSearchKeyRange returns {3,1}. */
712         readerTxn = env.beginTransaction(null, txnConfig);
713         cursor = db.openCursor(readerTxn, null);
714         IntegerBinding.intToEntry(2, key);
715         status = cursor.getSearchKeyRange(key, data, null);
716         assertEquals(OperationStatus.SUCCESS, status);
717         assertEquals(3, IntegerBinding.entryToInt(key));
718         assertEquals(1, IntegerBinding.entryToInt(data));
719         cursor.close();
720         readerTxn.commit();
721
722         closeEnv();
723     }
724     
725     /*
726      * A testGetSearchBothRange_Success test case is not possible because it is
727      * not possible to insert a duplicate when only one LN for the key already
728      * exists, without locking the existing LN. Therefore, the insert thread
729      * will deadlock with the reader thread, which has the existing LN locked.
730      * This is a testing anomoly, not a bug.
731      */

732     
733     public void testGetSearchBothRange_Success_Dup()
734         throws DatabaseException, InterruptedException JavaDoc {
735
736         openEnv(true);
737         DatabaseEntry key = new DatabaseEntry();
738         DatabaseEntry data = new DatabaseEntry();
739         OperationStatus status;
740
741         /* Insert dups. */
742         insert(1, 1);
743         insert(1, 2);
744         insert(3, 2);
745         insert(3, 3);
746
747         /* getSearchBothRange for {3, 0} returns {3,2}. */
748         Transaction readerTxn = env.beginTransaction(null, txnConfig);
749         Cursor cursor = db.openCursor(readerTxn, null);
750         IntegerBinding.intToEntry(3, key);
751         IntegerBinding.intToEntry(0, data);
752         status = cursor.getSearchBothRange(key, data, null);
753         assertEquals(OperationStatus.SUCCESS, status);
754         assertEquals(3, IntegerBinding.entryToInt(key));
755         assertEquals(2, IntegerBinding.entryToInt(data));
756
757         /* Insert {3,1} in a writer thread. */
758         startInsert(3, 1);
759         
760         /*
761          * If serializable, getSearchBothRange should return {3,2} again;
762          * otherwise getSearchBothRange should see {3,1}.
763          */

764         IntegerBinding.intToEntry(3, key);
765         IntegerBinding.intToEntry(0, data);
766         status = cursor.getSearchBothRange(key, data, null);
767         assertEquals(OperationStatus.SUCCESS, status);
768         if (txnSerializable) {
769             assertEquals(3, IntegerBinding.entryToInt(key));
770             assertEquals(2, IntegerBinding.entryToInt(data));
771         } else {
772             assertEquals(3, IntegerBinding.entryToInt(key));
773             assertEquals(1, IntegerBinding.entryToInt(data));
774         }
775
776         /* Close reader to allow writer to finish. */
777         cursor.close();
778         readerTxn.commitNoSync();
779         waitForInsert();
780
781         /* getSearchBothRange returns {3,1}. */
782         readerTxn = env.beginTransaction(null, txnConfig);
783         cursor = db.openCursor(readerTxn, null);
784         IntegerBinding.intToEntry(3, key);
785         IntegerBinding.intToEntry(0, data);
786         status = cursor.getSearchBothRange(key, data, null);
787         assertEquals(OperationStatus.SUCCESS, status);
788         assertEquals(3, IntegerBinding.entryToInt(key));
789         assertEquals(1, IntegerBinding.entryToInt(data));
790         cursor.close();
791         readerTxn.commit();
792
793         closeEnv();
794     }
795     
796     public void testGetSearchBothRange_NotFound()
797         throws DatabaseException, InterruptedException JavaDoc {
798
799         openEnv(false);
800         DatabaseEntry key = new DatabaseEntry();
801         DatabaseEntry data = new DatabaseEntry();
802         OperationStatus status;
803
804         /* Insert key 1. */
805         insert(1);
806
807         /* getSearchBothRange for {3, 0} returns NOTFOUND. */
808         Transaction readerTxn = env.beginTransaction(null, txnConfig);
809         Cursor cursor = db.openCursor(readerTxn, null);
810         IntegerBinding.intToEntry(3, key);
811         IntegerBinding.intToEntry(0, data);
812         status = cursor.getSearchBothRange(key, data, null);
813         assertEquals(OperationStatus.NOTFOUND, status);
814
815         /* Insert {3, 1} in a writer thread. */
816         startInsert(3, 1);
817         
818         /*
819          * If serializable, getSearchBothRange should return NOTFOUND again;
820          * otherwise getSearchBothRange should see key 3.
821          */

822         IntegerBinding.intToEntry(3, key);
823         IntegerBinding.intToEntry(0, data);
824         status = cursor.getSearchBothRange(key, data, null);
825         if (txnSerializable) {
826             assertEquals(OperationStatus.NOTFOUND, status);
827         } else {
828             assertEquals(OperationStatus.SUCCESS, status);
829             assertEquals(3, IntegerBinding.entryToInt(key));
830             assertEquals(1, IntegerBinding.entryToInt(data));
831         }
832
833         /* Close reader to allow writer to finish. */
834         cursor.close();
835         readerTxn.commitNoSync();
836         waitForInsert();
837
838         /* getSearchBothRange returns key 3. */
839         readerTxn = env.beginTransaction(null, txnConfig);
840         cursor = db.openCursor(readerTxn, null);
841         IntegerBinding.intToEntry(3, key);
842         IntegerBinding.intToEntry(0, data);
843         status = cursor.getSearchBothRange(key, data, null);
844         assertEquals(OperationStatus.SUCCESS, status);
845         assertEquals(3, IntegerBinding.entryToInt(key));
846         assertEquals(1, IntegerBinding.entryToInt(data));
847         cursor.close();
848         readerTxn.commit();
849
850         closeEnv();
851     }
852     
853     public void testGetSearchBothRange_NotFound_Dup()
854         throws DatabaseException, InterruptedException JavaDoc {
855
856         openEnv(true);
857         DatabaseEntry key = new DatabaseEntry();
858         DatabaseEntry data = new DatabaseEntry();
859         OperationStatus status;
860
861         /* Insert dups. */
862         insert(3, 0);
863         insert(3, 1);
864
865         /* getSearchBothRange for {3, 2} returns NOTFOUND. */
866         Transaction readerTxn = env.beginTransaction(null, txnConfig);
867         Cursor cursor = db.openCursor(readerTxn, null);
868         IntegerBinding.intToEntry(3, key);
869         IntegerBinding.intToEntry(2, data);
870         status = cursor.getSearchBothRange(key, data, null);
871         assertEquals(OperationStatus.NOTFOUND, status);
872
873         /* Insert {3,3} in a writer thread. */
874         startInsert(3, 3);
875         
876         /*
877          * If serializable, getSearchBothRange should return NOTFOUND again;
878          * otherwise getSearchBothRange should see {3,3}.
879          */

880         IntegerBinding.intToEntry(3, key);
881         IntegerBinding.intToEntry(2, data);
882         status = cursor.getSearchBothRange(key, data, null);
883         if (txnSerializable) {
884             assertEquals(OperationStatus.NOTFOUND, status);
885         } else {
886             assertEquals(OperationStatus.SUCCESS, status);
887             assertEquals(3, IntegerBinding.entryToInt(key));
888             assertEquals(3, IntegerBinding.entryToInt(data));
889         }
890
891         /* Close reader to allow writer to finish. */
892         cursor.close();
893         readerTxn.commitNoSync();
894         waitForInsert();
895
896         /* getSearchBothRange returns {3,3}. */
897         readerTxn = env.beginTransaction(null, txnConfig);
898         cursor = db.openCursor(readerTxn, null);
899         IntegerBinding.intToEntry(3, key);
900         IntegerBinding.intToEntry(2, data);
901         status = cursor.getSearchBothRange(key, data, null);
902         assertEquals(OperationStatus.SUCCESS, status);
903         assertEquals(3, IntegerBinding.entryToInt(key));
904         assertEquals(3, IntegerBinding.entryToInt(data));
905         cursor.close();
906         readerTxn.commit();
907
908         closeEnv();
909     }
910     
911     public void testGetFirst_Success()
912         throws DatabaseException, InterruptedException JavaDoc {
913
914         openEnv(false);
915         DatabaseEntry key = new DatabaseEntry();
916         DatabaseEntry data = new DatabaseEntry();
917         OperationStatus status;
918
919         /* Insert key 2. */
920         insert(2);
921
922         /* getFirst returns key 2. */
923         Transaction readerTxn = env.beginTransaction(null, txnConfig);
924         Cursor cursor = db.openCursor(readerTxn, null);
925         status = cursor.getFirst(key, data, null);
926         assertEquals(OperationStatus.SUCCESS, status);
927         assertEquals(2, IntegerBinding.entryToInt(key));
928
929         /* Insert key 1 in a writer thread. */
930         startInsert(1);
931         
932         /*
933          * If serializable, getFirst should return key 2 again; otherwise
934          * getFirst should see key 1.
935          */

936         status = cursor.getFirst(key, data, null);
937         assertEquals(OperationStatus.SUCCESS, status);
938         if (txnSerializable) {
939             assertEquals(2, IntegerBinding.entryToInt(key));
940         } else {
941             assertEquals(1, IntegerBinding.entryToInt(key));
942         }
943
944         /* Close reader to allow writer to finish. */
945         cursor.close();
946         readerTxn.commitNoSync();
947         waitForInsert();
948
949         /* getFirst returns key 1. */
950         readerTxn = env.beginTransaction(null, txnConfig);
951         cursor = db.openCursor(readerTxn, null);
952         status = cursor.getFirst(key, data, null);
953         assertEquals(OperationStatus.SUCCESS, status);
954         assertEquals(1, IntegerBinding.entryToInt(key));
955         cursor.close();
956         readerTxn.commit();
957
958         closeEnv();
959     }
960     
961     public void testGetFirst_Success_Dup()
962         throws DatabaseException, InterruptedException JavaDoc {
963
964         openEnv(true);
965         DatabaseEntry key = new DatabaseEntry();
966         DatabaseEntry data = new DatabaseEntry();
967         OperationStatus status;
968
969         /* Insert dups. */
970         insert(1, 2);
971         insert(1, 3);
972
973         /* getFirst returns {1,2}. */
974         Transaction readerTxn = env.beginTransaction(null, txnConfig);
975         Cursor cursor = db.openCursor(readerTxn, null);
976         status = cursor.getFirst(key, data, null);
977         assertEquals(OperationStatus.SUCCESS, status);
978         assertEquals(1, IntegerBinding.entryToInt(key));
979         assertEquals(2, IntegerBinding.entryToInt(data));
980
981         /* Insert {1,1} in a writer thread. */
982         startInsert(1, 1);
983         
984         /*
985          * If serializable, getFirst should return {1,2} again; otherwise
986          * getFirst should see {1,1}.
987          */

988         status = cursor.getFirst(key, data, null);
989         assertEquals(OperationStatus.SUCCESS, status);
990         if (txnSerializable) {
991             assertEquals(1, IntegerBinding.entryToInt(key));
992             assertEquals(2, IntegerBinding.entryToInt(data));
993         } else {
994             assertEquals(1, IntegerBinding.entryToInt(key));
995             assertEquals(1, IntegerBinding.entryToInt(data));
996         }
997
998         /* Close reader to allow writer to finish. */
999         cursor.close();
1000        readerTxn.commitNoSync();
1001        waitForInsert();
1002
1003        /* getFirst returns {1,1}. */
1004        readerTxn = env.beginTransaction(null, txnConfig);
1005        cursor = db.openCursor(readerTxn, null);
1006        status = cursor.getFirst(key, data, null);
1007        assertEquals(OperationStatus.SUCCESS, status);
1008        assertEquals(1, IntegerBinding.entryToInt(key));
1009        assertEquals(1, IntegerBinding.entryToInt(data));
1010        cursor.close();
1011        readerTxn.commit();
1012
1013        closeEnv();
1014    }
1015    
1016    public void testGetFirst_NotFound()
1017        throws DatabaseException, InterruptedException JavaDoc {
1018
1019        openEnv(false);
1020        DatabaseEntry key = new DatabaseEntry();
1021        DatabaseEntry data = new DatabaseEntry();
1022        OperationStatus status;
1023
1024        /* getFirst returns NOTFOUND. */
1025        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1026        Cursor cursor = db.openCursor(readerTxn, null);
1027        status = cursor.getFirst(key, data, null);
1028        assertEquals(OperationStatus.NOTFOUND, status);
1029
1030        /* Insert key 1 in a writer thread. */
1031        startInsert(1);
1032        
1033        /*
1034         * If serializable, getFirst should return NOTFOUND again; otherwise
1035         * getFirst should see key 1.
1036         */

1037        status = cursor.getFirst(key, data, null);
1038        if (txnSerializable) {
1039            assertEquals(OperationStatus.NOTFOUND, status);
1040        } else {
1041            assertEquals(OperationStatus.SUCCESS, status);
1042            assertEquals(1, IntegerBinding.entryToInt(key));
1043        }
1044
1045        /* Close reader to allow writer to finish. */
1046        cursor.close();
1047        readerTxn.commitNoSync();
1048        waitForInsert();
1049
1050        /* getFirst returns key 1. */
1051        readerTxn = env.beginTransaction(null, txnConfig);
1052        cursor = db.openCursor(readerTxn, null);
1053        status = cursor.getFirst(key, data, null);
1054        assertEquals(OperationStatus.SUCCESS, status);
1055        assertEquals(1, IntegerBinding.entryToInt(key));
1056        cursor.close();
1057        readerTxn.commit();
1058
1059        closeEnv();
1060    }
1061    
1062    public void testGetFirst_NotFound_Dup()
1063        throws DatabaseException, InterruptedException JavaDoc {
1064
1065        openEnv(true);
1066        DatabaseEntry key = new DatabaseEntry();
1067        DatabaseEntry data = new DatabaseEntry();
1068        OperationStatus status;
1069
1070        /* getFirst returns NOTFOUND. */
1071        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1072        Cursor cursor = db.openCursor(readerTxn, null);
1073        status = cursor.getFirst(key, data, null);
1074        assertEquals(OperationStatus.NOTFOUND, status);
1075
1076        /* Insert {1,1} in a writer thread. */
1077        startInsert(1, 1);
1078        
1079        /*
1080         * If serializable, getFirst should return NOTFOUND again; otherwise
1081         * getFirst should see {1,1}.
1082         */

1083        status = cursor.getFirst(key, data, null);
1084        if (txnSerializable) {
1085            assertEquals(OperationStatus.NOTFOUND, status);
1086        } else {
1087            assertEquals(OperationStatus.SUCCESS, status);
1088            assertEquals(1, IntegerBinding.entryToInt(key));
1089            assertEquals(1, IntegerBinding.entryToInt(data));
1090        }
1091
1092        /* Close reader to allow writer to finish. */
1093        cursor.close();
1094        readerTxn.commitNoSync();
1095        waitForInsert();
1096
1097        /* getFirst returns {1,1}. */
1098        readerTxn = env.beginTransaction(null, txnConfig);
1099        cursor = db.openCursor(readerTxn, null);
1100        status = cursor.getFirst(key, data, null);
1101        assertEquals(OperationStatus.SUCCESS, status);
1102        assertEquals(1, IntegerBinding.entryToInt(key));
1103        cursor.close();
1104        readerTxn.commit();
1105
1106        closeEnv();
1107    }
1108    
1109    public void testGetLast_Success()
1110        throws DatabaseException, InterruptedException JavaDoc {
1111
1112        openEnv(false);
1113        DatabaseEntry key = new DatabaseEntry();
1114        DatabaseEntry data = new DatabaseEntry();
1115        OperationStatus status;
1116
1117        /* Insert key 1. */
1118        insert(1);
1119
1120        /* getLast returns key 1. */
1121        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1122        Cursor cursor = db.openCursor(readerTxn, null);
1123        status = cursor.getLast(key, data, null);
1124        assertEquals(OperationStatus.SUCCESS, status);
1125        assertEquals(1, IntegerBinding.entryToInt(key));
1126
1127        /* Insertions before current position are never blocked. */
1128        try {
1129            insert(0);
1130        } catch (DeadlockException e) {
1131            fail();
1132        }
1133
1134        /* Insert key 2 in a writer thread. */
1135        startInsert(2);
1136        
1137        /*
1138         * If serializable, getLast should return key 1 again; otherwise
1139         * getLast should see key 2.
1140         */

1141        status = cursor.getLast(key, data, null);
1142        assertEquals(OperationStatus.SUCCESS, status);
1143        if (txnSerializable) {
1144            assertEquals(1, IntegerBinding.entryToInt(key));
1145        } else {
1146            assertEquals(2, IntegerBinding.entryToInt(key));
1147        }
1148
1149        /* Close reader to allow writer to finish. */
1150        cursor.close();
1151        readerTxn.commitNoSync();
1152        waitForInsert();
1153
1154        /* getLast returns key 2. */
1155        readerTxn = env.beginTransaction(null, txnConfig);
1156        cursor = db.openCursor(readerTxn, null);
1157        status = cursor.getLast(key, data, null);
1158        assertEquals(OperationStatus.SUCCESS, status);
1159        assertEquals(2, IntegerBinding.entryToInt(key));
1160        cursor.close();
1161        readerTxn.commit();
1162
1163        closeEnv();
1164    }
1165    
1166    public void testGetLast_Success_Dup()
1167        throws DatabaseException, InterruptedException JavaDoc {
1168
1169        openEnv(true);
1170        DatabaseEntry key = new DatabaseEntry();
1171        DatabaseEntry data = new DatabaseEntry();
1172        OperationStatus status;
1173
1174        /* Insert dups. */
1175        insert(1, 0);
1176        insert(1, 2);
1177
1178        /* getLast returns {1,2}. */
1179        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1180        Cursor cursor = db.openCursor(readerTxn, null);
1181        status = cursor.getLast(key, data, null);
1182        assertEquals(OperationStatus.SUCCESS, status);
1183        assertEquals(1, IntegerBinding.entryToInt(key));
1184        assertEquals(2, IntegerBinding.entryToInt(data));
1185
1186        /* Insertions before current position are never blocked. */
1187        try {
1188            insert(1, 1);
1189        } catch (DeadlockException e) {
1190            fail();
1191        }
1192
1193        /* Insert {1,3} in a writer thread. */
1194        startInsert(1, 3);
1195        
1196        /*
1197         * If serializable, getLast should return {1,2} again; otherwise
1198         * getLast should see {1,3}.
1199         */

1200        status = cursor.getLast(key, data, null);
1201        assertEquals(OperationStatus.SUCCESS, status);
1202        if (txnSerializable) {
1203            assertEquals(1, IntegerBinding.entryToInt(key));
1204            assertEquals(2, IntegerBinding.entryToInt(data));
1205        } else {
1206            assertEquals(1, IntegerBinding.entryToInt(key));
1207            assertEquals(3, IntegerBinding.entryToInt(data));
1208        }
1209
1210        /* Close reader to allow writer to finish. */
1211        cursor.close();
1212        readerTxn.commitNoSync();
1213        waitForInsert();
1214
1215        /* getLast returns {1,3}. */
1216        readerTxn = env.beginTransaction(null, txnConfig);
1217        cursor = db.openCursor(readerTxn, null);
1218        status = cursor.getLast(key, data, null);
1219        assertEquals(OperationStatus.SUCCESS, status);
1220        assertEquals(1, IntegerBinding.entryToInt(key));
1221        assertEquals(3, IntegerBinding.entryToInt(data));
1222        cursor.close();
1223        readerTxn.commit();
1224
1225        closeEnv();
1226    }
1227    
1228    public void testGetLast_NotFound()
1229        throws DatabaseException, InterruptedException JavaDoc {
1230
1231        openEnv(false);
1232        DatabaseEntry key = new DatabaseEntry();
1233        DatabaseEntry data = new DatabaseEntry();
1234        OperationStatus status;
1235
1236        /* getLast returns NOTFOUND. */
1237        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1238        Cursor cursor = db.openCursor(readerTxn, null);
1239        status = cursor.getLast(key, data, null);
1240        assertEquals(OperationStatus.NOTFOUND, status);
1241
1242        /* Insert key 1 in a writer thread. */
1243        startInsert(1);
1244        
1245        /*
1246         * If serializable, getLast should return NOTFOUND again; otherwise
1247         * getLast should see key 1.
1248         */

1249        status = cursor.getLast(key, data, null);
1250        if (txnSerializable) {
1251            assertEquals(OperationStatus.NOTFOUND, status);
1252        } else {
1253            assertEquals(OperationStatus.SUCCESS, status);
1254            assertEquals(1, IntegerBinding.entryToInt(key));
1255        }
1256
1257        /* Close reader to allow writer to finish. */
1258        cursor.close();
1259        readerTxn.commitNoSync();
1260        waitForInsert();
1261
1262        /* getLast returns key 1. */
1263        readerTxn = env.beginTransaction(null, txnConfig);
1264        cursor = db.openCursor(readerTxn, null);
1265        status = cursor.getLast(key, data, null);
1266        assertEquals(OperationStatus.SUCCESS, status);
1267        assertEquals(1, IntegerBinding.entryToInt(key));
1268        cursor.close();
1269        readerTxn.commit();
1270
1271        closeEnv();
1272    }
1273    
1274    public void testGetLast_NotFound_Dup()
1275        throws DatabaseException, InterruptedException JavaDoc {
1276
1277        openEnv(true);
1278        DatabaseEntry key = new DatabaseEntry();
1279        DatabaseEntry data = new DatabaseEntry();
1280        OperationStatus status;
1281
1282        /* getLast returns NOTFOUND. */
1283        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1284        Cursor cursor = db.openCursor(readerTxn, null);
1285        status = cursor.getLast(key, data, null);
1286        assertEquals(OperationStatus.NOTFOUND, status);
1287
1288        /* Insert {1,1} in a writer thread. */
1289        startInsert(1, 1);
1290        
1291        /*
1292         * If serializable, getLast should return NOTFOUND again; otherwise
1293         * getLast should see {1,1}.
1294         */

1295        status = cursor.getLast(key, data, null);
1296        if (txnSerializable) {
1297            assertEquals(OperationStatus.NOTFOUND, status);
1298        } else {
1299            assertEquals(OperationStatus.SUCCESS, status);
1300            assertEquals(1, IntegerBinding.entryToInt(key));
1301            assertEquals(1, IntegerBinding.entryToInt(data));
1302        }
1303
1304        /* Close reader to allow writer to finish. */
1305        cursor.close();
1306        readerTxn.commitNoSync();
1307        waitForInsert();
1308
1309        /* getLast returns {1,1}. */
1310        readerTxn = env.beginTransaction(null, txnConfig);
1311        cursor = db.openCursor(readerTxn, null);
1312        status = cursor.getLast(key, data, null);
1313        assertEquals(OperationStatus.SUCCESS, status);
1314        assertEquals(1, IntegerBinding.entryToInt(key));
1315        assertEquals(1, IntegerBinding.entryToInt(data));
1316        cursor.close();
1317        readerTxn.commit();
1318
1319        closeEnv();
1320    }
1321    
1322    public void testGetNext_Success()
1323        throws DatabaseException, InterruptedException JavaDoc {
1324
1325        openEnv(false);
1326        DatabaseEntry key = new DatabaseEntry();
1327        DatabaseEntry data = new DatabaseEntry();
1328        OperationStatus status;
1329
1330        /* Insert key 1 and 3. */
1331        insert(1);
1332        insert(3);
1333
1334        /* getNext returns key 3. */
1335        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1336        Cursor cursor = db.openCursor(readerTxn, null);
1337        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1338        status = cursor.getNext(key, data, null);
1339        assertEquals(OperationStatus.SUCCESS, status);
1340        assertEquals(3, IntegerBinding.entryToInt(key));
1341
1342        /* Insert key 2 in a writer thread. */
1343        startInsert(2);
1344
1345        /*
1346         * If serializable, getNext should return key 3 again; otherwise
1347         * getNext should see key 2.
1348         */

1349        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1350        status = cursor.getNext(key, data, null);
1351        assertEquals(OperationStatus.SUCCESS, status);
1352        if (txnSerializable) {
1353            assertEquals(3, IntegerBinding.entryToInt(key));
1354        } else {
1355            assertEquals(2, IntegerBinding.entryToInt(key));
1356        }
1357
1358        /* Close reader to allow writer to finish. */
1359        cursor.close();
1360        readerTxn.commitNoSync();
1361        waitForInsert();
1362
1363        /* getNext returns key 2. */
1364        readerTxn = env.beginTransaction(null, txnConfig);
1365        cursor = db.openCursor(readerTxn, null);
1366        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1367        status = cursor.getNext(key, data, null);
1368        assertEquals(OperationStatus.SUCCESS, status);
1369        assertEquals(2, IntegerBinding.entryToInt(key));
1370        cursor.close();
1371        readerTxn.commit();
1372
1373        closeEnv();
1374    }
1375    
1376    public void testGetNext_Success_Dup()
1377        throws DatabaseException, InterruptedException JavaDoc {
1378
1379        openEnv(true);
1380        DatabaseEntry key = new DatabaseEntry();
1381        DatabaseEntry data = new DatabaseEntry();
1382        OperationStatus status;
1383
1384        /* Insert dups. */
1385        insert(1, 1);
1386        insert(1, 3);
1387
1388        /* getNext returns {1,3}. */
1389        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1390        Cursor cursor = db.openCursor(readerTxn, null);
1391        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1392        status = cursor.getNext(key, data, null);
1393        assertEquals(OperationStatus.SUCCESS, status);
1394        assertEquals(1, IntegerBinding.entryToInt(key));
1395        assertEquals(3, IntegerBinding.entryToInt(data));
1396
1397        /* Insert {1,2} in a writer thread. */
1398        startInsert(1, 2);
1399
1400        /*
1401         * If serializable, getNext should return {1,3} again; otherwise
1402         * getNext should see {1,2}.
1403         */

1404        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1405        status = cursor.getNext(key, data, null);
1406        assertEquals(OperationStatus.SUCCESS, status);
1407        if (txnSerializable) {
1408            assertEquals(1, IntegerBinding.entryToInt(key));
1409            assertEquals(3, IntegerBinding.entryToInt(data));
1410        } else {
1411            assertEquals(1, IntegerBinding.entryToInt(key));
1412            assertEquals(2, IntegerBinding.entryToInt(data));
1413        }
1414
1415        /* Close reader to allow writer to finish. */
1416        cursor.close();
1417        readerTxn.commitNoSync();
1418        waitForInsert();
1419
1420        /* getNext returns {1,2}. */
1421        readerTxn = env.beginTransaction(null, txnConfig);
1422        cursor = db.openCursor(readerTxn, null);
1423        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1424        status = cursor.getNext(key, data, null);
1425        assertEquals(OperationStatus.SUCCESS, status);
1426        assertEquals(1, IntegerBinding.entryToInt(key));
1427        assertEquals(2, IntegerBinding.entryToInt(data));
1428        cursor.close();
1429        readerTxn.commit();
1430
1431        closeEnv();
1432    }
1433    
1434    public void testGetNext_NotFound()
1435        throws DatabaseException, InterruptedException JavaDoc {
1436
1437        openEnv(false);
1438        DatabaseEntry key = new DatabaseEntry();
1439        DatabaseEntry data = new DatabaseEntry();
1440        OperationStatus status;
1441
1442        /* Insert key 1. */
1443        insert(1);
1444
1445        /* getNext returns NOTFOUND. */
1446        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1447        Cursor cursor = db.openCursor(readerTxn, null);
1448        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1449        status = cursor.getNext(key, data, null);
1450        assertEquals(OperationStatus.NOTFOUND, status);
1451
1452        /* Insert key 2 in a writer thread. */
1453        startInsert(2);
1454
1455        /*
1456         * If serializable, getNext should return NOTFOUND again; otherwise
1457         * getNext should see key 2.
1458         */

1459        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1460        status = cursor.getNext(key, data, null);
1461        if (txnSerializable) {
1462            assertEquals(OperationStatus.NOTFOUND, status);
1463        } else {
1464            assertEquals(OperationStatus.SUCCESS, status);
1465            assertEquals(2, IntegerBinding.entryToInt(key));
1466        }
1467
1468        /* Close reader to allow writer to finish. */
1469        cursor.close();
1470        readerTxn.commitNoSync();
1471        waitForInsert();
1472
1473        /* getNext returns key 2. */
1474        readerTxn = env.beginTransaction(null, txnConfig);
1475        cursor = db.openCursor(readerTxn, null);
1476        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1477        status = cursor.getNext(key, data, null);
1478        assertEquals(OperationStatus.SUCCESS, status);
1479        assertEquals(2, IntegerBinding.entryToInt(key));
1480        cursor.close();
1481        readerTxn.commit();
1482
1483        closeEnv();
1484    }
1485    
1486    public void testGetNext_NotFound_Dup()
1487        throws DatabaseException, InterruptedException JavaDoc {
1488
1489        openEnv(true);
1490        DatabaseEntry key = new DatabaseEntry();
1491        DatabaseEntry data = new DatabaseEntry();
1492        OperationStatus status;
1493
1494        /* Insert dups. */
1495        insert(1, 1);
1496        insert(1, 2);
1497
1498        /* getNext returns NOTFOUND. */
1499        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1500        Cursor cursor = db.openCursor(readerTxn, null);
1501        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
1502        status = cursor.getNext(key, data, null);
1503        assertEquals(OperationStatus.NOTFOUND, status);
1504
1505        /* Insert {1,3} in a writer thread. */
1506        startInsert(1, 3);
1507
1508        /*
1509         * If serializable, getNext should return NOTFOUND again; otherwise
1510         * getNext should see {1,3}.
1511         */

1512        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
1513        status = cursor.getNext(key, data, null);
1514        if (txnSerializable) {
1515            assertEquals(OperationStatus.NOTFOUND, status);
1516        } else {
1517            assertEquals(OperationStatus.SUCCESS, status);
1518            assertEquals(1, IntegerBinding.entryToInt(key));
1519            assertEquals(3, IntegerBinding.entryToInt(data));
1520        }
1521
1522        /* Close reader to allow writer to finish. */
1523        cursor.close();
1524        readerTxn.commitNoSync();
1525        waitForInsert();
1526
1527        /* getNext returns {1,3}. */
1528        readerTxn = env.beginTransaction(null, txnConfig);
1529        cursor = db.openCursor(readerTxn, null);
1530        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
1531        status = cursor.getNext(key, data, null);
1532        assertEquals(OperationStatus.SUCCESS, status);
1533        assertEquals(1, IntegerBinding.entryToInt(key));
1534        assertEquals(3, IntegerBinding.entryToInt(data));
1535        cursor.close();
1536        readerTxn.commit();
1537
1538        closeEnv();
1539    }
1540    
1541    public void testGetNextDup_Success_Dup()
1542        throws DatabaseException, InterruptedException JavaDoc {
1543
1544        openEnv(true);
1545        DatabaseEntry key = new DatabaseEntry();
1546        DatabaseEntry data = new DatabaseEntry();
1547        OperationStatus status;
1548
1549        /* Insert dups. */
1550        insert(1, 1);
1551        insert(1, 3);
1552
1553        /* getNextDup returns {1,3}. */
1554        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1555        Cursor cursor = db.openCursor(readerTxn, null);
1556        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1557        status = cursor.getNextDup(key, data, null);
1558        assertEquals(OperationStatus.SUCCESS, status);
1559        assertEquals(1, IntegerBinding.entryToInt(key));
1560        assertEquals(3, IntegerBinding.entryToInt(data));
1561
1562        /* Insert {1,2} in a writer thread. */
1563        startInsert(1, 2);
1564
1565        /*
1566         * If serializable, getNextDup should return {1,3} again; otherwise
1567         * getNextDup should see {1,2}.
1568         */

1569        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1570        status = cursor.getNextDup(key, data, null);
1571        assertEquals(OperationStatus.SUCCESS, status);
1572        if (txnSerializable) {
1573            assertEquals(1, IntegerBinding.entryToInt(key));
1574            assertEquals(3, IntegerBinding.entryToInt(data));
1575        } else {
1576            assertEquals(1, IntegerBinding.entryToInt(key));
1577            assertEquals(2, IntegerBinding.entryToInt(data));
1578        }
1579
1580        /* Close reader to allow writer to finish. */
1581        cursor.close();
1582        readerTxn.commitNoSync();
1583        waitForInsert();
1584
1585        /* getNextDup returns {1,2}. */
1586        readerTxn = env.beginTransaction(null, txnConfig);
1587        cursor = db.openCursor(readerTxn, null);
1588        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1589        status = cursor.getNextDup(key, data, null);
1590        assertEquals(OperationStatus.SUCCESS, status);
1591        assertEquals(1, IntegerBinding.entryToInt(key));
1592        assertEquals(2, IntegerBinding.entryToInt(data));
1593        cursor.close();
1594        readerTxn.commit();
1595
1596        closeEnv();
1597    }
1598    
1599    public void testGetNextDup_NotFound_Dup()
1600        throws DatabaseException, InterruptedException JavaDoc {
1601
1602        openEnv(true);
1603        DatabaseEntry key = new DatabaseEntry();
1604        DatabaseEntry data = new DatabaseEntry();
1605        OperationStatus status;
1606
1607        /* Insert dups. */
1608        insert(1, 1);
1609        insert(1, 2);
1610        insert(2, 1);
1611        insert(2, 2);
1612
1613        /* getNextDup returns NOTFOUND. */
1614        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1615        Cursor cursor = db.openCursor(readerTxn, null);
1616        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
1617        status = cursor.getNextDup(key, data, null);
1618        assertEquals(OperationStatus.NOTFOUND, status);
1619
1620        /* Insert {1,3} in a writer thread. */
1621        startInsert(1, 3);
1622
1623        /*
1624         * If serializable, getNextDup should return NOTFOUND again; otherwise
1625         * getNextDup should see {1,3}.
1626         */

1627        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
1628        status = cursor.getNextDup(key, data, null);
1629        if (txnSerializable) {
1630            assertEquals(OperationStatus.NOTFOUND, status);
1631        } else {
1632            assertEquals(OperationStatus.SUCCESS, status);
1633            assertEquals(1, IntegerBinding.entryToInt(key));
1634            assertEquals(3, IntegerBinding.entryToInt(data));
1635        }
1636
1637        /* Close reader to allow writer to finish. */
1638        cursor.close();
1639        readerTxn.commitNoSync();
1640        waitForInsert();
1641
1642        /* getNextDup returns {1,3}. */
1643        readerTxn = env.beginTransaction(null, txnConfig);
1644        cursor = db.openCursor(readerTxn, null);
1645        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 2));
1646        status = cursor.getNextDup(key, data, null);
1647        assertEquals(OperationStatus.SUCCESS, status);
1648        assertEquals(1, IntegerBinding.entryToInt(key));
1649        assertEquals(3, IntegerBinding.entryToInt(data));
1650        cursor.close();
1651        readerTxn.commit();
1652
1653        closeEnv();
1654    }
1655    
1656    public void testGetNextNoDup_Success()
1657        throws DatabaseException, InterruptedException JavaDoc {
1658
1659        openEnv(false);
1660        DatabaseEntry key = new DatabaseEntry();
1661        DatabaseEntry data = new DatabaseEntry();
1662        OperationStatus status;
1663
1664        /* Insert key 1 and 3. */
1665        insert(1);
1666        insert(3);
1667
1668        /* getNextNoDup returns key 3. */
1669        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1670        Cursor cursor = db.openCursor(readerTxn, null);
1671        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1672        status = cursor.getNextNoDup(key, data, null);
1673        assertEquals(OperationStatus.SUCCESS, status);
1674        assertEquals(3, IntegerBinding.entryToInt(key));
1675
1676        /* Insert key 2 in a writer thread. */
1677        startInsert(2);
1678
1679        /*
1680         * If serializable, getNextNoDup should return key 3 again; otherwise
1681         * getNextNoDup should see key 2.
1682         */

1683        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1684        status = cursor.getNextNoDup(key, data, null);
1685        assertEquals(OperationStatus.SUCCESS, status);
1686        if (txnSerializable) {
1687            assertEquals(3, IntegerBinding.entryToInt(key));
1688        } else {
1689            assertEquals(2, IntegerBinding.entryToInt(key));
1690        }
1691
1692        /* Close reader to allow writer to finish. */
1693        cursor.close();
1694        readerTxn.commitNoSync();
1695        waitForInsert();
1696
1697        /* getNextNoDup returns key 2. */
1698        readerTxn = env.beginTransaction(null, txnConfig);
1699        cursor = db.openCursor(readerTxn, null);
1700        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1701        status = cursor.getNextNoDup(key, data, null);
1702        assertEquals(OperationStatus.SUCCESS, status);
1703        assertEquals(2, IntegerBinding.entryToInt(key));
1704        cursor.close();
1705        readerTxn.commit();
1706
1707        closeEnv();
1708    }
1709    
1710    public void testGetNextNoDup_Success_Dup()
1711        throws DatabaseException, InterruptedException JavaDoc {
1712
1713        openEnv(true);
1714        DatabaseEntry key = new DatabaseEntry();
1715        DatabaseEntry data = new DatabaseEntry();
1716        OperationStatus status;
1717
1718        /* Insert dups. */
1719        insert(1, 1);
1720        insert(1, 2);
1721        insert(3, 1);
1722        insert(3, 2);
1723
1724        /* getNextNoDup returns {3,1}. */
1725        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1726        Cursor cursor = db.openCursor(readerTxn, null);
1727        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1728        status = cursor.getNextNoDup(key, data, null);
1729        assertEquals(OperationStatus.SUCCESS, status);
1730        assertEquals(3, IntegerBinding.entryToInt(key));
1731        assertEquals(1, IntegerBinding.entryToInt(data));
1732
1733        /* Insert {2,1} in a writer thread. */
1734        startInsert(2, 1);
1735
1736        /*
1737         * If serializable, getNextNoDup should return {3,1} again; otherwise
1738         * getNextNoDup should see {2,1}.
1739         */

1740        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1741        status = cursor.getNextNoDup(key, data, null);
1742        assertEquals(OperationStatus.SUCCESS, status);
1743        if (txnSerializable) {
1744            assertEquals(3, IntegerBinding.entryToInt(key));
1745            assertEquals(1, IntegerBinding.entryToInt(data));
1746        } else {
1747            assertEquals(2, IntegerBinding.entryToInt(key));
1748            assertEquals(1, IntegerBinding.entryToInt(data));
1749        }
1750
1751        /* Close reader to allow writer to finish. */
1752        cursor.close();
1753        readerTxn.commitNoSync();
1754        waitForInsert();
1755
1756        /* getNextNoDup returns {2,1}. */
1757        readerTxn = env.beginTransaction(null, txnConfig);
1758        cursor = db.openCursor(readerTxn, null);
1759        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1760        status = cursor.getNextNoDup(key, data, null);
1761        assertEquals(OperationStatus.SUCCESS, status);
1762        assertEquals(2, IntegerBinding.entryToInt(key));
1763        assertEquals(1, IntegerBinding.entryToInt(data));
1764        cursor.close();
1765        readerTxn.commit();
1766
1767        closeEnv();
1768    }
1769    
1770    public void testGetNextNoDup_NotFound()
1771        throws DatabaseException, InterruptedException JavaDoc {
1772
1773        openEnv(false);
1774        DatabaseEntry key = new DatabaseEntry();
1775        DatabaseEntry data = new DatabaseEntry();
1776        OperationStatus status;
1777
1778        /* Insert key 1. */
1779        insert(1);
1780
1781        /* getNextNoDup returns NOTFOUND. */
1782        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1783        Cursor cursor = db.openCursor(readerTxn, null);
1784        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1785        status = cursor.getNextNoDup(key, data, null);
1786        assertEquals(OperationStatus.NOTFOUND, status);
1787
1788        /* Insert key 2 in a writer thread. */
1789        startInsert(2);
1790
1791        /*
1792         * If serializable, getNextNoDup should return NOTFOUND again;
1793         * otherwise getNextNoDup should see key 2.
1794         */

1795        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1796        status = cursor.getNextNoDup(key, data, null);
1797        if (txnSerializable) {
1798            assertEquals(OperationStatus.NOTFOUND, status);
1799        } else {
1800            assertEquals(OperationStatus.SUCCESS, status);
1801            assertEquals(2, IntegerBinding.entryToInt(key));
1802        }
1803
1804        /* Close reader to allow writer to finish. */
1805        cursor.close();
1806        readerTxn.commitNoSync();
1807        waitForInsert();
1808
1809        /* getNextNoDup returns key 2. */
1810        readerTxn = env.beginTransaction(null, txnConfig);
1811        cursor = db.openCursor(readerTxn, null);
1812        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1));
1813        status = cursor.getNextNoDup(key, data, null);
1814        assertEquals(OperationStatus.SUCCESS, status);
1815        assertEquals(2, IntegerBinding.entryToInt(key));
1816        cursor.close();
1817        readerTxn.commit();
1818
1819        closeEnv();
1820    }
1821    
1822    public void testGetNextNoDup_NotFound_Dup()
1823        throws DatabaseException, InterruptedException JavaDoc {
1824
1825        openEnv(true);
1826        DatabaseEntry key = new DatabaseEntry();
1827        DatabaseEntry data = new DatabaseEntry();
1828        OperationStatus status;
1829
1830        /* Insert dups. */
1831        insert(1, 1);
1832        insert(1, 2);
1833
1834        /* getNextNoDup returns NOTFOUND. */
1835        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1836        Cursor cursor = db.openCursor(readerTxn, null);
1837        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1838        status = cursor.getNextNoDup(key, data, null);
1839        assertEquals(OperationStatus.NOTFOUND, status);
1840
1841        /* Insert {2,1} in a writer thread. */
1842        startInsert(2, 1);
1843
1844        /*
1845         * If serializable, getNextNoDup should return NOTFOUND again;
1846         * otherwise getNextNoDup should see {2,1}.
1847         */

1848        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1849        status = cursor.getNextNoDup(key, data, null);
1850        if (txnSerializable) {
1851            assertEquals(OperationStatus.NOTFOUND, status);
1852        } else {
1853            assertEquals(OperationStatus.SUCCESS, status);
1854            assertEquals(2, IntegerBinding.entryToInt(key));
1855            assertEquals(1, IntegerBinding.entryToInt(data));
1856        }
1857
1858        /* Close reader to allow writer to finish. */
1859        cursor.close();
1860        readerTxn.commitNoSync();
1861        waitForInsert();
1862
1863        /* getNextNoDup returns {2,1}. */
1864        readerTxn = env.beginTransaction(null, txnConfig);
1865        cursor = db.openCursor(readerTxn, null);
1866        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
1867        status = cursor.getNextNoDup(key, data, null);
1868        assertEquals(OperationStatus.SUCCESS, status);
1869        assertEquals(2, IntegerBinding.entryToInt(key));
1870        assertEquals(1, IntegerBinding.entryToInt(data));
1871        cursor.close();
1872        readerTxn.commit();
1873
1874        closeEnv();
1875    }
1876    
1877    public void testGetPrev_Success()
1878        throws DatabaseException, InterruptedException JavaDoc {
1879
1880        openEnv(false);
1881        DatabaseEntry key = new DatabaseEntry();
1882        DatabaseEntry data = new DatabaseEntry();
1883        OperationStatus status;
1884
1885        /* Insert key 1 and 3. */
1886        insert(1);
1887        insert(3);
1888
1889        /* getPrev returns key 1. */
1890        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1891        Cursor cursor = db.openCursor(readerTxn, null);
1892        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 3));
1893        status = cursor.getPrev(key, data, null);
1894        assertEquals(OperationStatus.SUCCESS, status);
1895        assertEquals(1, IntegerBinding.entryToInt(key));
1896
1897        /* Insertions before current position are never blocked. */
1898        try {
1899            insert(0);
1900        } catch (DeadlockException e) {
1901            fail();
1902        }
1903
1904        /* Insert key 2 in a writer thread. */
1905        startInsert(2);
1906
1907        /*
1908         * If serializable, getPrev should return key 1 again; otherwise
1909         * getPrev should see key 2.
1910         */

1911        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 3));
1912        status = cursor.getPrev(key, data, null);
1913        assertEquals(OperationStatus.SUCCESS, status);
1914        if (txnSerializable) {
1915            assertEquals(1, IntegerBinding.entryToInt(key));
1916        } else {
1917            assertEquals(2, IntegerBinding.entryToInt(key));
1918        }
1919
1920        /* Close reader to allow writer to finish. */
1921        cursor.close();
1922        readerTxn.commitNoSync();
1923        waitForInsert();
1924
1925        /* getPrev returns key 2. */
1926        readerTxn = env.beginTransaction(null, txnConfig);
1927        cursor = db.openCursor(readerTxn, null);
1928        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 3));
1929        status = cursor.getPrev(key, data, null);
1930        assertEquals(OperationStatus.SUCCESS, status);
1931        assertEquals(2, IntegerBinding.entryToInt(key));
1932        cursor.close();
1933        readerTxn.commit();
1934
1935        closeEnv();
1936    }
1937    
1938    public void testGetPrev_Success_Dup()
1939        throws DatabaseException, InterruptedException JavaDoc {
1940
1941        openEnv(true);
1942        DatabaseEntry key = new DatabaseEntry();
1943        DatabaseEntry data = new DatabaseEntry();
1944        OperationStatus status;
1945
1946        /* Insert dups. */
1947        insert(1, 1);
1948        insert(1, 3);
1949
1950        /* getPrev returns {1,1}. */
1951        Transaction readerTxn = env.beginTransaction(null, txnConfig);
1952        Cursor cursor = db.openCursor(readerTxn, null);
1953        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 3));
1954        status = cursor.getPrev(key, data, null);
1955        assertEquals(OperationStatus.SUCCESS, status);
1956        assertEquals(1, IntegerBinding.entryToInt(key));
1957        assertEquals(1, IntegerBinding.entryToInt(data));
1958
1959        /* Insertions before current position are never blocked. */
1960        try {
1961            insert(1, 0);
1962        } catch (DeadlockException e) {
1963            fail();
1964        }
1965
1966        /* Insert {1,2} in a writer thread. */
1967        startInsert(1, 2);
1968
1969        /*
1970         * If serializable, getPrev should return {1,1} again; otherwise
1971         * getPrev should see {1,2}.
1972         */

1973        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 3));
1974        status = cursor.getPrev(key, data, null);
1975        assertEquals(OperationStatus.SUCCESS, status);
1976        if (txnSerializable) {
1977            assertEquals(1, IntegerBinding.entryToInt(key));
1978            assertEquals(1, IntegerBinding.entryToInt(data));
1979        } else {
1980            assertEquals(1, IntegerBinding.entryToInt(key));
1981            assertEquals(2, IntegerBinding.entryToInt(data));
1982        }
1983
1984        /* Close reader to allow writer to finish. */
1985        cursor.close();
1986        readerTxn.commitNoSync();
1987        waitForInsert();
1988
1989        /* getPrev returns {1,2}. */
1990        readerTxn = env.beginTransaction(null, txnConfig);
1991        cursor = db.openCursor(readerTxn, null);
1992        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 3));
1993        status = cursor.getPrev(key, data, null);
1994        assertEquals(OperationStatus.SUCCESS, status);
1995        assertEquals(1, IntegerBinding.entryToInt(key));
1996        assertEquals(2, IntegerBinding.entryToInt(data));
1997        cursor.close();
1998        readerTxn.commit();
1999
2000        closeEnv();
2001    }
2002    
2003    public void testGetPrev_NotFound()
2004        throws DatabaseException, InterruptedException JavaDoc {
2005
2006        openEnv(false);
2007        DatabaseEntry key = new DatabaseEntry();
2008        DatabaseEntry data = new DatabaseEntry();
2009        OperationStatus status;
2010
2011        /* Insert key 2. */
2012        insert(2);
2013
2014        /* getPrev returns NOTFOUND. */
2015        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2016        Cursor cursor = db.openCursor(readerTxn, null);
2017        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
2018        status = cursor.getPrev(key, data, null);
2019        assertEquals(OperationStatus.NOTFOUND, status);
2020
2021        /* Insert key 1 in a writer thread. */
2022        startInsert(1);
2023
2024        /*
2025         * If serializable, getPrev should return NOTFOUND again; otherwise
2026         * getPrev should see key 1.
2027         */

2028        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
2029        status = cursor.getPrev(key, data, null);
2030        if (txnSerializable) {
2031            assertEquals(OperationStatus.NOTFOUND, status);
2032        } else {
2033            assertEquals(OperationStatus.SUCCESS, status);
2034            assertEquals(1, IntegerBinding.entryToInt(key));
2035        }
2036
2037        /* Close reader to allow writer to finish. */
2038        cursor.close();
2039        readerTxn.commitNoSync();
2040        waitForInsert();
2041
2042        /* getPrev returns key 1. */
2043        readerTxn = env.beginTransaction(null, txnConfig);
2044        cursor = db.openCursor(readerTxn, null);
2045        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
2046        status = cursor.getPrev(key, data, null);
2047        assertEquals(OperationStatus.SUCCESS, status);
2048        assertEquals(1, IntegerBinding.entryToInt(key));
2049        cursor.close();
2050        readerTxn.commit();
2051
2052        closeEnv();
2053    }
2054    
2055    public void testGetPrev_NotFound_Dup()
2056        throws DatabaseException, InterruptedException JavaDoc {
2057
2058        openEnv(true);
2059        DatabaseEntry key = new DatabaseEntry();
2060        DatabaseEntry data = new DatabaseEntry();
2061        OperationStatus status;
2062
2063        /* Insert dups. */
2064        insert(2, 2);
2065        insert(2, 3);
2066
2067        /* getPrev returns NOTFOUND. */
2068        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2069        Cursor cursor = db.openCursor(readerTxn, null);
2070        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2071        status = cursor.getPrev(key, data, null);
2072        assertEquals(OperationStatus.NOTFOUND, status);
2073
2074        /* Insert {2,1} in a writer thread. */
2075        startInsert(2, 1);
2076
2077        /*
2078         * If serializable, getPrev should return NOTFOUND again; otherwise
2079         * getPrev should see {2,1}.
2080         */

2081        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2082        status = cursor.getPrev(key, data, null);
2083        if (txnSerializable) {
2084            assertEquals(OperationStatus.NOTFOUND, status);
2085        } else {
2086            assertEquals(OperationStatus.SUCCESS, status);
2087            assertEquals(2, IntegerBinding.entryToInt(key));
2088            assertEquals(1, IntegerBinding.entryToInt(data));
2089        }
2090
2091        /* Close reader to allow writer to finish. */
2092        cursor.close();
2093        readerTxn.commitNoSync();
2094        waitForInsert();
2095
2096        /* getPrev returns {2,1}. */
2097        readerTxn = env.beginTransaction(null, txnConfig);
2098        cursor = db.openCursor(readerTxn, null);
2099        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2100        status = cursor.getPrev(key, data, null);
2101        assertEquals(OperationStatus.SUCCESS, status);
2102        assertEquals(2, IntegerBinding.entryToInt(key));
2103        assertEquals(1, IntegerBinding.entryToInt(data));
2104        cursor.close();
2105        readerTxn.commit();
2106
2107        closeEnv();
2108    }
2109    
2110    public void testGetPrevDup_Success_Dup()
2111        throws DatabaseException, InterruptedException JavaDoc {
2112
2113        openEnv(true);
2114        DatabaseEntry key = new DatabaseEntry();
2115        DatabaseEntry data = new DatabaseEntry();
2116        OperationStatus status;
2117
2118        /* Insert dups. */
2119        insert(1, 1);
2120        insert(1, 3);
2121
2122        /* getPrevDup returns {1,1}. */
2123        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2124        Cursor cursor = db.openCursor(readerTxn, null);
2125        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 3));
2126        status = cursor.getPrevDup(key, data, null);
2127        assertEquals(OperationStatus.SUCCESS, status);
2128        assertEquals(1, IntegerBinding.entryToInt(key));
2129        assertEquals(1, IntegerBinding.entryToInt(data));
2130
2131        /* Insertions before current position are never blocked. */
2132        try {
2133            insert(1, 0);
2134        } catch (DeadlockException e) {
2135            fail();
2136        }
2137
2138        /* Insert {1,2} in a writer thread. */
2139        startInsert(1, 2);
2140
2141        /*
2142         * If serializable, getPrevDup should return {1,1} again; otherwise
2143         * getPrevDup should see {1,2}.
2144         */

2145        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 3));
2146        status = cursor.getPrevDup(key, data, null);
2147        assertEquals(OperationStatus.SUCCESS, status);
2148        if (txnSerializable) {
2149            assertEquals(1, IntegerBinding.entryToInt(key));
2150            assertEquals(1, IntegerBinding.entryToInt(data));
2151        } else {
2152            assertEquals(1, IntegerBinding.entryToInt(key));
2153            assertEquals(2, IntegerBinding.entryToInt(data));
2154        }
2155
2156        /* Close reader to allow writer to finish. */
2157        cursor.close();
2158        readerTxn.commitNoSync();
2159        waitForInsert();
2160
2161        /* getPrevDup returns {1,2}. */
2162        readerTxn = env.beginTransaction(null, txnConfig);
2163        cursor = db.openCursor(readerTxn, null);
2164        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 3));
2165        status = cursor.getPrevDup(key, data, null);
2166        assertEquals(OperationStatus.SUCCESS, status);
2167        assertEquals(1, IntegerBinding.entryToInt(key));
2168        assertEquals(2, IntegerBinding.entryToInt(data));
2169        cursor.close();
2170        readerTxn.commit();
2171
2172        closeEnv();
2173    }
2174    
2175    public void testGetPrevDup_NotFound_Dup()
2176        throws DatabaseException, InterruptedException JavaDoc {
2177
2178        openEnv(true);
2179        DatabaseEntry key = new DatabaseEntry();
2180        DatabaseEntry data = new DatabaseEntry();
2181        OperationStatus status;
2182
2183        /* Insert dups. */
2184        insert(2, 2);
2185        insert(2, 3);
2186
2187        /* getPrevDup returns NOTFOUND. */
2188        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2189        Cursor cursor = db.openCursor(readerTxn, null);
2190        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2191        status = cursor.getPrevDup(key, data, null);
2192        assertEquals(OperationStatus.NOTFOUND, status);
2193
2194        /* Insert {2,1} in a writer thread. */
2195        startInsert(2, 1);
2196
2197        /*
2198         * If serializable, getPrevDup should return NOTFOUND again; otherwise
2199         * getPrevDup should see {2,1}.
2200         */

2201        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2202        status = cursor.getPrevDup(key, data, null);
2203        if (txnSerializable) {
2204            assertEquals(OperationStatus.NOTFOUND, status);
2205        } else {
2206            assertEquals(OperationStatus.SUCCESS, status);
2207            assertEquals(2, IntegerBinding.entryToInt(key));
2208            assertEquals(1, IntegerBinding.entryToInt(data));
2209        }
2210
2211        /* Close reader to allow writer to finish. */
2212        cursor.close();
2213        readerTxn.commitNoSync();
2214        waitForInsert();
2215
2216        /* getPrevDup returns {2,1}. */
2217        readerTxn = env.beginTransaction(null, txnConfig);
2218        cursor = db.openCursor(readerTxn, null);
2219        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2220        status = cursor.getPrevDup(key, data, null);
2221        assertEquals(OperationStatus.SUCCESS, status);
2222        assertEquals(2, IntegerBinding.entryToInt(key));
2223        assertEquals(1, IntegerBinding.entryToInt(data));
2224        cursor.close();
2225        readerTxn.commit();
2226
2227        closeEnv();
2228    }
2229    
2230    public void testGetPrevNoDup_Success()
2231        throws DatabaseException, InterruptedException JavaDoc {
2232
2233        openEnv(false);
2234        DatabaseEntry key = new DatabaseEntry();
2235        DatabaseEntry data = new DatabaseEntry();
2236        OperationStatus status;
2237
2238        /* Insert key 1 and 3. */
2239        insert(1);
2240        insert(3);
2241
2242        /* getPrevNoDup returns key 1. */
2243        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2244        Cursor cursor = db.openCursor(readerTxn, null);
2245        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 3));
2246        status = cursor.getPrevNoDup(key, data, null);
2247        assertEquals(OperationStatus.SUCCESS, status);
2248        assertEquals(1, IntegerBinding.entryToInt(key));
2249
2250        /* Insertions before current position are never blocked. */
2251        try {
2252            insert(0);
2253        } catch (DeadlockException e) {
2254            fail();
2255        }
2256
2257        /* Insert key 2 in a writer thread. */
2258        startInsert(2);
2259
2260        /*
2261         * If serializable, getPrevNoDup should return key 1 again; otherwise
2262         * getPrevNoDup should see key 2.
2263         */

2264        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 3));
2265        status = cursor.getPrevNoDup(key, data, null);
2266        assertEquals(OperationStatus.SUCCESS, status);
2267        if (txnSerializable) {
2268            assertEquals(1, IntegerBinding.entryToInt(key));
2269        } else {
2270            assertEquals(2, IntegerBinding.entryToInt(key));
2271        }
2272
2273        /* Close reader to allow writer to finish. */
2274        cursor.close();
2275        readerTxn.commitNoSync();
2276        waitForInsert();
2277
2278        /* getPrevNoDup returns key 2. */
2279        readerTxn = env.beginTransaction(null, txnConfig);
2280        cursor = db.openCursor(readerTxn, null);
2281        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 3));
2282        status = cursor.getPrevNoDup(key, data, null);
2283        assertEquals(OperationStatus.SUCCESS, status);
2284        assertEquals(2, IntegerBinding.entryToInt(key));
2285        cursor.close();
2286        readerTxn.commit();
2287
2288        closeEnv();
2289    }
2290    
2291    public void testGetPrevNoDup_Success_Dup()
2292        throws DatabaseException, InterruptedException JavaDoc {
2293
2294        openEnv(true);
2295        DatabaseEntry key = new DatabaseEntry();
2296        DatabaseEntry data = new DatabaseEntry();
2297        OperationStatus status;
2298
2299        /* Insert dups. */
2300        insert(1, 0);
2301        insert(1, 2);
2302        insert(3, 1);
2303        insert(3, 2);
2304
2305        /* getPrevNoDup returns {1,2}. */
2306        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2307        Cursor cursor = db.openCursor(readerTxn, null);
2308        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 3, 2));
2309        status = cursor.getPrevNoDup(key, data, null);
2310        assertEquals(OperationStatus.SUCCESS, status);
2311        assertEquals(1, IntegerBinding.entryToInt(key));
2312        assertEquals(2, IntegerBinding.entryToInt(data));
2313
2314        /* Insertions before current position are never blocked. */
2315        try {
2316            insert(1, 1);
2317            insert(0, 0);
2318        } catch (DeadlockException e) {
2319            fail();
2320        }
2321
2322        /* Insert {2,1} in a writer thread. */
2323        startInsert(2, 1);
2324
2325        /*
2326         * If serializable, getPrevNoDup should return {1,2} again; otherwise
2327         * getPrevNoDup should see {2,1}.
2328         */

2329        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 3, 2));
2330        status = cursor.getPrevNoDup(key, data, null);
2331        assertEquals(OperationStatus.SUCCESS, status);
2332        if (txnSerializable) {
2333            assertEquals(1, IntegerBinding.entryToInt(key));
2334            assertEquals(2, IntegerBinding.entryToInt(data));
2335        } else {
2336            assertEquals(2, IntegerBinding.entryToInt(key));
2337            assertEquals(1, IntegerBinding.entryToInt(data));
2338        }
2339
2340        /* Close reader to allow writer to finish. */
2341        cursor.close();
2342        readerTxn.commitNoSync();
2343        waitForInsert();
2344
2345        /* getPrevNoDup returns {2,1}. */
2346        readerTxn = env.beginTransaction(null, txnConfig);
2347        cursor = db.openCursor(readerTxn, null);
2348        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 3, 2));
2349        status = cursor.getPrevNoDup(key, data, null);
2350        assertEquals(OperationStatus.SUCCESS, status);
2351        assertEquals(2, IntegerBinding.entryToInt(key));
2352        assertEquals(1, IntegerBinding.entryToInt(data));
2353        cursor.close();
2354        readerTxn.commit();
2355
2356        closeEnv();
2357    }
2358    
2359    public void testGetPrevNoDup_NotFound()
2360        throws DatabaseException, InterruptedException JavaDoc {
2361
2362        openEnv(false);
2363        DatabaseEntry key = new DatabaseEntry();
2364        DatabaseEntry data = new DatabaseEntry();
2365        OperationStatus status;
2366
2367        /* Insert key 2. */
2368        insert(2);
2369
2370        /* getPrevNoDup returns NOTFOUND. */
2371        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2372        Cursor cursor = db.openCursor(readerTxn, null);
2373        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
2374        status = cursor.getPrevNoDup(key, data, null);
2375        assertEquals(OperationStatus.NOTFOUND, status);
2376
2377        /* Insert key 1 in a writer thread. */
2378        startInsert(1);
2379
2380        /*
2381         * If serializable, getPrevNoDup should return NOTFOUND again;
2382         * otherwise getPrevNoDup should see key 1.
2383         */

2384        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
2385        status = cursor.getPrevNoDup(key, data, null);
2386        if (txnSerializable) {
2387            assertEquals(OperationStatus.NOTFOUND, status);
2388        } else {
2389            assertEquals(OperationStatus.SUCCESS, status);
2390            assertEquals(1, IntegerBinding.entryToInt(key));
2391        }
2392
2393        /* Close reader to allow writer to finish. */
2394        cursor.close();
2395        readerTxn.commitNoSync();
2396        waitForInsert();
2397
2398        /* getPrevNoDup returns key 1. */
2399        readerTxn = env.beginTransaction(null, txnConfig);
2400        cursor = db.openCursor(readerTxn, null);
2401        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 2));
2402        status = cursor.getPrevNoDup(key, data, null);
2403        assertEquals(OperationStatus.SUCCESS, status);
2404        assertEquals(1, IntegerBinding.entryToInt(key));
2405        cursor.close();
2406        readerTxn.commit();
2407
2408        closeEnv();
2409    }
2410    
2411    public void testGetPrevNoDup_NotFound_Dup()
2412        throws DatabaseException, InterruptedException JavaDoc {
2413
2414        openEnv(true);
2415        DatabaseEntry key = new DatabaseEntry();
2416        DatabaseEntry data = new DatabaseEntry();
2417        OperationStatus status;
2418
2419        /* Insert dups. */
2420        insert(2, 1);
2421        insert(2, 2);
2422
2423        /* getPrevNoDup returns NOTFOUND. */
2424        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2425        Cursor cursor = db.openCursor(readerTxn, null);
2426        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2427        status = cursor.getPrevNoDup(key, data, null);
2428        assertEquals(OperationStatus.NOTFOUND, status);
2429
2430        /* Insert {1,1} in a writer thread. */
2431        startInsert(1, 1);
2432
2433        /*
2434         * If serializable, getPrevNoDup should return NOTFOUND again;
2435         * otherwise getPrevNoDup should see {1,1}.
2436         */

2437        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2438        status = cursor.getPrevNoDup(key, data, null);
2439        if (txnSerializable) {
2440            assertEquals(OperationStatus.NOTFOUND, status);
2441        } else {
2442            assertEquals(OperationStatus.SUCCESS, status);
2443            assertEquals(1, IntegerBinding.entryToInt(key));
2444            assertEquals(1, IntegerBinding.entryToInt(data));
2445        }
2446
2447        /* Close reader to allow writer to finish. */
2448        cursor.close();
2449        readerTxn.commitNoSync();
2450        waitForInsert();
2451
2452        /* getPrevNoDup returns {1,1}. */
2453        readerTxn = env.beginTransaction(null, txnConfig);
2454        cursor = db.openCursor(readerTxn, null);
2455        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 2, 2));
2456        status = cursor.getPrevNoDup(key, data, null);
2457        assertEquals(OperationStatus.SUCCESS, status);
2458        assertEquals(1, IntegerBinding.entryToInt(key));
2459        assertEquals(1, IntegerBinding.entryToInt(data));
2460        cursor.close();
2461        readerTxn.commit();
2462
2463        closeEnv();
2464    }
2465
2466    public void testIllegalTransactionConfig()
2467        throws DatabaseException, InterruptedException JavaDoc {
2468
2469        openEnv(false);
2470        TransactionConfig config = new TransactionConfig();
2471        config.setSerializableIsolation(true);
2472        config.setReadUncommitted(true);
2473        try {
2474            Transaction txn = env.beginTransaction(null, config);
2475            txn.abort();
2476            fail();
2477        } catch (IllegalArgumentException JavaDoc expected) {
2478        }
2479        closeEnv();
2480    }
2481    
2482    /*
2483     * In other tests we test TransactionConfig.setReadUncommitted and
2484     * TransactionConfig.setSerializableIsolation to make sure they result in
2485     * expected non-serializable or serializable behavior. Below we check
2486     * EnvironmentConfig.setSerializableIsolation,
2487     * CursorConfig.setSerializableIsolation, CursorConfig.setReadUncommitted
2488     * and LockMode.READ_UNCOMMITTED, although for a single test case only.
2489     */

2490
2491    public void testEnvironmentConfig()
2492        throws DatabaseException, InterruptedException JavaDoc {
2493
2494        EnvironmentConfig config = TestUtils.initEnvConfig();
2495        /* Control over isolation level is required by this test. */
2496        TestUtils.clearIsolationLevel(config);
2497        checkSerializable(false, config, null, null);
2498
2499        config.setTxnSerializableIsolation(true);
2500        checkSerializable(true, config, null, null);
2501    }
2502
2503    public void testCursorConfig()
2504        throws DatabaseException, InterruptedException JavaDoc {
2505
2506        CursorConfig config = new CursorConfig();
2507        checkSerializable(false, null, config, null);
2508
2509        config.setReadUncommitted(true);
2510        checkSerializable(false, null, config, null);
2511    }
2512
2513    public void testReadUncommittedLockMode()
2514        throws DatabaseException, InterruptedException JavaDoc {
2515
2516        EnvironmentConfig envConfig = TestUtils.initEnvConfig();
2517        /* Control over isolation level is required by this test. */
2518        TestUtils.clearIsolationLevel(envConfig);
2519        envConfig.setTxnSerializableIsolation(true);
2520
2521        checkSerializable(false, envConfig, null, LockMode.READ_UNCOMMITTED);
2522    }
2523
2524    private void checkSerializable(boolean expectSerializable,
2525                                   EnvironmentConfig envConfig,
2526                                   CursorConfig cursorConfig,
2527                                   LockMode lockMode)
2528        throws DatabaseException, InterruptedException JavaDoc {
2529
2530        openEnv(false, envConfig);
2531        DatabaseEntry key = new DatabaseEntry();
2532        DatabaseEntry data = new DatabaseEntry();
2533        OperationStatus status;
2534
2535        /* Insert key 2. */
2536        insert(2);
2537
2538        /* getFirst returns key 2. */
2539        Transaction readerTxn = env.beginTransaction(null, null);
2540        Cursor cursor = db.openCursor(readerTxn, cursorConfig);
2541        status = cursor.getFirst(key, data, lockMode);
2542        assertEquals(OperationStatus.SUCCESS, status);
2543        assertEquals(2, IntegerBinding.entryToInt(key));
2544
2545        /* Should deadlock iff serializable. */
2546        try {
2547            insert(1);
2548            assertTrue(!expectSerializable);
2549        } catch (DeadlockException e) {
2550            assertTrue(expectSerializable);
2551        }
2552
2553        cursor.close();
2554        readerTxn.commit();
2555
2556        /* This method is called multiple times so remove the database. */
2557        db.close();
2558        db = null;
2559        env.removeDatabase(null, DB_NAME);
2560
2561        closeEnv();
2562    }
2563    
2564    /**
2565     * Tests that with a single degree 3 txn we don't obtain the extra lock
2566     * during insert.
2567     */

2568    public void testSingleDegree3TxnOptimization()
2569        throws DatabaseException, InterruptedException JavaDoc {
2570
2571        openEnv(false);
2572
2573        /* Insert key 2. */
2574        insert(2);
2575
2576        StatsConfig clearStats = new StatsConfig();
2577        clearStats.setClear(true);
2578
2579        /* Clear before inserting. */
2580        LockStats stats = env.getLockStats(clearStats);
2581
2582        /* Insert key 1, which would lock key 2 while inserting. */
2583        insert(1);
2584
2585        /* Expect a single lock was requested. */
2586        stats = env.getLockStats(clearStats);
2587        assertEquals(1, stats.getNRequests());
2588
2589        closeEnv();
2590    }
2591    
2592    /**
2593     * Tests a particular getSearchBothRange bug that has come up in several
2594     * contexts. This test is probably redundant with GetSearchBothTest but
2595     * I've left it here for good measure.
2596     */

2597    public void testSingleDatumBug()
2598        throws DatabaseException, InterruptedException JavaDoc {
2599
2600        openEnv(true);
2601        DatabaseEntry key = new DatabaseEntry();
2602        DatabaseEntry data = new DatabaseEntry();
2603        OperationStatus status;
2604
2605        insert(1, 1);
2606        insert(2, 2);
2607
2608        /* getSearchBothRange for {2, 1} returns {2, 2}. */
2609        Transaction readerTxn = env.beginTransaction(null, txnConfig);
2610        Cursor cursor = db.openCursor(readerTxn, null);
2611        IntegerBinding.intToEntry(2, key);
2612        IntegerBinding.intToEntry(1, data);
2613        status = cursor.getSearchBothRange(key, data, null);
2614        assertEquals(OperationStatus.SUCCESS, status);
2615        assertEquals(2, IntegerBinding.entryToInt(key));
2616        assertEquals(2, IntegerBinding.entryToInt(data));
2617
2618        /* If serializable, inserting in the locked range should deadlock. */
2619        try {
2620            insert(1, 2);
2621            if (txnSerializable) {
2622                fail();
2623            }
2624        } catch (DeadlockException e) {
2625            if (!txnSerializable) {
2626                fail();
2627            }
2628        }
2629
2630        cursor.close();
2631        readerTxn.commitNoSync();
2632        closeEnv();
2633    }
2634    
2635    /**
2636     * Tests that searchKey returns SUCCESS when it must skip over a deleted
2637     * duplicate. This did not work at one point and was causing warnings
2638     * (Cursor Not Initialized) in duplicate.conf testing.
2639     */

2640    public void testSearchKeySkipDeletedDup()
2641        throws DatabaseException, InterruptedException JavaDoc {
2642
2643        openEnv(true);
2644
2645        /* Insert {1,1} and {1,2}. */
2646        insert(1, 1);
2647        insert(1, 2);
2648
2649        /* Delete {1,1}. */
2650        Transaction txn = env.beginTransaction(null, txnConfig);
2651        Cursor cursor = db.openCursor(txn, null);
2652        assertEquals(OperationStatus.SUCCESS, searchBoth(cursor, 1, 1));
2653        OperationStatus status = cursor.delete();
2654        assertEquals(OperationStatus.SUCCESS, status);
2655
2656        /* Search for key 1 -- should not return NOTFOUND. */
2657        assertEquals(OperationStatus.SUCCESS, searchKey(cursor, 1, 2));
2658
2659        cursor.close();
2660        txn.commitNoSync();
2661        closeEnv();
2662    }
2663
2664    /**
2665     * Performs getSearchKey on the given key, expects data to be zero.
2666     */

2667    private OperationStatus searchKey(Cursor cursor, int keyVal)
2668        throws DatabaseException {
2669
2670        return searchKey(cursor, keyVal, 0);
2671    }
2672
2673    /**
2674     * Performs getSearchKey on the given key, expects given data value.
2675     */

2676    private OperationStatus searchKey(Cursor cursor, int keyVal, int dataVal)
2677        throws DatabaseException {
2678
2679        DatabaseEntry key = new DatabaseEntry();
2680        DatabaseEntry data = new DatabaseEntry();
2681        IntegerBinding.intToEntry(keyVal, key);
2682        OperationStatus status = cursor.getSearchKey(key, data, null);
2683        if (status == OperationStatus.SUCCESS) {
2684            assertEquals(keyVal, IntegerBinding.entryToInt(key));
2685            assertEquals(dataVal, IntegerBinding.entryToInt(data));
2686        }
2687        return status;
2688    }
2689
2690    /**
2691     * Performs getSearchBoth on the given key and zero data.
2692     */

2693    private OperationStatus searchBoth(Cursor cursor, int keyVal)
2694        throws DatabaseException {
2695
2696        return searchBoth(cursor, keyVal, 0);
2697    }
2698
2699    /**
2700     * Performs getSearchBoth on the given key and data.
2701     */

2702    private OperationStatus searchBoth(Cursor cursor, int keyVal, int dataVal)
2703        throws DatabaseException {
2704
2705        DatabaseEntry key = new DatabaseEntry();
2706        DatabaseEntry data = new DatabaseEntry();
2707        IntegerBinding.intToEntry(keyVal, key);
2708        IntegerBinding.intToEntry(dataVal, data);
2709        OperationStatus status = cursor.getSearchBoth(key, data, null);
2710        if (status == OperationStatus.SUCCESS) {
2711            assertEquals(keyVal, IntegerBinding.entryToInt(key));
2712            assertEquals(dataVal, IntegerBinding.entryToInt(data));
2713        }
2714        return status;
2715    }
2716
2717    /**
2718     * Inserts the given key in a new transaction and commits it.
2719     */

2720    private void insert(int keyVal)
2721        throws DatabaseException {
2722
2723        insert(keyVal, 0);
2724    }
2725
2726    /**
2727     * Inserts the given key and data in a new transaction and commits it.
2728     */

2729    private void insert(int keyVal, int dataVal)
2730        throws DatabaseException {
2731
2732        DatabaseEntry key = new DatabaseEntry();
2733        DatabaseEntry data = new DatabaseEntry();
2734        IntegerBinding.intToEntry(keyVal, key);
2735        IntegerBinding.intToEntry(dataVal, data);
2736        OperationStatus status;
2737        Transaction writerTxn = env.beginTransaction(null, txnConfig);
2738        try {
2739            if (dups) {
2740                status = db.putNoDupData(writerTxn, key, data);
2741            } else {
2742                status = db.putNoOverwrite(writerTxn, key, data);
2743            }
2744        } catch (DeadlockException e) {
2745            writerTxn.abort();
2746            throw e;
2747        }
2748        assertEquals(OperationStatus.SUCCESS, status);
2749        writerTxn.commitNoSync();
2750    }
2751
2752    /**
2753     * Starts writer thread and waits for it to start the insert.
2754     */

2755    private void startInsert(final int keyVal)
2756        throws DatabaseException, InterruptedException JavaDoc {
2757
2758        startInsert(keyVal, 0);
2759    }
2760
2761    /**
2762     * Starts writer thread and waits for it to start the insert.
2763     */

2764    private void startInsert(final int keyVal, final int dataVal)
2765        throws DatabaseException, InterruptedException JavaDoc {
2766
2767        LockStats origStats = env.getLockStats(null);
2768        insertFinished = false;
2769
2770        writerThread = new JUnitThread("Writer") {
2771            public void testBody()
2772                throws DatabaseException {
2773                DatabaseEntry key = new DatabaseEntry();
2774                DatabaseEntry data = new DatabaseEntry();
2775                OperationStatus status;
2776                IntegerBinding.intToEntry(keyVal, key);
2777                IntegerBinding.intToEntry(dataVal, data);
2778                Transaction writerTxn = env.beginTransaction(null, txnConfig);
2779                if (dups) {
2780                    status = db.putNoDupData(writerTxn, key, data);
2781                } else {
2782                    status = db.putNoOverwrite(writerTxn, key, data);
2783                }
2784                assertEquals(OperationStatus.SUCCESS, status);
2785                writerTxn.commitNoSync();
2786                insertFinished = true;
2787            }
2788        };
2789
2790        writerThread.start();
2791
2792        long startTime = System.currentTimeMillis();
2793        while (true) {
2794
2795            /* Give some time to the writer thread. */
2796            Thread.yield();
2797            Thread.sleep(10);
2798            if (System.currentTimeMillis() - startTime > MAX_INSERT_MILLIS) {
2799                fail("Timeout doing insert");
2800            }
2801
2802            if (txnSerializable) {
2803
2804                /* Wait for the insert to block. */
2805                LockStats stats = env.getLockStats(null);
2806                if (stats.getNWaiters() > origStats.getNWaiters()) {
2807                    break;
2808                }
2809            } else {
2810
2811                /* Wait for the operation to complete. */
2812                if (insertFinished) {
2813                    insertFinished = false;
2814                    break;
2815                }
2816            }
2817        }
2818    }
2819
2820    /**
2821     * Waits for the writer thread to finish.
2822     */

2823    private void waitForInsert() {
2824
2825        try {
2826            writerThread.finishTest();
2827        } catch (Throwable JavaDoc e) {
2828            e.printStackTrace();
2829            fail(e.toString());
2830        } finally {
2831            writerThread = null;
2832        }
2833    }
2834}
2835
Popular Tags