KickJava   Java API By Example, From Geeks To Geeks.

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


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

8
9 package com.sleepycat.je.test;
10
11 import java.util.Arrays JavaDoc;
12 import java.util.List JavaDoc;
13
14 import junit.framework.Test;
15
16 import com.sleepycat.je.Cursor;
17 import com.sleepycat.je.Database;
18 import com.sleepycat.je.DatabaseConfig;
19 import com.sleepycat.je.DatabaseEntry;
20 import com.sleepycat.je.DatabaseException;
21 import com.sleepycat.je.EnvironmentConfig;
22 import com.sleepycat.je.LockMode;
23 import com.sleepycat.je.OperationStatus;
24 import com.sleepycat.je.SecondaryConfig;
25 import com.sleepycat.je.SecondaryCursor;
26 import com.sleepycat.je.SecondaryDatabase;
27 import com.sleepycat.je.SecondaryKeyCreator;
28 import com.sleepycat.je.Transaction;
29 import com.sleepycat.je.config.EnvironmentParams;
30 import com.sleepycat.je.util.TestUtils;
31
32 public class SecondaryTest extends MultiKeyTxnTestCase {
33
34     private static final int NUM_RECS = 5;
35     private static final int KEY_OFFSET = 100;
36
37     private static EnvironmentConfig envConfig = TestUtils.initEnvConfig();
38     static {
39         envConfig.setConfigParam(EnvironmentParams.ENV_CHECK_LEAKS.getName(),
40                                  "false");
41         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
42                                  "6");
43         envConfig.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
44         envConfig.setAllowCreate(true);
45     }
46
47     public static Test suite() {
48
49         return multiKeyTxnTestSuite(SecondaryTest.class, envConfig, null);
50     }
51
52     public void testPutAndDelete()
53         throws DatabaseException {
54
55         SecondaryDatabase secDb = initDb();
56         Database priDb = secDb.getPrimaryDatabase();
57
58         DatabaseEntry data = new DatabaseEntry();
59         DatabaseEntry key = new DatabaseEntry();
60         OperationStatus status;
61         Transaction txn = txnBegin();
62         
63         /* Database.put() */
64         status = priDb.put(txn, entry(1), entry(2));
65         assertSame(OperationStatus.SUCCESS, status);
66         status = secDb.get(txn, entry(102), key, data, LockMode.DEFAULT);
67         assertSame(OperationStatus.SUCCESS, status);
68         assertDataEquals(entry(1), key);
69         assertDataEquals(entry(2), data);
70
71         /* Database.putNoOverwrite() */
72         status = priDb.putNoOverwrite(txn, entry(1), entry(1));
73         assertSame(OperationStatus.KEYEXIST, status);
74         status = secDb.get(txn, entry(102), key, data, LockMode.DEFAULT);
75         assertSame(OperationStatus.SUCCESS, status);
76         assertDataEquals(entry(1), key);
77         assertDataEquals(entry(2), data);
78         
79         /* Database.put() overwrite */
80         status = priDb.put(txn, entry(1), entry(3));
81         assertSame(OperationStatus.SUCCESS, status);
82         status = secDb.get(txn, entry(102), key, data, LockMode.DEFAULT);
83         assertSame(OperationStatus.NOTFOUND, status);
84         status = secDb.get(txn, entry(103), key, data, LockMode.DEFAULT);
85         assertSame(OperationStatus.SUCCESS, status);
86         assertDataEquals(entry(1), key);
87         assertDataEquals(entry(3), data);
88         
89         /* Database.delete() */
90         status = priDb.delete(txn, entry(1));
91         assertSame(OperationStatus.SUCCESS, status);
92         status = priDb.delete(txn, entry(1));
93         assertSame(OperationStatus.NOTFOUND, status);
94         status = secDb.get(txn, entry(103), key, data, LockMode.DEFAULT);
95         assertSame(OperationStatus.NOTFOUND, status);
96         
97         /* SecondaryDatabase.delete() */
98         status = priDb.put(txn, entry(1), entry(1));
99         assertSame(OperationStatus.SUCCESS, status);
100         status = priDb.put(txn, entry(2), entry(1));
101         assertSame(OperationStatus.SUCCESS, status);
102         status = secDb.get(txn, entry(101), key, data, LockMode.DEFAULT);
103         assertSame(OperationStatus.SUCCESS, status);
104         assertDataEquals(entry(1), key);
105         assertDataEquals(entry(1), data);
106         status = secDb.delete(txn, entry(101));
107         assertSame(OperationStatus.SUCCESS, status);
108         status = secDb.delete(txn, entry(101));
109         assertSame(OperationStatus.NOTFOUND, status);
110         status = secDb.get(txn, entry(101), key, data, LockMode.DEFAULT);
111         assertSame(OperationStatus.NOTFOUND, status);
112         status = priDb.get(txn, entry(1), data, LockMode.DEFAULT);
113         assertSame(OperationStatus.NOTFOUND, status);
114         status = priDb.get(txn, entry(2), data, LockMode.DEFAULT);
115         assertSame(OperationStatus.NOTFOUND, status);
116
117         /*
118          * Database.putNoDupData() cannot be called since the primary cannot be
119          * configured for duplicates.
120          */

121
122         /* Primary and secondary are empty now. */
123
124         /* Get a txn for a cursor. */
125         txnCommit(txn);
126         txn = txnBeginCursor();
127
128         Cursor priCursor = null;
129         SecondaryCursor secCursor = null;
130         try {
131             priCursor = priDb.openCursor(txn, null);
132             secCursor = secDb.openSecondaryCursor(txn, null);
133
134             /* Cursor.putNoOverwrite() */
135             status = priCursor.putNoOverwrite(entry(1), entry(2));
136             assertSame(OperationStatus.SUCCESS, status);
137             status = secCursor.getSearchKey(entry(102), key, data,
138                                             LockMode.DEFAULT);
139             assertSame(OperationStatus.SUCCESS, status);
140             assertDataEquals(entry(1), key);
141             assertDataEquals(entry(2), data);
142
143             /* Cursor.putCurrent() */
144             status = priCursor.putCurrent(entry(3));
145             assertSame(OperationStatus.SUCCESS, status);
146             status = secCursor.getSearchKey(entry(102), key, data,
147                                             LockMode.DEFAULT);
148             assertSame(OperationStatus.NOTFOUND, status);
149             status = secCursor.getSearchKey(entry(103), key, data,
150                                             LockMode.DEFAULT);
151             assertSame(OperationStatus.SUCCESS, status);
152             assertDataEquals(entry(1), key);
153             assertDataEquals(entry(3), data);
154
155             /* Cursor.delete() */
156             status = priCursor.delete();
157             assertSame(OperationStatus.SUCCESS, status);
158             status = priCursor.delete();
159             assertSame(OperationStatus.KEYEMPTY, status);
160             status = secCursor.getSearchKey(entry(103), key, data,
161                                             LockMode.DEFAULT);
162             assertSame(OperationStatus.NOTFOUND, status);
163             status = priCursor.getSearchKey(entry(1), data,
164                                             LockMode.DEFAULT);
165             assertSame(OperationStatus.NOTFOUND, status);
166
167             /* Cursor.put() */
168             status = priCursor.put(entry(1), entry(4));
169             assertSame(OperationStatus.SUCCESS, status);
170             status = secCursor.getSearchKey(entry(104), key, data,
171                                             LockMode.DEFAULT);
172             assertSame(OperationStatus.SUCCESS, status);
173             assertDataEquals(entry(1), key);
174             assertDataEquals(entry(4), data);
175
176             /* SecondaryCursor.delete() */
177             status = secCursor.delete();
178             assertSame(OperationStatus.SUCCESS, status);
179             status = secCursor.delete();
180             assertSame(OperationStatus.KEYEMPTY, status);
181             status = secCursor.getCurrent(new DatabaseEntry(), key, data,
182                                           LockMode.DEFAULT);
183             assertSame(OperationStatus.KEYEMPTY, status);
184             status = secCursor.getSearchKey(entry(104), key, data,
185                                             LockMode.DEFAULT);
186             assertSame(OperationStatus.NOTFOUND, status);
187             status = priCursor.getSearchKey(entry(1), data,
188                                             LockMode.DEFAULT);
189             assertSame(OperationStatus.NOTFOUND, status);
190
191             /*
192              * Cursor.putNoDupData() cannot be called since the primary cannot
193              * be configured for duplicates.
194              */

195
196             /* Primary and secondary are empty now. */
197         } finally {
198             if (secCursor != null) {
199                 secCursor.close();
200             }
201             if (priCursor != null) {
202                 priCursor.close();
203             }
204         }
205
206         txnCommit(txn);
207         secDb.close();
208         priDb.close();
209     }
210
211     public void testGet()
212         throws DatabaseException {
213
214         SecondaryDatabase secDb = initDb();
215         Database priDb = secDb.getPrimaryDatabase();
216
217         DatabaseEntry data = new DatabaseEntry();
218         DatabaseEntry key = new DatabaseEntry();
219         DatabaseEntry secKey = new DatabaseEntry();
220         OperationStatus status;
221         Transaction txn = txnBegin();
222
223         /*
224          * For parameters that do not require initialization with a non-null
225          * data array, we set them to null to make sure this works. [#12121]
226          */

227
228         /* Add one record for each key with one data/duplicate. */
229         for (int i = 0; i < NUM_RECS; i += 1) {
230             status = priDb.put(txn, entry(i), entry(i));
231             assertSame(OperationStatus.SUCCESS, status);
232         }
233
234         /* SecondaryDatabase.get() */
235         for (int i = 0; i < NUM_RECS; i += 1) {
236
237             data.setData(null);
238             status = secDb.get(txn, entry(i + KEY_OFFSET), key,
239                                data, LockMode.DEFAULT);
240             assertSame(OperationStatus.SUCCESS, status);
241             assertDataEquals(entry(i), key);
242             assertDataEquals(entry(i), data);
243         }
244         data.setData(null);
245         status = secDb.get(txn, entry(NUM_RECS + KEY_OFFSET), key,
246                            data, LockMode.DEFAULT);
247         assertSame(OperationStatus.NOTFOUND, status);
248
249         /* SecondaryDatabase.getSearchBoth() */
250         for (int i = 0; i < NUM_RECS; i += 1) {
251             data.setData(null);
252             status = secDb.getSearchBoth(txn, entry(i + KEY_OFFSET), entry(i),
253                                          data, LockMode.DEFAULT);
254             assertSame(OperationStatus.SUCCESS, status);
255             assertDataEquals(entry(i), data);
256         }
257         data.setData(null);
258         status = secDb.getSearchBoth(txn, entry(NUM_RECS + KEY_OFFSET),
259                                      entry(NUM_RECS), data, LockMode.DEFAULT);
260         assertSame(OperationStatus.NOTFOUND, status);
261
262         /* Get a cursor txn. */
263         txnCommit(txn);
264         txn = txnBeginCursor();
265
266         SecondaryCursor cursor = secDb.openSecondaryCursor(txn, null);
267         try {
268             /* SecondaryCursor.getFirst()/getNext() */
269             secKey.setData(null);
270             key.setData(null);
271             data.setData(null);
272             status = cursor.getFirst(secKey, key, data, LockMode.DEFAULT);
273             for (int i = 0; i < NUM_RECS; i += 1) {
274                 assertSame(OperationStatus.SUCCESS, status);
275                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
276                 assertDataEquals(entry(i), key);
277                 assertDataEquals(entry(i), data);
278                 secKey.setData(null);
279                 key.setData(null);
280                 data.setData(null);
281                 status = cursor.getNext(secKey, key, data, LockMode.DEFAULT);
282             }
283             assertSame(OperationStatus.NOTFOUND, status);
284
285             /* SecondaryCursor.getCurrent() (last) */
286             secKey.setData(null);
287             key.setData(null);
288             data.setData(null);
289             status = cursor.getCurrent(secKey, key, data, LockMode.DEFAULT);
290             assertSame(OperationStatus.SUCCESS, status);
291             assertDataEquals(entry(NUM_RECS - 1 + KEY_OFFSET), secKey);
292             assertDataEquals(entry(NUM_RECS - 1), key);
293             assertDataEquals(entry(NUM_RECS - 1), data);
294
295             /* SecondaryCursor.getLast()/getPrev() */
296             secKey.setData(null);
297             key.setData(null);
298             data.setData(null);
299             status = cursor.getLast(secKey, key, data, LockMode.DEFAULT);
300             for (int i = NUM_RECS - 1; i >= 0; i -= 1) {
301                 assertSame(OperationStatus.SUCCESS, status);
302                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
303                 assertDataEquals(entry(i), key);
304                 assertDataEquals(entry(i), data);
305                 secKey.setData(null);
306                 key.setData(null);
307                 data.setData(null);
308                 status = cursor.getPrev(secKey, key, data, LockMode.DEFAULT);
309             }
310             assertSame(OperationStatus.NOTFOUND, status);
311
312             /* SecondaryCursor.getCurrent() (first) */
313             secKey.setData(null);
314             key.setData(null);
315             data.setData(null);
316             status = cursor.getCurrent(secKey, key, data, LockMode.DEFAULT);
317             assertSame(OperationStatus.SUCCESS, status);
318             assertDataEquals(entry(0 + KEY_OFFSET), secKey);
319             assertDataEquals(entry(0), key);
320             assertDataEquals(entry(0), data);
321
322             /* SecondaryCursor.getSearchKey() */
323             key.setData(null);
324             data.setData(null);
325             status = cursor.getSearchKey(entry(KEY_OFFSET - 1), key,
326                                          data, LockMode.DEFAULT);
327             assertSame(OperationStatus.NOTFOUND, status);
328             for (int i = 0; i < NUM_RECS; i += 1) {
329                 key.setData(null);
330                 data.setData(null);
331                 status = cursor.getSearchKey(entry(i + KEY_OFFSET), key,
332                                              data, LockMode.DEFAULT);
333                 assertSame(OperationStatus.SUCCESS, status);
334                 assertDataEquals(entry(i), key);
335                 assertDataEquals(entry(i), data);
336             }
337             key.setData(null);
338             data.setData(null);
339             status = cursor.getSearchKey(entry(NUM_RECS + KEY_OFFSET), key,
340                                          data, LockMode.DEFAULT);
341             assertSame(OperationStatus.NOTFOUND, status);
342
343             /* SecondaryCursor.getSearchBoth() */
344             data.setData(null);
345             status = cursor.getSearchKey(entry(KEY_OFFSET - 1), entry(0),
346                                          data, LockMode.DEFAULT);
347             assertSame(OperationStatus.NOTFOUND, status);
348             for (int i = 0; i < NUM_RECS; i += 1) {
349                 data.setData(null);
350                 status = cursor.getSearchBoth(entry(i + KEY_OFFSET), entry(i),
351                                               data, LockMode.DEFAULT);
352                 assertSame(OperationStatus.SUCCESS, status);
353                 assertDataEquals(entry(i), data);
354             }
355             data.setData(null);
356             status = cursor.getSearchBoth(entry(NUM_RECS + KEY_OFFSET),
357                                           entry(NUM_RECS), data,
358                                           LockMode.DEFAULT);
359             assertSame(OperationStatus.NOTFOUND, status);
360
361             /* SecondaryCursor.getSearchKeyRange() */
362             key.setData(null);
363             data.setData(null);
364             status = cursor.getSearchKeyRange(entry(KEY_OFFSET - 1), key,
365                                               data, LockMode.DEFAULT);
366             assertSame(OperationStatus.SUCCESS, status);
367             assertDataEquals(entry(0), key);
368             assertDataEquals(entry(0), data);
369             for (int i = 0; i < NUM_RECS; i += 1) {
370                 key.setData(null);
371                 data.setData(null);
372                 status = cursor.getSearchKeyRange(entry(i + KEY_OFFSET), key,
373                                                   data, LockMode.DEFAULT);
374                 assertSame(OperationStatus.SUCCESS, status);
375                 assertDataEquals(entry(i), key);
376                 assertDataEquals(entry(i), data);
377             }
378             key.setData(null);
379             data.setData(null);
380             status = cursor.getSearchKeyRange(entry(NUM_RECS + KEY_OFFSET),
381                                               key, data, LockMode.DEFAULT);
382             assertSame(OperationStatus.NOTFOUND, status);
383
384             /* SecondaryCursor.getSearchBothRange() */
385             data.setData(null);
386             status = cursor.getSearchBothRange(entry(1 + KEY_OFFSET), entry(1),
387                                                data, LockMode.DEFAULT);
388             assertSame(OperationStatus.SUCCESS, status);
389             assertDataEquals(entry(1), data);
390             for (int i = 0; i < NUM_RECS; i += 1) {
391                 data.setData(null);
392                 status = cursor.getSearchBothRange(entry(i + KEY_OFFSET),
393                                                    entry(i), data,
394                                                    LockMode.DEFAULT);
395                 assertSame(OperationStatus.SUCCESS, status);
396                 assertDataEquals(entry(i), data);
397             }
398             data.setData(null);
399             status = cursor.getSearchBothRange(entry(NUM_RECS + KEY_OFFSET),
400                                                entry(NUM_RECS), data,
401                                                LockMode.DEFAULT);
402             assertSame(OperationStatus.NOTFOUND, status);
403
404             /* Add one duplicate for each key. */
405             Cursor priCursor = priDb.openCursor(txn, null);
406             try {
407                 for (int i = 0; i < NUM_RECS; i += 1) {
408                     status = priCursor.put(entry(i + KEY_OFFSET), entry(i));
409                     assertSame(OperationStatus.SUCCESS, status);
410                 }
411             } finally {
412                 priCursor.close();
413             }
414
415             /* SecondaryCursor.getNextDup() */
416             secKey.setData(null);
417             key.setData(null);
418             data.setData(null);
419             status = cursor.getFirst(secKey, key, data, LockMode.DEFAULT);
420             for (int i = 0; i < NUM_RECS; i += 1) {
421                 assertSame(OperationStatus.SUCCESS, status);
422                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
423                 assertDataEquals(entry(i), key);
424                 assertDataEquals(entry(i), data);
425                 secKey.setData(null);
426                 key.setData(null);
427                 data.setData(null);
428                 status = cursor.getNextDup(secKey, key, data,
429                                            LockMode.DEFAULT);
430                 assertSame(OperationStatus.SUCCESS, status);
431                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
432                 assertDataEquals(entry(i + KEY_OFFSET), key);
433                 assertDataEquals(entry(i), data);
434                 secKey.setData(null);
435                 key.setData(null);
436                 data.setData(null);
437                 status = cursor.getNextDup(secKey, key, data,
438                                            LockMode.DEFAULT);
439                 assertSame(OperationStatus.NOTFOUND, status);
440                 secKey.setData(null);
441                 key.setData(null);
442                 data.setData(null);
443                 status = cursor.getNext(secKey, key, data, LockMode.DEFAULT);
444             }
445             assertSame(OperationStatus.NOTFOUND, status);
446
447             /* SecondaryCursor.getNextNoDup() */
448             secKey.setData(null);
449             key.setData(null);
450             data.setData(null);
451             status = cursor.getFirst(secKey, key, data, LockMode.DEFAULT);
452             for (int i = 0; i < NUM_RECS; i += 1) {
453                 assertSame(OperationStatus.SUCCESS, status);
454                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
455                 assertDataEquals(entry(i), key);
456                 assertDataEquals(entry(i), data);
457                 secKey.setData(null);
458                 key.setData(null);
459                 data.setData(null);
460                 status = cursor.getNextNoDup(secKey, key, data,
461                                              LockMode.DEFAULT);
462             }
463             assertSame(OperationStatus.NOTFOUND, status);
464
465             /* SecondaryCursor.getPrevDup() */
466             secKey.setData(null);
467             key.setData(null);
468             data.setData(null);
469             status = cursor.getLast(secKey, key, data, LockMode.DEFAULT);
470             for (int i = NUM_RECS - 1; i >= 0; i -= 1) {
471                 assertSame(OperationStatus.SUCCESS, status);
472                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
473                 assertDataEquals(entry(i + KEY_OFFSET), key);
474                 assertDataEquals(entry(i), data);
475                 secKey.setData(null);
476                 key.setData(null);
477                 data.setData(null);
478                 status = cursor.getPrevDup(secKey, key, data,
479                                            LockMode.DEFAULT);
480                 assertSame(OperationStatus.SUCCESS, status);
481                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
482                 assertDataEquals(entry(i), key);
483                 assertDataEquals(entry(i), data);
484                 secKey.setData(null);
485                 key.setData(null);
486                 data.setData(null);
487                 status = cursor.getPrevDup(secKey, key, data,
488                                            LockMode.DEFAULT);
489                 assertSame(OperationStatus.NOTFOUND, status);
490                 secKey.setData(null);
491                 key.setData(null);
492                 data.setData(null);
493                 status = cursor.getPrev(secKey, key, data, LockMode.DEFAULT);
494             }
495             assertSame(OperationStatus.NOTFOUND, status);
496
497             /* SecondaryCursor.getPrevNoDup() */
498             secKey.setData(null);
499             key.setData(null);
500             data.setData(null);
501             status = cursor.getLast(secKey, key, data, LockMode.DEFAULT);
502             for (int i = NUM_RECS - 1; i >= 0; i -= 1) {
503                 assertSame(OperationStatus.SUCCESS, status);
504                 assertDataEquals(entry(i + KEY_OFFSET), secKey);
505                 assertDataEquals(entry(i + KEY_OFFSET), key);
506                 assertDataEquals(entry(i), data);
507                 secKey.setData(null);
508                 key.setData(null);
509                 data.setData(null);
510                 status = cursor.getPrevNoDup(secKey, key, data,
511                                              LockMode.DEFAULT);
512             }
513             assertSame(OperationStatus.NOTFOUND, status);
514         } finally {
515             cursor.close();
516         }
517
518         txnCommit(txn);
519         secDb.close();
520         priDb.close();
521     }
522
523     public void testOpenAndClose()
524         throws DatabaseException {
525
526         Database priDb = openDatabase(false, "testDB", false);
527
528         /* Open two secondaries as regular databases and as secondaries. */
529         Database secDbDetached = openDatabase(true, "testSecDB", false);
530         SecondaryDatabase secDb = openSecondary(priDb, true, "testSecDB",
531                                                 false, false);
532         Database secDb2Detached = openDatabase(true, "testSecDB2", false);
533         SecondaryDatabase secDb2 = openSecondary(priDb, true, "testSecDB2",
534                                                  false, false);
535         assertEquals(priDb.getSecondaryDatabases(),
536                      Arrays.asList(new SecondaryDatabase[] {secDb, secDb2}));
537
538         Transaction txn = txnBegin();
539
540         /* Check that primary writes to both secondaries. */
541         checkSecondaryUpdate(txn, priDb, 1, secDbDetached, true,
542                                             secDb2Detached, true);
543         
544         /* New txn before closing database. */
545         txnCommit(txn);
546         txn = txnBegin();
547
548         /* Close 2nd secondary. */
549         secDb2.close();
550         assertEquals(priDb.getSecondaryDatabases(),
551                      Arrays.asList(new SecondaryDatabase[] {secDb }));
552
553         /* Check that primary writes to 1st secondary only. */
554         checkSecondaryUpdate(txn, priDb, 2, secDbDetached, true,
555                                              secDb2Detached, false);
556         
557         /* New txn before closing database. */
558         txnCommit(txn);
559         txn = txnBegin();
560
561         /* Close 1st secondary. */
562         secDb.close();
563         assertEquals(0, priDb.getSecondaryDatabases().size());
564
565         /* Check that primary writes to no secondaries. */
566         checkSecondaryUpdate(txn, priDb, 3, secDbDetached, false,
567                                             secDb2Detached, false);
568
569         /* Open the two secondaries again. */
570         secDb = openSecondary(priDb, true, "testSecDB", false, false);
571         secDb2 = openSecondary(priDb, true, "testSecDB2", false, false);
572         assertEquals(priDb.getSecondaryDatabases(),
573                      Arrays.asList(new SecondaryDatabase[] {secDb, secDb2}));
574
575         /* Check that primary writes to both secondaries. */
576         checkSecondaryUpdate(txn, priDb, 4, secDbDetached, true,
577                                             secDb2Detached, true);
578
579         /* Close the primary first to disassociate secondaries. */
580         txnCommit(txn);
581         priDb.close();
582         assertNull(secDb.getPrimaryDatabase());
583         assertNull(secDb2.getPrimaryDatabase());
584         secDb2.close();
585         secDb.close();
586
587         secDb2Detached.close();
588         secDbDetached.close();
589     }
590
591     /**
592      * Check that primary put() writes to each secondary that is open.
593      */

594     private void checkSecondaryUpdate(Transaction txn, Database priDb, int val,
595                                       Database secDb, boolean expectSecDbVal,
596                                       Database secDb2, boolean expectSecDb2Val)
597         throws DatabaseException {
598
599         OperationStatus status;
600         DatabaseEntry data = new DatabaseEntry();
601         int secVal = KEY_OFFSET + val;
602
603         status = priDb.put(txn, entry(val), entry(val));
604         assertSame(OperationStatus.SUCCESS, status);
605
606         status = secDb.get(txn, entry(secVal), data, LockMode.DEFAULT);
607         assertSame(expectSecDbVal ? OperationStatus.SUCCESS
608                                   : OperationStatus.NOTFOUND, status);
609
610
611         status = secDb2.get(txn, entry(secVal), data, LockMode.DEFAULT);
612         assertSame(expectSecDb2Val ? OperationStatus.SUCCESS
613                                    : OperationStatus.NOTFOUND, status);
614
615         status = priDb.delete(txn, entry(val));
616         assertSame(OperationStatus.SUCCESS, status);
617     }
618
619     public void testReadOnly()
620         throws DatabaseException {
621
622         SecondaryDatabase secDb = initDb();
623         Database priDb = secDb.getPrimaryDatabase();
624         OperationStatus status;
625         Transaction txn = txnBegin();
626
627         for (int i = 0; i < NUM_RECS; i += 1) {
628             status = priDb.put(txn, entry(i), entry(i));
629             assertSame(OperationStatus.SUCCESS, status);
630         }
631
632         /*
633          * Secondaries can be opened without a key creator if the primary is
634          * read only. openSecondary will specify a null key creator if the
635          * readOnly param is false.
636          */

637         Database readOnlyPriDb = openDatabase(false, "testDB", true);
638         SecondaryDatabase readOnlySecDb = openSecondary(readOnlyPriDb,
639                                                         true, "testSecDB",
640                                                         false, true);
641         assertNull(readOnlySecDb.getSecondaryConfig().getKeyCreator());
642         verifyRecords(txn, readOnlySecDb, NUM_RECS, true);
643
644         txnCommit(txn);
645         readOnlySecDb.close();
646         readOnlyPriDb.close();
647         secDb.close();
648         priDb.close();
649     }
650
651     public void testPopulate()
652         throws DatabaseException {
653
654         Database priDb = openDatabase(false, "testDB", false);
655         Transaction txn = txnBegin();
656
657         /* Test population of newly created secondary database. */
658         
659         for (int i = 0; i < NUM_RECS; i += 1) {
660             assertSame(OperationStatus.SUCCESS,
661                        priDb.put(txn, entry(i), entry(i)));
662         }
663         txnCommit(txn);
664
665         SecondaryDatabase secDb = openSecondary(priDb, true, "testSecDB",
666                                                 true, false);
667         txn = txnBegin();
668         verifyRecords(txn, secDb, NUM_RECS, true);
669         txnCommit(txn);
670
671         /*
672          * Clear secondary and perform populate again, to test the case where
673          * an existing database is opened, and therefore a write txn will only
674          * be created in order to populate it
675          */

676         Database secDbDetached = openDatabase(true, "testSecDB", false);
677         secDb.close();
678         txn = txnBegin();
679         for (int i = 0; i < NUM_RECS; i += 1) {
680             assertSame(OperationStatus.SUCCESS,
681                        secDbDetached.delete(txn, entry(i + KEY_OFFSET)));
682         }
683         verifyRecords(txn, secDbDetached, 0, true);
684         txnCommit(txn);
685         secDb = openSecondary(priDb, true, "testSecDB", true, false);
686         txn = txnBegin();
687         verifyRecords(txn, secDb, NUM_RECS, true);
688         verifyRecords(txn, secDbDetached, NUM_RECS, true);
689
690         txnCommit(txn);
691         secDbDetached.close();
692         secDb.close();
693         priDb.close();
694     }
695
696     public void testTruncate()
697         throws DatabaseException {
698
699         SecondaryDatabase secDb = initDb();
700         Database priDb = secDb.getPrimaryDatabase();
701         Transaction txn = txnBegin();
702         
703         for (int i = 0; i < NUM_RECS; i += 1) {
704             priDb.put(txn, entry(i), entry(i));
705         }
706         verifyRecords(txn, priDb, NUM_RECS, false);
707         verifyRecords(txn, secDb, NUM_RECS, true);
708         txnCommit(txn);
709         secDb.close();
710         priDb.close();
711
712         txn = txnBegin();
713         assertEquals(NUM_RECS, env.truncateDatabase(txn, "testDB", true));
714         assertEquals(NUM_RECS, env.truncateDatabase(txn, "testSecDB", true));
715         txnCommit(txn);
716
717         secDb = initDb();
718         priDb = secDb.getPrimaryDatabase();
719
720         txn = txnBegin();
721         verifyRecords(txn, priDb, 0, false);
722         verifyRecords(txn, secDb, 0, true);
723         txnCommit(txn);
724
725         secDb.close();
726         priDb.close();
727     }
728
729     private void verifyRecords(Transaction txn, Database db, int numRecs,
730                                boolean isSecondary)
731         throws DatabaseException {
732
733         /* We're only reading, so txn may be null. */
734         Cursor cursor = db.openCursor(txn, null);
735         try {
736             DatabaseEntry data = new DatabaseEntry();
737             DatabaseEntry key = new DatabaseEntry();
738             OperationStatus status;
739             int count = 0;
740             status = cursor.getFirst(key, data, LockMode.DEFAULT);
741             while (status == OperationStatus.SUCCESS) {
742                 assertDataEquals(entry(count), data);
743                 if (isSecondary) {
744                     assertDataEquals(entry(count + KEY_OFFSET), key);
745                 } else {
746                     assertDataEquals(entry(count), key);
747                 }
748                 count += 1;
749                 status = cursor.getNext(key, data, LockMode.DEFAULT);
750             }
751             assertEquals(numRecs, count);
752         } finally {
753             cursor.close();
754         }
755     }
756
757     public void testUniqueSecondaryKey()
758         throws DatabaseException {
759
760         Database priDb = openDatabase(false, "testDB", false);
761         SecondaryDatabase secDb = openSecondary(priDb, false, "testSecDB",
762                                                 false, false);
763         DatabaseEntry key;
764         DatabaseEntry data;
765         DatabaseEntry pkey = new DatabaseEntry();
766         Transaction txn;
767
768         /* Put {0, 0} */
769         txn = txnBegin();
770         key = entry(0);
771         data = entry(0);
772         priDb.put(txn, key, data);
773         txnCommit(txn);
774         assertEquals(OperationStatus.SUCCESS,
775                      secDb.get(null, entry(0 + KEY_OFFSET),
776                                pkey, data, null));
777         assertEquals(0, TestUtils.getTestVal(pkey.getData()));
778         assertEquals(0, TestUtils.getTestVal(data.getData()));
779
780         /* Put {1, 1} */
781         txn = txnBegin();
782         key = entry(1);
783         data = entry(1);
784         priDb.put(txn, key, data);
785         txnCommit(txn);
786         assertEquals(OperationStatus.SUCCESS,
787                      secDb.get(null, entry(1 + KEY_OFFSET),
788                                pkey, data, null));
789         assertEquals(1, TestUtils.getTestVal(pkey.getData()));
790         assertEquals(1, TestUtils.getTestVal(data.getData()));
791
792         /* Put {2, 0} */
793         txn = txnBegin();
794         key = entry(2);
795         data = entry(0);
796         try {
797             priDb.put(txn, key, data);
798             /* Expect exception because secondary key must be unique. */
799             fail();
800         } catch (DatabaseException e) {
801             txnAbort(txn);
802             /* Ensure that primary record was not inserted. */
803             assertEquals(OperationStatus.NOTFOUND,
804                          secDb.get(null, key, data, null));
805             /* Ensure that secondary record has not changed. */
806             assertEquals(OperationStatus.SUCCESS,
807                          secDb.get(null, entry(0 + KEY_OFFSET),
808                                    pkey, data, null));
809             assertEquals(0, TestUtils.getTestVal(pkey.getData()));
810             assertEquals(0, TestUtils.getTestVal(data.getData()));
811         }
812
813         /* Overwrite {1, 1} */
814         txn = txnBegin();
815         key = entry(1);
816         data = entry(1);
817         priDb.put(txn, key, data);
818         txnCommit(txn);
819         assertEquals(OperationStatus.SUCCESS,
820                      secDb.get(null, entry(1 + KEY_OFFSET),
821                                pkey, data, null));
822         assertEquals(1, TestUtils.getTestVal(pkey.getData()));
823         assertEquals(1, TestUtils.getTestVal(data.getData()));
824
825         /* Modify secondary key to {1, 3} */
826         txn = txnBegin();
827         key = entry(1);
828         data = entry(3);
829         priDb.put(txn, key, data);
830         txnCommit(txn);
831         assertEquals(OperationStatus.SUCCESS,
832                      secDb.get(null, entry(3 + KEY_OFFSET),
833                                pkey, data, null));
834         assertEquals(1, TestUtils.getTestVal(pkey.getData()));
835         assertEquals(3, TestUtils.getTestVal(data.getData()));
836
837         secDb.close();
838         priDb.close();
839     }
840
841     /**
842      * @deprecated use of Database.truncate
843      */

844     public void testOperationsNotAllowed()
845         throws DatabaseException {
846
847         SecondaryDatabase secDb = initDb();
848         Database priDb = secDb.getPrimaryDatabase();
849         Transaction txn = txnBegin();
850
851         /* Open secondary without a key creator. */
852         try {
853             env.openSecondaryDatabase(txn, "xxx", priDb, null);
854             fail();
855         } catch (NullPointerException JavaDoc expected) { }
856         try {
857             env.openSecondaryDatabase(txn, "xxx", priDb,
858                                       new SecondaryConfig());
859             fail();
860         } catch (NullPointerException JavaDoc expected) { }
861
862         /* Open secondary with both single and multi key creators. */
863         SecondaryConfig config = new SecondaryConfig();
864         config.setKeyCreator(new MyKeyCreator());
865         config.setMultiKeyCreator
866             (new SimpleMultiKeyCreator(new MyKeyCreator()));
867         try {
868             env.openSecondaryDatabase(txn, "xxx", priDb, config);
869             fail();
870         } catch (IllegalArgumentException JavaDoc expected) { }
871         
872         /* Database operations. */
873
874         DatabaseEntry key = entry(1);
875         DatabaseEntry data = entry(2);
876
877         try {
878             secDb.getSearchBoth(txn, key, data, LockMode.DEFAULT);
879             fail();
880         } catch (UnsupportedOperationException JavaDoc expected) { }
881
882         try {
883             secDb.put(txn, key, data);
884             fail();
885         } catch (UnsupportedOperationException JavaDoc expected) { }
886
887         try {
888             secDb.putNoOverwrite(txn, key, data);
889             fail();
890         } catch (UnsupportedOperationException JavaDoc expected) { }
891
892         try {
893             secDb.putNoDupData(txn, key, data);
894             fail();
895         } catch (UnsupportedOperationException JavaDoc expected) { }
896
897         try {
898             secDb.truncate(txn, true);
899             fail();
900         } catch (UnsupportedOperationException JavaDoc expected) { }
901
902         try {
903             secDb.join(new Cursor[0], null);
904             fail();
905         } catch (UnsupportedOperationException JavaDoc expected) { }
906
907         /* Cursor operations. */
908
909         txnCommit(txn);
910         txn = txnBeginCursor();
911
912         SecondaryCursor cursor = null;
913         try {
914             cursor = secDb.openSecondaryCursor(txn, null);
915
916             try {
917                 cursor.getSearchBoth(key, data, LockMode.DEFAULT);
918                 fail();
919             } catch (UnsupportedOperationException JavaDoc expected) { }
920
921             try {
922                 cursor.getSearchBothRange(key, data, LockMode.DEFAULT);
923                 fail();
924             } catch (UnsupportedOperationException JavaDoc expected) { }
925
926             try {
927                 cursor.putCurrent(data);
928                 fail();
929             } catch (UnsupportedOperationException JavaDoc expected) { }
930
931             try {
932                 cursor.put(key, data);
933                 fail();
934             } catch (UnsupportedOperationException JavaDoc expected) { }
935
936             try {
937                 cursor.putNoOverwrite(key, data);
938                 fail();
939             } catch (UnsupportedOperationException JavaDoc expected) { }
940
941             try {
942                 cursor.putNoDupData(key, data);
943                 fail();
944             } catch (UnsupportedOperationException JavaDoc expected) { }
945         } finally {
946             if (cursor != null) {
947                 cursor.close();
948             }
949         }
950
951         txnCommit(txn);
952         secDb.close();
953         priDb.close();
954
955         /* Primary with duplicates. */
956         priDb = openDatabase(true, "testDBWithDups", false);
957         try {
958             openSecondary(priDb, true, "testSecDB", false, false);
959             fail();
960         } catch (IllegalArgumentException JavaDoc expected) {}
961
962         priDb.close();
963
964         /* Single secondary with two primaries.*/
965         Database pri1 = openDatabase(false, "pri1", false);
966         Database pri2 = openDatabase(false, "pri2", false);
967         Database sec1 = openSecondary(pri1, false, "sec", false, false);
968         try {
969             openSecondary(pri2, false, "sec", false, false);
970             fail();
971         } catch (IllegalArgumentException JavaDoc expected) {}
972         sec1.close();
973         pri1.close();
974         pri2.close();
975     }
976
977     /**
978      * Test that null can be passed for the LockMode to all get methods.
979      */

980     public void testNullLockMode()
981         throws DatabaseException {
982
983         SecondaryDatabase secDb = initDb();
984         Database priDb = secDb.getPrimaryDatabase();
985         Transaction txn = txnBegin();
986
987         DatabaseEntry key = entry(0);
988         DatabaseEntry data = entry(0);
989         DatabaseEntry secKey = entry(KEY_OFFSET);
990         DatabaseEntry found = new DatabaseEntry();
991         DatabaseEntry found2 = new DatabaseEntry();
992         DatabaseEntry found3 = new DatabaseEntry();
993
994         assertEquals(OperationStatus.SUCCESS,
995                      priDb.put(txn, key, data));
996         assertEquals(OperationStatus.SUCCESS,
997                      priDb.put(txn, entry(1), data));
998         assertEquals(OperationStatus.SUCCESS,
999                      priDb.put(txn, entry(2), entry(2)));
1000
1001        /* Database operations. */
1002
1003        assertEquals(OperationStatus.SUCCESS,
1004                     priDb.get(txn, key, found, null));
1005        assertEquals(OperationStatus.SUCCESS,
1006                     priDb.getSearchBoth(txn, key, data, null));
1007        assertEquals(OperationStatus.SUCCESS,
1008                     secDb.get(txn, secKey, found, null));
1009        assertEquals(OperationStatus.SUCCESS,
1010                     secDb.get(txn, secKey, found, found2, null));
1011        assertEquals(OperationStatus.SUCCESS,
1012                     secDb.getSearchBoth(txn, secKey, key, found, null));
1013
1014        /* Cursor operations. */
1015
1016        txnCommit(txn);
1017        txn = txnBeginCursor();
1018        Cursor cursor = priDb.openCursor(txn, null);
1019        SecondaryCursor secCursor = secDb.openSecondaryCursor(txn, null);
1020
1021        assertEquals(OperationStatus.SUCCESS,
1022                     cursor.getSearchKey(key, found, null));
1023        assertEquals(OperationStatus.SUCCESS,
1024                     cursor.getSearchBoth(key, data, null));
1025        assertEquals(OperationStatus.SUCCESS,
1026                     cursor.getSearchKeyRange(key, found, null));
1027        assertEquals(OperationStatus.SUCCESS,
1028                     cursor.getSearchBothRange(key, data, null));
1029        assertEquals(OperationStatus.SUCCESS,
1030                     cursor.getFirst(found, found2, null));
1031        assertEquals(OperationStatus.SUCCESS,
1032                     cursor.getNext(found, found2, null));
1033        assertEquals(OperationStatus.SUCCESS,
1034                     cursor.getPrev(found, found2, null));
1035        assertEquals(OperationStatus.NOTFOUND,
1036                     cursor.getNextDup(found, found2, null));
1037        assertEquals(OperationStatus.NOTFOUND,
1038                     cursor.getPrevDup(found, found2, null));
1039        assertEquals(OperationStatus.SUCCESS,
1040                     cursor.getNextNoDup(found, found2, null));
1041        assertEquals(OperationStatus.SUCCESS,
1042                     cursor.getPrevNoDup(found, found2, null));
1043        assertEquals(OperationStatus.SUCCESS,
1044                     cursor.getLast(found, found2, null));
1045
1046        assertEquals(OperationStatus.SUCCESS,
1047                     secCursor.getSearchKey(secKey, found, null));
1048        assertEquals(OperationStatus.SUCCESS,
1049                     secCursor.getSearchKeyRange(secKey, found, null));
1050        assertEquals(OperationStatus.SUCCESS,
1051                     secCursor.getFirst(found, found2, null));
1052        assertEquals(OperationStatus.SUCCESS,
1053                     secCursor.getNext(found, found2, null));
1054        assertEquals(OperationStatus.SUCCESS,
1055                     secCursor.getPrev(found, found2, null));
1056        assertEquals(OperationStatus.SUCCESS,
1057                     secCursor.getNextDup(found, found2, null));
1058        assertEquals(OperationStatus.SUCCESS,
1059                     secCursor.getPrevDup(found, found2, null));
1060        assertEquals(OperationStatus.SUCCESS,
1061                     secCursor.getNextNoDup(found, found2, null));
1062        assertEquals(OperationStatus.SUCCESS,
1063                     secCursor.getPrevNoDup(found, found2, null));
1064        assertEquals(OperationStatus.SUCCESS,
1065                     secCursor.getLast(found, found2, null));
1066
1067        assertEquals(OperationStatus.SUCCESS,
1068                     secCursor.getSearchKey(secKey, found, found2, null));
1069        assertEquals(OperationStatus.SUCCESS,
1070                     secCursor.getSearchBoth(secKey, data, found, null));
1071        assertEquals(OperationStatus.SUCCESS,
1072                     secCursor.getSearchKeyRange(secKey, found, found2, null));
1073        assertEquals(OperationStatus.SUCCESS,
1074                     secCursor.getSearchBothRange(secKey, data, found, null));
1075        assertEquals(OperationStatus.SUCCESS,
1076                     secCursor.getFirst(found, found2, found3, null));
1077        assertEquals(OperationStatus.SUCCESS,
1078                     secCursor.getNext(found, found2, found3, null));
1079        assertEquals(OperationStatus.SUCCESS,
1080                     secCursor.getPrev(found, found2, found3, null));
1081        assertEquals(OperationStatus.SUCCESS,
1082                     secCursor.getNextDup(found, found2, found3, null));
1083        assertEquals(OperationStatus.SUCCESS,
1084                     secCursor.getPrevDup(found, found2, found3, null));
1085        assertEquals(OperationStatus.SUCCESS,
1086                     secCursor.getNextNoDup(found, found2, found3, null));
1087        assertEquals(OperationStatus.SUCCESS,
1088                     secCursor.getPrevNoDup(found, found2, found3, null));
1089        assertEquals(OperationStatus.SUCCESS,
1090                     secCursor.getLast(found, found2, found3, null));
1091
1092        secCursor.close();
1093        cursor.close();
1094        txnCommit(txn);
1095        secDb.close();
1096        priDb.close();
1097        env.close();
1098        env = null;
1099    }
1100
1101    /**
1102     * Test that an exception is thrown when a cursor is used in the wrong
1103     * state. No put or get is allowed in the closed state, and certain gets
1104     * and puts are not allowed in the uninitialized state.
1105     */

1106    public void testCursorState()
1107        throws DatabaseException {
1108
1109        SecondaryDatabase secDb = initDb();
1110        Database priDb = secDb.getPrimaryDatabase();
1111        Transaction txn = txnBegin();
1112
1113        DatabaseEntry key = entry(0);
1114        DatabaseEntry data = entry(0);
1115        DatabaseEntry secKey = entry(KEY_OFFSET);
1116        DatabaseEntry found = new DatabaseEntry();
1117        DatabaseEntry found2 = new DatabaseEntry();
1118
1119        assertEquals(OperationStatus.SUCCESS,
1120                     priDb.put(txn, key, data));
1121
1122        txnCommit(txn);
1123        txn = txnBeginCursor();
1124        Cursor cursor = priDb.openCursor(txn, null);
1125        SecondaryCursor secCursor = secDb.openSecondaryCursor(txn, null);
1126
1127        /* Check the uninitialized state for certain operations. */
1128
1129        try {
1130            cursor.count();
1131            fail();
1132        } catch (DatabaseException expected) {}
1133        try {
1134            cursor.delete();
1135            fail();
1136        } catch (DatabaseException expected) {}
1137        try {
1138            cursor.putCurrent(data);
1139            fail();
1140        } catch (DatabaseException expected) {}
1141        try {
1142            cursor.getCurrent(key, data, null);
1143            fail();
1144        } catch (DatabaseException expected) {}
1145        try {
1146            cursor.getNextDup(found, found2, null);
1147            fail();
1148        } catch (DatabaseException expected) {}
1149        try {
1150            cursor.getPrevDup(found, found2, null);
1151            fail();
1152        } catch (DatabaseException expected) {}
1153
1154        try {
1155            secCursor.count();
1156            fail();
1157        } catch (DatabaseException expected) {}
1158        try {
1159            secCursor.delete();
1160            fail();
1161        } catch (DatabaseException expected) {}
1162        try {
1163            secCursor.getCurrent(key, data, null);
1164            fail();
1165        } catch (DatabaseException expected) {}
1166        try {
1167            secCursor.getNextDup(found, found2, null);
1168            fail();
1169        } catch (DatabaseException expected) {}
1170        try {
1171            secCursor.getPrevDup(found, found2, null);
1172            fail();
1173        } catch (DatabaseException expected) {}
1174
1175        /* Initialize, then close, then check all operations. */
1176
1177        assertEquals(OperationStatus.SUCCESS,
1178                     cursor.getSearchKey(key, found, null));
1179        assertEquals(OperationStatus.SUCCESS,
1180                     secCursor.getSearchKey(secKey, found, null));
1181        secCursor.close();
1182        cursor.close();
1183
1184        try {
1185            cursor.close();
1186            fail();
1187        } catch (DatabaseException expected) {}
1188        try {
1189            cursor.count();
1190            fail();
1191        } catch (DatabaseException expected) {}
1192        try {
1193            cursor.delete();
1194            fail();
1195        } catch (DatabaseException expected) {}
1196        try {
1197            cursor.put(key, data);
1198            fail();
1199        } catch (DatabaseException expected) {}
1200        try {
1201            cursor.putNoOverwrite(key, data);
1202            fail();
1203        } catch (DatabaseException expected) {}
1204        try {
1205            cursor.putNoDupData(key, data);
1206            fail();
1207        } catch (DatabaseException expected) {}
1208        try {
1209            cursor.putCurrent(data);
1210            fail();
1211        } catch (DatabaseException expected) {}
1212        try {
1213            cursor.getCurrent(key, data, null);
1214            fail();
1215        } catch (DatabaseException expected) {}
1216        try {
1217            cursor.getSearchKey(key, found, null);
1218            fail();
1219        } catch (DatabaseException expected) {}
1220        try {
1221            cursor.getSearchBoth(key, data, null);
1222            fail();
1223        } catch (DatabaseException expected) {}
1224        try {
1225            cursor.getSearchKeyRange(key, found, null);
1226            fail();
1227        } catch (DatabaseException expected) {}
1228        try {
1229            cursor.getSearchBothRange(key, data, null);
1230            fail();
1231        } catch (DatabaseException expected) {}
1232        try {
1233            cursor.getFirst(found, found2, null);
1234            fail();
1235        } catch (DatabaseException expected) {}
1236        try {
1237            cursor.getNext(found, found2, null);
1238            fail();
1239        } catch (DatabaseException expected) {}
1240        try {
1241            cursor.getPrev(found, found2, null);
1242            fail();
1243        } catch (DatabaseException expected) {}
1244        try {
1245            cursor.getNextDup(found, found2, null);
1246            fail();
1247        } catch (DatabaseException expected) {}
1248        try {
1249            cursor.getPrevDup(found, found2, null);
1250            fail();
1251        } catch (DatabaseException expected) {}
1252        try {
1253            cursor.getNextNoDup(found, found2, null);
1254            fail();
1255        } catch (DatabaseException expected) {}
1256        try {
1257            cursor.getPrevNoDup(found, found2, null);
1258            fail();
1259        } catch (DatabaseException expected) {}
1260        try {
1261            cursor.getLast(found, found2, null);
1262            fail();
1263        } catch (DatabaseException expected) {}
1264
1265        try {
1266            secCursor.close();
1267            fail();
1268        } catch (DatabaseException expected) {}
1269        try {
1270            secCursor.count();
1271            fail();
1272        } catch (DatabaseException expected) {}
1273        try {
1274            secCursor.delete();
1275            fail();
1276        } catch (DatabaseException expected) {}
1277        try {
1278            secCursor.getCurrent(key, data, null);
1279            fail();
1280        } catch (DatabaseException expected) {}
1281        try {
1282            secCursor.getSearchKey(secKey, found, null);
1283            fail();
1284        } catch (DatabaseException expected) {}
1285        try {
1286            secCursor.getSearchKeyRange(secKey, found, null);
1287            fail();
1288        } catch (DatabaseException expected) {}
1289        try {
1290            secCursor.getFirst(found, found2, null);
1291            fail();
1292        } catch (DatabaseException expected) {}
1293        try {
1294            secCursor.getNext(found, found2, null);
1295            fail();
1296        } catch (DatabaseException expected) {}
1297        try {
1298            secCursor.getPrev(found, found2, null);
1299            fail();
1300        } catch (DatabaseException expected) {}
1301        try {
1302            secCursor.getNextDup(found, found2, null);
1303            fail();
1304        } catch (DatabaseException expected) {}
1305        try {
1306            secCursor.getPrevDup(found, found2, null);
1307            fail();
1308        } catch (DatabaseException expected) {}
1309        try {
1310            secCursor.getNextNoDup(found, found2, null);
1311            fail();
1312        } catch (DatabaseException expected) {}
1313        try {
1314            secCursor.getPrevNoDup(found, found2, null);
1315            fail();
1316        } catch (DatabaseException expected) {}
1317        try {
1318            secCursor.getLast(found, found2, null);
1319            fail();
1320        } catch (DatabaseException expected) {}
1321
1322        txnCommit(txn);
1323        secDb.close();
1324        priDb.close();
1325        env.close();
1326        env = null;
1327    }
1328
1329    /**
1330     * [#14966]
1331     */

1332    public void testDirtyReadPartialGet()
1333        throws DatabaseException {
1334
1335        SecondaryDatabase secDb = initDb();
1336        Database priDb = secDb.getPrimaryDatabase();
1337
1338        DatabaseEntry data = new DatabaseEntry();
1339        DatabaseEntry key = new DatabaseEntry();
1340        DatabaseEntry secKey = new DatabaseEntry();
1341        OperationStatus status;
1342
1343        /* Put a record */
1344        Transaction txn = txnBegin();
1345        status = priDb.put(txn, entry(0), entry(0));
1346        assertSame(OperationStatus.SUCCESS, status);
1347        txnCommit(txn);
1348
1349        /* Regular get */
1350        status = secDb.get(null, entry(0 + KEY_OFFSET), key,
1351                           data, LockMode.DEFAULT);
1352        assertSame(OperationStatus.SUCCESS, status);
1353        assertDataEquals(entry(0), key);
1354        assertDataEquals(entry(0), data);
1355
1356        /* Dirty read returning no data */
1357        data.setPartial(0, 0, true);
1358        status = secDb.get(null, entry(0 + KEY_OFFSET), key,
1359                           data, LockMode.READ_UNCOMMITTED);
1360        assertSame(OperationStatus.SUCCESS, status);
1361        assertDataEquals(entry(0), key);
1362        assertEquals(0, data.getData().length);
1363        assertEquals(0, data.getSize());
1364
1365        /* Dirty read returning partial data */
1366        data.setPartial(0, 1, true);
1367        status = secDb.get(null, entry(0 + KEY_OFFSET), key,
1368                           data, LockMode.READ_UNCOMMITTED);
1369        assertSame(OperationStatus.SUCCESS, status);
1370        assertDataEquals(entry(0), key);
1371        assertEquals(1, data.getData().length);
1372        assertEquals(1, data.getSize());
1373
1374        secDb.close();
1375        priDb.close();
1376    }
1377
1378    /**
1379     * Open environment, primary and secondary db
1380     */

1381    private SecondaryDatabase initDb()
1382        throws DatabaseException {
1383
1384        Database priDb = openDatabase(false, "testDB", false);
1385        SecondaryDatabase secDb = openSecondary(priDb, true, "testSecDB",
1386                                                false, false);
1387        return secDb;
1388    }
1389
1390    private Database openDatabase(boolean allowDuplicates, String JavaDoc name,
1391                                  boolean readOnly)
1392        throws DatabaseException {
1393
1394        DatabaseConfig dbConfig = new DatabaseConfig();
1395        dbConfig.setTransactional(isTransactional);
1396        dbConfig.setAllowCreate(true);
1397        dbConfig.setSortedDuplicates(allowDuplicates);
1398        dbConfig.setReadOnly(readOnly);
1399        Transaction txn = txnBegin();
1400        Database priDb;
1401        try {
1402            priDb = env.openDatabase(txn, name, dbConfig);
1403        } finally {
1404            txnCommit(txn);
1405        }
1406        assertNotNull(priDb);
1407        return priDb;
1408    }
1409
1410    private SecondaryDatabase openSecondary(Database priDb,
1411                                            boolean allowDuplicates,
1412                                            String JavaDoc dbName,
1413                                            boolean allowPopulate,
1414                                            boolean readOnly)
1415        throws DatabaseException {
1416
1417        List JavaDoc secListBefore = priDb.getSecondaryDatabases();
1418        SecondaryConfig dbConfig = new SecondaryConfig();
1419        dbConfig.setTransactional(isTransactional);
1420        dbConfig.setAllowCreate(true);
1421        dbConfig.setSortedDuplicates(allowDuplicates);
1422        dbConfig.setReadOnly(readOnly);
1423        dbConfig.setAllowPopulate(allowPopulate);
1424        if (!readOnly) {
1425            if (useMultiKey) {
1426                dbConfig.setMultiKeyCreator
1427                    (new SimpleMultiKeyCreator(new MyKeyCreator()));
1428            } else {
1429                dbConfig.setKeyCreator(new MyKeyCreator());
1430            }
1431        }
1432        Transaction txn = txnBegin();
1433        SecondaryDatabase secDb;
1434        try {
1435            secDb = env.openSecondaryDatabase(txn, dbName, priDb, dbConfig);
1436        } finally {
1437            txnCommit(txn);
1438        }
1439        assertNotNull(secDb);
1440
1441        /* Check configuration. */
1442        assertSame(priDb, secDb.getPrimaryDatabase());
1443        SecondaryConfig config2 = secDb.getSecondaryConfig();
1444        assertEquals(allowPopulate, config2.getAllowPopulate());
1445        assertEquals(dbConfig.getKeyCreator(), config2.getKeyCreator());
1446
1447        /* Make sure the new secondary is added to the primary's list. */
1448        List JavaDoc secListAfter = priDb.getSecondaryDatabases();
1449        assertTrue(secListAfter.remove(secDb));
1450        assertEquals(secListBefore, secListAfter);
1451
1452        return secDb;
1453    }
1454
1455    private DatabaseEntry entry(int val) {
1456
1457        return new DatabaseEntry(TestUtils.getTestArray(val));
1458    }
1459
1460    private void assertDataEquals(DatabaseEntry e1, DatabaseEntry e2) {
1461        assertTrue(e1.equals(e2));
1462    }
1463
1464    private static class MyKeyCreator implements SecondaryKeyCreator {
1465
1466        public boolean createSecondaryKey(SecondaryDatabase secondary,
1467                                          DatabaseEntry key,
1468                                          DatabaseEntry data,
1469                                          DatabaseEntry result)
1470            throws DatabaseException {
1471
1472            result.setData(
1473                TestUtils.getTestArray(
1474                    TestUtils.getTestVal(data.getData()) + KEY_OFFSET));
1475            return true;
1476        }
1477    }
1478}
1479
Popular Tags