Subversion Repositories SmartDukaan

Rev

Rev 4952 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/**
 * 
 */
package in.shop2020.util;

import in.shop2020.storage.bdb.StorageManager;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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

/**
 * This Runnable takes hot back up of the bdb database files.
 * 
 * @author mandeep
 */
public class BDBHotBackupTask implements Runnable {
    private static Log          log                    = LogFactory.getLog(BDBHotBackupTask.class);

    /**
     * Archival location of backups
     */
    private static final String MASTER_BACKUP_DIR      = "/data/CMS-daily-backup/bdb-backup";

    @Override
    public void run() {
        log.info("Starting backup process");
        DbBackup backupHelper = null;

        try {
            Environment env = StorageManager.getStorageManager()
                    .getEnvironment();

            backupHelper = new DbBackup(env);

            // Start backup, find out what needs to be copied.
            backupHelper.startBackup();
            String[] filesForBackup = backupHelper.getLogFilesInBackupSet();

            // Copy the files to archival storage.
            backupFiles(filesForBackup, env.getHome(), new File(MASTER_BACKUP_DIR + File.separator + new Date().getTime()));
        } finally {
            // Remember to exit backup mode, or all log files won't be cleaned
            // and disk usage will bloat.
            backupHelper.endBackup();
        }

        deleteOldBackupDirectories();
    }

    /**
     * Deletes directories older than 4 days
     */
    private void deleteOldBackupDirectories() {
        File[] directoriesToBeDeleted = new File(MASTER_BACKUP_DIR).listFiles(new FileFilter() {

            @Override
            public boolean accept(File file) {
                long ONE_DAYS_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 1;
                if (new Date().getTime() - file.lastModified() > ONE_DAYS_IN_MILLISECONDS) {
                    return true;
                }

                return false;
            }
        });

        for (File directory : directoriesToBeDeleted) {
            log.info("Deleting directory: " + directory.getName());
            for (File file : directory.listFiles()) {
                file.delete();
            }

            directory.delete();
        }
    }

    /**
     * Copies files to back up directory.
     *
     * @param filesForBackup    Files to be copied
     * @param databaseDir       Source directory
     * @param backupDir         backup archival directory
     */
    private void backupFiles(String[] filesForBackup, File databaseDir,
            File backupDir) {
        // Determine size of backup
        long size = 0;
        for (String name : filesForBackup) {
            size += new File(databaseDir, name).length();
        }

        log.info(String.format("Backing up %d files with a total of %.1fMB",
                filesForBackup.length, mb(size)));

        // Ensure files are sorted in order, so that if we fail part way
        // through, we don't lose stuff
        Arrays.sort(filesForBackup);

        // Creating directory if it does not exists
        if (!backupDir.exists()) {
            backupDir.mkdir();
        }

        long total = 0;
        for (String name : filesForBackup) {
            File source = new File(databaseDir, name);
            File dest = new File(backupDir, name);

            log.info(String.format("% 3d%% Copying %s", total * 100 / size,
                    name));
            try {
                copyFile(source, dest);
            } catch (IOException e) {
                // If the destination file exists, delete it
                if (dest.exists()) {
                    dest.delete();
                }
                throw new RuntimeException(
                        "Error occured while copying "
                                + name
                                + ". Deleting to ensure we don't have a corrupt backup.",
                        e);
            }

            total += source.length();
        }
    }

    // Fast NIO copy method
    private void copyFile(File sourceFile, File destFile) throws IOException {
        if (!destFile.exists()) {
            destFile.createNewFile();
        }

        FileChannel source = null;
        FileChannel destination = null;

        try {
            source = new FileInputStream(sourceFile).getChannel();
            destination = new FileOutputStream(destFile).getChannel();
            destination.transferFrom(source, 0, source.size());
        } finally {
            if (source != null) {
                source.close();
            }
            if (destination != null) {
                destination.close();
            }
        }
    }

    private static double mb(long value) {
        return ((double) value) / 1048576;
    }
}