-/* 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.
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);
}
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)
} else if (rc == SQLITE_ROW) {
ref = ObjectReference(IdToSegment(sqlite3_column_int64(stmt, 0)),
(const char *)sqlite3_column_text(stmt, 1));
+ ref.set_range(0, size);
} else {
fprintf(stderr, "Could not execute SELECT statement!\n");
ReportError(rc);
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);