KickJava   Java API By Example, From Geeks To Geeks.

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


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

8
9 package com.sleepycat.je;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13
14 import junit.framework.TestCase;
15
16 import com.sleepycat.bind.tuple.IntegerBinding;
17 import com.sleepycat.je.config.EnvironmentParams;
18 import com.sleepycat.je.dbi.DatabaseImpl;
19 import com.sleepycat.je.dbi.DbTree;
20 import com.sleepycat.je.dbi.EnvironmentImpl;
21 import com.sleepycat.je.util.TestUtils;
22
23 /**
24  * Basic database operations, excluding configuration testing.
25  */

26 public class TruncateTest extends TestCase {
27     private static final int NUM_RECS = 257;
28     private static final String JavaDoc DB_NAME = "testDb";
29
30     private File JavaDoc envHome;
31     private Environment env;
32
33     public TruncateTest() {
34         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
35     }
36
37     public void setUp()
38         throws IOException JavaDoc {
39
40         TestUtils.removeLogFiles("Setup", envHome, false);
41     }
42     
43     public void tearDown()
44         throws Exception JavaDoc {
45
46         try {
47             /* Close in case we hit an exception and didn't close. */
48             env.close();
49         } catch (DatabaseException e) {
50             /* Ok if already closed */
51         }
52         env = null; // for JUNIT, to reduce memory usage when run in a suite.
53
TestUtils.removeLogFiles("TearDown", envHome, false);
54     }
55
56     public void testEnvTruncateAbort()
57         throws Throwable JavaDoc {
58         doTruncateAndAdd(true, // transactional
59
256, // step1 num records
60
false, // step2 autocommit
61
150, // step3 num records
62
true, // step4 abort
63
0 ); // step5 num records
64
}
65
66     public void testEnvTruncateCommit()
67         throws Throwable JavaDoc {
68         doTruncateAndAdd(true, // transactional
69
256, // step1 num records
70
false, // step2 autocommit
71
150, // step3 num records
72
false, // step4 abort
73
150 ); // step5 num records
74
}
75
76     public void testEnvTruncateAutocommit()
77         throws Throwable JavaDoc {
78         doTruncateAndAdd(true, // transactional
79
256, // step1 num records
80
true, // step2 autocommit
81
150, // step3 num records
82
false, // step4 abort
83
150 ); // step5 num records
84
}
85
86     public void testEnvTruncateNoFirstInsert()
87         throws Throwable JavaDoc {
88         doTruncateAndAdd(true, // transactional
89
0, // step1 num records
90
false, // step2 autocommit
91
150, // step3 num records
92
false, // step4 abort
93
150 ); // step5 num records
94
}
95
96     public void testNoTxnEnvTruncateCommit()
97         throws Throwable JavaDoc {
98         doTruncateAndAdd(false, // transactional
99
256, // step1 num records
100
false, // step2 autocommit
101
150, // step3 num records
102
false, // step4 abort
103
150 ); // step5 num records
104
}
105
106     public void testTruncateCommit()
107         throws Throwable JavaDoc {
108
109         doTruncate(false, false);
110     }
111
112     public void testTruncateCommitAutoTxn()
113         throws Throwable JavaDoc {
114
115         doTruncate(false, true);
116     }
117
118     public void testTruncateAbort()
119         throws Throwable JavaDoc {
120
121         doTruncate(true, false);
122     }
123
124     /*
125      * SR 10386, 11252. This used to deadlock, because the truncate did not
126      * use an AutoTxn on the new mapLN, and the put operations conflicted with
127      * the held write lock.
128      */

129     public void testWriteAfterTruncate()
130         throws Throwable JavaDoc {
131
132         try {
133             Database myDb = initEnvAndDb(true);
134
135             myDb.close();
136             Transaction txn = env.beginTransaction(null, null);
137             long truncateCount = env.truncateDatabase(txn, DB_NAME, true);
138             assertEquals(0, truncateCount);
139             txn.commit();
140             env.close();
141         } catch (Throwable JavaDoc t) {
142             t.printStackTrace();
143             throw t;
144         }
145     }
146
147     /**
148      * 1. Populate a database.
149      * 2. Truncate.
150      * 3. Commit or abort.
151      * 4. Check that database has the right amount of records.
152      */

153     private void doTruncate(boolean abort,
154                 boolean useAutoTxn)
155         throws Throwable JavaDoc {
156
157         try {
158             int numRecsAfterTruncate =
159                 useAutoTxn ? 0 : ((abort) ? NUM_RECS : 0);
160             Database myDb = initEnvAndDb(true);
161             DatabaseEntry key = new DatabaseEntry();
162             DatabaseEntry data = new DatabaseEntry();
163
164             /* Populate database. */
165             for (int i = NUM_RECS; i > 0; i--) {
166                 key.setData(TestUtils.getTestArray(i));
167                 data.setData(TestUtils.getTestArray(i));
168                 assertEquals(OperationStatus.SUCCESS,
169                  myDb.put(null, key, data));
170             }
171
172             /* Truncate, check the count, commit. */
173             myDb.close();
174             long truncateCount = 0;
175             if (useAutoTxn) {
176                 truncateCount = env.truncateDatabase(null, DB_NAME, true);
177             } else {
178                 Transaction txn = env.beginTransaction(null, null);
179                 truncateCount = env.truncateDatabase(txn, DB_NAME, true);
180
181                 if (abort) {
182                     txn.abort();
183                 } else {
184                     txn.commit();
185                 }
186             }
187
188                 assertEquals(NUM_RECS, truncateCount);
189             
190
191             /* Do a cursor read, make sure there's the right amount of data. */
192             DatabaseConfig dbConfig = new DatabaseConfig();
193             dbConfig.setSortedDuplicates(true);
194             myDb = env.openDatabase(null, DB_NAME, dbConfig);
195             int count = 0;
196             Cursor cursor = myDb.openCursor(null, null);
197             while (cursor.getNext(key, data, LockMode.DEFAULT) ==
198                    OperationStatus.SUCCESS) {
199                 count++;
200             }
201             assertEquals(numRecsAfterTruncate, count);
202         cursor.close();
203
204             /* Recover the database. */
205             myDb.close();
206             env.close();
207             myDb = initEnvAndDb(true);
208
209             /* Check data after recovery. */
210             count = 0;
211             cursor = myDb.openCursor(null, null);
212             while (cursor.getNext(key, data, LockMode.DEFAULT) ==
213                    OperationStatus.SUCCESS) {
214                 count++;
215             }
216             assertEquals(numRecsAfterTruncate, count);
217         cursor.close();
218             myDb.close();
219             env.close();
220         } catch (Throwable JavaDoc t) {
221             t.printStackTrace();
222             throw t;
223         }
224     }
225
226     /**
227      * This method can be configured to execute a number of these steps:
228      * - Populate a database with 0 or N records
229
230      * 2. Truncate.
231      * 3. add more records
232      * 4. abort or commit
233      * 5. Check that database has the right amount of records.
234      */

235     private void doTruncateAndAdd(boolean transactional,
236                                   int step1NumRecs,
237                                   boolean step2AutoCommit,
238                                   int step3NumRecs,
239                                   boolean step4Abort,
240                                   int step5NumRecs)
241         throws Throwable JavaDoc {
242
243         String JavaDoc databaseName = "testdb";
244
245         try {
246             /* Use enough records to force a split. */
247             EnvironmentConfig envConfig = TestUtils.initEnvConfig();
248             envConfig.setTransactional(transactional);
249             envConfig.setAllowCreate(true);
250             envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
251                                      "6");
252             env = new Environment(envHome, envConfig);
253
254
255             /* Make a db and open it. */
256             DatabaseConfig dbConfig = new DatabaseConfig();
257             dbConfig.setTransactional(transactional);
258             dbConfig.setAllowCreate(true);
259             Database myDb = env.openDatabase(null, databaseName, dbConfig);
260
261             DatabaseEntry key = new DatabaseEntry();
262             DatabaseEntry data = new DatabaseEntry();
263
264             /* Populate database with step1NumRecs. */
265             Transaction txn = null;
266             if (transactional) {
267                 txn = env.beginTransaction(null, null);
268             }
269             for (int i = 0; i < step1NumRecs; i++) {
270                 IntegerBinding.intToEntry(i, key);
271                 IntegerBinding.intToEntry(i, data);
272                 assertEquals(OperationStatus.SUCCESS,
273                  myDb.put(txn, key, data));
274             }
275
276             myDb.close();
277
278             /* Truncate. Possibly autocommit*/
279             if (step2AutoCommit && transactional) {
280                 txn.commit();
281                 txn = null;
282             }
283
284             /*
285              * Before truncate, there should be two databases in the system:
286              * the testDb database, and the FileSummary database.
287              */

288             countLNs(2, 2);
289             long truncateCount = env.truncateDatabase(txn, databaseName, true);
290             assertEquals(step1NumRecs, truncateCount);
291
292
293             /*
294              * The naming tree should always have two entries now, the
295              * mapping tree might have 2 or 3, depending on abort.
296              */

297             if (step2AutoCommit || !transactional) {
298                 countLNs(2, 2);
299             } else {
300                 countLNs(2, 3);
301             }
302
303
304             /* Add more records. */
305             myDb = env.openDatabase(txn, databaseName, dbConfig);
306             checkCount(myDb, txn, 0);
307             for (int i = 0; i < step3NumRecs; i++) {
308                 IntegerBinding.intToEntry(i, key);
309                 IntegerBinding.intToEntry(i, data);
310                 assertEquals(OperationStatus.SUCCESS,
311                  myDb.put(txn, key, data));
312             }
313
314             checkCount(myDb, txn, step3NumRecs);
315             myDb.close();
316
317             if (txn != null) {
318                 if (step4Abort) {
319                     txn.abort();
320                 } else {
321                     txn.commit();
322
323                 }
324             }
325             /* Now the mapping tree should only have two entries. */
326             countLNs(2, 2);
327
328             /* Do a cursor read, make sure there's the right amount of data. */
329             myDb = env.openDatabase(null, databaseName, dbConfig);
330             checkCount(myDb, null, step5NumRecs);
331             myDb.close();
332             env.close();
333
334             /* Check data after recovery. */
335             env = new Environment(envHome, envConfig);
336             myDb = env.openDatabase(null, databaseName, dbConfig);
337             checkCount(myDb, null, step5NumRecs);
338             myDb.close();
339             env.close();
340             
341         } catch (Throwable JavaDoc t) {
342             t.printStackTrace();
343             throw t;
344         }
345     }
346
347     /**
348      * Set up the environment and db.
349      */

350     private Database initEnvAndDb(boolean isTransactional)
351         throws DatabaseException {
352
353         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
354         envConfig.setTransactional(isTransactional);
355         envConfig.setConfigParam
356             (EnvironmentParams.ENV_CHECK_LEAKS.getName(), "false");
357         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(), "6");
358         envConfig.setAllowCreate(true);
359         env = new Environment(envHome, envConfig);
360
361         /* Make a db and open it. */
362         DatabaseConfig dbConfig = new DatabaseConfig();
363         dbConfig.setTransactional(isTransactional);
364         dbConfig.setSortedDuplicates(true);
365         dbConfig.setAllowCreate(true);
366         Database myDb = env.openDatabase(null, DB_NAME, dbConfig);
367         return myDb;
368     }
369
370     private void checkCount(Database db, Transaction txn, int expectedCount)
371         throws DatabaseException {
372
373         Cursor cursor = db.openCursor(txn, null);
374         int count = 0;
375         DatabaseEntry key = new DatabaseEntry();
376         DatabaseEntry data = new DatabaseEntry();
377         while (cursor.getNext(key, data, null) == OperationStatus.SUCCESS) {
378             count++;
379         }
380         assertEquals(expectedCount, count);
381         cursor.close();
382     }
383
384     /**
385      * Use stats to count the number of LNs in the id and name mapping
386      * trees. It's not possible to use Cursor, and stats areg easier to use than
387      * CursorImpl. This relies on the fact that the stats actually correctly
388      * account for deleted entries.
389      */

390     private void countLNs(int expectNameLNs,
391                           int expectMapLNs)
392         throws DatabaseException {
393         EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
394
395         /* check number of LNs in the id mapping tree. */
396         DatabaseImpl mapDbImpl =
397             envImpl.getDbMapTree().getDb(DbTree.ID_DB_ID);
398         // mapDbImpl.getTree().dump();
399
BtreeStats mapStats =
400             (BtreeStats) mapDbImpl.stat(new StatsConfig());
401         assertEquals(expectMapLNs,
402                      (mapStats.getLeafNodeCount()));
403
404         /* check number of LNs in the naming tree. */
405         DatabaseImpl nameDbImpl =
406             envImpl.getDbMapTree().getDb(DbTree.NAME_DB_ID);
407         BtreeStats nameStats =
408             (BtreeStats) nameDbImpl.stat(new StatsConfig());
409         assertEquals(expectNameLNs,
410                      (nameStats.getLeafNodeCount()));
411     }
412 }
413
Popular Tags