]> git.ipfire.org Git - pakfire.git/commitdiff
db: Store a timestamp when the database was modified last
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 9 Dec 2021 15:57:20 +0000 (15:57 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 9 Dec 2021 15:57:20 +0000 (15:57 +0000)
This is useful to detect whether things have changed since the database
was opened and whether things have to be re-read from it.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/db.c

index 2edd73241fb67242404fc7c13836ec01bcbeaf28..9deaca54e7f6724705602d53db57cd350ab05215 100644 (file)
@@ -50,6 +50,7 @@ struct pakfire_db {
 
        sqlite3* handle;
        int schema;
+       time_t last_modified_at;
 };
 
 static void logging_callback(void* data, int r, const char* msg) {
@@ -59,62 +60,6 @@ static void logging_callback(void* data, int r, const char* msg) {
                sqlite3_errstr(r), msg);
 }
 
-static int pakfire_db_execute(struct pakfire_db* db, const char* stmt) {
-       int r;
-
-       DEBUG(db->pakfire, "Executing database query: %s\n", stmt);
-
-       do {
-               r = sqlite3_exec(db->handle, stmt, NULL, NULL, NULL);
-       } while (r == SQLITE_BUSY);
-
-       // Log any errors
-       if (r) {
-               ERROR(db->pakfire, "Database query failed: %s\n", sqlite3_errmsg(db->handle));
-       }
-
-       return r;
-}
-
-static int pakfire_db_begin_transaction(struct pakfire_db* db) {
-       return pakfire_db_execute(db, "BEGIN TRANSACTION");
-}
-
-static int pakfire_db_commit(struct pakfire_db* db) {
-       return pakfire_db_execute(db, "COMMIT");
-}
-
-static int pakfire_db_rollback(struct pakfire_db* db) {
-       return pakfire_db_execute(db, "ROLLBACK");
-}
-
-/*
-       This function performs any fast optimization and tries to truncate the WAL log file
-       to keep the database as compact as possible on disk.
-*/
-static void pakfire_db_optimize(struct pakfire_db* db) {
-       pakfire_db_execute(db, "PRAGMA optimize");
-       pakfire_db_execute(db, "PRAGMA wal_checkpoint = TRUNCATE");
-}
-
-static void pakfire_db_free(struct pakfire_db* db) {
-       if (db->handle) {
-               // Optimize the database before it is being closed
-               pakfire_db_optimize(db);
-
-               // Close database handle
-               int r = sqlite3_close(db->handle);
-               if (r != SQLITE_OK) {
-                       ERROR(db->pakfire, "Could not close database handle: %s\n",
-                               sqlite3_errmsg(db->handle));
-               }
-       }
-
-       pakfire_unref(db->pakfire);
-
-       free(db);
-}
-
 static sqlite3_value* pakfire_db_get(struct pakfire_db* db, const char* key) {
        sqlite3_stmt* stmt = NULL;
        sqlite3_value* val = NULL;
@@ -167,6 +112,8 @@ static int pakfire_db_set_int(struct pakfire_db* db, const char* key, int val) {
        sqlite3_stmt* stmt = NULL;
        int r;
 
+       DEBUG(db->pakfire, "Setting %s to '%d'\n", key, val);
+
        const char* sql = "INSERT INTO settings(key, val) VALUES(?, ?) \
                ON CONFLICT (key) DO UPDATE SET val = excluded.val";
 
@@ -207,6 +154,103 @@ ERROR:
        return r;
 }
 
+static time_t pakfire_read_modification_time(struct pakfire_db* db) {
+       time_t t = 0;
+
+       // Fetch the value from the database
+       sqlite3_value* value = pakfire_db_get(db, "last_modified_at");
+       if (value) {
+               t = sqlite3_value_int64(value);
+               sqlite3_value_free(value);
+       } else {
+               DEBUG(db->pakfire, "Could not find last modification timestamp\n");
+       }
+
+       return t;
+}
+
+static int pakfire_update_modification_time(struct pakfire_db* db) {
+       // Get the current time in UTC
+       time_t t = time(NULL);
+
+       // Store it in the database
+       int r = pakfire_db_set_int(db, "last_modified_at", t);
+       if (r)
+               return r;
+
+       // Update the last modification timestamp
+       db->last_modified_at = t;
+
+       return r;
+}
+
+static int pakfire_db_execute(struct pakfire_db* db, const char* stmt) {
+       int r;
+
+       DEBUG(db->pakfire, "Executing database query: %s\n", stmt);
+
+       do {
+               r = sqlite3_exec(db->handle, stmt, NULL, NULL, NULL);
+       } while (r == SQLITE_BUSY);
+
+       // Log any errors
+       if (r) {
+               ERROR(db->pakfire, "Database query failed: %s\n", sqlite3_errmsg(db->handle));
+       }
+
+       return r;
+}
+
+static int pakfire_db_begin_transaction(struct pakfire_db* db) {
+       return pakfire_db_execute(db, "BEGIN TRANSACTION");
+}
+
+static int pakfire_db_commit(struct pakfire_db* db) {
+       /*
+               If the database was opened in read-write mode, we will store the
+               timestamp of the latest modification to compare whether the database
+               has been changed mid-transaction.
+       */
+       if (db->mode == PAKFIRE_DB_READWRITE) {
+               int r = pakfire_update_modification_time(db);
+               if (r)
+                       return r;
+       }
+
+       return pakfire_db_execute(db, "COMMIT");
+}
+
+static int pakfire_db_rollback(struct pakfire_db* db) {
+       return pakfire_db_execute(db, "ROLLBACK");
+}
+
+/*
+       This function performs any fast optimization and tries to truncate the WAL log file
+       to keep the database as compact as possible on disk.
+*/
+static void pakfire_db_optimize(struct pakfire_db* db) {
+       pakfire_db_execute(db, "PRAGMA optimize");
+       pakfire_db_execute(db, "PRAGMA wal_checkpoint = TRUNCATE");
+}
+
+static void pakfire_db_free(struct pakfire_db* db) {
+       if (db->handle) {
+               // Optimize the database before it is being closed
+               pakfire_db_optimize(db);
+
+               // Close database handle
+               int r = sqlite3_close(db->handle);
+               if (r != SQLITE_OK) {
+                       ERROR(db->pakfire, "Could not close database handle: %s\n",
+                               sqlite3_errmsg(db->handle));
+               }
+       }
+
+       pakfire_unref(db->pakfire);
+
+       free(db);
+}
+
 static int pakfire_db_get_schema(struct pakfire_db* db) {
        sqlite3_value* value = pakfire_db_get(db, "schema");
        if (!value)
@@ -419,6 +463,11 @@ static int pakfire_db_setup(struct pakfire_db* db) {
                return 1;
        }
 
+       // Read modification timestamp
+       db->last_modified_at = pakfire_read_modification_time(db);
+
+       DEBUG(db->pakfire, "The database was last modified at %ld\n", db->last_modified_at);
+
        // Done when not in read-write mode
        if (db->mode != PAKFIRE_DB_READWRITE)
                return 0;