KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > txn > TxnEndTest


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

8
9 package com.sleepycat.je.txn;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.util.Arrays JavaDoc;
14
15 import junit.framework.TestCase;
16
17 import com.sleepycat.je.Cursor;
18 import com.sleepycat.je.CursorConfig;
19 import com.sleepycat.je.Database;
20 import com.sleepycat.je.DatabaseConfig;
21 import com.sleepycat.je.DatabaseEntry;
22 import com.sleepycat.je.DatabaseException;
23 import com.sleepycat.je.DbInternal;
24 import com.sleepycat.je.Environment;
25 import com.sleepycat.je.EnvironmentConfig;
26 import com.sleepycat.je.EnvironmentStats;
27 import com.sleepycat.je.LockMode;
28 import com.sleepycat.je.OperationStatus;
29 import com.sleepycat.je.Transaction;
30 import com.sleepycat.je.TransactionStats;
31 import com.sleepycat.je.VerifyConfig;
32 import com.sleepycat.je.config.EnvironmentParams;
33 import com.sleepycat.je.dbi.DatabaseImpl;
34 import com.sleepycat.je.junit.JUnitThread;
35 import com.sleepycat.je.log.FileManager;
36 import com.sleepycat.je.util.TestUtils;
37
38 /*
39  * Test transaction aborts and commits.
40  */

41 public class TxnEndTest extends TestCase {
42     private static final int NUM_DBS = 1;
43     private Environment env;
44     private File JavaDoc envHome;
45     private Database[] dbs;
46     private Cursor[] cursors;
47
48     public TxnEndTest()
49     throws DatabaseException {
50
51         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
52     }
53
54     public void setUp()
55         throws IOException JavaDoc, DatabaseException {
56
57         TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
58       
59         /*
60          * Run environment without in compressor on so we can check the
61          * compressor queue in a deterministic way.
62          */

63         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
64         envConfig.setTransactional(true);
65         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(), "6");
66         envConfig.setConfigParam(EnvironmentParams.
67                  ENV_RUN_INCOMPRESSOR.getName(),
68                                  "false");
69         envConfig.setAllowCreate(true);
70         env = new Environment(envHome, envConfig);
71     }
72
73     public void tearDown()
74         throws IOException JavaDoc, DatabaseException {
75
76         if (env != null) {
77             try {
78                 env.close();
79             } catch (Exception JavaDoc e) {
80                 System.out.println("tearDown: " + e);
81             }
82         }
83         env = null;
84
85         TestUtils.removeFiles("TearDown", envHome, FileManager.JE_SUFFIX);
86     }
87
88     private void createDbs()
89         throws DatabaseException {
90
91         // Make databases
92
dbs = new Database[NUM_DBS];
93         cursors = new Cursor[NUM_DBS];
94
95         DatabaseConfig dbConfig = new DatabaseConfig();
96         dbConfig.setTransactional(true);
97         dbConfig.setAllowCreate(true);
98         for (int i = 0; i < NUM_DBS; i++) {
99             dbs[i] = env.openDatabase(null, "testDB" + i, dbConfig);
100         }
101     }
102
103     private void closeAll()
104         throws DatabaseException {
105
106         for (int i = 0; i < NUM_DBS; i++) {
107             dbs[i].close();
108         }
109         dbs = null;
110         env.close();
111         env = null;
112     }
113
114     /**
115      * Create cursors with this owning transaction
116      */

117     private void createCursors(Transaction txn)
118         throws DatabaseException {
119
120         for (int i = 0; i < cursors.length; i++) {
121             cursors[i] = dbs[i].openCursor(txn, null);
122         }
123     }
124
125     /**
126      * Close the current set of cursors
127      */

128     private void closeCursors()
129         throws DatabaseException {
130
131         for (int i = 0; i < cursors.length; i++) {
132             cursors[i].close();
133         }
134     }
135     
136     /**
137      * Insert keys from i=start; i <end using a cursor
138      */

139     private void cursorInsertData(int start, int end)
140         throws DatabaseException {
141
142         DatabaseEntry key = new DatabaseEntry();
143         DatabaseEntry data = new DatabaseEntry();
144         for (int i = 0; i < NUM_DBS; i++) {
145             for (int d = start; d < end; d++) {
146                 key.setData(TestUtils.getTestArray(d));
147                 data.setData(TestUtils.getTestArray(d));
148                 cursors[i].put(key, data);
149             }
150         }
151     }
152     /**
153      * Insert keys from i=start; i < end using a db
154      */

155     private void dbInsertData(int start, int end, Transaction txn)
156         throws DatabaseException {
157
158         DatabaseEntry key = new DatabaseEntry();
159         DatabaseEntry data = new DatabaseEntry();
160         for (int i = 0; i < NUM_DBS; i++) {
161             for (int d = start; d < end; d++) {
162                 key.setData(TestUtils.getTestArray(d));
163                 data.setData(TestUtils.getTestArray(d));
164                 dbs[i].put(txn, key, data);
165             }
166         }
167     }
168
169     /**
170      * Modify keys from i=start; i <end
171      */

172     private void cursorModifyData(int start, int end, int valueOffset)
173         throws DatabaseException {
174
175         DatabaseEntry key = new DatabaseEntry();
176         DatabaseEntry data = new DatabaseEntry();
177         for (int i = 0; i < NUM_DBS; i++) {
178             OperationStatus status =
179         cursors[i].getFirst(key, data, LockMode.DEFAULT);
180             for (int d = start; d < end; d++) {
181                 assertEquals(OperationStatus.SUCCESS, status);
182                 byte[] changedVal =
183                     TestUtils.getTestArray(d + valueOffset);
184                 data.setData(changedVal);
185                 cursors[i].putCurrent(data);
186                 status = cursors[i].getNext(key, data, LockMode.DEFAULT);
187             }
188         }
189     }
190
191     /**
192      * Delete records from i = start; i < end.
193      */

194     private void cursorDeleteData(int start, int end)
195         throws DatabaseException {
196
197         DatabaseEntry key = new DatabaseEntry();
198         DatabaseEntry foundData = new DatabaseEntry();
199         for (int i = 0; i < NUM_DBS; i++) {
200             for (int d = start; d < end; d++) {
201                 byte[] searchValue =
202                     TestUtils.getTestArray(d);
203                 key.setData(searchValue);
204                 OperationStatus status =
205             cursors[i].getSearchKey(key, foundData, LockMode.DEFAULT);
206                 assertEquals(OperationStatus.SUCCESS, status);
207                 assertEquals(OperationStatus.SUCCESS, cursors[i].delete());
208             }
209         }
210     }
211
212     /**
213      * Delete records with a db.
214      */

215     private void dbDeleteData(int start, int end, Transaction txn)
216         throws DatabaseException {
217
218         DatabaseEntry key = new DatabaseEntry();
219         for (int i = 0; i < NUM_DBS; i++) {
220             for (int d = start; d < end; d++) {
221                 byte[] searchValue =
222                     TestUtils.getTestArray(d);
223                 key.setData(searchValue);
224                 dbs[i].delete(txn, key);
225             }
226         }
227     }
228
229     /**
230      * Check that there are numKeys records in each db, and their value
231      * is i + offset.
232      */

233     private void verifyData(int numKeys, int valueOffset)
234         throws DatabaseException {
235
236         for (int i = 0; i < NUM_DBS; i++) {
237             /* Run verify */
238             DatabaseImpl dbImpl = DbInternal.dbGetDatabaseImpl(dbs[i]);
239             assertTrue(dbImpl.verify(new VerifyConfig(),
240                                       dbImpl.getEmptyStats()));
241
242             Cursor verifyCursor =
243         dbs[i].openCursor(null, CursorConfig.READ_UNCOMMITTED);
244             DatabaseEntry key = new DatabaseEntry();
245             DatabaseEntry data = new DatabaseEntry();
246             OperationStatus status =
247         verifyCursor.getFirst(key, data, LockMode.DEFAULT);
248             for (int d = 0; d < numKeys; d++) {
249                 assertEquals("key=" + d, OperationStatus.SUCCESS, status);
250                 byte[] expected = TestUtils.getTestArray(d + valueOffset);
251                 assertTrue(Arrays.equals(expected, key.getData()));
252                 assertTrue("Expected= " + TestUtils.dumpByteArray(expected) +
253                            " saw=" + TestUtils.dumpByteArray(data.getData()),
254                            Arrays.equals(expected, data.getData()));
255                 status = verifyCursor.getNext(key, data, LockMode.DEFAULT);
256             }
257             // should be the end of this database
258
assertTrue("More data than expected",
259                (status != OperationStatus.SUCCESS));
260             verifyCursor.close();
261         }
262     }
263
264     /**
265      * Test basic commits, aborts with cursors
266      */

267     public void testBasicCursor()
268         throws Throwable JavaDoc {
269
270         try {
271             int numKeys = 7;
272             createDbs();
273
274             // Insert more data with a user transaction, commit
275
Transaction txn = env.beginTransaction(null, null);
276             createCursors(txn);
277             cursorInsertData(0, numKeys*2);
278             closeCursors();
279             txn.commit();
280             verifyData(numKeys*2, 0);
281
282             // Insert more data, abort, check that data is unchanged
283
txn = env.beginTransaction(null, null);
284             createCursors(txn);
285             cursorInsertData(numKeys*2, numKeys*3);
286             closeCursors();
287             txn.abort();
288             verifyData(numKeys*2, 0);
289
290             /*
291              * Check the in compressor queue, we should have some number of
292              * bins on. If the queue size is 0, then check the processed stats,
293              * the in compressor thread may have already woken up and dealt
294              * with the entries.
295              */

296             EnvironmentStats envStat = env.getStats(TestUtils.FAST_STATS);
297             int queueSize = envStat.getInCompQueueSize();
298             assertTrue(queueSize > 0);
299
300             // Modify data, abort, check that data is unchanged
301
txn = env.beginTransaction(null, null);
302             createCursors(txn);
303             cursorModifyData(0, numKeys * 2, 1);
304             closeCursors();
305             txn.abort();
306             verifyData(numKeys*2, 0);
307
308             // Delete data, abort, check that data is still there
309
txn = env.beginTransaction(null, null);
310             createCursors(txn);
311             cursorDeleteData(numKeys+1, numKeys*2);
312             closeCursors();
313             txn.abort();
314             verifyData(numKeys*2, 0);
315             // Check the in compressor queue, nothing should be loaded
316
envStat = env.getStats(TestUtils.FAST_STATS);
317             assertEquals(queueSize, envStat.getInCompQueueSize());
318
319             // Delete data, commit, check that data is gone
320
txn = env.beginTransaction(null, null);
321             createCursors(txn);
322             cursorDeleteData(numKeys, numKeys*2);
323             closeCursors();
324             txn.commit();
325             verifyData(numKeys, 0);
326
327             // Check the inCompressor queue, there should be more entries.
328
envStat = env.getStats(TestUtils.FAST_STATS);
329             assertTrue(envStat.getInCompQueueSize() > queueSize);
330
331             closeAll();
332
333         } catch (Throwable JavaDoc t) {
334             // print stacktrace before attempt to run tearDown
335
t.printStackTrace();
336             throw t;
337         }
338     }
339
340     /**
341      * Test db creation and deletion.
342      */

343     public void testTxnClose()
344         throws DatabaseException {
345
346         createDbs();
347         Transaction txn = env.beginTransaction(null, null);
348         createCursors(txn);
349         try {
350             txn.commit();
351             fail("Commit should fail");
352         } catch (DatabaseException e) {
353         }
354     closeCursors();
355         closeAll();
356     }
357
358     class CascadingAbortTestJUnitThread extends JUnitThread {
359     Transaction txn = null;
360     Database db = null;
361
362     CascadingAbortTestJUnitThread(Transaction txn,
363                       Database db) {
364         super("testCascadingAborts");
365         this.txn = txn;
366         this.db = db;
367     }
368     }
369
370     /**
371      * Test cascading aborts in the face of deletes.
372      * [work in progress: cwl 1/15/04]
373      */

374     public void xtestCascadingAborts()
375     throws Throwable JavaDoc {
376
377         Database db = null;
378
379     try {
380         DatabaseConfig dbConfig = new DatabaseConfig();
381         dbConfig.setAllowCreate(true);
382             dbConfig.setTransactional(true);
383         db = env.openDatabase(null, "testDB", dbConfig);
384
385         DatabaseEntry key = new DatabaseEntry();
386         DatabaseEntry data = new DatabaseEntry();
387
388         Transaction txn = env.beginTransaction(null, null);
389         key.setData("abb".getBytes());
390         data.setData("def".getBytes());
391         //db.put(txn, key, data, null);
392
key.setData("abc".getBytes());
393         data.setData("def".getBytes());
394         db.put(txn, key, data);
395         txn.commit();
396
397         //DbInternal.dbGetDatabaseImpl(db).getTree().dump();
398

399         Transaction txn1 = env.beginTransaction(null, null);
400         Transaction txn2 = env.beginTransaction(null, null);
401
402         CascadingAbortTestJUnitThread tester1 =
403         new CascadingAbortTestJUnitThread(txn2, db) {
404             public void testBody()
405             throws Throwable JavaDoc {
406
407             Cursor c = db.openCursor(txn, null);
408             DatabaseEntry data = new DatabaseEntry();
409             try {
410                 Thread.yield();
411                 DatabaseEntry key = new DatabaseEntry();
412                 key.setData("abc".getBytes());
413                 OperationStatus status;
414                 status =
415                 c.getSearchKeyRange(key, data, LockMode.DEFAULT);
416                 status = c.delete();
417             } catch (Throwable JavaDoc T) {
418                 T.printStackTrace();
419             } finally {
420                 c.close();
421             }
422             }
423         };
424
425         tester1.start();
426         Thread.yield();
427         key.setData("abc".getBytes());
428         OperationStatus status;
429         status = db.delete(txn1, key);
430
431         txn1.abort();
432         Thread.yield();
433
434         txn2.abort();
435         tester1.finishTest();
436
437         //DbInternal.dbGetDatabaseImpl(db).getTree().dump();
438

439         if (false) {
440         db.close();
441         env.close();
442         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
443         envConfig.setTransactional(true);
444         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
445                      "6");
446         envConfig.setConfigParam(EnvironmentParams.
447                      ENV_RUN_INCOMPRESSOR.
448                      getName(),
449                      "false");
450         envConfig.setAllowCreate(true);
451         env = new Environment(envHome, envConfig);
452         db = env.openDatabase(null, "testDB", dbConfig);
453         }
454
455         txn = env.beginTransaction(null, null);
456         System.out.println(db.getSearchBoth(txn, key, data,
457                                                 LockMode.DEFAULT));
458         txn.commit();
459     } catch (Throwable JavaDoc T) {
460         T.printStackTrace();
461     } finally {
462         db.close();
463     }
464     }
465
466     /**
467      * Test use through db.
468      */

469     public void testBasicDb()
470         throws Throwable JavaDoc {
471
472         try {
473             TransactionStats stats =
474                 env.getTransactionStats(TestUtils.FAST_STATS);
475             assertEquals(0, stats.getNAborts());
476             int initialCommits = 1; // 1 commits for adding UP database
477
assertEquals(initialCommits, stats.getNCommits());
478
479             int numKeys = 7;
480             createDbs();
481
482             // Insert data with autocommit
483
dbInsertData(0, numKeys, null);
484             verifyData(numKeys, 0);
485
486             // Insert data with a txn
487
Transaction txn = env.beginTransaction(null, null);
488             dbInsertData(numKeys, numKeys*2, txn);
489             txn.commit();
490             verifyData(numKeys*2, 0);
491
492             stats = env.getTransactionStats(TestUtils.FAST_STATS);
493             assertEquals(0, stats.getNAborts());
494             assertEquals((initialCommits + 1 + // 1 explicit commit above
495
(1 * NUM_DBS) + // 1 per create/open
496
(numKeys*NUM_DBS)), // 1 per record, using autotxn
497
stats.getNCommits());
498
499             // delete data with a txn, abort
500
txn = env.beginTransaction(null, null);
501             dbDeleteData(numKeys, numKeys * 2, txn);
502             verifyData(numKeys, 0); // verify w/dirty read
503
txn.abort();
504             
505             closeAll();
506         } catch (Throwable JavaDoc t) {
507             t.printStackTrace();
508             throw t;
509         }
510     }
511
512     /**
513      * Test db creation and deletion
514      */

515
516     public void testDbCreation()
517         throws DatabaseException {
518
519         Transaction txnA = env.beginTransaction(null, null);
520         Transaction txnB = env.beginTransaction(null, null);
521
522         DatabaseConfig dbConfig = new DatabaseConfig();
523         dbConfig.setAllowCreate(true);
524         dbConfig.setTransactional(true);
525         Database dbA =
526         env.openDatabase(txnA, "foo", dbConfig);
527
528         // Try to see this database with another txn -- we should not see it
529

530         dbConfig.setAllowCreate(false);
531
532         try {
533             txnB.setLockTimeout(1000);
534
535         env.openDatabase(txnB, "foo", dbConfig);
536             fail("Shouldn't be able to open foo");
537         } catch (DatabaseException e) {
538         }
539     /* txnB must be aborted since openDatabase timed out. */
540     txnB.abort();
541
542         // Open this database with the same txn and another handle
543
Database dbC =
544         env.openDatabase(txnA, "foo", dbConfig);
545         
546         // Now commit txnA and txnB should be able to open this.
547
txnA.commit();
548     txnB = env.beginTransaction(null, null);
549         Database dbB =
550         env.openDatabase(txnB, "foo", dbConfig);
551         txnB.commit();
552
553         // XXX, test db deletion
554

555         dbA.close();
556         dbB.close();
557         dbC.close();
558     }
559
560     /* Test that the transaction is unsable about a close. */
561     public void testClose()
562         throws DatabaseException {
563
564         Transaction txnA = env.beginTransaction(null, null);
565         txnA.commit();
566
567         try {
568             env.openDatabase(txnA, "foo", null);
569             fail("Should not be able to use a closed exception");
570         } catch (DatabaseException expected) {
571         }
572     }
573
574 }
575
Popular Tags