KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > util > DbBackupTest


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

8
9 package com.sleepycat.je.util;
10
11 import java.io.File JavaDoc;
12 import java.io.FileInputStream JavaDoc;
13 import java.io.FileOutputStream JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.nio.channels.FileChannel JavaDoc;
16
17 import junit.framework.TestCase;
18
19 import com.sleepycat.bind.tuple.IntegerBinding;
20 import com.sleepycat.je.CheckpointConfig;
21 import com.sleepycat.je.Cursor;
22 import com.sleepycat.je.Database;
23 import com.sleepycat.je.DatabaseConfig;
24 import com.sleepycat.je.DatabaseEntry;
25 import com.sleepycat.je.DatabaseException;
26 import com.sleepycat.je.DbInternal;
27 import com.sleepycat.je.Environment;
28 import com.sleepycat.je.EnvironmentConfig;
29 import com.sleepycat.je.EnvironmentStats;
30 import com.sleepycat.je.LockMode;
31 import com.sleepycat.je.OperationStatus;
32 import com.sleepycat.je.StatsConfig;
33 import com.sleepycat.je.config.EnvironmentParams;
34 import com.sleepycat.je.dbi.EnvironmentImpl;
35 import com.sleepycat.je.log.FileManager;
36 import com.sleepycat.je.utilint.DbLsn;
37
38 public class DbBackupTest extends TestCase {
39
40     private static StatsConfig CLEAR_CONFIG = new StatsConfig();
41     static {
42         CLEAR_CONFIG.setClear(true);
43     }
44     
45     private static CheckpointConfig FORCE_CONFIG = new CheckpointConfig();
46     static {
47         FORCE_CONFIG.setForce(true);
48     }
49
50     private static final String JavaDoc SAVE1 = "save1";
51     private static final String JavaDoc SAVE2 = "save2";
52     private static final String JavaDoc SAVE3 = "save3";
53     private static final int NUM_RECS = 50;
54
55     private File JavaDoc envHome;
56     private Environment env;
57     private FileManager fileManager;
58
59     public DbBackupTest() {
60         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
61     }
62
63     public void setUp()
64         throws IOException JavaDoc {
65
66         TestUtils.removeLogFiles("Setup", envHome, false);
67         deleteSaveDir(SAVE1);
68         deleteSaveDir(SAVE2);
69         deleteSaveDir(SAVE3);
70     }
71     
72     public void tearDown()
73         throws Exception JavaDoc {
74
75         TestUtils.removeLogFiles("TearDown", envHome, false);
76         deleteSaveDir(SAVE1);
77         deleteSaveDir(SAVE2);
78         deleteSaveDir(SAVE3);
79     }
80
81     /**
82      * Test basic backup, make sure log cleaning isn't running.
83      */

84     public void testBackupVsCleaning()
85         throws Throwable JavaDoc {
86
87         env = createEnv(false, envHome); /* read-write env */
88         EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
89         fileManager = envImpl.getFileManager();
90
91         try {
92
93             /*
94              * Grow files, creating obsolete entries to create cleaner
95              * opportunity.
96              */

97             growFiles("db1", env, 8);
98
99             /* Start backup. */
100             DbBackup backupHelper = new DbBackup(env);
101             backupHelper.startBackup();
102
103             long lastFileNum = backupHelper.getLastFileInBackupSet();
104             long checkLastFileNum = lastFileNum;
105             
106             /* Copy the backup set. */
107             saveFiles(backupHelper, -1, lastFileNum, SAVE1);
108             
109             /*
110              * Try to clean and checkpoint. Check that the logs grew as
111              * a result.
112              */

113             batchClean(0);
114             long newLastFileNum = (fileManager.getLastFileNum()).longValue();
115             assertTrue(checkLastFileNum < newLastFileNum);
116             checkLastFileNum = newLastFileNum;
117  
118             /* Copy the backup set after attempting cleaning */
119             saveFiles(backupHelper, -1, lastFileNum, SAVE2);
120
121             /* Insert more data. */
122             growFiles("db2", env, 8);
123
124             /*
125              * Try to clean and checkpoint. Check that the logs grew as
126              * a result.
127              */

128             batchClean(0);
129             newLastFileNum = fileManager.getLastFileNum().longValue();
130             assertTrue(checkLastFileNum < newLastFileNum);
131             checkLastFileNum = newLastFileNum;
132
133             /* Copy the backup set after inserting more data */
134             saveFiles(backupHelper, -1, lastFileNum, SAVE3);
135
136             /* Check the membership of the saved set. */
137             long lastFile = backupHelper.getLastFileInBackupSet();
138             String JavaDoc [] backupSet = backupHelper.getLogFilesInBackupSet();
139             assertEquals((lastFile + 1), backupSet.length);
140
141             /* End backup. */
142             backupHelper.endBackup();
143
144             /*
145              * Run cleaning, and verify that quite a few files are deleted.
146              */

147             long numCleaned = batchClean(100);
148             assertTrue(numCleaned > 5);
149             env.close();
150             env = null;
151
152             /* Verify backups. */
153             TestUtils.removeLogFiles("Verify", envHome, false);
154             verifyDb1(SAVE1, true);
155             TestUtils.removeLogFiles("Verify", envHome, false);
156             verifyDb1(SAVE2, true);
157             TestUtils.removeLogFiles("Verify", envHome, false);
158             verifyDb1(SAVE3, true);
159         } finally {
160             if (env != null) {
161                 env.close();
162             }
163         }
164     }
165
166     /**
167      * Test multiple backup passes
168      */

169     public void testIncrementalBackup()
170         throws Throwable JavaDoc {
171
172         env = createEnv(false, envHome); /* read-write env */
173         EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
174         fileManager = envImpl.getFileManager();
175
176         try {
177
178             /*
179              * Grow files, creating obsolete entries to create cleaner
180              * opportunity.
181              */

182             growFiles("db1", env, 8);
183
184             /* Backup1. */
185             DbBackup backupHelper = new DbBackup(env);
186             backupHelper.startBackup();
187             long b1LastFile = backupHelper.getLastFileInBackupSet();
188             saveFiles(backupHelper, -1, b1LastFile, SAVE1);
189             String JavaDoc lastName = fileManager.getFullFileName(b1LastFile,
190                                                  FileManager.JE_SUFFIX);
191             File JavaDoc f = new File JavaDoc(lastName);
192             long savedLength = f.length();
193             backupHelper.endBackup();
194
195             /*
196              * Add more data. Check that the file did flip, and is not modified
197              * by the additional data.
198              */

199             growFiles("db2", env, 8);
200             checkFileLen(b1LastFile, savedLength);
201
202             /* Backup2. */
203             backupHelper.startBackup();
204             long b2LastFile = backupHelper.getLastFileInBackupSet();
205             saveFiles(backupHelper, b1LastFile, b2LastFile, SAVE2);
206             backupHelper.endBackup();
207
208             env.close();
209             env = null;
210
211             /* Verify backups. */
212             TestUtils.removeLogFiles("Verify", envHome, false);
213             verifyDb1(SAVE1, false);
214             TestUtils.removeLogFiles("Verify", envHome, false);
215             verifyBothDbs(SAVE1, SAVE2);
216         } finally {
217             if (env != null) {
218                 env.close();
219             }
220         }
221     }
222
223     public void testBadUsage()
224         throws Exception JavaDoc {
225
226         Environment env = createEnv(false, envHome); /* read-write env */
227
228         try {
229             DbBackup backup = new DbBackup(env);
230
231             /* end can only be called after start. */
232             try {
233                 backup.endBackup();
234                 fail("should fail");
235             } catch (DatabaseException expected) {
236             }
237
238             /* start can't be called twice. */
239             backup.startBackup();
240             try {
241                 backup.startBackup();
242                 fail("should fail");
243             } catch (DatabaseException expected) {
244             }
245
246             /*
247              * You can only get the backup set when you're in between start
248              * and end.
249              */

250             backup.endBackup();
251         
252             try {
253                 backup.getLastFileInBackupSet();
254                 fail("should fail");
255             } catch (DatabaseException expected) {
256             }
257
258             try {
259                 backup.getLogFilesInBackupSet();
260                 fail("should fail");
261             } catch (DatabaseException expected) {
262             }
263
264             try {
265                 backup.getLogFilesInBackupSet(0);
266                 fail("should fail");
267             } catch (DatabaseException expected) {
268             }
269         } finally {
270             env.close();
271         }
272     }
273
274     /*
275      * This test can't be run by default, because it makes a directory
276      * read/only, and Java doesn't support a way to make it writable again
277      * except in Mustang. There's no way to clean up a read-only directory.
278      */

279     public void xtestReadOnly()
280         throws Exception JavaDoc {
281
282         /* Make a read-only handle on a read-write environment directory.*/
283         Environment env = createEnv(true, envHome);
284
285         try {
286             DbBackup backup = new DbBackup(env);
287             fail("Should fail because env is read/only.");
288         } catch (DatabaseException expected) {
289         }
290
291         env.close();
292
293         /*
294          * Make a read-only handle on a read-only environment directory. Use a
295          * new environment directory because we're going to set it read0nly and
296          * there doesn't seem to be a way of undoing that.
297          */

298         File JavaDoc tempEnvDir = new File JavaDoc(envHome, SAVE1);
299         assertTrue(tempEnvDir.mkdirs());
300         env = createEnv(false, tempEnvDir);
301         growFiles("db1", env, 8);
302         env.close();
303         //assertTrue(tempEnvDir.setReadOnly());
304

305         env = createEnv(true, tempEnvDir);
306
307         DbBackup backupHelper = new DbBackup(env);
308         backupHelper.startBackup();
309
310         FileManager fileManager =
311             DbInternal.envGetEnvironmentImpl(env).getFileManager();
312         long lastFile = fileManager.getLastFileNum().longValue();
313         assertEquals(lastFile, backupHelper.getLastFileInBackupSet());
314
315         backupHelper.endBackup();
316         env.close();
317         assertTrue(tempEnvDir.delete());
318     }
319
320     private Environment createEnv(boolean readOnly, File JavaDoc envDir)
321         throws DatabaseException {
322
323         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
324         DbInternal.disableParameterValidation(envConfig);
325         envConfig.setAllowCreate(true);
326         envConfig.setReadOnly(readOnly);
327         envConfig.setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
328                                  "400");
329         envConfig.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER.getName(),
330                                  "false");
331
332         Environment env = new Environment(envDir, envConfig);
333
334         return env;
335     }
336
337     private long growFiles(String JavaDoc dbName,
338                            Environment env,
339                            int minNumFiles)
340         throws DatabaseException {
341
342         DatabaseConfig dbConfig = new DatabaseConfig();
343         dbConfig.setAllowCreate(true);
344         Database db = env.openDatabase(null, dbName, dbConfig);
345         FileManager fileManager =
346             DbInternal.envGetEnvironmentImpl(env).getFileManager();
347         long startLastFileNum =
348             DbLsn.getFileNumber(fileManager.getLastUsedLsn());
349
350         DatabaseEntry key = new DatabaseEntry();
351         DatabaseEntry data = new DatabaseEntry();
352         /* Update twice, in order to create plenty of cleaning opportunity. */
353         for (int i = 0; i < NUM_RECS; i++) {
354             IntegerBinding.intToEntry(i, key);
355             IntegerBinding.intToEntry(i, data);
356             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
357         }
358
359         for (int i = 0; i < NUM_RECS; i++) {
360             IntegerBinding.intToEntry(i, key);
361             IntegerBinding.intToEntry(i+5, data);
362             assertEquals(OperationStatus.SUCCESS, db.put(null, key, data));
363         }
364
365         db.close();
366
367         long endLastFileNum =
368             DbLsn.getFileNumber(fileManager.getLastUsedLsn());
369         assertTrue((endLastFileNum -
370                     startLastFileNum) >= minNumFiles);
371         return endLastFileNum;
372     }
373
374     private int batchClean(int expectedDeletions)
375         throws DatabaseException {
376
377         EnvironmentStats stats = env.getStats(CLEAR_CONFIG);
378         while (env.cleanLog() > 0) {
379         }
380         env.checkpoint(FORCE_CONFIG);
381         stats = env.getStats(CLEAR_CONFIG);
382         assertTrue(stats.getNCleanerDeletions() <= expectedDeletions);
383
384         return stats.getNCleanerDeletions();
385     }
386
387     private void saveFiles(DbBackup backupHelper,
388                            long lastFileFromPrevBackup,
389                            long lastFileNum,
390                            String JavaDoc saveDirName)
391         throws IOException JavaDoc, DatabaseException {
392
393         /* Check that the backup set contains only the files it should have. */
394         String JavaDoc [] fileList =
395             backupHelper.getLogFilesInBackupSet(lastFileFromPrevBackup);
396         assertEquals(lastFileNum,
397                      fileManager.getNumFromName(fileList[fileList.length-1]).
398                      longValue());
399
400         /* Make a new save directory. */
401         File JavaDoc saveDir = new File JavaDoc(envHome, saveDirName);
402         assertTrue(saveDir.mkdir());
403         copyFiles(envHome, saveDir, fileList);
404     }
405
406     private void copyFiles(File JavaDoc sourceDir, File JavaDoc destDir, String JavaDoc [] fileList)
407         throws DatabaseException {
408
409         try {
410             for (int i = 0; i < fileList.length; i++) {
411                 File JavaDoc source = new File JavaDoc(sourceDir, fileList[i]);
412                 FileChannel JavaDoc sourceChannel =
413                     new FileInputStream JavaDoc(source).getChannel();
414                 File JavaDoc save = new File JavaDoc(destDir, fileList[i]);
415                 FileChannel JavaDoc saveChannel =
416                     new FileOutputStream JavaDoc(save).getChannel();
417
418                 saveChannel.transferFrom(sourceChannel, 0,
419                                          sourceChannel.size());
420     
421                 // Close the channels
422
sourceChannel.close();
423                 saveChannel.close();
424             }
425         } catch (IOException JavaDoc e) {
426             throw new DatabaseException(e);
427         }
428     }
429
430     /**
431      * Delete all the contents and the directory itself.
432      */

433     private void deleteSaveDir(String JavaDoc saveDirName)
434         throws IOException JavaDoc {
435
436         File JavaDoc saveDir = new File JavaDoc(envHome, saveDirName);
437         if (saveDir.exists()) {
438             String JavaDoc [] savedFiles = saveDir.list();
439             if (savedFiles != null) {
440             for (int i = 0; i < savedFiles.length; i++) {
441                 File JavaDoc f = new File JavaDoc(saveDir, savedFiles[i]);
442                 assertTrue(f.delete());
443             }
444             assertTrue(saveDir.delete());
445             }
446         }
447     }
448
449     /**
450      * Copy the saved files in, check values.
451      */

452     private void verifyDb1(String JavaDoc saveDirName, boolean rename)
453         throws DatabaseException {
454
455         File JavaDoc saveDir = new File JavaDoc(envHome, saveDirName);
456         String JavaDoc [] savedFiles = saveDir.list();
457         if (rename){
458             for (int i = 0; i < savedFiles.length; i++) {
459                 File JavaDoc saved = new File JavaDoc(saveDir, savedFiles[i]);
460                 File JavaDoc dest = new File JavaDoc(envHome, savedFiles[i]);
461                 assertTrue(saved.renameTo(dest));
462             }
463         } else {
464             /* copy. */
465             copyFiles(saveDir, envHome, savedFiles);
466         }
467         env = createEnv(false, envHome);
468         try {
469             checkDb("db1");
470
471             /* Db 2 should not exist. */
472             DatabaseConfig dbConfig = new DatabaseConfig();
473             try {
474                 Database db = env.openDatabase(null, "db2", dbConfig);
475                 fail("db2 should not exist");
476             } catch (DatabaseException expected) {
477             }
478
479         } finally {
480             env.close();
481             env = null;
482         }
483     }
484
485     /**
486      * Copy the saved files in, check values.
487      */

488     private void verifyBothDbs(String JavaDoc saveDirName1, String JavaDoc saveDirName2)
489         throws DatabaseException {
490
491         File JavaDoc saveDir = new File JavaDoc(envHome, saveDirName1);
492         String JavaDoc [] savedFiles = saveDir.list();
493         for (int i = 0; i < savedFiles.length; i++) {
494             File JavaDoc saved = new File JavaDoc(saveDir, savedFiles[i]);
495             File JavaDoc dest = new File JavaDoc(envHome, savedFiles[i]);
496             assertTrue(saved.renameTo(dest));
497         }
498
499         saveDir = new File JavaDoc(envHome, saveDirName2);
500         savedFiles = saveDir.list();
501         for (int i = 0; i < savedFiles.length; i++) {
502             File JavaDoc saved = new File JavaDoc(saveDir, savedFiles[i]);
503             File JavaDoc dest = new File JavaDoc(envHome, savedFiles[i]);
504             assertTrue(saved.renameTo(dest));
505         }
506
507         env = createEnv(false, envHome);
508         try {
509             checkDb("db1");
510             checkDb("db2");
511         } finally {
512             env.close();
513             env = null;
514         }
515     }
516
517     private void checkDb(String JavaDoc dbName)
518         throws DatabaseException {
519
520         DatabaseConfig dbConfig = new DatabaseConfig();
521         Database db = env.openDatabase(null, dbName, dbConfig);
522         Cursor c = null;
523         try {
524             DatabaseEntry key = new DatabaseEntry();
525             DatabaseEntry data = new DatabaseEntry();
526             c = db.openCursor(null, null);
527
528             for (int i = 0; i < NUM_RECS; i++) {
529                 assertEquals(OperationStatus.SUCCESS,
530                              c.getNext(key, data, LockMode.DEFAULT));
531                 assertEquals(i, IntegerBinding.entryToInt(key));
532                 assertEquals(i + 5, IntegerBinding.entryToInt(data));
533             }
534             assertEquals(OperationStatus.NOTFOUND,
535                          c.getNext(key, data, LockMode.DEFAULT));
536         } finally {
537             if (c != null)
538                 c.close();
539             db.close();
540         }
541     }
542
543     private void checkFileLen(long fileNum, long length)
544         throws IOException JavaDoc {
545         String JavaDoc fileName = fileManager.getFullFileName(fileNum,
546                                                       FileManager.JE_SUFFIX);
547         File JavaDoc f = new File JavaDoc(fileName);
548         assertEquals(length, f.length());
549     }
550 }
551
552
553
Popular Tags