using std::string;
-void LocalDb::Open(const char *path, const char *snapshot_name)
+/* Helper function to prepare a statement for execution in the current
+ * database. */
+sqlite3_stmt *LocalDb::Prepare(const char *sql)
+{
+ sqlite3_stmt *stmt;
+ int rc;
+ const char *tail;
+
+ rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, &tail);
+ if (rc != SQLITE_OK) {
+ throw IOException(string("Error preparing statement: ") + sql);
+ }
+
+ return stmt;
+}
+
+void LocalDb::ReportError(int rc)
+{
+ fprintf(stderr, "Result code: %d\n", rc);
+ fprintf(stderr, "Error message: %s\n", sqlite3_errmsg(db));
+}
+
+void LocalDb::Open(const char *path, const char *snapshot_name,
+ const char *snapshot_scheme)
{
int rc;
throw IOException("Error starting transaction");
}
+ sqlite3_extended_result_codes(db, 1);
+
/* Insert this snapshot into the database, and determine the integer key
* which will be used to identify it. */
- sqlite3_stmt *stmt;
- static const char s[] =
- "insert into snapshots(name, timestamp) "
- "values (?, julianday('now'))";
- const char *tail;
-
- rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
- if (rc != SQLITE_OK) {
- sqlite3_close(db);
- throw IOException("Error adding snapshot");
- }
-
+ sqlite3_stmt *stmt = Prepare("insert into "
+ "snapshots(name, scheme, timestamp) "
+ "values (?, ?, julianday('now'))");
sqlite3_bind_text(stmt, 1, snapshot_name, strlen(snapshot_name),
SQLITE_TRANSIENT);
+ if (snapshot_scheme == NULL)
+ sqlite3_bind_null(stmt, 2);
+ else
+ sqlite3_bind_text(stmt, 2, snapshot_scheme, strlen(snapshot_scheme),
+ SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
+ ReportError(rc);
sqlite3_close(db);
throw IOException("Database execution error!");
}
snapshotid = sqlite3_last_insert_rowid(db);
sqlite3_finalize(stmt);
if (snapshotid == 0) {
+ ReportError(rc);
sqlite3_close(db);
throw IOException("Find snapshot id");
}
int rc;
rc = sqlite3_exec(db, "commit", NULL, NULL, NULL);
if (rc != SQLITE_OK) {
- fprintf(stderr, "Can't commit database!\n");
+ fprintf(stderr, "DATABASE ERROR: Can't commit database!\n");
+ ReportError(rc);
}
sqlite3_close(db);
}
{
int rc;
sqlite3_stmt *stmt;
- static const char s1[] =
- "insert or ignore into segments(segment) values (?);";
- static const char s2[] =
- "select segmentid from segments where segment = ?";
- const char *tail;
int64_t result;
- rc = sqlite3_prepare_v2(db, s1, strlen(s1), &stmt, &tail);
- if (rc != SQLITE_OK) {
- throw IOException("Find id by segment name");
- }
+ stmt = Prepare("insert or ignore into segments(segment) values (?)");
sqlite3_bind_text(stmt, 1, segment.c_str(), segment.size(),
SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
}
sqlite3_finalize(stmt);
- rc = sqlite3_prepare_v2(db, s2, strlen(s2), &stmt, &tail);
- if (rc != SQLITE_OK) {
- throw IOException("Find id by segment name");
- }
-
+ stmt = Prepare("select segmentid from segments where segment = ?");
sqlite3_bind_text(stmt, 1, segment.c_str(), segment.size(),
SQLITE_TRANSIENT);
{
int rc;
sqlite3_stmt *stmt;
- static const char s[] =
- "select segment from segments where segmentid = ?";
- const char *tail;
string result;
- rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
- if (rc != SQLITE_OK) {
- throw IOException("Find segment by id");
- }
-
+ stmt = Prepare("select segment from segments where segmentid = ?");
sqlite3_bind_int64(stmt, 1, segmentid);
rc = sqlite3_step(stmt);
}
void LocalDb::StoreObject(const ObjectReference& ref,
- const string &checksum, int64_t size)
+ const string &checksum, int64_t size,
+ double age)
{
int rc;
sqlite3_stmt *stmt;
- static const char s[] =
- "insert into "
- "block_index(segmentid, object, checksum, size, timestamp) "
- "values (?, ?, ?, ?, julianday('now'))";
- const char *tail;
- rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
- if (rc != SQLITE_OK) {
- return;
+ if (age == 0.0) {
+ stmt = Prepare("insert into block_index("
+ "segmentid, object, checksum, size, timestamp) "
+ "values (?, ?, ?, ?, julianday('now'))");
+ } else {
+ stmt = Prepare("insert into block_index("
+ "segmentid, object, checksum, size, timestamp) "
+ "values (?, ?, ?, ?, ?)");
}
sqlite3_bind_int64(stmt, 1, SegmentToId(ref.get_segment()));
sqlite3_bind_text(stmt, 3, checksum.c_str(), checksum.size(),
SQLITE_TRANSIENT);
sqlite3_bind_int64(stmt, 4, size);
+ if (age != 0.0)
+ sqlite3_bind_double(stmt, 5, age);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
fprintf(stderr, "Could not execute INSERT statement!\n");
+ ReportError(rc);
}
sqlite3_finalize(stmt);
{
int rc;
sqlite3_stmt *stmt;
- static const char s[] =
- "select segmentid, object from block_index "
- "where checksum = ? and size = ? and expired is null";
- const char *tail;
-
ObjectReference ref;
- rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
- if (rc != SQLITE_OK) {
- return ref;
- }
-
+ stmt = Prepare("select segmentid, object from block_index "
+ "where checksum = ? and size = ? and expired is null");
sqlite3_bind_text(stmt, 1, checksum.c_str(), checksum.size(),
SQLITE_TRANSIENT);
sqlite3_bind_int64(stmt, 2, size);
(const char *)sqlite3_column_text(stmt, 1));
} else {
fprintf(stderr, "Could not execute SELECT statement!\n");
+ ReportError(rc);
}
sqlite3_finalize(stmt);
return ref;
}
-bool LocalDb::IsOldObject(const string &checksum, int64_t size)
+bool LocalDb::IsOldObject(const string &checksum, int64_t size, double *age,
+ int *group)
{
int rc;
sqlite3_stmt *stmt;
- static const char s[] =
- "select segmentid, object from block_index "
- "where checksum = ? and size = ?";
- const char *tail;
-
bool found = false;
- rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
- if (rc != SQLITE_OK) {
- return false;
- }
-
+ stmt = Prepare("select segmentid, object, timestamp, expired "
+ "from block_index where checksum = ? and size = ?");
sqlite3_bind_text(stmt, 1, checksum.c_str(), checksum.size(),
SQLITE_TRANSIENT);
sqlite3_bind_int64(stmt, 2, size);
found = false;
} else if (rc == SQLITE_ROW) {
found = true;
+ *age = sqlite3_column_double(stmt, 2);
+ *group = sqlite3_column_int(stmt, 3);
} else {
fprintf(stderr, "Could not execute SELECT statement!\n");
+ ReportError(rc);
}
sqlite3_finalize(stmt);
return found;
}
-void LocalDb::UseObject(const ObjectReference& ref)
+/* Does this object still exist in the database (and not expired)? */
+bool LocalDb::IsAvailable(const ObjectReference &ref)
{
int rc;
sqlite3_stmt *stmt;
- static const char s[] =
- "insert or ignore into snapshot_contents "
- "select blockid, ? as snapshotid from block_index "
- "where segmentid = ? and object = ?";
- const char *tail;
+ bool found = false;
- rc = sqlite3_prepare_v2(db, s, strlen(s), &stmt, &tail);
- if (rc != SQLITE_OK) {
- return;
+ stmt = Prepare("select count(*) from block_index "
+ "where segmentid = ? and object = ? and expired is null");
+ sqlite3_bind_int64(stmt, 1, SegmentToId(ref.get_segment()));
+ sqlite3_bind_text(stmt, 2, ref.get_sequence().c_str(),
+ ref.get_sequence().size(), SQLITE_TRANSIENT);
+
+ rc = sqlite3_step(stmt);
+ if (rc == SQLITE_DONE) {
+ found = false;
+ } else if (rc == SQLITE_ROW) {
+ if (sqlite3_column_int(stmt, 0) > 0)
+ found = true;
+ } else {
+ fprintf(stderr, "Could not execute SELECT statement!\n");
+ ReportError(rc);
}
+ sqlite3_finalize(stmt);
+
+ return found;
+}
+
+void LocalDb::UseObject(const ObjectReference& ref)
+{
+ int rc;
+ sqlite3_stmt *stmt;
+
+ stmt = Prepare("insert or ignore into snapshot_contents "
+ "select blockid, ? as snapshotid from block_index "
+ "where segmentid = ? and object = ?");
sqlite3_bind_int64(stmt, 1, snapshotid);
sqlite3_bind_int64(stmt, 2, SegmentToId(ref.get_segment()));
string obj = ref.get_sequence();
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
fprintf(stderr, "Could not execute INSERT statement!\n");
+ ReportError(rc);
+ }
+
+ sqlite3_finalize(stmt);
+}
+
+void LocalDb::SetSegmentChecksum(const std::string &segment,
+ const std::string &path,
+ const std::string &checksum)
+{
+ int rc;
+ sqlite3_stmt *stmt;
+
+ stmt = Prepare("update segments set path = ?, checksum = ? "
+ "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));
+
+ rc = sqlite3_step(stmt);
+ if (rc != SQLITE_DONE) {
+ fprintf(stderr, "Could not update segment checksum in database!\n");
+ ReportError(rc);
}
sqlite3_finalize(stmt);
}
+
+bool LocalDb::GetSegmentChecksum(const string &segment,
+ string *seg_path,
+ string *seg_checksum)
+{
+ int rc;
+ sqlite3_stmt *stmt;
+ ObjectReference ref;
+ int found = false;
+
+ stmt = Prepare("select path, checksum from segments where segment = ?");
+ sqlite3_bind_text(stmt, 1, segment.c_str(), segment.size(),
+ SQLITE_TRANSIENT);
+
+ rc = sqlite3_step(stmt);
+ if (rc == SQLITE_DONE) {
+ } else if (rc == SQLITE_ROW) {
+ found = true;
+ const char *val;
+
+ val = (const char *)sqlite3_column_text(stmt, 0);
+ if (val == NULL)
+ found = false;
+ else
+ *seg_path = val;
+
+ val = (const char *)sqlite3_column_text(stmt, 1);
+ if (val == NULL)
+ found = false;
+ else
+ *seg_checksum = val;
+ } else {
+ fprintf(stderr, "Could not execute SELECT statement!\n");
+ ReportError(rc);
+ }
+
+ sqlite3_finalize(stmt);
+
+ return found;
+}