X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=futatabi%2Fdb.cpp;h=9c6748fb257ffaa439c21e0e0f510565b0fa77cc;hb=02ea864dc5a6dde7450c497581ff18d784ab832c;hp=13e3f6ee7174dc105df1de4136dff33c905e5bd0;hpb=ffe2343de3fe982cc52a449b13f01137819ed42d;p=nageru diff --git a/futatabi/db.cpp b/futatabi/db.cpp index 13e3f6e..9c6748f 100644 --- a/futatabi/db.cpp +++ b/futatabi/db.cpp @@ -3,6 +3,7 @@ #include "frame.pb.h" #include +#include using namespace std; @@ -11,24 +12,40 @@ DB::DB(const string &filename) int ret = sqlite3_open(filename.c_str(), &db); if (ret != SQLITE_OK) { fprintf(stderr, "%s: %s\n", filename.c_str(), sqlite3_errmsg(db)); - exit(1); + abort(); + } + + // Set an effectively infinite timeout for waiting for write locks; + // if we get SQLITE_LOCKED, we just exit out, so this is much better. + ret = sqlite3_busy_timeout(db, 3600000); + if (ret != SQLITE_OK) { + fprintf(stderr, "sqlite3_busy_timeout: %s\n", sqlite3_errmsg(db)); + abort(); } sqlite3_exec(db, R"( CREATE TABLE IF NOT EXISTS state (state BLOB); - )", nullptr, nullptr, nullptr); // Ignore errors. + )", + nullptr, nullptr, nullptr); // Ignore errors. + + sqlite3_exec(db, "CREATE UNIQUE INDEX only_one_state ON state (1);", nullptr, nullptr, nullptr); // Ignore errors. sqlite3_exec(db, R"( CREATE TABLE IF NOT EXISTS settings (settings BLOB); - )", nullptr, nullptr, nullptr); // Ignore errors. + )", + nullptr, nullptr, nullptr); // Ignore errors. + + sqlite3_exec(db, "CREATE UNIQUE INDEX only_one_settings ON settings (1);", nullptr, nullptr, nullptr); // Ignore errors. sqlite3_exec(db, R"( DROP TABLE file; - )", nullptr, nullptr, nullptr); // Ignore errors. + )", + nullptr, nullptr, nullptr); // Ignore errors. sqlite3_exec(db, R"( DROP TABLE frame; - )", nullptr, nullptr, nullptr); // Ignore errors. + )", + nullptr, nullptr, nullptr); // Ignore errors. sqlite3_exec(db, R"( CREATE TABLE IF NOT EXISTS filev2 ( @@ -37,7 +54,8 @@ DB::DB(const string &filename) size BIGINT NOT NULL, frames BLOB NOT NULL ); - )", nullptr, nullptr, nullptr); // Ignore errors. + )", + nullptr, nullptr, nullptr); // Ignore errors. sqlite3_exec(db, "PRAGMA journal_mode=WAL", nullptr, nullptr, nullptr); // Ignore errors. sqlite3_exec(db, "PRAGMA synchronous=NORMAL", nullptr, nullptr, nullptr); // Ignore errors. @@ -51,7 +69,7 @@ StateProto DB::get_state() int ret = sqlite3_prepare_v2(db, "SELECT state FROM state", -1, &stmt, 0); if (ret != SQLITE_OK) { fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_step(stmt); @@ -59,17 +77,17 @@ StateProto DB::get_state() bool ok = state.ParseFromArray(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0)); if (!ok) { fprintf(stderr, "State in database is corrupted!\n"); - exit(1); + abort(); } } else if (ret != SQLITE_DONE) { fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_finalize(stmt); if (ret != SQLITE_OK) { fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } return state; @@ -83,40 +101,34 @@ void DB::store_state(const StateProto &state) int ret = sqlite3_exec(db, "BEGIN", nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "BEGIN: %s\n", sqlite3_errmsg(db)); - exit(1); - } - - ret = sqlite3_exec(db, "DELETE FROM state", nullptr, nullptr, nullptr); - if (ret != SQLITE_OK) { - fprintf(stderr, "DELETE: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } sqlite3_stmt *stmt; - ret = sqlite3_prepare_v2(db, "INSERT INTO state VALUES (?)", -1, &stmt, 0); + ret = sqlite3_prepare_v2(db, "REPLACE INTO state VALUES (?)", -1, &stmt, 0); if (ret != SQLITE_OK) { - fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db)); - exit(1); + fprintf(stderr, "REPLACE prepare: %s\n", sqlite3_errmsg(db)); + abort(); } sqlite3_bind_blob(stmt, 1, serialized.data(), serialized.size(), SQLITE_STATIC); ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { - fprintf(stderr, "INSERT step: %s\n", sqlite3_errmsg(db)); - exit(1); + fprintf(stderr, "REPLACE step: %s\n", sqlite3_errmsg(db)); + abort(); } ret = sqlite3_finalize(stmt); if (ret != SQLITE_OK) { - fprintf(stderr, "INSERT finalize: %s\n", sqlite3_errmsg(db)); - exit(1); + fprintf(stderr, "REPLACE finalize: %s\n", sqlite3_errmsg(db)); + abort(); } ret = sqlite3_exec(db, "COMMIT", nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "COMMIT: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } } @@ -128,7 +140,7 @@ SettingsProto DB::get_settings() int ret = sqlite3_prepare_v2(db, "SELECT settings FROM settings", -1, &stmt, 0); if (ret != SQLITE_OK) { fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_step(stmt); @@ -136,17 +148,17 @@ SettingsProto DB::get_settings() bool ok = settings.ParseFromArray(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0)); if (!ok) { fprintf(stderr, "State in database is corrupted!\n"); - exit(1); + abort(); } } else if (ret != SQLITE_DONE) { fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_finalize(stmt); if (ret != SQLITE_OK) { fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } return settings; @@ -160,40 +172,34 @@ void DB::store_settings(const SettingsProto &settings) int ret = sqlite3_exec(db, "BEGIN", nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "BEGIN: %s\n", sqlite3_errmsg(db)); - exit(1); - } - - ret = sqlite3_exec(db, "DELETE FROM settings", nullptr, nullptr, nullptr); - if (ret != SQLITE_OK) { - fprintf(stderr, "DELETE: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } sqlite3_stmt *stmt; - ret = sqlite3_prepare_v2(db, "INSERT INTO settings VALUES (?)", -1, &stmt, 0); + ret = sqlite3_prepare_v2(db, "REPLACE INTO settings VALUES (?)", -1, &stmt, 0); if (ret != SQLITE_OK) { - fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db)); - exit(1); + fprintf(stderr, "REPLACE prepare: %s\n", sqlite3_errmsg(db)); + abort(); } sqlite3_bind_blob(stmt, 1, serialized.data(), serialized.size(), SQLITE_STATIC); ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { - fprintf(stderr, "INSERT step: %s\n", sqlite3_errmsg(db)); - exit(1); + fprintf(stderr, "REPLACE step: %s\n", sqlite3_errmsg(db)); + abort(); } ret = sqlite3_finalize(stmt); if (ret != SQLITE_OK) { - fprintf(stderr, "INSERT finalize: %s\n", sqlite3_errmsg(db)); - exit(1); + fprintf(stderr, "REPLACE finalize: %s\n", sqlite3_errmsg(db)); + abort(); } ret = sqlite3_exec(db, "COMMIT", nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "COMMIT: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } } @@ -205,7 +211,7 @@ vector DB::load_frame_file(const string &filename, int ret = sqlite3_prepare_v2(db, "SELECT frames FROM filev2 WHERE filename=? AND size=?", -1, &stmt, 0); if (ret != SQLITE_OK) { fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), SQLITE_STATIC); @@ -216,17 +222,17 @@ vector DB::load_frame_file(const string &filename, bool ok = file_contents.ParseFromArray(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0)); if (!ok) { fprintf(stderr, "Frame list in database is corrupted!\n"); - exit(1); + abort(); } } else if (ret != SQLITE_DONE) { fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_finalize(stmt); if (ret != SQLITE_OK) { fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } vector frames; @@ -238,6 +244,11 @@ vector DB::load_frame_file(const string &filename, frame.frame.pts = stream.pts(i); frame.frame.offset = stream.offset(i); frame.frame.size = stream.file_size(i); + if (i < stream.audio_size_size()) { + frame.frame.audio_size = stream.audio_size(i); + } else { + frame.frame.audio_size = 0; + } frames.push_back(frame); } } @@ -250,32 +261,12 @@ void DB::store_frame_file(const string &filename, size_t size, const vector seen_stream_idx; // Usually only one. @@ -288,6 +279,7 @@ void DB::store_frame_file(const string &filename, size_t size, const vectormutable_pts()->Reserve(frames.size()); stream->mutable_offset()->Reserve(frames.size()); stream->mutable_file_size()->Reserve(frames.size()); + stream->mutable_audio_size()->Reserve(frames.size()); for (const FrameOnDiskAndStreamIdx &frame : frames) { if (frame.stream_idx != stream_idx) { continue; @@ -295,16 +287,17 @@ void DB::store_frame_file(const string &filename, size_t size, const vectoradd_pts(frame.frame.pts); stream->add_offset(frame.frame.offset); stream->add_file_size(frame.frame.size); + stream->add_audio_size(frame.frame.audio_size); } } string serialized; file_contents.SerializeToString(&serialized); // Insert the new row. - ret = sqlite3_prepare_v2(db, "INSERT INTO filev2 (filename, size, frames) VALUES (?, ?, ?)", -1, &stmt, 0); + ret = sqlite3_prepare_v2(db, "REPLACE INTO filev2 (filename, size, frames) VALUES (?, ?, ?)", -1, &stmt, 0); if (ret != SQLITE_OK) { fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), SQLITE_STATIC); @@ -313,21 +306,21 @@ void DB::store_frame_file(const string &filename, size_t size, const vector &used_filenames) int ret = sqlite3_exec(db, "BEGIN", nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "BEGIN: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_exec(db, R"( CREATE TEMPORARY TABLE used_filenames ( filename VARCHAR NOT NULL PRIMARY KEY ) - )", nullptr, nullptr, nullptr); + )", + nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "CREATE TEMPORARY TABLE: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } // Insert the new rows. @@ -353,7 +347,7 @@ void DB::clean_unused_frame_files(const vector &used_filenames) ret = sqlite3_prepare_v2(db, "INSERT INTO used_filenames (filename) VALUES (?)", -1, &stmt, 0); if (ret != SQLITE_OK) { fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } for (const string &filename : used_filenames) { @@ -362,44 +356,46 @@ void DB::clean_unused_frame_files(const vector &used_filenames) ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { fprintf(stderr, "INSERT step: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_reset(stmt); if (ret == SQLITE_ROW) { fprintf(stderr, "INSERT reset: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } } ret = sqlite3_finalize(stmt); if (ret != SQLITE_OK) { fprintf(stderr, "INSERT finalize: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_exec(db, R"( DELETE FROM filev2 WHERE filename NOT IN ( SELECT filename FROM used_filenames ) - )", nullptr, nullptr, nullptr); + )", + nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "DELETE: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } ret = sqlite3_exec(db, R"( DROP TABLE used_filenames - )", nullptr, nullptr, nullptr); + )", + nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "DROP TABLE: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } // Commit. ret = sqlite3_exec(db, "COMMIT", nullptr, nullptr, nullptr); if (ret != SQLITE_OK) { fprintf(stderr, "COMMIT: %s\n", sqlite3_errmsg(db)); - exit(1); + abort(); } }