KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > CursorTest


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

8
9 package com.sleepycat.je;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.util.Arrays JavaDoc;
14
15 import junit.framework.TestCase;
16
17 import com.sleepycat.je.DbInternal;
18 import com.sleepycat.je.config.EnvironmentParams;
19 import com.sleepycat.je.junit.JUnitThread;
20 import com.sleepycat.je.util.TestUtils;
21
22 public class CursorTest extends TestCase {
23     private static final boolean DEBUG = false;
24     private static final int NUM_RECS = 257;
25
26     /*
27      * Use a ridiculous value because we've seen extreme slowness on ocicat
28      * where dbperf is often running.
29      */

30     private static final long LOCK_TIMEOUT = 50000000L;
31
32     private static final String JavaDoc DUPKEY = "DUPKEY";
33
34     private Environment env;
35     private Database db;
36     private PhantomTestConfiguration config;
37
38     private File JavaDoc envHome;
39     
40     private volatile int sequence;
41
42     public CursorTest() {
43         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
44     }
45
46     public void setUp()
47     throws IOException JavaDoc {
48
49         TestUtils.removeLogFiles("Setup", envHome, false);
50     }
51     
52     public void tearDown()
53     throws IOException JavaDoc {
54
55         if (env != null) {
56             try {
57                 env.close();
58             } catch (Throwable JavaDoc e) {
59                 System.out.println("tearDown: " + e);
60             }
61         }
62     db = null;
63     env = null;
64
65         TestUtils.removeLogFiles("TearDown", envHome, false);
66     }
67
68     public void testGetConfig()
69     throws DatabaseException {
70
71         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
72         envConfig.setTransactional(true);
73         envConfig.setAllowCreate(true);
74         envConfig.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
75         env = new Environment(envHome, envConfig);
76         Transaction txn = env.beginTransaction(null, null);
77         DatabaseConfig dbConfig = new DatabaseConfig();
78         dbConfig.setTransactional(true);
79         dbConfig.setSortedDuplicates(true);
80         dbConfig.setAllowCreate(true);
81         db = env.openDatabase(txn, "testDB", dbConfig);
82     txn.commit();
83     Cursor cursor = null;
84     Transaction txn1 =
85         env.beginTransaction(null, TransactionConfig.DEFAULT);
86     try {
87         cursor = db.openCursor(txn1, CursorConfig.DEFAULT);
88         CursorConfig config = cursor.getConfig();
89         if (config == CursorConfig.DEFAULT) {
90         fail("didn't clone");
91         }
92     } catch (DatabaseException DBE) {
93         DBE.printStackTrace();
94         fail("caught DatabaseException " + DBE);
95     } finally {
96         if (cursor != null) {
97         cursor.close();
98         }
99         txn1.abort();
100         db.close();
101         env.close();
102             env = null;
103     }
104     }
105
106     /**
107      * Put some data in a database, take it out. Yank the file size down so we
108      * have many files.
109      */

110     public void testBasic()
111     throws Throwable JavaDoc {
112
113     try {
114         insertMultiDb(1);
115     } catch (Throwable JavaDoc t) {
116         t.printStackTrace();
117         throw t;
118     }
119     }
120
121     public void testMulti()
122     throws Throwable JavaDoc {
123
124     try {
125         insertMultiDb(4);
126     } catch (Throwable JavaDoc t) {
127         t.printStackTrace();
128         throw t;
129     }
130     }
131
132     /**
133      * Specifies a test configuration. This is just a struct for holding
134      * parameters to be passed down to threads in inner classes.
135      */

136     class PhantomTestConfiguration {
137     String JavaDoc testName;
138     String JavaDoc thread1EntryToLock;
139     String JavaDoc thread1OpArg;
140     String JavaDoc thread2Start;
141     String JavaDoc expectedResult;
142     boolean doInsert;
143     boolean doGetNext;
144     boolean doCommit;
145
146     PhantomTestConfiguration(String JavaDoc testName,
147                  String JavaDoc thread1EntryToLock,
148                  String JavaDoc thread1OpArg,
149                  String JavaDoc thread2Start,
150                  String JavaDoc expectedResult,
151                  boolean doInsert,
152                  boolean doGetNext,
153                  boolean doCommit) {
154         this.testName = testName;
155         this.thread1EntryToLock = thread1EntryToLock;
156         this.thread1OpArg = thread1OpArg;
157         this.thread2Start = thread2Start;
158         this.expectedResult = expectedResult;
159         this.doInsert = doInsert;
160         this.doGetNext = doGetNext;
161         this.doCommit = doCommit;
162     }
163     }
164
165     /**
166      * This series of tests sets up a simple 2 BIN tree with a specific set of
167      * elements (see setupDatabaseAndEnv()). It creates two threads.
168      *
169      * Thread 1 positions a cursor on an element on the edge of a BIN (either
170      * the last element on the left BIN or the first element on the right BIN).
171      * This locks that element. It throws control to thread 2.
172      *
173      * Thread 2 positions a cursor on the adjacent element on the other BIN
174      * (either the first element on the right BIN or the last element on the
175      * left BIN, resp.) It throws control to thread 1. After it signals
176      * thread 1 to continue, thread 2 does either a getNext or getPrev. This
177      * should block because thread 1 has the next/prev element locked.
178      *
179      * Thread 1 then waits a short time (250ms) so that thread 2 can execute
180      * the getNext/getPrev. Thread 1 then inserts or deletes the "phantom
181      * element" right in between the cursors that were set up in the previous
182      * two steps, sleeps a second, and either commits or aborts.
183      *
184      * Thread 2 will then return from the getNext/getPrev. The returned key
185      * from the getNext/getPrev is then verified.
186      *
187      * The Serializable isolation level is not used for either thread so as to
188      * allow phantoms; otherwise, this test would deadlock.
189      *
190      * These parameters are all configured through a PhantomTestConfiguration
191      * instance passed to phantomWorker which has the template for the steps
192      * described above.
193      */

194
195     /**
196      * Phantom test inserting and committing a phantom while doing a getNext.
197      */

198     public void testPhantomInsertGetNextCommit()
199     throws Throwable JavaDoc {
200         
201         try {
202             phantomWorker
203                 (new PhantomTestConfiguration
204                  ("testPhantomInsertGetNextCommit",
205                   "F", "D", "C", "D",
206                   true, true, true));
207         } catch (Exception JavaDoc e) {
208             e.printStackTrace();
209             throw e;
210         }
211     }
212
213     /**
214      * Phantom test inserting and aborting a phantom while doing a getNext.
215      */

216     public void testPhantomInsertGetNextAbort()
217     throws Throwable JavaDoc {
218
219     phantomWorker
220         (new PhantomTestConfiguration
221          ("testPhantomInsertGetNextAbort",
222           "F", "D", "C", "F",
223           true, true, false));
224     }
225
226     /**
227      * Phantom test inserting and committing a phantom while doing a getPrev.
228      */

229     public void testPhantomInsertGetPrevCommit()
230     throws Throwable JavaDoc {
231
232     phantomWorker
233         (new PhantomTestConfiguration
234          ("testPhantomInsertGetPrevCommit",
235           "C", "F", "G", "F",
236           true, false, true));
237     }
238
239     /**
240      * Phantom test inserting and aborting a phantom while doing a getPrev.
241      */

242     public void testPhantomInsertGetPrevAbort()
243     throws Throwable JavaDoc {
244
245     phantomWorker
246         (new PhantomTestConfiguration
247          ("testPhantomInsertGetPrevAbort",
248           "C", "F", "G", "C",
249           true, false, false));
250     }
251
252     /**
253      * Phantom test deleting and committing an edge element while doing a
254      * getNext.
255      */

256     public void testPhantomDeleteGetNextCommit()
257     throws Throwable JavaDoc {
258
259     phantomWorker
260         (new PhantomTestConfiguration
261          ("testPhantomDeleteGetNextCommit",
262           "F", "F", "C", "G",
263           false, true, true));
264     }
265
266     /**
267      * Phantom test deleting and aborting an edge element while doing a
268      * getNext.
269      */

270     public void testPhantomDeleteGetNextAbort()
271     throws Throwable JavaDoc {
272
273     phantomWorker
274         (new PhantomTestConfiguration
275          ("testPhantomDeleteGetNextAbort",
276           "F", "F", "C", "F",
277           false, true, false));
278     }
279
280     /**
281      * Phantom test deleting and committing an edge element while doing a
282      * getPrev.
283      */

284     public void testPhantomDeleteGetPrevCommit()
285     throws Throwable JavaDoc {
286
287     phantomWorker
288         (new PhantomTestConfiguration
289          ("testPhantomDeleteGetPrevCommit",
290           "F", "F", "G", "C",
291           false, false, true));
292     }
293
294     /**
295      * Phantom test deleting and aborting an edge element while doing a
296      * getPrev.
297      */

298     public void testPhantomDeleteGetPrevAbort()
299     throws Throwable JavaDoc {
300
301     phantomWorker
302         (new PhantomTestConfiguration
303          ("testPhantomDeleteGetPrevAbort",
304           "F", "F", "G", "F",
305           false, false, false));
306     }
307
308     /**
309      * Phantom Dup test inserting and committing a phantom while doing a
310      * getNext.
311      */

312     public void testPhantomDupInsertGetNextCommit()
313     throws Throwable JavaDoc {
314
315         try {
316             phantomDupWorker
317                 (new PhantomTestConfiguration
318                  ("testPhantomDupInsertGetNextCommit",
319                   "F", "D", "C", "D",
320                   true, true, true));
321         } catch (Exception JavaDoc e) {
322             e.printStackTrace();
323             throw e;
324         }
325     }
326
327     /**
328      * Phantom Dup test inserting and aborting a phantom while doing a getNext.
329      */

330     public void testPhantomDupInsertGetNextAbort()
331     throws Throwable JavaDoc {
332
333     phantomDupWorker
334         (new PhantomTestConfiguration
335          ("testPhantomDupInsertGetNextAbort",
336           "F", "D", "C", "F",
337           true, true, false));
338     }
339
340     /**
341      * Phantom Dup test inserting and committing a phantom while doing a
342      * getPrev.
343      */

344     public void testPhantomDupInsertGetPrevCommit()
345     throws Throwable JavaDoc {
346
347     phantomDupWorker
348         (new PhantomTestConfiguration
349          ("testPhantomDupInsertGetPrevCommit",
350           "C", "F", "G", "F",
351           true, false, true));
352     }
353
354     /**
355      * Phantom Dup test inserting and aborting a phantom while doing a getPrev.
356      */

357     public void testPhantomDupInsertGetPrevAbort()
358     throws Throwable JavaDoc {
359
360     phantomDupWorker
361         (new PhantomTestConfiguration
362          ("testPhantomDupInsertGetPrevAbort",
363           "C", "F", "G", "C",
364           true, false, false));
365     }
366
367     /**
368      * Phantom Dup test deleting and committing an edge element while doing a
369      * getNext.
370      */

371     public void testPhantomDupDeleteGetNextCommit()
372     throws Throwable JavaDoc {
373
374     phantomDupWorker
375         (new PhantomTestConfiguration
376          ("testPhantomDupDeleteGetNextCommit",
377           "F", "F", "C", "G",
378           false, true, true));
379     }
380
381     /**
382      * Phantom Dup test deleting and aborting an edge element while doing a
383      * getNext.
384      */

385     public void testPhantomDupDeleteGetNextAbort()
386     throws Throwable JavaDoc {
387
388     phantomDupWorker
389         (new PhantomTestConfiguration
390          ("testPhantomDupDeleteGetNextAbort",
391           "F", "F", "C", "F",
392           false, true, false));
393     }
394
395     /**
396      * Phantom Dup test deleting and committing an edge element while doing a
397      * getPrev.
398      */

399     public void testPhantomDupDeleteGetPrevCommit()
400     throws Throwable JavaDoc {
401
402     phantomDupWorker
403         (new PhantomTestConfiguration
404          ("testPhantomDupDeleteGetPrevCommit",
405           "F", "F", "G", "C",
406           false, false, true));
407     }
408
409     /**
410      * Phantom Dup test deleting and aborting an edge element while doing a
411      * getPrev.
412      */

413     public void testPhantomDupDeleteGetPrevAbort()
414     throws Throwable JavaDoc {
415
416     phantomDupWorker
417         (new PhantomTestConfiguration
418          ("testPhantomDupDeleteGetPrevAbort",
419           "F", "F", "G", "F",
420           false, false, false));
421     }
422
423     private void phantomWorker(PhantomTestConfiguration c)
424     throws Throwable JavaDoc {
425
426     try {
427         this.config = c;
428         setupDatabaseAndEnv(false);
429
430         if (config.doInsert &&
431         !config.doGetNext) {
432
433         Transaction txnDel =
434             env.beginTransaction(null, TransactionConfig.DEFAULT);
435
436         /*
437          * Delete the first entry in the second bin so that we can
438          * reinsert it in tester1 and have it be the first entry in
439          * that bin. If we left F and then tried to insert something
440          * to the left of F, it would end up in the first bin.
441          */

442         assertEquals(OperationStatus.SUCCESS,
443                  db.delete(txnDel,
444                        new DatabaseEntry("F".getBytes())));
445         txnDel.commit();
446         }
447
448         JUnitThread tester1 =
449         new JUnitThread(config.testName + "1") {
450             public void testBody()
451             throws Throwable JavaDoc {
452
453             Cursor cursor = null;
454             try {
455                 Transaction txn1 =
456                 env.beginTransaction(null, null);
457                 cursor = db.openCursor(txn1, CursorConfig.DEFAULT);
458                 OperationStatus status =
459                 cursor.getSearchKey
460                 (new DatabaseEntry
461                  (config.thread1EntryToLock.getBytes()),
462                  new DatabaseEntry(),
463                  LockMode.RMW);
464                 assertEquals(OperationStatus.SUCCESS, status);
465                 sequence++; // 0 -> 1
466

467                 while (sequence < 2) {
468                 Thread.yield();
469                 }
470
471                 /*
472                  * Since we can't increment sequence when tester2
473                  * blocks on the getNext call, all we can do is
474                  * bump sequence right before the getNext, and then
475                  * wait a little in this thread for tester2 to
476                  * block.
477                  */

478                 try {
479                 Thread.sleep(250);
480                 } catch (InterruptedException JavaDoc IE) {
481                 }
482
483                 if (config.doInsert) {
484                 status = db.put
485                     (txn1,
486                      new DatabaseEntry
487                      (config.thread1OpArg.getBytes()),
488                      new DatabaseEntry(new byte[10]));
489                 } else {
490                 status = db.delete
491                     (txn1,
492                      new DatabaseEntry
493                      (config.thread1OpArg.getBytes()));
494                 }
495                 assertEquals(OperationStatus.SUCCESS, status);
496                 sequence++; // 2 -> 3
497

498                 try {
499                 Thread.sleep(1000);
500                 } catch (InterruptedException JavaDoc IE) {
501                 }
502
503                 cursor.close();
504                 cursor = null;
505                 if (config.doCommit) {
506                 txn1.commit();
507                 } else {
508                 txn1.abort();
509                 }
510             } catch (DatabaseException DBE) {
511                 if (cursor != null) {
512                 cursor.close();
513                 }
514                 DBE.printStackTrace();
515                 fail("caught DatabaseException " + DBE);
516             }
517             }
518         };
519
520         JUnitThread tester2 =
521         new JUnitThread(config.testName + "2") {
522             public void testBody()
523             throws Throwable JavaDoc {
524
525             Cursor cursor = null;
526             try {
527                 Transaction txn2 =
528                 env.beginTransaction(null, null);
529                 txn2.setLockTimeout(LOCK_TIMEOUT);
530                 cursor = db.openCursor(txn2, CursorConfig.DEFAULT);
531
532                 while (sequence < 1) {
533                 Thread.yield();
534                 }
535
536                 OperationStatus status =
537                 cursor.getSearchKey
538                 (new DatabaseEntry
539                  (config.thread2Start.getBytes()),
540                  new DatabaseEntry(),
541                  LockMode.DEFAULT);
542                 assertEquals(OperationStatus.SUCCESS, status);
543
544                 sequence++; // 1 -> 2
545
DatabaseEntry nextKey = new DatabaseEntry();
546                 try {
547
548                 /*
549                  * This will block until tester1 above commits.
550                  */

551                 if (config.doGetNext) {
552                     status =
553                     cursor.getNext(nextKey,
554                                new DatabaseEntry(),
555                                LockMode.DEFAULT);
556                 } else {
557                     status =
558                     cursor.getPrev(nextKey,
559                                new DatabaseEntry(),
560                                LockMode.DEFAULT);
561                 }
562                 } catch (DatabaseException DBE) {
563                 System.out.println("t2 caught " + DBE);
564                 }
565                 assertEquals(3, sequence);
566                 assertEquals(config.expectedResult,
567                      new String JavaDoc(nextKey.getData()));
568                 cursor.close();
569                 cursor = null;
570                 txn2.commit();
571             } catch (DatabaseException DBE) {
572                 if (cursor != null) {
573                 cursor.close();
574                 }
575                 DBE.printStackTrace();
576                 fail("caught DatabaseException " + DBE);
577             }
578             }
579         };
580
581         tester1.start();
582         tester2.start();
583
584         tester1.finishTest();
585         tester2.finishTest();
586     } finally {
587         db.close();
588         env.close();
589             env = null;
590     }
591     }
592
593     private void phantomDupWorker(PhantomTestConfiguration c)
594     throws Throwable JavaDoc {
595
596     Cursor cursor = null;
597     try {
598         this.config = c;
599         setupDatabaseAndEnv(true);
600
601         if (config.doInsert &&
602         !config.doGetNext) {
603
604         Transaction txnDel =
605             env.beginTransaction(null, TransactionConfig.DEFAULT);
606         cursor = db.openCursor(txnDel, CursorConfig.DEFAULT);
607
608         /*
609          * Delete the first entry in the second bin so that we can
610          * reinsert it in tester1 and have it be the first entry in
611          * that bin. If we left F and then tried to insert something
612          * to the left of F, it would end up in the first bin.
613          */

614         assertEquals(OperationStatus.SUCCESS, cursor.getSearchBoth
615                  (new DatabaseEntry(DUPKEY.getBytes()),
616                   new DatabaseEntry("F".getBytes()),
617                   LockMode.DEFAULT));
618         assertEquals(OperationStatus.SUCCESS, cursor.delete());
619         cursor.close();
620         cursor = null;
621         txnDel.commit();
622         }
623
624         JUnitThread tester1 =
625         new JUnitThread(config.testName + "1") {
626             public void testBody()
627             throws Throwable JavaDoc {
628
629             Cursor cursor = null;
630             Cursor c = null;
631             try {
632                 Transaction txn1 =
633                 env.beginTransaction(null, null);
634                 cursor = db.openCursor(txn1, CursorConfig.DEFAULT);
635                 OperationStatus status =
636                 cursor.getSearchBoth
637                 (new DatabaseEntry(DUPKEY.getBytes()),
638                  new DatabaseEntry
639                  (config.thread1EntryToLock.getBytes()),
640                  LockMode.RMW);
641                 assertEquals(OperationStatus.SUCCESS, status);
642                 cursor.close();
643                 cursor = null;
644                 sequence++; // 0 -> 1
645

646                 while (sequence < 2) {
647                 Thread.yield();
648                 }
649
650                 /*
651                  * Since we can't increment sequence when tester2
652                  * blocks on the getNext call, all we can do is
653                  * bump sequence right before the getNext, and then
654                  * wait a little in this thread for tester2 to
655                  * block.
656                  */

657                 try {
658                 Thread.sleep(250);
659                 } catch (InterruptedException JavaDoc IE) {
660                 }
661
662                 if (config.doInsert) {
663                 status = db.put
664                     (txn1,
665                      new DatabaseEntry(DUPKEY.getBytes()),
666                      new DatabaseEntry
667                      (config.thread1OpArg.getBytes()));
668                 } else {
669                 c = db.openCursor(txn1, CursorConfig.DEFAULT);
670                 assertEquals(OperationStatus.SUCCESS,
671                          c.getSearchBoth
672                          (new DatabaseEntry
673                           (DUPKEY.getBytes()),
674                           new DatabaseEntry
675                           (config.thread1OpArg.getBytes()),
676                           LockMode.DEFAULT));
677                 assertEquals(OperationStatus.SUCCESS,
678                          c.delete());
679                 c.close();
680                 c = null;
681                 }
682                 assertEquals(OperationStatus.SUCCESS, status);
683                 sequence++; // 2 -> 3
684

685                 try {
686                 Thread.sleep(1000);
687                 } catch (InterruptedException JavaDoc IE) {
688                 }
689
690                 if (config.doCommit) {
691                 txn1.commit();
692                 } else {
693                 txn1.abort();
694                 }
695             } catch (DatabaseException DBE) {
696                 if (cursor != null) {
697                 cursor.close();
698                 }
699                 if (c != null) {
700                 c.close();
701                 }
702                 DBE.printStackTrace();
703                 fail("caught DatabaseException " + DBE);
704             }
705             }
706         };
707
708         JUnitThread tester2 =
709         new JUnitThread("testPhantomInsert2") {
710             public void testBody()
711             throws Throwable JavaDoc {
712
713             Cursor cursor = null;
714             try {
715                 Transaction txn2 =
716                 env.beginTransaction(null, null);
717                 txn2.setLockTimeout(LOCK_TIMEOUT);
718                 cursor = db.openCursor(txn2, CursorConfig.DEFAULT);
719
720                 while (sequence < 1) {
721                 Thread.yield();
722                 }
723
724                 OperationStatus status =
725                 cursor.getSearchBoth
726                 (new DatabaseEntry(DUPKEY.getBytes()),
727                  new DatabaseEntry
728                  (config.thread2Start.getBytes()),
729                  LockMode.DEFAULT);
730                 assertEquals(OperationStatus.SUCCESS, status);
731
732                 sequence++; // 1 -> 2
733
DatabaseEntry nextKey = new DatabaseEntry();
734                 DatabaseEntry nextData = new DatabaseEntry();
735                 try {
736
737                 /*
738                  * This will block until tester1 above commits.
739                  */

740                 if (config.doGetNext) {
741                     status =
742                     cursor.getNextDup(nextKey, nextData,
743                               LockMode.DEFAULT);
744                 } else {
745                     status =
746                     cursor.getPrevDup(nextKey, nextData,
747                               LockMode.DEFAULT);
748                 }
749                 } catch (DatabaseException DBE) {
750                 System.out.println("t2 caught " + DBE);
751                 }
752                 assertEquals(3, sequence);
753                 byte[] data = nextData.getData();
754                 assertEquals(config.expectedResult,
755                      new String JavaDoc(data));
756                 cursor.close();
757                 cursor = null;
758                 txn2.commit();
759             } catch (DatabaseException DBE) {
760                 if (cursor != null) {
761                 cursor.close();
762                 }
763                 DBE.printStackTrace();
764                 fail("caught DatabaseException " + DBE);
765             }
766             }
767         };
768
769         tester1.start();
770         tester2.start();
771
772         tester1.finishTest();
773         tester2.finishTest();
774     } finally {
775         if (cursor != null) {
776         cursor.close();
777         }
778         db.close();
779         env.close();
780             env = null;
781     }
782     }
783
784     /**
785      * Sets up a small database with a tree containing 2 bins, one with A, B,
786      * and C, and the other with F, G, H, and I.
787      */

788     private void setupDatabaseAndEnv(boolean writeAsDuplicateData)
789     throws DatabaseException {
790
791         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
792
793         /* RepeatableRead isolation is required by this test. */
794         TestUtils.clearIsolationLevel(envConfig);
795
796     DbInternal.disableParameterValidation(envConfig);
797         envConfig.setTransactional(true);
798         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
799                                  "6");
800         envConfig.setConfigParam(EnvironmentParams.NODE_MAX_DUPTREE.getName(),
801                                  "6");
802         envConfig.setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
803                                  "1024");
804         envConfig.setConfigParam(EnvironmentParams.ENV_CHECK_LEAKS.getName(),
805                                  "true");
806         envConfig.setAllowCreate(true);
807         envConfig.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
808         env = new Environment(envHome, envConfig);
809         Transaction txn = env.beginTransaction(null, null);
810         DatabaseConfig dbConfig = new DatabaseConfig();
811         dbConfig.setTransactional(true);
812         dbConfig.setSortedDuplicates(true);
813         dbConfig.setAllowCreate(true);
814         db = env.openDatabase(txn, "testDB", dbConfig);
815
816     if (writeAsDuplicateData) {
817         writeDuplicateData(db, txn);
818     } else {
819         writeData(db, txn);
820     }
821
822     txn.commit();
823     }
824
825     String JavaDoc[] dataStrings = {
826     "A", "B", "C", "F", "G", "H", "I"
827     };
828
829     private void writeData(Database db, Transaction txn)
830     throws DatabaseException {
831
832     for (int i = 0; i < dataStrings.length; i++) {
833         db.put(txn, new DatabaseEntry(dataStrings[i].getBytes()),
834            new DatabaseEntry(new byte[10]));
835     }
836     }
837
838     private void writeDuplicateData(Database db, Transaction txn)
839     throws DatabaseException {
840
841     for (int i = 0; i < dataStrings.length; i++) {
842         db.put(txn, new DatabaseEntry(DUPKEY.getBytes()),
843            new DatabaseEntry(dataStrings[i].getBytes()));
844     }
845     }
846
847     /**
848      * Insert data over many databases.
849      */

850     private void insertMultiDb(int numDbs)
851     throws DatabaseException {
852
853         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
854
855         /* RepeatableRead isolation is required by this test. */
856         TestUtils.clearIsolationLevel(envConfig);
857
858     DbInternal.disableParameterValidation(envConfig);
859         envConfig.setTransactional(true);
860         envConfig.setConfigParam
861         (EnvironmentParams.LOG_FILE_MAX.getName(), "1024");
862         envConfig.setConfigParam
863         (EnvironmentParams.ENV_CHECK_LEAKS.getName(), "true");
864     envConfig.setConfigParam
865         (EnvironmentParams.NODE_MAX.getName(), "6");
866         envConfig.setConfigParam
867         (EnvironmentParams.NODE_MAX_DUPTREE.getName(), "6");
868         envConfig.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
869         envConfig.setAllowCreate(true);
870         Environment env = new Environment(envHome, envConfig);
871
872         Database[] myDb = new Database[numDbs];
873         Cursor[] cursor = new Cursor[numDbs];
874         Transaction txn =
875         env.beginTransaction(null, TransactionConfig.DEFAULT);
876
877         DatabaseConfig dbConfig = new DatabaseConfig();
878         dbConfig.setTransactional(true);
879         dbConfig.setAllowCreate(true);
880         dbConfig.setSortedDuplicates(true);
881         for (int i = 0; i < numDbs; i++) {
882             myDb[i] = env.openDatabase(txn, "testDB" + i, dbConfig);
883
884             cursor[i] = myDb[i].openCursor(txn, CursorConfig.DEFAULT);
885         }
886
887         /* Insert data in a round robin fashion to spread over log. */
888         DatabaseEntry key = new DatabaseEntry();
889         DatabaseEntry data = new DatabaseEntry();
890         for (int i = NUM_RECS; i > 0; i--) {
891             for (int c = 0; c < numDbs; c++) {
892                 key.setData(TestUtils.getTestArray(i + c));
893                 data.setData(TestUtils.getTestArray(i + c));
894                 if (DEBUG) {
895                     System.out.println("i = " + i +
896                                        TestUtils.dumpByteArray(key.getData()));
897                 }
898                 cursor[c].put(key, data);
899             }
900         }
901
902         for (int i = 0; i < numDbs; i++) {
903             cursor[i].close();
904             myDb[i].close();
905         }
906         txn.commit();
907
908         assertTrue(env.verify(null, System.err));
909         env.close();
910         env = null;
911
912         envConfig.setAllowCreate(false);
913         env = new Environment(envHome, envConfig);
914
915         /*
916          * Before running the verifier, run the cleaner to make sure it has
917          * completed. Otherwise, the cleaner will be running when we call
918          * verify, and open txns will be reported.
919          */

920         env.cleanLog();
921
922         env.verify(null, System.err);
923
924         /* Check each db in turn, using null transactions. */
925         dbConfig.setTransactional(false);
926         dbConfig.setAllowCreate(false);
927         for (int d = 0; d < numDbs; d++) {
928             Database checkDb = env.openDatabase(null, "testDB" + d,
929                         dbConfig);
930             Cursor myCursor = checkDb.openCursor(null, CursorConfig.DEFAULT);
931
932             OperationStatus status =
933         myCursor.getFirst(key, data, LockMode.DEFAULT);
934
935             int i = 1;
936             while (status == OperationStatus.SUCCESS) {
937                 byte[] expectedKey = TestUtils.getTestArray(i + d);
938                 byte[] expectedData = TestUtils.getTestArray(i + d);
939
940                 if (DEBUG) {
941                     System.out.println("Database " + d + " Key " + i +
942                                        " expected = " +
943                                        TestUtils.dumpByteArray(expectedKey) +
944                                        " seen = " +
945                                        TestUtils.dumpByteArray(key.getData()));
946                 }
947
948                 assertTrue("Database " + d + " Key " + i + " expected = " +
949                            TestUtils.dumpByteArray(expectedKey) +
950                            " seen = " +
951                            TestUtils.dumpByteArray(key.getData()),
952                            Arrays.equals(expectedKey, key.getData()));
953                 assertTrue("Data " + i, Arrays.equals(expectedData,
954                                                       data.getData()));
955                 i++;
956
957                 status = myCursor.getNext(key, data, LockMode.DEFAULT);
958             }
959         myCursor.close();
960             assertEquals("Number recs seen", NUM_RECS, i-1);
961             checkDb.close();
962         }
963         env.close();
964         env = null;
965     }
966 }
967
Popular Tags