X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=cumulus-util;h=1bac12b6604004e42d8176b575f6b313f7a3d4ec;hb=f6d3d525bf2c0afa0190e767f6de575cdbd5bcfd;hp=f5d5fa36de960a2ba0dfffe152242e21a6fa5a20;hpb=8bff41ddef78fa851b09d141c93bdf387abc1dee;p=cumulus.git diff --git a/cumulus-util b/cumulus-util index f5d5fa3..1bac12b 100755 --- a/cumulus-util +++ b/cumulus-util @@ -4,6 +4,12 @@ import getpass, os, stat, sys, time from optparse import OptionParser + +# Automatically set Python path, based on script directory. This should be +# removed if the tools are properly installed somewhere. +script_directory = os.path.dirname(sys.argv[0]) +sys.path.append(os.path.join(script_directory, 'python')) + import cumulus # Compatibility @@ -21,6 +27,8 @@ def check_version(format): parser = OptionParser(usage="%prog [option]... command [arg]...") parser.add_option("-v", action="store_true", dest="verbose", default=False, help="increase verbosity") +parser.add_option("-n", action="store_true", dest="dry_run", default=False, + help="dry run") parser.add_option("--store", dest="store", help="specify path to backup data store") parser.add_option("--localdb", dest="localdb", @@ -78,22 +86,58 @@ def cmd_list_snapshots(): # Syntax: $0 --data=DATADIR list-snapshot-sizes def cmd_list_snapshot_sizes(): lowlevel = lbs.LowlevelDataStore(options.store) + lowlevel.scan() store = lbs.ObjectStore(lowlevel) previous = set() for s in sorted(lowlevel.list_snapshots()): d = lbs.parse_full(store.load_snapshot(s)) check_version(d['Format']) + + try: + intent = float(d['Backup-Intent']) + except: + intent = 1.0 + segments = d['Segments'].split() - (size, added, removed) = (0, 0, 0) + (size, added, removed, addcount, remcount) = (0, 0, 0, 0, 0) for seg in segments: segsize = lowlevel.lowlevel_stat(seg + ".tar.gpg")['size'] size += segsize - if seg not in previous: added += segsize + if seg not in previous: + added += segsize + addcount += 1 for seg in previous: if seg not in segments: removed += lowlevel.lowlevel_stat(seg + ".tar.gpg")['size'] + remcount += 1 previous = set(segments) - print "%s: %.3f +%.3f -%.3f" % (s, size / 1024.0**2, added / 1024.0**2, removed / 1024.0**2) + print "%s [%s]: %.3f +%.3f -%.3f (+%d/-%d segments)" % (s, intent, size / 1024.0**2, added / 1024.0**2, removed / 1024.0**2, addcount, remcount) + +# Search for any files which are not needed by any current snapshots and offer +# to delete them. +# Syntax: $0 --store=DATADIR gc +def cmd_garbage_collect(): + lowlevel = lbs.LowlevelDataStore(options.store) + lowlevel.scan() + store = lbs.ObjectStore(lowlevel) + snapshots = set(lowlevel.list_snapshots()) + segments = set() + for s in snapshots: + d = lbs.parse_full(store.load_snapshot(s)) + check_version(d['Format']) + segments.update(d['Segments'].split()) + + referenced = snapshots.union(segments) + reclaimed = 0 + for (t, r) in cumulus.store.type_patterns.items(): + for f in lowlevel.store.list(t): + m = r.match(f) + if m is None or m.group(1) not in referenced: + print "Garbage:", (t, f) + reclaimed += lowlevel.store.stat(t, f)['size'] + if not options.dry_run: + lowlevel.store.delete(t, f) + print "Reclaimed space:", reclaimed # Build checksum list for objects in the given segments, or all segments if # none are specified. @@ -348,6 +392,8 @@ elif cmd == 'read-metadata': cmd_read_metadata(args[0]) elif cmd == 'list-snapshot-sizes': cmd_list_snapshot_sizes() +elif cmd == 'gc': + cmd_garbage_collect() elif cmd == 'verify-snapshots': cmd_verify_snapshots(args) elif cmd == 'restore-snapshot':