KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2004,2006 Oracle. All rights reserved.
5  *
6  * $Id: CheckReverseSplitsTest.java,v 1.8 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.BtreeStats;
15 import com.sleepycat.je.CheckpointConfig;
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.DbInternal;
22 import com.sleepycat.je.EnvironmentConfig;
23 import com.sleepycat.je.LockMode;
24 import com.sleepycat.je.OperationStatus;
25 import com.sleepycat.je.StatsConfig;
26 import com.sleepycat.je.config.EnvironmentParams;
27 import com.sleepycat.je.recovery.stepwise.TestData;
28 import com.sleepycat.je.util.TestUtils;
29 import com.sleepycat.je.utilint.Tracer;
30
31 /*
32  * Exercise reverse splits (deletes of subtrees). Add a comprehensive
33  * "stepwise" approach, where we run the test repeatedly, truncating the log
34  * at each log entry point. At recovery, we check that we have all expected
35  * values. In particular, this approach was required to reproduce SR [#13501],
36  * which only failed if the log was broken off at a given point, between
37  * the logging of an IN and the update of a mapln.
38  */

39 public class CheckReverseSplitsTest extends CheckBase {
40
41     private static final boolean DEBUG = false;
42     private static final String JavaDoc DB_NAME = "simpleDB";
43
44     private int max = 12;
45     private boolean useDups;
46     private boolean purgeRoot = false;
47     private static CheckpointConfig FORCE_CONFIG = new CheckpointConfig();
48     static {
49         FORCE_CONFIG.setForce(true);
50     }
51     
52     /**
53      * SR #13501
54      * Reverse splits require the same upward propagation as regular splits,
55      * to avoid logging inconsistent versions of ancestor INs.
56      */

57     public void testReverseSplit()
58         throws Throwable JavaDoc {
59
60         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
61         turnOffEnvDaemons(envConfig);
62         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
63                                  "4");
64         envConfig.setAllowCreate(true);
65
66         DatabaseConfig dbConfig = new DatabaseConfig();
67         dbConfig.setSortedDuplicates(useDups);
68         dbConfig.setAllowCreate(true);
69
70         /* Run the full test case w/out truncating the log. */
71         testOneCase(DB_NAME, envConfig, dbConfig,
72                     new TestGenerator(true /* generate log description */){
73                         void generateData(Database db)
74                             throws DatabaseException {
75                             setupReverseSplit(db);
76                         }
77                     },
78                     envConfig, dbConfig);
79
80         
81         /*
82          * Now run the test in a stepwise loop, truncate after each
83          * log entry.
84          */

85
86         /* Establish the base set of records we expect. */
87         HashSet JavaDoc currentExpected = new HashSet JavaDoc();
88         DatabaseEntry keyEntry = new DatabaseEntry();
89         DatabaseEntry dataEntry = new DatabaseEntry();
90         for (int i = 2; i < max; i++) {
91             if (useDups) {
92                 IntegerBinding.intToEntry(0, keyEntry);
93             } else {
94                 IntegerBinding.intToEntry(i, keyEntry);
95             }
96             IntegerBinding.intToEntry(i, dataEntry);
97             currentExpected.add(new TestData(keyEntry, dataEntry));
98         }
99
100         stepwiseLoop(DB_NAME, envConfig, dbConfig, currentExpected, 0);
101     }
102
103     public void testReverseSplitDups()
104         throws Throwable JavaDoc {
105
106         useDups = true;
107         testReverseSplit();
108     }
109
110     /**
111      * Create this:
112      * <p>
113      * <pre>
114
115                          INa level 3
116                    / \
117                 INb INc level 2
118              / | \ / \
119            BINs BINt BINu BINv BINw level 1
120      * </pre>
121      * <p>
122      * First provoke an IN compression which removes BINs, and then
123      * provoke a split of BINw which results in propagating the change
124      * all the way up the tree. The bug therefore created a version of INa
125      * on disk which did not include the removal of BINs.
126      */

127     private void setupReverseSplit(Database db)
128         throws DatabaseException {
129
130         DatabaseEntry key = new DatabaseEntry();
131         DatabaseEntry data = new DatabaseEntry();
132
133         /* Populate a tree so it grows to 3 levels. */
134         for (int i = 0; i < max; i ++) {
135             if (useDups) {
136                 IntegerBinding.intToEntry(0, key);
137             } else {
138                 IntegerBinding.intToEntry(i, key);
139             }
140             IntegerBinding.intToEntry(i, data);
141             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
142         }
143
144         /* Empty out the leftmost bin */
145         Cursor c = db.openCursor(null, null);
146         try {
147             assertEquals(OperationStatus.SUCCESS, c.getFirst(key, data,
148                                                          LockMode.DEFAULT));
149             assertEquals(OperationStatus.SUCCESS, c.delete());
150             assertEquals(OperationStatus.SUCCESS,
151                          c.getFirst(key, data, LockMode.DEFAULT));
152             assertEquals(OperationStatus.SUCCESS, c.delete());
153         } finally {
154             c.close();
155         }
156
157         Tracer.trace(Level.SEVERE, DbInternal.envGetEnvironmentImpl(env),
158                      "After deletes");
159
160         /* For log description start. */
161         setStepwiseStart();
162
163         /*
164          * Checkpoint so that the deleted lns are not replayed, and recovery
165          * relies on INs.
166          */

167         env.checkpoint(FORCE_CONFIG);
168
169         /* Now remove the empty BIN. */
170         env.compress();
171         Tracer.trace(Level.SEVERE, DbInternal.envGetEnvironmentImpl(env),
172                      "After compress");
173
174         /*
175          * Add enough keys to split the level 2 IN on the right hand side.
176          * This makes an INa which still references the obsolete BINs.
177          * Truncate the log before the mapLN which refers to the new INa,
178          * else the case will not fail, because recovery will first apply the
179          * new INa, and then apply the INDelete of BINs. We want this case
180          * to apply the INDelete of BINs, and then follow with a splicing in
181          * of the new root.
182          */

183         for (int i = max; i < max+13; i ++) {
184             if (useDups) {
185                 IntegerBinding.intToEntry(0, key);
186             } else {
187                 IntegerBinding.intToEntry(i, key);
188             }
189             IntegerBinding.intToEntry(i, data);
190             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
191         }
192
193         Tracer.trace(Level.SEVERE, DbInternal.envGetEnvironmentImpl(env),
194                      "After data setup");
195
196     }
197
198     /**
199      * Create a tree, remove it all, replace with new records.
200      */

201     public void testCompleteRemoval()
202         throws Throwable JavaDoc {
203
204         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
205         turnOffEnvDaemons(envConfig);
206         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
207                                  "4");
208         envConfig.setAllowCreate(true);
209         if (purgeRoot) {
210             envConfig.setConfigParam(
211                        EnvironmentParams.COMPRESSOR_PURGE_ROOT.getName(),
212                        "true");
213         }
214
215         DatabaseConfig dbConfig = new DatabaseConfig();
216         dbConfig.setSortedDuplicates(useDups);
217         dbConfig.setAllowCreate(true);
218
219         /* Run the full test case w/out truncating the log. */
220         testOneCase(DB_NAME, envConfig, dbConfig,
221                     new TestGenerator(true /* generate log description. */){
222                         void generateData(Database db)
223                             throws DatabaseException {
224                             setupCompleteRemoval(db);
225                         }
226                     },
227                     envConfig, dbConfig);
228
229         
230         /*
231          * Now run the test in a stepwise loop, truncate after each log entry.
232          * Our baseline expected set is empty -- no records expected.
233          */

234         HashSet JavaDoc currentExpected = new HashSet JavaDoc();
235         stepwiseLoop(DB_NAME, envConfig, dbConfig, currentExpected, 0);
236     }
237
238     public void testCompleteRemovalDups()
239         throws Throwable JavaDoc {
240
241         useDups = true;
242         testCompleteRemoval();
243     }
244
245     public void testCompleteRemovalPurgeRoot()
246         throws Throwable JavaDoc {
247
248         purgeRoot = true;
249         testCompleteRemoval();
250     }
251
252     /**
253      * Create a populated tree, delete all records, then begin to insert again.
254      */

255     private void setupCompleteRemoval(Database db)
256         throws DatabaseException {
257
258         DatabaseEntry key = new DatabaseEntry();
259         DatabaseEntry data = new DatabaseEntry();
260
261         /* Populate a tree so it grows to 3 levels. */
262         for (int i = 0; i < max; i ++) {
263             if (useDups) {
264                 IntegerBinding.intToEntry(0, key);
265             } else {
266                 IntegerBinding.intToEntry(i, key);
267             }
268             IntegerBinding.intToEntry(i, data);
269             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
270         }
271
272         Tracer.trace(Level.SEVERE, DbInternal.envGetEnvironmentImpl(env),
273                      "After inserts");
274
275         /* Now delete it all. */
276         Cursor c = db.openCursor(null, null);
277         try {
278             int count = 0;
279             while (c.getNext(key, data, LockMode.DEFAULT) ==
280                    OperationStatus.SUCCESS) {
281                 assertEquals(OperationStatus.SUCCESS, c.delete());
282                 count++;
283             }
284         } finally {
285             c.close();
286         }
287         Tracer.trace(Level.SEVERE, DbInternal.envGetEnvironmentImpl(env),
288                      "After deletes");
289         
290
291
292         /* For log description start. */
293         setStepwiseStart();
294
295         /* Checkpoint before, so we don't simply replay all the deleted LNs */
296         env.checkpoint(FORCE_CONFIG);
297
298         /* Compress, and make sure the subtree was removed. */
299         env.compress();
300         BtreeStats stats = (BtreeStats) db.getStats(new StatsConfig());
301         if (useDups) {
302             assertEquals(0, stats.getDuplicateInternalNodeCount());
303         } else {
304             if (purgeRoot) {
305                 assertEquals(0, stats.getInternalNodeCount());
306             } else {
307                 assertEquals(1, stats.getBottomInternalNodeCount());
308             }
309         }
310
311         /* Insert new data. */
312         for (int i = max*2; i < ((max*2) +5); i ++) {
313             if (useDups) {
314                 IntegerBinding.intToEntry(0, key);
315             } else {
316                 IntegerBinding.intToEntry(i, key);
317             }
318             IntegerBinding.intToEntry(i, data);
319             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
320         }
321     }
322 }
323
Popular Tags