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, const char *snapshot_name)
29 snapshot = snapshot_name;
31 rc = sqlite3_open(path, &db);
33 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
35 throw IOException("Error opening local database");
38 rc = sqlite3_exec(db, "begin", NULL, NULL, NULL);
40 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
42 throw IOException("Error starting transaction");
49 rc = sqlite3_exec(db, "commit", NULL, NULL, NULL);
50 if (rc != SQLITE_OK) {
51 fprintf(stderr, "Can't commit database!\n");
56 void LocalDb::StoreObject(const ObjectReference& ref,
57 const string &checksum, int64_t size)
61 static const char s[] =
62 "insert into block_index(segment, object, checksum, size, timestamp) "
63 "values (?, ?, ?, ?, julianday('now'))";
66 rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
67 if (rc != SQLITE_OK) {
71 string seg = ref.get_segment();
72 sqlite3_bind_text(stmt, 1, seg.c_str(), seg.size(), SQLITE_TRANSIENT);
73 string obj = ref.get_sequence();
74 sqlite3_bind_text(stmt, 2, obj.c_str(), obj.size(), SQLITE_TRANSIENT);
75 sqlite3_bind_text(stmt, 3, checksum.c_str(), checksum.size(),
77 sqlite3_bind_int64(stmt, 4, size);
79 rc = sqlite3_step(stmt);
80 if (rc != SQLITE_DONE) {
81 fprintf(stderr, "Could not execute INSERT statement!\n");
84 sqlite3_finalize(stmt);
87 ObjectReference LocalDb::FindObject(const string &checksum, int64_t size)
91 static const char s[] =
92 "select segment, object from block_index "
93 "where checksum = ? and size = ?";
98 rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
99 if (rc != SQLITE_OK) {
103 sqlite3_bind_text(stmt, 1, checksum.c_str(), checksum.size(),
105 sqlite3_bind_int64(stmt, 2, size);
107 rc = sqlite3_step(stmt);
108 if (rc == SQLITE_DONE) {
109 } else if (rc == SQLITE_ROW) {
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);
121 void LocalDb::UseObject(const ObjectReference& ref)
125 static const char s[] =
126 "insert into snapshot_contents "
127 "select blockid, ? as snapshot from block_index "
128 "where segment = ? and object = ?";
131 rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
132 if (rc != SQLITE_OK) {
136 sqlite3_bind_text(stmt, 1, snapshot.c_str(), snapshot.size(),
138 string seg = ref.get_segment();
139 sqlite3_bind_text(stmt, 2, seg.c_str(), seg.size(), SQLITE_TRANSIENT);
140 string obj = ref.get_sequence();
141 sqlite3_bind_text(stmt, 3, obj.c_str(), obj.size(), SQLITE_TRANSIENT);
143 rc = sqlite3_step(stmt);
144 if (rc != SQLITE_DONE) {
145 fprintf(stderr, "Could not execute INSERT statement!\n");
148 sqlite3_finalize(stmt);