Manual 2to3 fixups.
[cumulus.git] / python / cumulus / main.py
index 50b3170..8d4156c 100644 (file)
@@ -1,7 +1,6 @@
-# Cumulus: Smart Filesystem Backup to Dumb Servers
-#
-# Copyright (C) 2012  Google Inc.
-# Written by Michael Vrable <mvrable@cs.ucsd.edu>
+# Cumulus: Efficient Filesystem Backup to the Cloud
+# Copyright (C) 2012 The Cumulus Developers
+# See the AUTHORS file for a list of contributors.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -23,6 +22,9 @@ This implements maintenance functions and is a wrapper around the C++
 cumulus-backup program.
 """
 
+from __future__ import division, print_function, unicode_literals
+
+import datetime
 import re
 import sys
 
@@ -47,24 +49,68 @@ def prune_backups(backup_config, scheme):
             expired_snapshots.append(snapshot)
     # The most recent snapshot is never removed.
     if expired_snapshots: expired_snapshots.pop()
-    print expired_snapshots
+    print(expired_snapshots)
 
     # TODO: Clean up the expiration part...
     for snapshot in expired_snapshots:
         store.store.delete("snapshot", "snapshot-%s.lbs" % snapshot)
 
-    print "Collecting garbage..."
+    print("Collecting garbage...")
     options = FakeOptions()
     options.store = backup_config.get_global("dest")
     options.dry_run = False
     cmd_util.options = options
     cmd_util.cmd_garbage_collect([])
 
+def prune_localdb(backup_config, scheme, next_snapshot=None):
+    """Clean old snapshots out of the local database.
+
+    Clear old snapshots out of the local database, possibly in preparation for
+    running a new backup.  One snapshot of each configured retention period is
+    kept (i.e., one weekly and one daily), and the most recent snapshot is
+    always retained.  If next_snapshot is not None, it should be the timestamp
+    when (approximately) the next snapshot will be taken; if that snapshot
+    would be a daily, weekly, etc. snapshot, then it may result in the previous
+    snapshot of the same duration being evicted from the local database.
+
+    Note that in this sense, "evict" merely refers to tracking the snapshots in
+    the local database; this function does not delete backups from the backup
+    storage.
+    """
+    # Fetch the list of existing snapshots in the local database.  Pruning only
+    # makes sense if there are more than one snapshots present.
+    db = cumulus.LocalDatabase(backup_config.get_global("localdb"))
+    snapshots = sorted(db.list_snapshots(scheme))
+    if len(snapshots) <= 1:
+        return
+
+    # Classify the snapshots (daily, weekly, etc.) and keep the most recent one
+    # of each category.  Also ensure that the most recent snapshot is retained.
+    retention = backup_config.get_retention_for_scheme(scheme)
+    for snapshot in snapshots:
+        retention.consider_snapshot(snapshot)
+    if next_snapshot is not None:
+        retention.consider_snapshot(next_snapshot)
+    retained = set(retention.last_snapshots().values())
+    retained.add(snapshots[-1])
+    print(retention.last_snapshots())
+    print(retained)
+    for s in snapshots:
+        print(s, s in retained)
+
+    evicted = [s for s in snapshots if s not in retained]
+    for s in evicted:
+        db.delete_snapshot(scheme, s)
+    db.garbage_collect()
+    db.commit()
+
 def main(argv):
     backup_config = config.CumulusConfig(argv[1])
     for scheme in backup_config.backup_schemes():
-        print scheme
-        prune_backups(backup_config, scheme)
+        print(scheme)
+        #prune_backups(backup_config, scheme)
+        prune_localdb(backup_config, scheme, datetime.datetime.utcnow())
+        #prune_localdb(backup_config, scheme, datetime.datetime(2013, 1, 1))
 
 if __name__ == "__main__":
     main(sys.argv)