KickJava   Java API By Example, From Geeks To Geeks.

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


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

8 package com.sleepycat.je.recovery;
9
10 import java.util.HashSet JavaDoc;
11 import java.util.logging.Level JavaDoc;
12
13 import com.sleepycat.bind.tuple.IntegerBinding;
14 import com.sleepycat.je.CheckpointConfig;
15 import com.sleepycat.je.Cursor;
16 import com.sleepycat.je.Database;
17 import com.sleepycat.je.DatabaseConfig;
18 import com.sleepycat.je.DatabaseEntry;
19 import com.sleepycat.je.DatabaseException;
20 import com.sleepycat.je.DbInternal;
21 import com.sleepycat.je.EnvironmentConfig;
22 import com.sleepycat.je.OperationStatus;
23 import com.sleepycat.je.config.EnvironmentParams;
24 import com.sleepycat.je.util.TestUtils;
25 import com.sleepycat.je.utilint.Tracer;
26
27 public class CheckSplitsTest extends CheckBase {
28
29     private static final String JavaDoc DB_NAME = "simpleDB";
30     private boolean useDups;
31
32     /**
33      * Test basic inserts.
34      */

35     public void testBasicInsert()
36         throws Throwable JavaDoc {
37         boolean foo = TestUtils.runLongTests();
38
39         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
40         turnOffEnvDaemons(envConfig);
41         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
42                                  "4");
43         envConfig.setAllowCreate(true);
44                                  
45         DatabaseConfig dbConfig = new DatabaseConfig();
46         dbConfig.setAllowCreate(true);
47         dbConfig.setSortedDuplicates(useDups);
48
49         DatabaseConfig validateDbConfig = new DatabaseConfig();
50         validateDbConfig.setSortedDuplicates(useDups);
51
52         testOneCase(DB_NAME,
53                     envConfig,
54                     dbConfig,
55                     new TestGenerator(true /* generate log description */){
56                         void generateData(Database db)
57                             throws DatabaseException {
58                             setupBasicInsertData(db);
59                         }
60                     },
61                     envConfig,
62                     validateDbConfig);
63
64         /*
65          * Now run the test in a stepwise loop, truncate after each
66          * log entry. We start the steps before the inserts, so the base
67          * expected set is empty.
68          */

69         HashSet JavaDoc currentExpected = new HashSet JavaDoc();
70         stepwiseLoop(DB_NAME, envConfig, dbConfig, currentExpected, 0);
71     }
72     
73     public void testBasicInsertDups()
74         throws Throwable JavaDoc {
75         
76         useDups = true;
77         testBasicInsert();
78     }
79
80     private void setupBasicInsertData(Database db)
81         throws DatabaseException {
82
83         setStepwiseStart();
84
85         /* If using dups, create several dup trees. */
86         DatabaseEntry key = new DatabaseEntry();
87         DatabaseEntry data = new DatabaseEntry();
88         for (int i = 0; i < 21; i++) {
89             if (useDups) {
90                 IntegerBinding.intToEntry(i%3, key);
91             } else {
92                 IntegerBinding.intToEntry(i, key);
93             }
94             IntegerBinding.intToEntry(i, data);
95             db.put(null, key, data);
96         }
97     }
98
99     /**
100      * SR #10715
101      * Splits must propagate up the tree at split time to avoid logging
102      * inconsistent versions of ancestor INs.
103      */

104     public void testSplitPropagation()
105         throws Throwable JavaDoc {
106
107         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
108         turnOffEnvDaemons(envConfig);
109         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
110                                  "6");
111         envConfig.setAllowCreate(true);
112         envConfig.setTransactional(true);
113                                  
114         DatabaseConfig dbConfig = new DatabaseConfig();
115         dbConfig.setAllowCreate(true);
116         dbConfig.setTransactional(true);
117
118         EnvironmentConfig restartConfig = TestUtils.initEnvConfig();
119         turnOffEnvDaemons(envConfig);
120         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
121                                  "6");
122         envConfig.setTransactional(true);
123
124         testOneCase(DB_NAME,
125                     envConfig,
126                     dbConfig,
127                     new TestGenerator(true){
128                         void generateData(Database db)
129                             throws DatabaseException {
130                             setupSplitData(db);
131                         }
132                     },
133                     restartConfig,
134                     new DatabaseConfig());
135
136         /*
137          * Now run the test in a stepwise loop, truncate after each
138          * log entry. We start the steps before the inserts, so the base
139          * expected set is empty.
140          */

141         HashSet JavaDoc currentExpected = new HashSet JavaDoc();
142         if (TestUtils.runLongTests()) {
143             stepwiseLoop(DB_NAME, envConfig, dbConfig, currentExpected, 0);
144         }
145     }
146
147     private void setupSplitData(Database db)
148         throws DatabaseException {
149
150         setStepwiseStart();
151
152         int max = 120;
153
154         DatabaseEntry key = new DatabaseEntry();
155         DatabaseEntry data = new DatabaseEntry();
156
157         /* Populate a tree so it grows to 4 levels, then checkpoint. */
158
159         for (int i = 0; i < max; i ++) {
160             IntegerBinding.intToEntry(i*10, key);
161             IntegerBinding.intToEntry(i*10, data);
162             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
163         }
164
165
166         CheckpointConfig ckptConfig = new CheckpointConfig();
167         ckptConfig.setForce(true);
168         env.checkpoint(ckptConfig);
169
170
171         /* Add enough keys to split the left hand branch again. */
172         for (int i = 50; i < 100; i+=2) {
173             IntegerBinding.intToEntry(i, key);
174             IntegerBinding.intToEntry(i, data);
175             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
176         }
177
178         /* Add enough keys to split the right hand branch. */
179         for (int i = 630; i < 700; i ++) {
180             IntegerBinding.intToEntry(i, key);
181             IntegerBinding.intToEntry(i, data);
182             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
183         }
184
185         Tracer.trace(Level.SEVERE, DbInternal.envGetEnvironmentImpl(env),
186                      "before split");
187
188         /* Add enough keys to split the left hand branch again. */
189         for (int i = 58; i < 75; i++) {
190             IntegerBinding.intToEntry(i, key);
191             IntegerBinding.intToEntry(i, data);
192             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
193         }
194     }
195
196     /**
197      * [#13435] Checks that a DIN can be replayed with a full BIN parent.
198      * When a DIN is replayed, it may already be present in the parent BIN.
199      * Before fixing this bug, we searched without allowing splits and then
200      * called IN.insertEntry, which would throw InconsistentNodeException if
201      * the BIN was full. We now search with splits allowed, which avoids the
202      * exception; however, it causes a split when one is not needed.
203      *
204      * Note that an alternate fix would be to revert to an earlier version of
205      * RecoveryManager.replaceOrInsertDuplicateRoot (differences are between
206      * version 1.184 and 1.185). The older version searches for an existing
207      * entry, and then inserts if necessary. This would avoid the extra split.
208      * However, we had to search with splits allowed anyway to fix another
209      * problem -- see testBINSplitDuringDeletedDINReplay.
210      */

211     public void testBINSplitDuringDINReplay()
212         throws Throwable JavaDoc {
213
214         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
215         turnOffEnvDaemons(envConfig);
216         envConfig.setAllowCreate(true);
217
218         DatabaseConfig dbConfig = new DatabaseConfig();
219         dbConfig.setAllowCreate(true);
220         dbConfig.setSortedDuplicates(true);
221
222         testOneCase(DB_NAME,
223                     envConfig,
224                     dbConfig,
225                     new TestGenerator(true){
226                         void generateData(Database db)
227                             throws DatabaseException {
228                             setupBINSplitDuringDINReplay(db);
229                         }
230                     },
231                     envConfig,
232                     dbConfig);
233
234         /*
235          * Now run the test in a stepwise loop, truncate after each
236          * log entry. We start the steps before the inserts, so the base
237          * expected set is empty.
238          */

239         HashSet JavaDoc currentExpected = new HashSet JavaDoc();
240         if (TestUtils.runLongTests()) {
241             stepwiseLoop(DB_NAME, envConfig, dbConfig, currentExpected, 0);
242         }
243     }
244
245     /**
246      * Fill a BIN with entries, with a DIN in the first entry; then force the
247      * BIN to be flushed, as might occur via eviction or checkpointing.
248      */

249     private void setupBINSplitDuringDINReplay(Database db)
250         throws DatabaseException {
251
252         setStepwiseStart();
253
254         final int max = 128;
255
256         DatabaseEntry key = new DatabaseEntry();
257         DatabaseEntry data = new DatabaseEntry();
258
259         IntegerBinding.intToEntry(1, key);
260         IntegerBinding.intToEntry(0, data);
261         assertEquals(OperationStatus.SUCCESS,
262                      db.putNoOverwrite(null, key, data));
263         IntegerBinding.intToEntry(1, data);
264         assertEquals(OperationStatus.SUCCESS,
265                      db.putNoDupData(null, key, data));
266
267         Cursor cursor = db.openCursor(null, null);
268
269         for (int i = 2; i <= max; i ++) {
270             IntegerBinding.intToEntry(i, key);
271             IntegerBinding.intToEntry(0, data);
272             assertEquals(OperationStatus.SUCCESS,
273                          cursor.putNoOverwrite(key, data));
274         }
275
276         TestUtils.logBINAndIN(env, cursor);
277
278         cursor.close();
279     }
280
281     /**
282      * [#13435] Checks that recovering a DIN causes a BIN split when needed.
283      * This occurs when a DIN has been deleted and subsequently the BIN is
284      * filled. The DIN and the INDupDelete will be be replayed; we will insert
285      * the DIN and then delete it. In order to insert it, we may need to split
286      * the BIN. The sequence is:
287      *
288      * LN-a
289      * (DupCountLN/) DIN (/DBIN/DupCountLN)
290      * LN-b
291      * DelDupLN-a (/DupCountLN)
292      * DelDupLN-b (/DupCountLN)
293      * INDupDelete compress
294      * LN-c/etc to fill the BIN
295      * BIN
296      *
297      * LN-a and LN-b are dups (same key). After being compressed away, the
298      * BIN is filled completely and flushed by the evictor or checkpointer.
299      *
300      * During recovery, when we replay the DIN and need to insert it into the
301      * full BIN, therefore we need to split. Before the bug fix, we did not
302      * search with splits allowed, and got an InconsistentNodeException.
303      */

304     public void testBINSplitDuringDeletedDINReplay()
305         throws Throwable JavaDoc {
306
307         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
308         turnOffEnvDaemons(envConfig);
309         envConfig.setAllowCreate(true);
310
311         DatabaseConfig dbConfig = new DatabaseConfig();
312         dbConfig.setAllowCreate(true);
313         dbConfig.setSortedDuplicates(true);
314
315         testOneCase(DB_NAME,
316                     envConfig,
317                     dbConfig,
318                     new TestGenerator(true){
319                         void generateData(Database db)
320                             throws DatabaseException {
321                             setupBINSplitDuringDeletedDINReplay(db);
322                         }
323                     },
324                     envConfig,
325                     dbConfig);
326
327         /*
328          * Now run the test in a stepwise loop, truncate after each
329          * log entry. We start the steps before the inserts, so the base
330          * expected set is empty.
331          */

332         HashSet JavaDoc currentExpected = new HashSet JavaDoc();
333         if (TestUtils.runLongTests()) {
334             stepwiseLoop(DB_NAME, envConfig, dbConfig, currentExpected, 0);
335         }
336     }
337
338     /**
339      * Insert two dups, delete them, and compress to free the BIN entry;
340      * then fill the BIN with LNs and flush the BIN.
341      */

342     private void setupBINSplitDuringDeletedDINReplay(Database db)
343         throws DatabaseException {
344
345         setStepwiseStart();
346
347         int max = 128;
348
349         DatabaseEntry key = new DatabaseEntry();
350         DatabaseEntry data = new DatabaseEntry();
351
352         IntegerBinding.intToEntry(0, key);
353         IntegerBinding.intToEntry(0, data);
354         assertEquals(OperationStatus.SUCCESS,
355                      db.putNoOverwrite(null, key, data));
356         IntegerBinding.intToEntry(1, data);
357         assertEquals(OperationStatus.SUCCESS,
358                      db.putNoDupData(null, key, data));
359
360         assertEquals(OperationStatus.SUCCESS,
361                      db.delete(null, key));
362
363         env.compress();
364
365         Cursor cursor = db.openCursor(null, null);
366
367         for (int i = 1; i <= max; i ++) {
368             IntegerBinding.intToEntry(i, key);
369             IntegerBinding.intToEntry(0, data);
370             assertEquals(OperationStatus.SUCCESS,
371                          cursor.putNoOverwrite(key, data));
372         }
373
374         TestUtils.logBINAndIN(env, cursor);
375
376         cursor.close();
377     }
378 }
379
Popular Tags