--- /dev/null
+/* LBS: An LFS-inspired filesystem backup system
+ * Copyright (C) 2007 Michael Vrable
+ *
+ * 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.
+ *
+ * The database is implemented as an SQLite3 database, but this implementation
+ * detail is kept internal to this file, so that the storage format may be
+ * changed later. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sqlite3.h>
+
+#include <string>
+
+#include "localdb.h"
+#include "store.h"
+
+using std::string;
+
+void LocalDb::Open(const char *path)
+{
+ int rc;
+
+ rc = sqlite3_open(path, &db);
+ if (rc) {
+ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ throw IOException("Error opening local database");
+ }
+
+ rc = sqlite3_exec(db, "begin", NULL, NULL, NULL);
+ if (rc) {
+ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ throw IOException("Error starting transaction");
+ }
+}
+
+void LocalDb::Close()
+{
+ int rc;
+ rc = sqlite3_exec(db, "commit", NULL, NULL, NULL);
+ if (rc != SQLITE_OK) {
+ fprintf(stderr, "Can't commit database!\n");
+ }
+ sqlite3_close(db);
+}
+
+void LocalDb::StoreObject(const ObjectReference& ref,
+ const string &checksum, int64_t size)
+{
+ int rc;
+ sqlite3_stmt *stmt;
+ static const char s[] =
+ "insert into block_index(segment, object, checksum, size) "
+ "values (?, ?, ?, ?)";
+ const char *tail;
+
+ rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
+ if (rc != SQLITE_OK) {
+ return;
+ }
+
+ string seg = ref.get_segment();
+ sqlite3_bind_text(stmt, 1, seg.c_str(), seg.size(), SQLITE_TRANSIENT);
+ string obj = ref.get_sequence();
+ sqlite3_bind_text(stmt, 2, obj.c_str(), obj.size(), SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 3, checksum.c_str(), checksum.size(),
+ SQLITE_TRANSIENT);
+ sqlite3_bind_int64(stmt, 4, size);
+
+ rc = sqlite3_step(stmt);
+ if (rc != SQLITE_DONE) {
+ fprintf(stderr, "Could not execute INSERT statement!\n");
+ }
+
+ sqlite3_finalize(stmt);
+}
--- /dev/null
+/* LBS: An LFS-inspired filesystem backup system
+ * Copyright (C) 2007 Michael Vrable
+ *
+ * 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.
+ *
+ * The database is implemented as an SQLite3 database, but this implementation
+ * detail is kept internal to this file, so that the storage format may be
+ * changed later. */
+
+#ifndef _LBS_LOCALDB_H
+#define _LBS_LOCALDB_H
+
+#include <sqlite3.h>
+
+#include <string>
+
+#include "ref.h"
+
+class LocalDb {
+public:
+ void Open(const char *path);
+ void Close();
+ void StoreObject(const ObjectReference& ref,
+ const std::string &checksum, int64_t size);
+private:
+ sqlite3 *db;
+};
+
+#endif // _LBS_LOCALDB_H
#include <set>
#include "format.h"
+#include "localdb.h"
#include "store.h"
#include "sha1.h"
static const size_t LBS_METADATA_BLOCK_SIZE = 65536;
+/* Local database, which tracks objects written in this and previous
+ * invocations to help in creating incremental snapshots. */
+LocalDb *db;
+
/* Contents of the root object. This will contain a set of indirect links to
* the metadata objects. */
std::ostringstream metadata_root;
o->write(tss);
object_list.push_back(o->get_name());
segment_list.insert(o->get_ref().get_segment());
- delete o;
+
+ // Index this block so it can be used by future snapshots
+ SHA1Checksum block_hash;
+ block_hash.process(block_buf, bytes);
+ db->StoreObject(o->get_ref(), block_hash.checksum_str(), bytes);
size += bytes;
+
+ delete o;
}
file_info["checksum"] = hash.checksum_str();
tss = new TarSegmentStore(backup_dest);
+ string database_path = backup_dest + "/localdb.sqlite";
+ db = new LocalDb;
+ db->Open(database_path.c_str());
+
/* Write a backup descriptor file, which says which segments are needed and
* where to start to restore this snapshot. The filename is based on the
* current time. */
descriptor << " " << *i << "\n";
}
+ db->Close();
+
tss->sync();
delete tss;