KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > recovery > RecoveryTestBase


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

8
9 package com.sleepycat.je.recovery;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Comparator JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Hashtable JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.Set JavaDoc;
23
24 import junit.framework.TestCase;
25
26 import com.sleepycat.je.CheckpointConfig;
27 import com.sleepycat.je.Cursor;
28 import com.sleepycat.je.Database;
29 import com.sleepycat.je.DatabaseConfig;
30 import com.sleepycat.je.DatabaseEntry;
31 import com.sleepycat.je.DatabaseException;
32 import com.sleepycat.je.DbInternal;
33 import com.sleepycat.je.Environment;
34 import com.sleepycat.je.EnvironmentConfig;
35 import com.sleepycat.je.LockMode;
36 import com.sleepycat.je.OperationStatus;
37 import com.sleepycat.je.Transaction;
38 import com.sleepycat.je.XAEnvironment;
39 import com.sleepycat.je.config.EnvironmentParams;
40 import com.sleepycat.je.dbi.EnvironmentImpl;
41 import com.sleepycat.je.log.FileManager;
42 import com.sleepycat.je.tree.Key;
43 import com.sleepycat.je.util.TestUtils;
44
45 public class RecoveryTestBase extends TestCase {
46     private static final boolean DEBUG = false;
47
48     protected static final int NUM_RECS = 257;
49     protected static final int N_DUPLICATES_PER_KEY = 28;
50     protected static final int NUM_DBS = 3;
51         
52     protected static final String JavaDoc DB_NAME = "testDb";
53
54     protected File JavaDoc envHome;
55     protected Environment env;
56     protected Database[] dbs;
57     protected EnvironmentConfig envConfig;
58     protected CheckpointConfig forceConfig;
59     protected Comparator JavaDoc btreeComparisonFunction = null;
60     
61     public RecoveryTestBase() {
62     init();
63     }
64
65     public RecoveryTestBase(boolean reduceMemory) {
66     init();
67     envConfig.setConfigParam(EnvironmentParams.MAX_MEMORY.getName(),
68                  new Long JavaDoc(1 << 24).toString());
69     }
70
71     private void init() {
72         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
73         Key.DUMP_BINARY = true;
74         envConfig = TestUtils.initEnvConfig();
75         forceConfig = new CheckpointConfig();
76         forceConfig.setForce(true);
77     }
78
79     public void setUp()
80         throws IOException JavaDoc, DatabaseException {
81
82         TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
83     }
84     
85     public void tearDown()
86     throws IOException JavaDoc, DatabaseException {
87
88         if (env != null) {
89             try {
90                 env.close();
91             } catch (DatabaseException E) {
92             }
93         }
94     env = null;
95     dbs = null;
96     envConfig = null;
97     forceConfig = null;
98         /* TestUtils.removeFiles("TearDown", envHome,
99                               FileManager.JE_SUFFIX, true);
100         */

101     }
102
103     /**
104      * Make an environment and databases, commit the db creation by default.
105      * Running with or without the checkpoint daemon changes how recovery is
106      * exercised.
107      */

108     protected void createEnv(int fileSize, boolean runCheckpointDaemon)
109         throws DatabaseException {
110
111     createEnvInternal(fileSize, runCheckpointDaemon, false);
112     }
113
114     protected void createXAEnv(int fileSize, boolean runCheckpointDaemon)
115         throws DatabaseException {
116
117     createEnvInternal(fileSize, runCheckpointDaemon, true);
118     }
119
120     private void createEnvInternal(int fileSize,
121                    boolean runCheckpointDaemon,
122                    boolean createXAEnv)
123         throws DatabaseException {
124
125         /* Make an environment and open it. */
126     DbInternal.disableParameterValidation(envConfig);
127         envConfig.setTransactional(true);
128         envConfig.setAllowCreate(true);
129         envConfig.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
130         envConfig.
131         setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
132                Integer.toString(fileSize));
133         envConfig.setConfigParam(EnvironmentParams.ENV_CHECK_LEAKS.getName(),
134                  "false");
135         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(), "6");
136     envConfig.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER.getName(),
137                  "false");
138     envConfig.setConfigParam(EnvironmentParams.ENV_RUN_EVICTOR.getName(),
139                  "false");
140
141         if (!runCheckpointDaemon) {
142             envConfig.setConfigParam
143         (EnvironmentParams.ENV_RUN_CHECKPOINTER.getName(), "false");
144         }
145         setExtraProperties();
146     if (createXAEnv) {
147         env = new XAEnvironment(envHome, envConfig);
148     } else {
149         env = new Environment(envHome, envConfig);
150     }
151     }
152
153     /*
154      * Overriden by using class.
155      */

156     protected void setExtraProperties()
157         throws DatabaseException {
158
159     }
160
161     /**
162      * Make an environment and databases, commit the db creation by default.
163      */

164     protected void createDbs(Transaction txn, int numDbs)
165         throws DatabaseException {
166
167         /* Make a db and open it. */
168         dbs = new Database[numDbs];
169
170         DatabaseConfig dbConfig = new DatabaseConfig();
171     if (btreeComparisonFunction != null) {
172         dbConfig.setBtreeComparator(btreeComparisonFunction.getClass());
173     }
174         dbConfig.setTransactional(true);
175         dbConfig.setAllowCreate(true);
176         dbConfig.setSortedDuplicates(true);
177         for (int i = 0; i < numDbs; i++) {
178             dbs[i] = env.openDatabase(txn, DB_NAME + i, dbConfig);
179         }
180     }
181
182     /**
183      * Make an environment and databases.
184      */

185     protected void createEnvAndDbs(int fileSize,
186                                    boolean runCheckpointerDaemon,
187                                    int numDbs)
188         throws DatabaseException {
189
190     createEnvAndDbsInternal(fileSize, runCheckpointerDaemon,
191                 numDbs, false);
192     }
193
194     protected void createXAEnvAndDbs(int fileSize,
195                      boolean runCheckpointerDaemon,
196                      int numDbs)
197         throws DatabaseException {
198
199     createEnvAndDbsInternal(fileSize, runCheckpointerDaemon,
200                 numDbs, true);
201     }
202
203     protected void createEnvAndDbsInternal(int fileSize,
204                        boolean runCheckpointerDaemon,
205                        int numDbs,
206                        boolean createXAEnv)
207         throws DatabaseException {
208
209         createEnvInternal(fileSize, runCheckpointerDaemon, createXAEnv);
210         Transaction txn = env.beginTransaction(null, null);
211         createDbs(txn, numDbs);
212         txn.commit();
213     }
214
215     /**
216      * Throw away the environment so the next open will cause a recovery.
217      */

218     protected void closeEnv()
219         throws DatabaseException {
220
221         TestUtils.validateNodeMemUsage(DbInternal.envGetEnvironmentImpl(env),
222                                       false);
223
224         /* Close the environment. */
225         if (dbs != null) {
226             for (int i = 0; i < dbs.length; i++) {
227                 if (dbs[i] != null) {
228                     dbs[i].close();
229                 }
230             }
231         }
232     forceCloseEnvOnly();
233     }
234
235     /* Force the environment to be closed even if with outstanding handles.*/
236     protected void forceCloseEnvOnly()
237     throws DatabaseException {
238
239     /* Close w/out checkpointing, in order to exercise recovery better.*/
240     DbInternal.envGetEnvironmentImpl(env).close(false);
241     env = null;
242     }
243
244     /*
245      * Recover the databases and check the data. Return a list of the
246      * RecoveryInfos generated by each recovery.
247      */

248     protected List JavaDoc recoverAndVerify(Hashtable JavaDoc expectedData, int numDbs)
249         throws DatabaseException {
250
251     return recoverAndVerifyInternal(expectedData, numDbs,
252                                         false, // XA
253
false); // readOnly
254
}
255
256     protected List JavaDoc recoverROAndVerify(Hashtable JavaDoc expectedData, int numDbs)
257         throws DatabaseException {
258
259     return recoverAndVerifyInternal(expectedData, numDbs,
260                                         false, // XA
261
true); // readOnly
262
}
263
264     /*
265      * Recover the databases and check the data. Return a list of the
266      * RecoveryInfos generated by each recovery.
267      */

268     protected List JavaDoc xaRecoverAndVerify(Hashtable JavaDoc expectedData, int numDbs)
269         throws DatabaseException {
270
271     return recoverAndVerifyInternal(expectedData, numDbs,
272                             true, // XA
273
false); // readOnly
274
}
275
276     private List JavaDoc recoverAndVerifyInternal(Hashtable JavaDoc expectedData,
277                       int numDbs,
278                       boolean createXAEnv,
279                                           boolean readOnlyMode)
280         throws DatabaseException {
281
282     List JavaDoc infoList = recoverOnlyInternal(numDbs, createXAEnv, readOnlyMode);
283         verifyData(expectedData, numDbs);
284     TestUtils.validateNodeMemUsage(DbInternal.envGetEnvironmentImpl(env),
285                                       false);
286         /* Run verify again. */
287         DbInternal.envGetEnvironmentImpl(env).close(false);
288         env = new Environment(envHome, getRecoveryConfig(readOnlyMode));
289         EnvironmentImpl envImpl =
290         DbInternal.envGetEnvironmentImpl(env);
291         infoList.add(envImpl.getLastRecoveryInfo());
292         verifyData(expectedData, numDbs);
293         TestUtils.validateNodeMemUsage(envImpl, false);
294         env.close();
295     return infoList;
296     }
297
298     private EnvironmentConfig getRecoveryConfig(boolean readOnlyMode) {
299         EnvironmentConfig recoveryConfig = TestUtils.initEnvConfig();
300         recoveryConfig.setConfigParam
301             (EnvironmentParams.NODE_MAX.getName(), "6");
302     recoveryConfig.setConfigParam(EnvironmentParams.MAX_MEMORY.getName(),
303                       new Long JavaDoc(1 << 24).toString());
304         recoveryConfig.setReadOnly(readOnlyMode);
305
306         /*
307          * Don't run checkLeaks, because verify is running while the system is
308          * not quiescent. The other daemons are running.
309          */

310         recoveryConfig.setConfigParam
311         (EnvironmentParams.ENV_CHECK_LEAKS.getName(), "false");
312     recoveryConfig.setConfigParam
313         (EnvironmentParams.ENV_RUN_CLEANER.getName(), "false");
314     recoveryConfig.setConfigParam
315         (EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false");
316
317         if (DEBUG) {
318             recoveryConfig.setConfigParam
319                 (EnvironmentParams.JE_LOGGING_FILE.getName(), "true");
320             recoveryConfig.setConfigParam
321                 (EnvironmentParams.JE_LOGGING_LEVEL.getName(), "FINE");
322         }
323
324     recoveryConfig.setTransactional(true);
325     return recoveryConfig;
326     }
327
328     protected List JavaDoc recoverOnly(int numDbs)
329     throws DatabaseException {
330
331     return recoverOnlyInternal(numDbs,
332                                    false, // XA
333
false); // read only
334
}
335
336     protected List JavaDoc xaRecoverOnly(int numDbs)
337     throws DatabaseException {
338
339     return recoverOnlyInternal(numDbs,
340                                    true, // XA
341
false); // read only
342
}
343
344     private List JavaDoc recoverOnlyInternal(int numDbs,
345                                      boolean createXAEnv,
346                                      boolean readOnlyMode)
347     throws DatabaseException {
348
349         List JavaDoc infoList = new ArrayList JavaDoc();
350
351         /* Open it again, which will run recovery. */
352     if (createXAEnv) {
353         env = new XAEnvironment(envHome, getRecoveryConfig(readOnlyMode));
354     } else {
355         env = new Environment(envHome, getRecoveryConfig(readOnlyMode));
356     }
357         TestUtils.validateNodeMemUsage(DbInternal.envGetEnvironmentImpl(env),
358                                       false);
359
360         infoList.add
361             (DbInternal.envGetEnvironmentImpl(env).getLastRecoveryInfo());
362         
363         return infoList;
364     }
365
366     /**
367      * Compare the data in the databases agains the data in the expected data
368      * set.
369      */

370     protected void verifyData(Hashtable JavaDoc expectedData, int numDbs)
371         throws DatabaseException {
372
373         verifyData(expectedData, true, numDbs);
374     }
375
376     /**
377      * Compare the data in the databases against the data in the expected data
378      * set.
379      */

380     protected void verifyData(Hashtable JavaDoc expectedData,
381                               boolean checkInList,
382                               int numDbs)
383         throws DatabaseException {
384
385     verifyData(expectedData, checkInList, 0, numDbs);
386     }
387
388     protected void verifyData(Hashtable JavaDoc expectedData,
389                               boolean checkInList,
390                   int startDb,
391                               int endDb)
392         throws DatabaseException {
393
394         /* Run verify. */
395         if (checkInList) {
396             assertTrue(env.verify(null, System.err));
397         } else {
398             assertTrue(env.verify(null, System.err));
399         }
400
401         /*
402          * Get a deep copy of expected data (cloning the data sets, not the
403          * items within dataSet, since verifyData will remove items, and we
404          * need to keep the expectedData set intact because we call verify
405          * repeatedly.
406          */

407         Map JavaDoc useData = new Hashtable JavaDoc();
408         Iterator JavaDoc iter = expectedData.entrySet().iterator();
409         while (iter.hasNext()) {
410             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
411             useData.put(entry.getKey(), ((HashSet JavaDoc) entry.getValue()).clone());
412         }
413
414         /* Generate an expected count map. */
415         Map JavaDoc countMap = generateCountMap(expectedData);
416
417         /* Check each db in turn. */
418         DatabaseConfig dbConfig = new DatabaseConfig();
419     if (btreeComparisonFunction != null) {
420         dbConfig.setBtreeComparator(btreeComparisonFunction.getClass());
421     }
422         dbConfig.setTransactional(env.getConfig().getTransactional());
423         dbConfig.setSortedDuplicates(true);
424         dbConfig.setReadOnly(true);
425         for (int d = startDb; d < endDb; d++) {
426             Database checkDb = env.openDatabase(null, DB_NAME + d,
427                         dbConfig);
428             Cursor myCursor = checkDb.openCursor(null, null);
429             DatabaseEntry key = new DatabaseEntry();
430             DatabaseEntry data = new DatabaseEntry();
431             OperationStatus status =
432         myCursor.getFirst(key, data, LockMode.DEFAULT);
433             DbInternal.envGetEnvironmentImpl(env).verifyCursors();
434             int numSeen = 0;
435
436             while (status == OperationStatus.SUCCESS) {
437
438                 /* The key should have been in the expected data set. */
439                 removeExpectedData(useData, d, key, data, true);
440
441                 /* The count should be right. */
442                 int count = myCursor.count();
443                 assertEquals("Count not right for key " +
444                              TestUtils.dumpByteArray(key.getData()),
445                              getExpectedCount(countMap, d, key), count);
446                 
447                 status = myCursor.getNext(key, data, LockMode.DEFAULT);
448                 numSeen++;
449             }
450
451             myCursor.close();
452
453             /* Should be nothing left in the expected data map. */
454             if (DEBUG) {
455                 System.out.println("Finished db" + d + " numSeen=" +numSeen);
456                 dumpExpected(useData);
457             }
458             checkDb.close();
459         }
460
461         assertEquals(0, useData.size());
462     }
463
464     /**
465      * Process the expected data map to generate expected counts. For each
466      * database, make a map of key value to count.
467      */

468     private Map JavaDoc generateCountMap(Map JavaDoc expectedData) {
469
470         Map JavaDoc countMap = new HashMap JavaDoc();
471
472         Iterator JavaDoc iter = expectedData.values().iterator();
473         while (iter.hasNext()) {
474             Set JavaDoc dataSet = (Set JavaDoc) iter.next();
475             Iterator JavaDoc dataIter = dataSet.iterator();
476             while (dataIter.hasNext()) {
477                 TestData t = (TestData) dataIter.next();
478                 TestData countKey = new TestData(t.dbNum, t.key);
479                 Integer JavaDoc count = (Integer JavaDoc) countMap.get(countKey);
480                 if (count == null) {
481                     countMap.put(countKey, new Integer JavaDoc(1));
482                 } else {
483                     countMap.put(countKey, new Integer JavaDoc(count.intValue()+1));
484                 }
485             }
486         }
487         return countMap;
488     }
489
490     /**
491      * @return the expected count value for a given key in a given db.
492      */

493     private int getExpectedCount(Map JavaDoc countMap,
494                  int whichDb,
495                  DatabaseEntry key) {
496         return ((Integer JavaDoc)
497                 countMap.get(new TestData(whichDb, key.getData()))).intValue();
498     }
499     
500     /**
501      * Insert data over many databases.
502      */

503     protected void insertData(Transaction txn,
504                               int startVal,
505                               int endVal,
506                               Map JavaDoc expectedData,
507                               int nDuplicatesPerKey,
508                               boolean addToExpectedData,
509                               int numDbs)
510         throws DatabaseException {
511
512         insertData(txn, startVal, endVal, expectedData,
513                    nDuplicatesPerKey, false, addToExpectedData,
514                    0, numDbs);
515     }
516
517     protected void insertData(Transaction txn,
518                               int startVal,
519                               int endVal,
520                               Map JavaDoc expectedData,
521                               int nDuplicatesPerKey,
522                               boolean addToExpectedData,
523                               int startDb,
524                   int endDb)
525         throws DatabaseException {
526
527         insertData(txn, startVal, endVal, expectedData,
528                    nDuplicatesPerKey, false, addToExpectedData,
529                    startDb, endDb);
530     }
531
532     /**
533      * Insert data over many databases.
534      *
535      * @param toggle if true, insert every other value.
536      */

537     protected void insertData(Transaction txn,
538                               int startVal,
539                               int endVal,
540                               Map JavaDoc expectedData,
541                               int nDuplicatesPerKey,
542                               boolean toggle,
543                               boolean addToExpectedData,
544                               int numDbs)
545         throws DatabaseException {
546
547     insertData(txn, startVal, endVal, expectedData, nDuplicatesPerKey,
548            toggle, addToExpectedData, 0, numDbs);
549     }
550
551     /**
552      * Insert data over many databases.
553      *
554      * @param toggle if true, insert every other value.
555      */

556     protected void insertData(Transaction txn,
557                               int startVal,
558                               int endVal,
559                               Map JavaDoc expectedData,
560                               int nDuplicatesPerKey,
561                               boolean toggle,
562                               boolean addToExpectedData,
563                               int startDb,
564                   int endDb)
565         throws DatabaseException {
566
567         Cursor[] cursors = getCursors(txn, startDb, endDb);
568
569         /* Make sure this test inserts something! */
570         assertTrue(endVal - startVal > -1);
571
572         /* Are we inserting in an ascending or descending way? */
573         int incVal = (toggle) ? 2 : 1;
574         if (startVal < endVal) {
575             for (int i = startVal; i <= endVal; i += incVal) {
576                 insertOneRecord(cursors, i, expectedData,
577                                 nDuplicatesPerKey, addToExpectedData);
578             }
579         } else {
580             for (int i = startVal; i >= endVal; i -= incVal) {
581                 insertOneRecord(cursors, i, expectedData,
582                                 nDuplicatesPerKey, addToExpectedData);
583             }
584         }
585
586         for (int i = 0; i < cursors.length; i++) {
587             cursors[i].close();
588         }
589     }
590
591     /**
592      * Add to the set of expected results. ExpectedData is keyed by a TestData
593      * object that wraps db number and key, and points to sets of TestData
594      * objects that wrap db number, key, and data.
595      */

596     protected void addExpectedData(Map JavaDoc expectedData,
597                    int dbNum,
598                    DatabaseEntry key,
599                    DatabaseEntry data,
600                    boolean expectCommit) {
601         if (expectCommit) {
602             TestData keyTestData = new TestData(dbNum, key, null);
603             Set JavaDoc dataSet = (Set JavaDoc) expectedData.get(keyTestData);
604             if (dataSet == null) {
605                 dataSet = new HashSet JavaDoc();
606                 expectedData.put(keyTestData, dataSet);
607             }
608
609             dataSet.add(new TestData(dbNum, key, data));
610         }
611     }
612
613     /**
614      * Remove from the set of expected results.
615      */

616     private void removeExpectedData(Map JavaDoc expectedData,
617                     int dbNum,
618                     DatabaseEntry key,
619                                     DatabaseEntry data,
620                     boolean expectCommit) {
621         if (expectCommit) {
622             TestData keyTestData = new TestData(dbNum, key, null);
623             Set JavaDoc dataSet = (Set JavaDoc) expectedData.get(keyTestData);
624             assertTrue("Should be a data set for " + keyTestData,
625                        (dataSet != null));
626             assertTrue("Should be able to remove key " + key +
627                        " from expected data ",
628                        dataSet.remove(new TestData(dbNum, key, data)));
629             if (dataSet.size() == 0) {
630                 expectedData.remove(keyTestData);
631             }
632         }
633     }
634
635     /**
636      * @return a set of cursors for the test databases.
637      */

638     private Cursor[] getCursors(Transaction txn, int startDb, int endDb)
639         throws DatabaseException {
640
641         Cursor[] cursors = new Cursor[endDb - startDb];
642         for (int i = 0; i < cursors.length; i++) {
643             cursors[i] = dbs[startDb + i].openCursor(txn, null);
644         }
645         return cursors;
646     }
647
648     /**
649      * Insert the given record into all databases.
650      */

651     private void insertOneRecord(Cursor[] cursors,
652                                  int val,
653                                  Map JavaDoc expectedData,
654                                  int nDuplicatesPerKey,
655                                  boolean expectCommit)
656         throws DatabaseException {
657
658         DatabaseEntry key = new DatabaseEntry();
659         DatabaseEntry data = new DatabaseEntry();
660
661         for (int c = 0; c < cursors.length; c++) {
662
663             int testVal = val + c;
664             byte[] keyData = TestUtils.getTestArray(testVal);
665             byte[] dataData = TestUtils.byteArrayCopy(keyData);
666             key.setData(keyData);
667             for (int d = 0; d < nDuplicatesPerKey; d++) {
668                 dataData = TestUtils.byteArrayCopy(dataData);
669                 dataData[1]++;
670                 data.setData(dataData);
671
672                 assertEquals("Insertion of key " +
673                              TestUtils.dumpByteArray(keyData),
674                              OperationStatus.SUCCESS,
675                  cursors[c].putNoDupData(key, data));
676
677                 addExpectedData(expectedData, c, key, data, expectCommit);
678             }
679         }
680     }
681     
682     /**
683      * Delete either every other or all data.
684      */

685     protected void deleteData(Transaction txn, Map JavaDoc expectedData,
686                               boolean all, boolean expectCommit, int numDbs)
687         throws DatabaseException {
688
689         Cursor[] cursors = getCursors(txn, 0, numDbs);
690         DatabaseEntry key = new DatabaseEntry();
691         DatabaseEntry data = new DatabaseEntry();
692
693         for (int d = 0; d < cursors.length; d++) {
694             OperationStatus status =
695         cursors[d].getFirst(key, data, LockMode.DEFAULT);
696             boolean toggle = true;
697             int deleteCount = 0;
698             while (status == OperationStatus.SUCCESS) {
699                 if (toggle) {
700                     removeExpectedData(expectedData, d, key, data,
701                                        expectCommit);
702                     assertEquals(OperationStatus.SUCCESS, cursors[d].delete());
703                     deleteCount++;
704                     toggle = all;
705                 } else {
706                     toggle = true;
707                 }
708                 status = cursors[d].getNext(key, data, LockMode.DEFAULT);
709             }
710             /* Make sure the test deletes something! */
711             assertTrue(deleteCount > 0);
712         }
713
714         for (int i = 0; i < cursors.length; i++) {
715             cursors[i].close();
716         }
717     }
718
719     /**
720      * Modify data
721      * @param txn owning txn
722      * @param endVal end point of the modification range
723      * @param expectedData store of expected values for verification at end
724      * @param increment used to modify the data.
725      * @param expectCommit if true, reflect change in expected map. Sometimes
726      * we don't want to do this because we plan to make the txn abort.
727      */

728     protected void modifyData(Transaction txn, int endVal,
729                               Map JavaDoc expectedData, int increment,
730                               boolean expectCommit, int numDbs)
731         throws DatabaseException {
732
733         Cursor[] cursors = getCursors(txn, 0, numDbs);
734         DatabaseEntry key = new DatabaseEntry();
735         DatabaseEntry data = new DatabaseEntry();
736
737         for (int d = 0; d < cursors.length; d++) {
738
739             /* Position cursor at the start value. */
740             OperationStatus status =
741         cursors[d].getFirst(key, data, LockMode.DEFAULT);
742
743             /* For each record within the range, change the data. */
744             int modCount = 0;
745             int keyVal = TestUtils.getTestVal(key.getData());
746             while ((status == OperationStatus.SUCCESS) && (keyVal <= endVal)) {
747
748                 /* Change the data. */
749                 removeExpectedData(expectedData, d, key, data, expectCommit);
750                 data.setData(TestUtils.getTestArray(keyVal + increment));
751                 cursors[d].delete();
752                 cursors[d].put(key, data);
753                 addExpectedData(expectedData, d, key, data, expectCommit);
754                 modCount++;
755
756                 status = cursors[d].getNext(key, data, LockMode.DEFAULT);
757
758                 if (status == OperationStatus.SUCCESS) {
759                     keyVal = TestUtils.getTestVal(key.getData());
760                 }
761             }
762             /* Make sure we modify something! */
763             assertTrue(modCount > 0);
764         }
765
766         for (int i = 0; i < cursors.length; i++) {
767             cursors[i].close();
768         }
769     }
770
771
772     /**
773      * Print the contents of the databases out for debugging
774      */

775     protected void dumpData(int numDbs)
776         throws DatabaseException {
777
778         DatabaseConfig dbConfig = new DatabaseConfig();
779     if (btreeComparisonFunction != null) {
780         dbConfig.setBtreeComparator(btreeComparisonFunction.getClass());
781     }
782         dbConfig.setSortedDuplicates(true);
783     dbConfig.setTransactional(true);
784         for (int d = 0; d < numDbs; d++) {
785             Database checkDb = env.openDatabase(null, DB_NAME + d, dbConfig);
786             Cursor myCursor = checkDb.openCursor(null, null);
787             DatabaseEntry key = new DatabaseEntry();
788             DatabaseEntry data = new DatabaseEntry();
789
790             OperationStatus status =
791         myCursor.getFirst(key, data, LockMode.DEFAULT);
792             while (status == OperationStatus.SUCCESS) {
793                 System.out.println("Database " + d +
794                                    " seen = " +
795                                    /*
796                                       new String(key.getData()) +
797                                       "/" +
798                                       new String(data.getData()));
799                                    */

800                                    TestUtils.dumpByteArray(key.getData()) +
801                                    "/" +
802                                    TestUtils.dumpByteArray(data.getData()));
803                 status = myCursor.getNext(key, data, LockMode.DEFAULT);
804             }
805             myCursor.close();
806         }
807     }
808
809     /**
810      * Print the contents of the expected map for debugging.
811      */

812     protected void dumpExpected(Map JavaDoc expectedData)
813         throws DatabaseException {
814         System.out.println("Expected = " );
815         Iterator JavaDoc iter = expectedData.values().iterator();
816         while (iter.hasNext()) {
817             Set JavaDoc dataSet = (Set JavaDoc) iter.next();
818             Iterator JavaDoc dataIter = dataSet.iterator();
819             while (dataIter.hasNext()) {
820                 TestData t = (TestData) dataIter.next();
821                 System.out.println(t);
822             }
823         }
824     }
825
826     protected class TestData {
827         public int dbNum;
828         public byte[] key;
829         public byte[] data;
830
831         TestData(int dbNum, DatabaseEntry keyDbt, DatabaseEntry dataDbt) {
832             this.dbNum = dbNum;
833             key = keyDbt.getData();
834             if (dataDbt == null) {
835                 dataDbt = new DatabaseEntry();
836                 dataDbt.setData(new byte[1]);
837             }
838             data = dataDbt.getData();
839         }
840
841         TestData(int dbNum, byte[] key) {
842             this.dbNum = dbNum;
843             this.key = key;
844         }
845         
846         public boolean equals(Object JavaDoc o ) {
847             if (this == o)
848                 return true;
849             if (!(o instanceof TestData))
850                 return false;
851
852             TestData other = (TestData) o;
853             if ((dbNum == other.dbNum) &&
854                 Arrays.equals(key, other.key) &&
855                 Arrays.equals(data, other.data)) {
856                 return true;
857             } else
858                 return false;
859         }
860
861         public String JavaDoc toString() {
862             if (data == null) {
863                 return "db=" + dbNum +
864                     " k=" + TestUtils.dumpByteArray(key);
865             } else {
866                 return "db=" + dbNum +
867                     " k=" + TestUtils.dumpByteArray(key) +
868                     " d=" + TestUtils.dumpByteArray(data);
869             }
870         }
871
872         public int hashCode() {
873             return toString().hashCode();
874         }
875     }
876 }
877
Popular Tags