X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=localdb.cc;h=3fcbafed2afad7c9d6fe62b28496afe2fd669319;hb=dd3fe2c70bef48563e0f67b7cb259f00bb42f45c;hp=c74e27dc5459f6fbfd98f8e9fae72f89a6667629;hpb=26f68e9df784020f16bbc295342123b0eca7de9b;p=cumulus.git diff --git a/localdb.cc b/localdb.cc index c74e27d..3fcbafe 100644 --- a/localdb.cc +++ b/localdb.cc @@ -1,7 +1,6 @@ -/* Cumulus: Smart Filesystem Backup to Dumb Servers - * - * Copyright (C) 2007-2008 The Regents of the University of California - * Written by Michael Vrable +/* Cumulus: Efficient Filesystem Backup to the Cloud + * Copyright (C) 2007-2008 The Cumulus Developers + * See the AUTHORS file for a list of contributors. * * 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 @@ -32,11 +31,14 @@ #include #include +#include #include #include "localdb.h" #include "store.h" +#include "util.h" +using std::min; using std::string; /* Helper function to prepare a statement for execution in the current @@ -50,7 +52,7 @@ sqlite3_stmt *LocalDb::Prepare(const char *sql) rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, &tail); if (rc != SQLITE_OK) { ReportError(rc); - throw IOException(string("Error preparing statement: ") + sql); + fatal(string("Error preparing statement: ") + sql); } return stmt; @@ -71,18 +73,21 @@ void LocalDb::Open(const char *path, const char *snapshot_name, if (rc) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); - throw IOException("Error opening local database"); + fatal("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"); + fatal("Error starting transaction"); } sqlite3_extended_result_codes(db, 1); + if (snapshot_scheme == NULL) + snapshot_scheme = ""; + /* Insert this snapshot into the database, and determine the integer key * which will be used to identify it. */ sqlite3_stmt *stmt = Prepare("insert into " @@ -90,18 +95,15 @@ void LocalDb::Open(const char *path, const char *snapshot_name, "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); + sqlite3_bind_text(stmt, 2, snapshot_scheme, strlen(snapshot_scheme), + SQLITE_TRANSIENT); sqlite3_bind_double(stmt, 3, intent); rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { ReportError(rc); sqlite3_close(db); - throw IOException("Database execution error!"); + fatal("Database execution error!"); } snapshotid = sqlite3_last_insert_rowid(db); @@ -109,7 +111,7 @@ void LocalDb::Open(const char *path, const char *snapshot_name, if (snapshotid == 0) { ReportError(rc); sqlite3_close(db); - throw IOException("Find snapshot id"); + fatal("Find snapshot id"); } /* Create a temporary table which will be used to keep track of the objects @@ -124,7 +126,7 @@ void LocalDb::Open(const char *path, const char *snapshot_name, if (rc != SQLITE_OK) { ReportError(rc); sqlite3_close(db); - throw IOException("Database initialization"); + fatal("Database initialization"); } rc = sqlite3_exec(db, "create unique index snapshot_refs_index " @@ -133,7 +135,7 @@ void LocalDb::Open(const char *path, const char *snapshot_name, if (rc != SQLITE_OK) { ReportError(rc); sqlite3_close(db); - throw IOException("Database initialization"); + fatal("Database initialization"); } } @@ -185,7 +187,7 @@ int64_t LocalDb::SegmentToId(const string &segment) SQLITE_TRANSIENT); rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { - throw IOException("Could not execute INSERT statement!"); + fatal("Could not execute INSERT statement!"); } sqlite3_finalize(stmt); @@ -195,11 +197,11 @@ int64_t LocalDb::SegmentToId(const string &segment) rc = sqlite3_step(stmt); if (rc == SQLITE_DONE) { - throw IOException("No segment found by id"); + fatal("No segment found by id"); } else if (rc == SQLITE_ROW) { result = sqlite3_column_int64(stmt, 0); } else { - throw IOException("Error executing find segment by id query"); + fatal("Error executing find segment by id query"); } sqlite3_finalize(stmt); @@ -218,11 +220,11 @@ string LocalDb::IdToSegment(int64_t segmentid) rc = sqlite3_step(stmt); if (rc == SQLITE_DONE) { - throw IOException("No segment found by id"); + fatal("No segment found by id"); } else if (rc == SQLITE_ROW) { result = (const char *)sqlite3_column_text(stmt, 0); } else { - throw IOException("Error executing find segment by id query"); + fatal("Error executing find segment by id query"); } sqlite3_finalize(stmt); @@ -293,7 +295,7 @@ 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); + ref.set_range(0, size, true); } else { fprintf(stderr, "Could not execute SELECT statement!\n"); ReportError(rc); @@ -376,20 +378,61 @@ void LocalDb::UseObject(const ObjectReference& ref) if (!ref.is_normal()) return; - stmt = Prepare("insert or ignore into snapshot_refs " - "select segmentid, object, size from block_index " + int64_t old_size = 0; + stmt = Prepare("select size from snapshot_refs " "where segmentid = ? and object = ?"); sqlite3_bind_int64(stmt, 1, SegmentToId(ref.get_segment())); string obj = ref.get_sequence(); sqlite3_bind_text(stmt, 2, obj.c_str(), obj.size(), SQLITE_TRANSIENT); - rc = sqlite3_step(stmt); - if (rc != SQLITE_DONE) { - fprintf(stderr, "Could not execute INSERT statement!\n"); - ReportError(rc); + if (rc == SQLITE_ROW) { + old_size = sqlite3_column_int64(stmt, 0); } + sqlite3_finalize(stmt); + int64_t block_size = 0; + stmt = Prepare("select size from block_index " + "where segmentid = ? and object = ?"); + sqlite3_bind_int64(stmt, 1, SegmentToId(ref.get_segment())); + obj = ref.get_sequence(); + sqlite3_bind_text(stmt, 2, obj.c_str(), obj.size(), SQLITE_TRANSIENT); + rc = sqlite3_step(stmt); + if (rc == SQLITE_ROW) { + block_size = sqlite3_column_int64(stmt, 0); + } else { + string refstr = ref.to_string(); + fprintf(stderr, "No block found in block_index for %s\n", + refstr.c_str()); + sqlite3_finalize(stmt); + return; + } sqlite3_finalize(stmt); + + int64_t new_size = old_size; + if (ref.has_range()) { + new_size += ref.get_range_length(); + new_size = min(new_size, block_size); + } else { + new_size = block_size; + } + + if (new_size != old_size) { + stmt = Prepare("insert or replace " + "into snapshot_refs(segmentid, object, size) " + "values (?, ?, ?)"); + sqlite3_bind_int64(stmt, 1, SegmentToId(ref.get_segment())); + obj = ref.get_sequence(); + sqlite3_bind_text(stmt, 2, obj.c_str(), obj.size(), SQLITE_TRANSIENT); + sqlite3_bind_int64(stmt, 3, new_size); + + rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE) { + fprintf(stderr, "Could not execute INSERT statement!\n"); + ReportError(rc); + } + + sqlite3_finalize(stmt); + } } void LocalDb::UseSegment(const std::string &segment, double utilization) @@ -492,7 +535,7 @@ bool LocalDb::LoadChunkSignatures(ObjectReference ref, sqlite3_stmt *stmt; int found = false; - stmt = Prepare("select algorithm, signatures from subblock_signatures " + stmt = Prepare("select signatures, algorithm from subblock_signatures " "where blockid = (select blockid from block_index " " where segmentid = ? and object = ?)"); sqlite3_bind_int64(stmt, 1, SegmentToId(ref.get_segment())); @@ -543,7 +586,7 @@ void LocalDb::StoreChunkSignatures(ObjectReference ref, fprintf(stderr, "Could not determine blockid in StoreChunkSignatures!\n"); ReportError(rc); - throw IOException("Error getting blockid"); + fatal("Error getting blockid"); } int64_t blockid = sqlite3_column_int64(stmt, 0); sqlite3_finalize(stmt);