sqlite3* handle;
int schema;
+ time_t last_modified_at;
};
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;
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";
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)
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;