/* * @(#) ClusterSnapshotTask.java * Created Sep 23, 2011 by oleg * (C) ONE, SIA */ package org.apache.cassandra.maint; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.Arrays; import java.util.Calendar; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.Table; import org.apache.cassandra.io.util.FileUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.log4j.Logger; /** * Runs on every node in cluster. Removes snapshots older than X days. * * @author Oleg Anastasyev<oa@hq.one.lv> * */ public class CleanOldSnapshotsTask implements MaintenanceTask, Runnable { private final Logger logger = Logger.getLogger(MaintenanceTaskManager.class); private long lastSuccessfulWindowMillis = 0l; private MaintenanceContext currentCtx ; private int daysOld = 3; public CleanOldSnapshotsTask(int daysold) { this.daysOld = daysold; } /* (non-Javadoc) * @see org.apache.cassandra.maint.MaintenanceTask#maybeRun(org.apache.cassandra.maint.MaintenanceContext) */ @Override public Runnable maybeRun(MaintenanceContext ctx) { this.currentCtx = ctx; return ctx.startedMillis()>lastSuccessfulWindowMillis ? this : null; } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { String[] dataFileLocations = DatabaseDescriptor.getAllDataFileLocations(); final long earliestSnapshot = earliestSnapshotMillis(); for (String dataDir : dataFileLocations) { for (Table table : Table.all()) { String snapshotDir = Table.getSnapshotPath(dataDir, table.name, ""); cleanDir(earliestSnapshot, new File( snapshotDir )); } } if (DatabaseDescriptor.isDataArchiveEnabled()) { for (Table table : Table.all()) { File snapshotDir = DatabaseDescriptor.getDataArchiveFileLocationForSnapshot(table.name); cleanDir(earliestSnapshot, snapshotDir); } } lastSuccessfulWindowMillis = currentCtx.startedMillis(); } private void cleanDir(final long earliestSnapshot, File snapshotDir) { File[] obsoleteSnapshotDirs = snapshotDir.listFiles(new FileFilter() { @Override public boolean accept(File dir) { try { return dir.isDirectory() && Long.parseLong(dir.getName().split("-")[0])<=earliestSnapshot; } catch (Exception e) { logger.warn("Snapshot directory is not understood and skipped: "+dir); return false; } } }); if (obsoleteSnapshotDirs!=null && obsoleteSnapshotDirs.length>0) { logger.info("Deleting obsolete snapshot directories (older than "+daysOld+" days): "+ArrayUtils.toString(obsoleteSnapshotDirs)); for (File file : obsoleteSnapshotDirs) { try { FileUtils.deleteDir(file); } catch (IOException e) { logger.error("Cannot remove "+file,e); } } } } /** * @return */ private long earliestSnapshotMillis() { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(currentCtx.startedMillis()); calendar.add(Calendar.DAY_OF_YEAR, -daysOld); return calendar.getTimeInMillis(); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Cleaning snapshots older than "+daysOld+" days"; } }