Author: jbellis
Date: Mon Jul 27 17:28:57 2009
New Revision: 798228
URL: http://svn.apache.org/viewvc?rev=798228&view=rev
Log:
finish snapshot support. patch by Sammy Yu; reviewed by jbellis and Michael
Greene for CASSANDRA-279
Modified:
incubator/cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageServiceMBean.java
incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java
incubator/cassandra/trunk/src/java/org/apache/cassandra/utils/FileUtils.java
Modified:
incubator/cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
URL:
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java?rev=798228&r1=798227&r2=798228&view=diff
==============================================================================
---
incubator/cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
(original)
+++
incubator/cassandra/trunk/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
Mon Jul 27 17:28:57 2009
@@ -56,7 +56,6 @@
private static int replicationFactor_ = 3;
private static long rpcTimeoutInMillis_ = 2000;
private static Set<String> seeds_ = new HashSet<String>();
- private static String snapshotDirectory_;
/* Keeps the list of data file directories */
private static String[] dataFileDirectories_;
/* Current index into the above list of directories */
@@ -233,11 +232,6 @@
columnIndexSizeInKB_ = Integer.parseInt(columnIndexSizeInKB);
}
- /* snapshot directory */
- snapshotDirectory_ =
xmlUtils.getNodeValue("/Storage/SnapshotDirectory");
- if ( snapshotDirectory_ != null )
- FileUtils.createDirectory(snapshotDirectory_);
-
/* data file directory */
dataFileDirectories_ =
xmlUtils.getNodeValues("/Storage/DataFileDirectories/DataFileDirectory");
if (dataFileDirectories_.length == 0)
@@ -682,21 +676,18 @@
return threadsPerPool_;
}
- public static String getSnapshotDirectory()
- {
- return snapshotDirectory_;
- }
-
- public static void setSnapshotDirectory(String snapshotDirectory)
- {
- snapshotDirectory_ = snapshotDirectory;
- }
-
public static String[] getAllDataFileLocations()
{
return dataFileDirectories_;
}
+ /**
+ * Get a list of data directories for a given table
+ *
+ * @param table name of the table.
+ *
+ * @return an array of path to the data directories.
+ */
public static String[] getAllDataFileLocationsForTable(String table)
{
String[] tableLocations = new String[dataFileDirectories_.length];
Modified:
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
URL:
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java?rev=798228&r1=798227&r2=798228&view=diff
==============================================================================
---
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
(original)
+++
incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
Mon Jul 27 17:28:57 2009
@@ -1523,6 +1523,37 @@
}
/**
+ * Take a snap shot of this columnfamily store.
+ *
+ * @param snapshotName the name of the associated with the snapshot
+ */
+ public void snapshot(String snapshotName) throws IOException
+ {
+ sstableLock_.readLock().lock();
+ try
+ {
+ for (String filename : new ArrayList<String>(ssTables_.keySet()))
+ {
+ File sourceFile = new File(filename);
+
+ File dataDirectory =
sourceFile.getParentFile().getParentFile();
+ String snapshotDirectoryPath =
Table.getSnapshotPath(dataDirectory.getAbsolutePath(), table_, snapshotName);
+ FileUtils.createDirectory(snapshotDirectoryPath);
+
+ File targetLink = new File(snapshotDirectoryPath,
sourceFile.getName());
+ FileUtils.createHardLink(new File(filename), targetLink);
+ if (logger_.isDebugEnabled())
+ logger_.debug("Snapshot for " + table_ + " table data file
" + sourceFile.getAbsolutePath() +
+ " created as " + targetLink.getAbsolutePath());
+ }
+ }
+ finally
+ {
+ sstableLock_.readLock().unlock();
+ }
+ }
+
+ /**
* for testing. no effort is made to clear historical memtables.
*/
void clearUnsafe()
Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
URL:
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java?rev=798228&r1=798227&r2=798228&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java
(original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/Table.java Mon
Jul 27 17:28:57 2009
@@ -56,6 +56,7 @@
public static final String SYSTEM_TABLE = "system";
private static Logger logger_ = Logger.getLogger(Table.class);
+ private static final String SNAPSHOT_SUBDIR_NAME = "snapshots";
/*
* This class represents the metadata of this Table. The metadata
@@ -403,16 +404,47 @@
}
}
- /*
- * Clear the existing snapshots in the system
+
+ /**
+ * Take a snapshot of the entire set of column families with a given
timestamp.
+ *
+ * @param clientSuppliedName the tag associated with the name of the
snapshot. This
+ * value can be null.
*/
- public void clearSnapshot()
+ public void snapshot(String clientSuppliedName) throws IOException
{
- String snapshotDir = DatabaseDescriptor.getSnapshotDirectory();
- File snapshot = new File(snapshotDir);
- FileUtils.deleteDir(snapshot);
+ String snapshotName = Long.toString(System.currentTimeMillis());
+ if (clientSuppliedName != null && !clientSuppliedName.equals(""))
+ {
+ snapshotName = snapshotName + "-" + clientSuppliedName;
+ }
+
+ for (ColumnFamilyStore cfStore : columnFamilyStores_.values())
+ {
+ cfStore.snapshot(snapshotName);
+ }
}
-
+
+
+ /**
+ * Clear all the snapshots for a given table.
+ */
+ public void clearSnapshot() throws IOException
+ {
+ for (String dataDirPath : DatabaseDescriptor.getAllDataFileLocations())
+ {
+ String snapshotPath = dataDirPath + File.separator + table_ +
File.separator + SNAPSHOT_SUBDIR_NAME;
+ File snapshotDir = new File(snapshotPath);
+ if (snapshotDir.exists())
+ {
+ if (logger_.isDebugEnabled())
+ logger_.debug("Removing snapshot directory " +
snapshotPath);
+ if (!FileUtils.deleteDir(snapshotDir))
+ throw new IOException("Could not clear snapshot directory
" + snapshotPath);
+ }
+ }
+ }
+
/*
* This method is invoked only during a bootstrap process. We basically
* do a complete compaction since we can figure out based on the ranges
@@ -729,4 +761,8 @@
}
}
+ public static String getSnapshotPath(String dataDirPath, String tableName,
String snapshotName)
+ {
+ return dataDirPath + File.separator + tableName + File.separator +
SNAPSHOT_SUBDIR_NAME + File.separator + snapshotName;
+ }
}
Modified:
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
URL:
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java?rev=798228&r1=798227&r2=798228&view=diff
==============================================================================
---
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
(original)
+++
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
Mon Jul 27 17:28:57 2009
@@ -734,6 +734,50 @@
}
}
+ /**
+ * Takes the snapshot for a given table.
+ *
+ * @param table the name of the table.
+ * @param tag the tag given to the snapshot (null is permissible)
+ */
+ public void takeSnapshot(String tableName, String tag) throws IOException
+ {
+ if (DatabaseDescriptor.getTable(tableName) == null)
+ {
+ throw new IOException("Table " + tableName + "does not exist");
+ }
+ Table tableInstance = Table.open(tableName);
+ tableInstance.snapshot(tag);
+ }
+
+ /**
+ * Takes a snapshot for every table.
+ *
+ * @param tag the tag given to the snapshot (null is permissible)
+ */
+ public void takeAllSnapshot(String tag) throws IOException
+ {
+ for (String tableName: DatabaseDescriptor.getTables())
+ {
+ Table tableInstance = Table.open(tableName);
+ tableInstance.snapshot(tag);
+ }
+ }
+
+ /**
+ * Remove all the existing snapshots.
+ */
+ public void clearSnapshot() throws IOException
+ {
+ for (String tableName: DatabaseDescriptor.getTables())
+ {
+ Table tableInstance = Table.open(tableName);
+ tableInstance.clearSnapshot();
+ }
+ if (logger_.isDebugEnabled())
+ logger_.debug("Cleared out all snapshot directories");
+ }
+
/* End of MBean interface methods */
/**
Modified:
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageServiceMBean.java
URL:
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageServiceMBean.java?rev=798228&r1=798227&r2=798228&view=diff
==============================================================================
---
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageServiceMBean.java
(original)
+++
incubator/cassandra/trunk/src/java/org/apache/cassandra/service/StorageServiceMBean.java
Mon Jul 27 17:28:57 2009
@@ -66,4 +66,24 @@
* @param target endpoint receiving data.
*/
public void forceHandoff(List<String> directories, String target) throws
IOException;
+
+ /**
+ * Takes the snapshot for a given table.
+ *
+ * @param tableName the name of the table.
+ * @param tag the tag given to the snapshot (null is permissible)
+ */
+ public void takeSnapshot(String tableName, String tag) throws IOException;
+
+ /**
+ * Takes a snapshot for every table.
+ *
+ * @param tag the tag given to the snapshot (null is permissible)
+ */
+ public void takeAllSnapshot(String tag) throws IOException;
+
+ /**
+ * Remove all the existing snapshots.
+ */
+ public void clearSnapshot() throws IOException;
}
Modified:
incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java
URL:
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java?rev=798228&r1=798227&r2=798228&view=diff
==============================================================================
---
incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java
(original)
+++
incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java
Mon Jul 27 17:28:57 2009
@@ -426,6 +426,24 @@
}
/**
+ * Take a snapshot of all the tables.
+ *
+ * @param snapshotName the name of the snapshot.
+ */
+ public void takeSnapshot(String snapshotName) throws IOException
+ {
+ ssProxy.takeAllSnapshot(snapshotName);
+ }
+
+ /**
+ * Remove all the existing snapshots.
+ */
+ public void clearSnapshot() throws IOException
+ {
+ ssProxy.clearSnapshot();
+ }
+
+ /**
* Retrieve any non-option arguments passed on the command line.
*
* @return non-option command args
@@ -454,7 +472,7 @@
{
HelpFormatter hf = new HelpFormatter();
String header = String.format(
- "%nAvailable commands: ring, cluster, info, cleanup, compact,
cfstats");
+ "%nAvailable commands: ring, cluster, info, cleanup, compact,
cfstats, snapshot [name], clearsnapshot");
String usage = String.format("java %s -host <arg> <command>%n",
NodeProbe.class.getName());
hf.printHelp(usage, "", options, header);
}
@@ -490,7 +508,8 @@
}
// Execute the requested command.
- String cmdName = probe.getArgs()[0];
+ String[] arguments = probe.getArgs();
+ String cmdName = arguments[0];
if (cmdName.equals("ring"))
{
probe.printRing(System.out);
@@ -515,6 +534,19 @@
{
probe.printColumnFamilyStats(System.out);
}
+ else if (cmdName.equals("snapshot"))
+ {
+ String snapshotName = "";
+ if (arguments.length > 1)
+ {
+ snapshotName = arguments[1];
+ }
+ probe.takeSnapshot(snapshotName);
+ }
+ else if (cmdName.equals("clearsnapshot"))
+ {
+ probe.clearSnapshot();
+ }
else
{
System.err.println("Unrecognized command: " + cmdName + ".");
Modified:
incubator/cassandra/trunk/src/java/org/apache/cassandra/utils/FileUtils.java
URL:
http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/utils/FileUtils.java?rev=798228&r1=798227&r2=798228&view=diff
==============================================================================
---
incubator/cassandra/trunk/src/java/org/apache/cassandra/utils/FileUtils.java
(original)
+++
incubator/cassandra/trunk/src/java/org/apache/cassandra/utils/FileUtils.java
Mon Jul 27 17:28:57 2009
@@ -263,4 +263,44 @@
// The directory is now empty so now it can be smoked
return dir.delete();
}
+
+ /**
+ * Create a hard link for a given file.
+ *
+ * @param sourceFile The name of the source file.
+ * @param destinationFile The name of the destination file.
+ *
+ * @throws IOException if an error has occurred while creating the link.
+ */
+ public static void createHardLink(File sourceFile, File destinationFile)
throws IOException
+ {
+ String osname = System.getProperty("os.name");
+ ProcessBuilder pb;
+ if (osname.startsWith("Windows"))
+ {
+ float osversion =
Float.parseFloat(System.getProperty("os.version"));
+ if (osversion >= 6.0f)
+ {
+ pb = new ProcessBuilder("cmd", "/c", "mklink", "/H",
destinationFile.getAbsolutePath(), sourceFile.getAbsolutePath());
+ }
+ else
+ {
+ pb = new ProcessBuilder("fsutil", "hardlink", "create",
destinationFile.getAbsolutePath(), sourceFile.getAbsolutePath());
+ }
+ }
+ else
+ {
+ pb = new ProcessBuilder("ln", sourceFile.getAbsolutePath(),
destinationFile.getAbsolutePath());
+ pb.redirectErrorStream(true);
+ }
+ Process p = pb.start();
+ try
+ {
+ p.waitFor();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
}