1 /* LBS: An LFS-inspired filesystem backup system
2 * Copyright (C) 2007 Michael Vrable
4 * When creating backup snapshots, maintain a local database of data blocks and
5 * checksums, in addition to the data contents (which may be stored remotely).
6 * This database is consulted when attempting to build incremental snapshots,
7 * as it says which objects can be reused.
9 * The database is implemented as an SQLite3 database, but this implementation
10 * detail is kept internal to this file, so that the storage format may be
25 void LocalDb::Open(const char *path)
29 rc = sqlite3_open(path, &db);
31 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
33 throw IOException("Error opening local database");
36 rc = sqlite3_exec(db, "begin", NULL, NULL, NULL);
38 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
40 throw IOException("Error starting transaction");
47 rc = sqlite3_exec(db, "commit", NULL, NULL, NULL);
48 if (rc != SQLITE_OK) {
49 fprintf(stderr, "Can't commit database!\n");
54 void LocalDb::StoreObject(const ObjectReference& ref,
55 const string &checksum, int64_t size)
59 static const char s[] =
60 "insert into block_index(segment, object, checksum, size) "
61 "values (?, ?, ?, ?)";
64 rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
65 if (rc != SQLITE_OK) {
69 string seg = ref.get_segment();
70 sqlite3_bind_text(stmt, 1, seg.c_str(), seg.size(), SQLITE_TRANSIENT);
71 string obj = ref.get_sequence();
72 sqlite3_bind_text(stmt, 2, obj.c_str(), obj.size(), SQLITE_TRANSIENT);
73 sqlite3_bind_text(stmt, 3, checksum.c_str(), checksum.size(),
75 sqlite3_bind_int64(stmt, 4, size);
77 rc = sqlite3_step(stmt);
78 if (rc != SQLITE_DONE) {
79 fprintf(stderr, "Could not execute INSERT statement!\n");
82 sqlite3_finalize(stmt);
85 ObjectReference LocalDb::FindObject(const string &checksum, int64_t size)
89 static const char s[] =
90 "select segment, object from block_index "
91 "where checksum = ? and size = ?";
96 rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
97 if (rc != SQLITE_OK) {
101 sqlite3_bind_text(stmt, 1, checksum.c_str(), checksum.size(),
103 sqlite3_bind_int64(stmt, 2, size);
105 rc = sqlite3_step(stmt);
106 if (rc == SQLITE_DONE) {
107 } else if (rc == SQLITE_ROW) {
108 printf("Can re-use block: %s/%s\n",
109 sqlite3_column_text(stmt, 0), sqlite3_column_text(stmt, 1));
110 ref = ObjectReference((const char *)sqlite3_column_text(stmt, 0),
111 (const char *)sqlite3_column_text(stmt, 1));
113 fprintf(stderr, "Could not execute SELECT statement!\n");
116 sqlite3_finalize(stmt);