Put updated copyright statements in all source files.
[cumulus.git] / localdb.cc
index 17337f0..58fe87a 100644 (file)
@@ -1,7 +1,24 @@
-/* LBS: An LFS-inspired filesystem backup system
- * Copyright (C) 2007  Michael Vrable
+/* Cumulus: Smart Filesystem Backup to Dumb Servers
  *
- * When creating backup snapshots, maintain a local database of data blocks and
+ * Copyright (C) 2007-2008  The Regents of the University of California
+ * Written by Michael Vrable <mvrable@cs.ucsd.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* When creating backup snapshots, maintain a local database of data blocks and
  * checksums, in addition to the data contents (which may be stored remotely).
  * This database is consulted when attempting to build incremental snapshots,
  * as it says which objects can be reused.
@@ -125,14 +142,21 @@ void LocalDb::Close()
     int rc;
 
     /* Summarize the snapshot_refs table into segments_used. */
-    sqlite3_stmt *stmt = Prepare("insert into segments_used "
-                                 "select ? as snapshotid, segmentid, "
-                                 "cast(used as real) / size as utilization "
-                                 "from "
-                                 "(select segmentid, sum(size) as used "
-                                 "from snapshot_refs group by segmentid) "
-                                 "join segments using (segmentid)");
+    sqlite3_stmt *stmt = Prepare(
+        "insert or replace into segments_used "
+        "select ? as snapshotid, segmentid, max(utilization) from ("
+        "    select segmentid, cast(used as real) / size as utilization "
+        "    from "
+        "    (select segmentid, sum(size) as used from snapshot_refs "
+        "       group by segmentid) "
+        "    join segments using (segmentid) "
+        "  union "
+        "    select segmentid, utilization from segments_used "
+        "    where snapshotid = ? "
+        ") group by segmentid"
+    );
     sqlite3_bind_int64(stmt, 1, snapshotid);
+    sqlite3_bind_int64(stmt, 2, snapshotid);
     rc = sqlite3_step(stmt);
     if (rc != SQLITE_OK && rc != SQLITE_DONE) {
         ReportError(rc);
@@ -239,6 +263,17 @@ void LocalDb::StoreObject(const ObjectReference& ref,
     }
 
     sqlite3_finalize(stmt);
+
+    if (age != 0.0) {
+        stmt = Prepare("update segments "
+                       "set mtime = coalesce(max(mtime, ?), ?) "
+                       "where segmentid = ?");
+        sqlite3_bind_double(stmt, 1, age);
+        sqlite3_bind_double(stmt, 2, age);
+        sqlite3_bind_int64(stmt, 3, SegmentToId(ref.get_segment()));
+        rc = sqlite3_step(stmt);
+        sqlite3_finalize(stmt);
+    }
 }
 
 ObjectReference LocalDb::FindObject(const string &checksum, int64_t size)
@@ -357,22 +392,43 @@ void LocalDb::UseObject(const ObjectReference& ref)
     sqlite3_finalize(stmt);
 }
 
+void LocalDb::UseSegment(const std::string &segment, double utilization)
+{
+    int rc;
+    sqlite3_stmt *stmt;
+
+    stmt = Prepare("insert or replace "
+                   "into segments_used(snapshotid, segmentid, utilization) "
+                   "values (?, ?, ?)");
+    sqlite3_bind_int64(stmt, 1, snapshotid);
+    sqlite3_bind_int64(stmt, 2, SegmentToId(segment));
+    sqlite3_bind_double(stmt, 3, utilization);
+
+    rc = sqlite3_step(stmt);
+    if (rc != SQLITE_DONE) {
+        fprintf(stderr, "Could not insert segment use record!\n");
+        ReportError(rc);
+    }
+
+    sqlite3_finalize(stmt);
+}
+
 void LocalDb::SetSegmentChecksum(const std::string &segment,
                                  const std::string &path,
-                                 const std::string &checksum)
+                                 const std::string &checksum,
+                                 int size)
 {
     int rc;
     sqlite3_stmt *stmt;
 
-    stmt = Prepare("update segments set path = ?, checksum = ?, "
-                   "size = (select sum(size) from block_index "
-                   "        where segmentid = ?) "
+    stmt = Prepare("update segments set path = ?, checksum = ?, size = ?, "
+                   "mtime = coalesce(mtime, julianday('now')) "
                    "where segmentid = ?");
     sqlite3_bind_text(stmt, 1, path.c_str(), path.size(),
                       SQLITE_TRANSIENT);
     sqlite3_bind_text(stmt, 2, checksum.c_str(), checksum.size(),
                       SQLITE_TRANSIENT);
-    sqlite3_bind_int64(stmt, 3, SegmentToId(segment));
+    sqlite3_bind_int64(stmt, 3, size);
     sqlite3_bind_int64(stmt, 4, SegmentToId(segment));
 
     rc = sqlite3_step(stmt);