diff options
-rw-r--r-- | ChangeLog.txt | 4 | ||||
-rw-r--r-- | pseudo_db.c | 250 |
2 files changed, 146 insertions, 108 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index aea94d3..6fbde57 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,7 @@ +2011-02-09: + * (seebs) the long-awaited cleanup of the database initialization + code. it's not really beautiful but it's quite a bit better. + 2011-02-08: * (seebs) Get full paths for exec*() diff --git a/pseudo_db.c b/pseudo_db.c index 86e42e0..575fd72 100644 --- a/pseudo_db.c +++ b/pseudo_db.c @@ -115,6 +115,31 @@ static struct sql_index { { NULL, NULL, NULL }, }; +static char *file_pragmas[] = { + "PRAGMA legacy_file_format = OFF;", + "PRAGMA journal_mode = OFF;", + "PRAGMA locking_mode = EXCLUSIVE;", + /* Setting this to NORMAL makes pseudo noticably slower + * than fakeroot, but is perhaps more secure. However, + * note that sqlite always flushes to the OS; what is lacking + * in non-synchronous mode is waiting for the OS to + * confirm delivery to media, and also a bunch of cache + * flushing and reloading which we probably don't really + * need. + */ + "PRAGMA synchronous = OFF;", + NULL +}; + +static char *log_pragmas[] = { + "PRAGMA legacy_file_format = OFF;", + "PRAGMA journal_mode = OFF;", + "PRAGMA locking_mode = EXCLUSIVE;", + "PRAGMA synchronous = OFF;", + NULL +}; + + /* table migrations: */ /* If there is no migration table, we assume "version -1" -- the * version shipped with wrlinux 3.0, which had no version @@ -173,6 +198,52 @@ static struct sql_migration { { NULL }, }; +/* cleanup database before getting started + * + * On a large build, the logs database gets GIGANTIC... And + * we rarely-if-ever delete things from it. So instead of + * doing the vacuum operation on it at startup, which can impose + * a several-minute delay, we do it only on deletions. + * + * There's no setup for log database right now. + */ +char *file_setups[] = { + "VACUUM;", + NULL, +}; + +struct database_info { + char *pathname; + struct sql_index *indexes; + struct sql_table *tables; + struct sql_migration *migrations; + char **pragmas; + char **setups; + struct sqlite3 **db; +}; + +static struct database_info db_infos[] = { + { + "logs.db", + log_indexes, + log_tables, + log_migrations, + log_pragmas, + NULL, + &log_db + }, + { + "files.db", + file_indexes, + file_tables, + file_migrations, + file_pragmas, + file_setups, + &file_db + }, + { 0, 0, 0, 0, 0, 0, 0 } +}; + /* pretty-print error along with the underlying SQL error. */ static void dberr(sqlite3 *db, char *fmt, ...) { @@ -235,7 +306,7 @@ make_tables(sqlite3 *db, if (sql_tables[i].values) { for (j = 0; sql_tables[i].values[j].fmt; ++j) { char buffer[256]; - sprintf(buffer, sql_tables[i].values[j].fmt, sql_tables[i].values[j].arg); + snprintf(buffer, sizeof(buffer), sql_tables[i].values[j].fmt, sql_tables[i].values[j].arg); sql = sqlite3_mprintf("INSERT INTO %s ( %s ) VALUES ( %s );", sql_tables[i].name, *sql_tables[i].names, @@ -383,125 +454,88 @@ cleanup_db(void) { sqlite3_close(log_db); } -/* I hate this function. - * The need to separate logs and files into separate database (performance - * and stability suffered when they were together) was discovered after - * this was written, and it is still full of half-considered code and - * unreasonable tests. The test for whether db == &file_db is particularly - * odious. - * - * The basic idea is to open the database, and make sure the tables exist - * (using the make_tables function above). Options are set to make sqlite - * run reasonably efficiently. +/* This function has been rewritten and I no longer hate it. I just feel + * like it's important to say that. */ static int -get_db(sqlite3 **db) { +get_db(struct database_info *dbinfo) { int rc; + int i; char *sql; char **results; int rows, columns; char *errmsg; static int registered_cleanup = 0; char *dbfile; + sqlite3 *db; - if (!db) + if (!dbinfo) + return 1; + if (!dbinfo->db) return 1; - if (*db) + /* this database is perhaps already initialized? */ + if (*(dbinfo->db)) return 0; - if (db == &file_db) { - dbfile = pseudo_localstatedir_path("files.db"); - rc = sqlite3_open(dbfile, db); -#ifdef NPROFILE - sqlite3_profile(*db, xProfile, NULL); -#endif - free(dbfile); - } else { - dbfile = pseudo_localstatedir_path("logs.db"); - rc = sqlite3_open(dbfile, db); - free(dbfile); - } + + dbfile = pseudo_localstatedir_path(dbinfo->pathname); + rc = sqlite3_open(dbfile, &db); + free(dbfile); if (rc) { - pseudo_diag("Failed: %s\n", sqlite3_errmsg(*db)); - sqlite3_close(*db); - *db = NULL; + pseudo_diag("Failed: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + *(dbinfo->db) = NULL; return 1; } + /* we store this in the database_info, but hereafter we'll just use + * the name db, because it is shorter. + */ + *dbinfo->db = db; if (!registered_cleanup) { atexit(cleanup_db); registered_cleanup = 1; } - if (db == &file_db) { - rc = sqlite3_exec(*db, "PRAGMA legacy_file_format = OFF;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "file_db legacy_file_format"); - } - rc = sqlite3_exec(*db, "PRAGMA journal_mode = OFF;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "file_db journal_mode"); - } - rc = sqlite3_exec(*db, "PRAGMA locking_mode = EXCLUSIVE;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "file_db locking_mode"); - } - /* Setting this to NORMAL makes pseudo noticably slower - * than fakeroot, but is perhaps more secure. However, - * note that sqlite always flushes to the OS; what is lacking - * in non-synchronous mode is waiting for the OS to - * confirm delivery to media, and also a bunch of cache - * flushing and reloading which we probably don't really - * need. - */ - rc = sqlite3_exec(*db, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "file_db synchronous"); - } - } else if (db == &log_db) { - rc = sqlite3_exec(*db, "PRAGMA legacy_file_format = OFF;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "log_db legacy_file_format"); - } - rc = sqlite3_exec(*db, "PRAGMA journal_mode = OFF;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "log_db journal_mode"); - } - rc = sqlite3_exec(*db, "PRAGMA locking_mode = EXCLUSIVE;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "log_db locking_mode"); - } - rc = sqlite3_exec(*db, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg); - if (rc) { - dberr(*db, "log_db synchronous"); + if (dbinfo->pragmas) { + for (i = 0; dbinfo->pragmas[i]; ++i) { + rc = sqlite3_exec(db, dbinfo->pragmas[i], NULL, NULL, &errmsg); + if (rc) { + dberr(db, dbinfo->pragmas[i]); + } } } /* create database tables or die trying */ sql = "SELECT name FROM sqlite_master " "WHERE type = 'table' " "ORDER BY name;"; - rc = sqlite3_get_table(*db, sql, &results, &rows, &columns, &errmsg); + rc = sqlite3_get_table(db, sql, &results, &rows, &columns, &errmsg); if (rc) { pseudo_diag("Failed: %s\n", errmsg); } else { - if (db == &file_db) { - rc = make_tables(*db, file_tables, file_indexes, file_migrations, results, rows); - } else if (db == &log_db) { - rc = make_tables(*db, log_tables, log_indexes, log_migrations, results, rows); - } + rc = make_tables(db, dbinfo->tables, dbinfo->indexes, dbinfo->migrations, results, rows); sqlite3_free_table(results); } - /* cleanup database before getting started - * - * On a large build, the logs database gets GIGANTIC... And - * we rarely-if-ever delete things from it. So instead of - * doing the vacuum operation on it at startup, which can impose - * a several-minute delay, we do it only on deletions. - * + /* as of now, the only setup is a vacuum operation which we don't care about + * the results of. */ - if (db == &file_db) { - sqlite3_exec(*db, "VACUUM;", NULL, NULL, &errmsg); + if (dbinfo->setups) { + for (i = 0; dbinfo->setups[i]; ++i) { + sqlite3_exec(db, dbinfo->setups[i], NULL, NULL, &errmsg); + } } return rc; } +static int +get_dbs(void) { + int err = 0; + int i; + for (i = 0; db_infos[i].db; ++i) { + if (get_db(&db_infos[i])) + err = 1; + + } + return !err; +} + /* put a prepared log entry into the database */ int pdb_log_traits(pseudo_query_t *traits) { @@ -509,7 +543,7 @@ pdb_log_traits(pseudo_query_t *traits) { log_entry *e; int rc; - if (!log_db && get_db(&log_db)) { + if (!log_db && get_dbs()) { pseudo_diag("database error.\n"); return 1; } @@ -607,7 +641,7 @@ pdb_log_entry(log_entry *e) { int field; int rc; - if (!log_db && get_db(&log_db)) { + if (!log_db && get_dbs()) { pseudo_diag("database error.\n"); return 1; } @@ -705,7 +739,7 @@ pdb_log_msg(pseudo_sev_t severity, pseudo_msg_t *msg, const char *program, const text = buffer; } - if (!log_db && get_db(&log_db)) { + if (!log_db && get_dbs()) { pseudo_diag("database error.\n"); return 1; } @@ -839,7 +873,7 @@ pdb_query(char *stmt_type, pseudo_query_t *traits, unsigned long fields, int uni pseudo_query_field_t f; static buffer *sql; - if (!log_db && get_db(&log_db)) { + if (!log_db && get_dbs()) { pseudo_diag("database error.\n"); return NULL; } @@ -1227,7 +1261,7 @@ pdb_link_file(pseudo_msg_t *msg) { " ( path, dev, ino, uid, gid, mode, rdev, deleting ) " " VALUES (?, ?, ?, ?, ?, ?, ?, 0);"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1272,7 +1306,7 @@ pdb_unlink_file_dev(pseudo_msg_t *msg) { int rc; char *sql = "DELETE FROM files WHERE dev = ? AND ino = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1305,7 +1339,7 @@ pdb_update_file_path(pseudo_msg_t *msg) { char *sql = "UPDATE files SET path = ? " "WHERE path = 'NAMELESS FILE' and dev = ? AND ino = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1339,7 +1373,7 @@ pdb_may_unlink_file(pseudo_msg_t *msg, int deleting) { int rc, exact; char *sql_mark_file = "UPDATE files SET deleting = ? WHERE path = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1383,7 +1417,7 @@ pdb_cancel_unlink_file(pseudo_msg_t *msg) { int rc, exact; char *sql_mark_file = "UPDATE files SET deleting = 0 WHERE path = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1423,7 +1457,7 @@ pdb_did_unlink_files(int deleting) { int rc, exact; char *sql_delete_exact = "DELETE FROM files WHERE deleting = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1457,7 +1491,7 @@ pdb_did_unlink_file(char *path, int deleting) { int rc, exact; char *sql_delete_exact = "DELETE FROM files WHERE path = ? AND deleting = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1492,7 +1526,7 @@ pdb_unlink_file(pseudo_msg_t *msg) { int rc, exact; char *sql_delete_exact = "DELETE FROM files WHERE path = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1538,7 +1572,7 @@ pdb_unlink_contents(pseudo_msg_t *msg) { char *sql_delete_sub = "DELETE FROM files WHERE " "(path > (? || '/') AND path < (? || '0'));"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1587,7 +1621,7 @@ pdb_rename_file(const char *oldpath, pseudo_msg_t *msg) { char *sql_update_sub = "UPDATE files SET path = replace(path, ?, ?) " "WHERE (path > (? || '/') AND path < (? || '0'));"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1656,7 +1690,7 @@ pdb_renumber_all(dev_t from, dev_t to) { " SET dev = ? " " WHERE dev = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1697,7 +1731,7 @@ pdb_update_inode(pseudo_msg_t *msg) { " SET dev = ?, ino = ? " " WHERE path = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1749,7 +1783,7 @@ pdb_update_file(pseudo_msg_t *msg) { " SET uid = ?, gid = ?, mode = ?, rdev = ? " " WHERE dev = ? AND ino = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1789,7 +1823,7 @@ pdb_find_file_exact(pseudo_msg_t *msg) { int rc; char *sql = "SELECT * FROM files WHERE path = ? AND dev = ? AND ino = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1840,7 +1874,7 @@ pdb_find_file_path(pseudo_msg_t *msg) { int rc; char *sql = "SELECT * FROM files WHERE path = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 1; } @@ -1897,7 +1931,7 @@ pdb_get_file_path(pseudo_msg_t *msg) { char *sql = "SELECT path FROM files WHERE dev = ? AND ino = ?;"; char *response; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1946,7 +1980,7 @@ pdb_find_file_dev(pseudo_msg_t *msg) { int rc; char *sql = "SELECT * FROM files WHERE dev = ? AND ino = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -1995,7 +2029,7 @@ pdb_find_file_ino(pseudo_msg_t *msg) { int rc; char *sql = "SELECT * FROM files WHERE ino = ?;"; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } @@ -2039,7 +2073,7 @@ pdb_file_list pdb_files(void) { pdb_file_list l; - if (!file_db && get_db(&file_db)) { + if (!file_db && get_dbs()) { pseudo_diag("database error.\n"); return 0; } |