Updated Branches: refs/heads/trunk 0b6f03f12 -> 719103b64
add listsnapshots command to nodetool patch by Sankalp Kohli and Lyuben Todorov for CASSANDRA-5742 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/719103b6 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/719103b6 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/719103b6 Branch: refs/heads/trunk Commit: 719103b649c1c5459683a8ffd1c013664f1ffbb6 Parents: 0b6f03f Author: Jonathan Ellis <jbel...@apache.org> Authored: Tue Jan 21 22:27:24 2014 -0800 Committer: Jonathan Ellis <jbel...@apache.org> Committed: Tue Jan 21 22:27:24 2014 -0800 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../apache/cassandra/db/ColumnFamilyStore.java | 9 ++++ .../org/apache/cassandra/db/Directories.java | 36 ++++++++++++++++ .../org/apache/cassandra/io/util/FileUtils.java | 18 ++++++++ .../cassandra/service/StorageService.java | 45 ++++++++++++++++++++ .../cassandra/service/StorageServiceMBean.java | 13 ++++++ .../org/apache/cassandra/tools/NodeProbe.java | 10 +++++ .../org/apache/cassandra/tools/NodeTool.java | 44 +++++++++++++++++++ 8 files changed, 176 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 6eeb819..5c9b64f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 2.1 + * add listsnapshots command to nodetool (CASSANDRA-5742) * Introduce AtomicBTreeColumns (CASSANDRA-6271) * Multithreaded commitlog (CASSANDRA-3578) * allocate fixed index summary memory pool and resample cold index summaries http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/src/java/org/apache/cassandra/db/ColumnFamilyStore.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java index 892e881..fe77d09 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@ -1839,6 +1839,15 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean List<File> snapshotDirs = directories.getCFDirectories(); Directories.clearSnapshot(snapshotName, snapshotDirs); } + /** + * + * @return Return a map of all snapshots to space being used + * The pair for a snapshot has true size and size on disk. + */ + public Map<String, Pair<Long,Long>> getSnapshotDetails() + { + return directories.getSnapshotDetails(); + } public boolean hasUnreclaimedSpace() { http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/src/java/org/apache/cassandra/db/Directories.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/Directories.java b/src/java/org/apache/cassandra/db/Directories.java index a124d67..b3723b3 100644 --- a/src/java/org/apache/cassandra/db/Directories.java +++ b/src/java/org/apache/cassandra/db/Directories.java @@ -485,6 +485,42 @@ public class Directories } } + /** + * + * @return Return a map of all snapshots to space being used + * The pair for a snapshot has size on disk and true size. + */ + public Map<String, Pair<Long, Long>> getSnapshotDetails() + { + final Map<String, Pair<Long, Long>> snapshotSpaceMap = new HashMap<>(); + for (final File dir : sstableDirectories) + { + final File snapshotDir = new File(dir,SNAPSHOT_SUBDIR); + if (snapshotDir.exists() && snapshotDir.isDirectory()) + { + final File[] snapshots = snapshotDir.listFiles(); + if (snapshots != null) + { + for (final File snapshot : snapshots) + { + if (snapshot.isDirectory()) + { + final long sizeOnDisk = FileUtils.folderSize(snapshot); + final long trueSize = getTrueAllocatedSizeIn(snapshot); + Pair<Long,Long> spaceUsed = snapshotSpaceMap.get(snapshot.getName()); + if (spaceUsed == null) + spaceUsed = Pair.create(sizeOnDisk,trueSize); + else + spaceUsed = Pair.create(spaceUsed.left + sizeOnDisk, spaceUsed.right + trueSize); + snapshotSpaceMap.put(snapshot.getName(), spaceUsed); + } + } + } + } + } + + return snapshotSpaceMap; + } public boolean snapshotExists(String snapshotName) { for (File dir : sstableDirectories) http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/src/java/org/apache/cassandra/io/util/FileUtils.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/io/util/FileUtils.java b/src/java/org/apache/cassandra/io/util/FileUtils.java index 3c84cc3..cbed4f8 100644 --- a/src/java/org/apache/cassandra/io/util/FileUtils.java +++ b/src/java/org/apache/cassandra/io/util/FileUtils.java @@ -447,4 +447,22 @@ public class FileUtils throw new IllegalStateException(); } } + + /** + * Get the size of a directory in bytes + * @param The directory for which we need size. + * @return The size of the directory + */ + public static long folderSize(File directory) + { + long length = 0; + for (File file : directory.listFiles()) + { + if (file.isFile()) + length += file.length(); + else + length += folderSize(file); + } + return length; + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/src/java/org/apache/cassandra/service/StorageService.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index 6f4788f..43fead0 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -34,6 +34,8 @@ import javax.management.MBeanServer; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.ObjectName; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; import static java.nio.charset.StandardCharsets.ISO_8859_1; @@ -2229,6 +2231,49 @@ public class StorageService extends NotificationBroadcasterSupport implements IE logger.debug("Cleared out snapshot directories"); } + public Map<String, TabularData> getSnapshotDetails() + { + final Map<String, TabularData> snapshotMap = new HashMap<>(); + for (final Keyspace keyspace : Keyspace.all()) + { + if (Keyspace.SYSTEM_KS.equals(keyspace.getName())) + continue; + + for (final ColumnFamilyStore cfStore : keyspace.getColumnFamilyStores()) + { + for (final Map.Entry<String, Pair<Long,Long>> snapshotDetail : cfStore.getSnapshotDetails().entrySet()) + { + TabularDataSupport data = (TabularDataSupport)snapshotMap.get(snapshotDetail.getKey()); + if (data == null) + { + data = new TabularDataSupport(SnapshotDetailsTabularData.TABULAR_TYPE); + snapshotMap.put(snapshotDetail.getKey(), data); + } + + SnapshotDetailsTabularData.from(snapshotDetail.getKey(), keyspace.getName(), cfStore.getColumnFamilyName(), snapshotDetail, data); + } + } + } + return snapshotMap; + } + + public long trueSnapshotsSize() + { + long total = 0; + for (final Keyspace keyspace : Keyspace.all()) + { + if (Keyspace.SYSTEM_KS.equals(keyspace.getName())) + continue; + + for (final ColumnFamilyStore cfStore : keyspace.getColumnFamilyStores()) + { + total += cfStore.trueSnapshotsSize(); + } + } + + return total; + } + /** * @param allowIndexes Allow index CF names to be passed in * @param autoAddIndexes Automatically add secondary indexes if a CF has them http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/src/java/org/apache/cassandra/service/StorageServiceMBean.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java b/src/java/org/apache/cassandra/service/StorageServiceMBean.java index e0bca26..390795e 100644 --- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java +++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java @@ -28,6 +28,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import javax.management.NotificationEmitter; +import javax.management.openmbean.TabularData; public interface StorageServiceMBean extends NotificationEmitter { @@ -216,6 +217,18 @@ public interface StorageServiceMBean extends NotificationEmitter public void clearSnapshot(String tag, String... keyspaceNames) throws IOException; /** + * Get the details of all the snapshot + * @return A map of snapshotName to all its details in Tabular form. + */ + public Map<String, TabularData> getSnapshotDetails(); + + /** + * Get the true size taken by all snapshots across all keyspaces. + * @return True size taken by all the snapshots. + */ + public long trueSnapshotsSize(); + + /** * Forces major compaction of a single keyspace */ public void forceKeyspaceCompaction(String keyspaceName, String... columnFamilies) throws IOException, ExecutionException, InterruptedException; http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/src/java/org/apache/cassandra/tools/NodeProbe.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java index 7727401..cbd43e9 100644 --- a/src/java/org/apache/cassandra/tools/NodeProbe.java +++ b/src/java/org/apache/cassandra/tools/NodeProbe.java @@ -452,6 +452,16 @@ public class NodeProbe implements AutoCloseable ssProxy.clearSnapshot(tag, keyspaces); } + public Map<String, TabularData> getSnapshotDetails() + { + return ssProxy.getSnapshotDetails(); + } + + public long trueSnapshotsSize() + { + return ssProxy.trueSnapshotsSize(); + } + public boolean isJoined() { return ssProxy.isJoined(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/719103b6/src/java/org/apache/cassandra/tools/NodeTool.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/tools/NodeTool.java b/src/java/org/apache/cassandra/tools/NodeTool.java index c9ddf4f..70580f2 100644 --- a/src/java/org/apache/cassandra/tools/NodeTool.java +++ b/src/java/org/apache/cassandra/tools/NodeTool.java @@ -42,6 +42,7 @@ import org.apache.cassandra.db.ColumnFamilyStoreMBean; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.compaction.CompactionManagerMBean; import org.apache.cassandra.db.compaction.OperationType; +import org.apache.cassandra.io.util.FileUtils; import org.apache.cassandra.locator.EndpointSnitchInfoMBean; import org.apache.cassandra.net.MessagingServiceMBean; import org.apache.cassandra.service.CacheServiceMBean; @@ -117,6 +118,7 @@ public class NodeTool SetStreamThroughput.class, SetTraceProbability.class, Snapshot.class, + ListSnapshots.class, Status.class, StatusBinary.class, StatusThrift.class, @@ -1645,6 +1647,48 @@ public class NodeTool } } + @Command(name = "listsnapshots", description = "Lists all the snapshots along with the size on disk and true size.") + public static class ListSnapshots extends NodeToolCmd + { + @Override + public void execute(NodeProbe probe) + { + try + { + System.out.println("Snapshot Details: "); + + final Map<String,TabularData> snapshotDetails = probe.getSnapshotDetails(); + if (snapshotDetails.isEmpty()) + { + System.out.printf("There are no snapshots"); + return; + } + + final long trueSnapshotsSize = probe.trueSnapshotsSize(); + final String format = "%-20s%-29s%-29s%-19s%-19s%n"; + // display column names only once + final List<String> indexNames = snapshotDetails.entrySet().iterator().next().getValue().getTabularType().getIndexNames(); + System.out.printf(format, (Object[]) indexNames.toArray(new String[indexNames.size()])); + + for (final Map.Entry<String, TabularData> snapshotDetail : snapshotDetails.entrySet()) + { + Set<?> values = snapshotDetail.getValue().keySet(); + for (Object eachValue : values) + { + final List<?> value = (List<?>) eachValue; + System.out.printf(format, value.toArray(new Object[value.size()])); + } + } + + System.out.println("\nTotal TrueDiskSpaceUsed: " + FileUtils.stringifyFileSize(trueSnapshotsSize) + "\n"); + } + catch (Exception e) + { + throw new RuntimeException("Error during list snapshot", e); + } + } + } + @Command(name = "status", description = "Print cluster information (state, load, IDs, ...)") public static class Status extends NodeToolCmd {