Performing Backups

Performing a Hot Backup
Performing an Offline Backup
Using the DbBackup Helper Class

This section describes how to backup your JE database(s) such that catastrophic recovery is possible.

To backup your database, you can either take a hot backup or an offline backup. A hot backup is performed while database write operations are in progress.

Do not confuse offline and hot backups with the concept of a full and incremental backup. Both an offline and a hot backup are full backups – you back up the entire database. The only difference between them is how much of the contents of the in-memory cache are contained in them. On the other hand, an incremental backup is a backup of just those log files modified or created since the time of the last backup. Most backup software is capable of performing both full and incremental backups for you.

Performing a Hot Backup

To perform a hot backup of your JE databases, copy all log files (*.jdb files) from your environment directory to your archival location or backup media. The files must be copied in alphabetical order (numerical in effect). You do not have to stop any database operations in order to do this.

Note

If you are using subdirectories to store your log files, then you must backup the subdirectories, making sure to keep log files in the subdirectory in which JE placed them. For information on using subdirectories to store your log files, see the Getting Started with Berkeley DB, Java Edition guide.

To make this process a bit easier, you may want to make use of the DbBackup helper class. See Using the DbBackup Helper Class for details.

Performing an Offline Backup

An offline backup guarantees that you have captured the database in its entirety, including all contents of your in-memory cache, at the moment that the backup was taken. To do this, you must make sure that no write operations are in progress and all database modifications have been written to your log files on disk. To obtain an offline backup:

  1. Stop writing your databases.

  2. Make sure all your in-memory changes have been flushed to disk. How you do this depends on the type of transactions that you are using:

    • If you are using transactions that writes all dirty data to disk on commit (this is the default behavior), you simply need to make sure all on-going transactions are committed or aborted.

    • If you are using transactions that do not synchronously write on commit, you must run a checkpoint. Remember that closing your environment causes a checkpoint to be run, so if your application is shutting down completely before taking the backup, you have met this requirement.

      For information on changing the transactional sync behavior, see Non-Durable Transactions. For information on running a checkpoint, see Checkpoints.

  3. If you are using durable transactions, then optionally run a checkpoint. Doing this can shorten the time required to restore your database from this back up.

  4. Copy all log files (*.jdb) from your environment directory to your archival location or backup media. To make this process a bit easier, you may want to make use of the DbBackup helper class. See the next section for details.

    Note

    If you are using subdirectories to store your log files, then you must backup the subdirectories, making sure to keep log files in the subdirectory in which JE placed them. For information on using subdirectories to store your log files, see the Getting Started with Berkeley DB, Java Edition guide.

You can now resume normal database operations.

Using the DbBackup Helper Class

In order to simplify backup operations, JE provides the DbBackup helper class. This class stops and restarts JE background activity in an open environment. It also lets the application create a backup which can support restoring the environment to a specific point in time.

Because you do not have to stop JE write activity in order to take a backup, it is usually necessary to examine your log files twice before you decide that your backup is complete. This is because JE may create a new log file while you are running your backup. A second pass over your log files allows you to ensure that no new files have been created and so you can declare your backup complete.

For example:

 time    files in                    activity
         environment

  t0     000000001.jdb     Backup starts copying file 1
         000000003.jdb
         000000004.jdb

  t1     000000001.jdb     JE log cleaner migrates portion of file 3 to
         000000004.jdb     newly created file 5 and deletes file 3. 
         000000005.jdb     Backup finishes file 1, starts copying file 4.
                           Backup MUST include file 5 for a consistent 
                           backup!

  t2     000000001.jdb     Backup finishes copying file 4, starts and 
         000000004.jdb     finishes file 5, has caught up. Backup ends.
         000000005.jdb

DbBackup works around this problem by defining the set of files that must be copied for each backup operation, and freezes all changes to those files. The application can copy that defined set of files and finish operation without checking for the ongoing creation of new files. Also, there will be no need to check for a newer version of the last file on the next backup.

In the example above, if DbBackup was used at t0, the application would only have to copy files 1, 3 and 4 to back up. On a subsequent backup, the application could start its copying at file 5. There would be no need to check for a newer version of file 4.

The following code fragment illustrates this class' usage. See the DbBackup javadoc for additional examples and more information on incremental backups.

package je.gettingStarted;

...
import com.sleepycat.je.util.DbBackup;
...

    // Find the file number of the last file in the previous backup
    // persistently, by either checking the backup archive, or saving
    // state in a persistent file.
    long lastFileCopiedInPrevBackup =  ...

    Environment env = new Environment(...);
    DbBackup backupHelper = new DbBackup(env, lastFileCopiedInPrevBackup);

    // Start backup, find out what needs to be copied.
    // If multiple environment subdirectories are in use,
    // the getLogFilesInBackupSet returns the log file
    // name prefixed with the dataNNN/ directory in which
    // it resides.
    backupHelper.startBackup();
    try {
        String[] filesForBackup = backupHelper.getLogFilesInBackupSet();

        // Copy the files to archival storage.
        myApplicationCopyMethod(filesForBackup)
        // Update our knowlege of the last file saved in the backup set,
        // so we can copy less on the next backup
        lastFileCopiedInPrevBackup = backupHelper.getLastFileInBackupSet();
        myApplicationSaveLastFile(lastFileCopiedInBackupSet);
    }
    finally {
        // Remember to exit backup mode, or all log files won't be cleaned
        // and disk usage will bloat.
       backupHelper.endBackup();
   }