]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/transaction: assign unique ids to transactions and encode them in log
authorMike Yuan <me@yhndnzj.com>
Sat, 4 Oct 2025 22:39:50 +0000 (00:39 +0200)
committerMike Yuan <me@yhndnzj.com>
Wed, 12 Nov 2025 22:47:38 +0000 (23:47 +0100)
Preparation for later commits, but I think this one makes
a ton of sense on its own. When debug logging is enabled
it's otherwise difficult to dig up the portion of journal
for transaction construction.

src/core/manager-serialize.c
src/core/manager.c
src/core/manager.h
src/core/transaction.c
src/core/transaction.h

index 469f51f448efa02675c7fb5fdd8b6af63d9bd10c..df97fde97ed3511f2af7a82208f83582c8ad8eae 100644 (file)
@@ -92,6 +92,8 @@ int manager_serialize(
 
         _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
 
+        (void) serialize_item_format(f, "last-transaction-id", "%" PRIu64, m->last_transaction_id);
+
         (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id);
         (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs);
         (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs);
@@ -325,7 +327,15 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                 if (r == 0) /* eof or end marker */
                         break;
 
-                if ((val = startswith(l, "current-job-id="))) {
+                if ((val = startswith(l, "last-transaction-id="))) {
+                        uint64_t id;
+
+                        if (safe_atou64(val, &id) < 0)
+                                log_notice("Failed to parse last transaction id value '%s', ignoring.", val);
+                        else
+                                m->last_transaction_id = MAX(m->last_transaction_id, id);
+
+                } else if ((val = startswith(l, "current-job-id="))) {
                         uint32_t id;
 
                         if (safe_atou32(val, &id) < 0)
index b501d3f1c5b34897df927045d456eb615ee225dc..bb2c1bece13de52506b2c5122335b7a13637b9ba 100644 (file)
@@ -2153,14 +2153,16 @@ int manager_add_job_full(
         if (mode == JOB_RESTART_DEPENDENCIES && type != JOB_START)
                 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=restart-dependencies is only valid for start.");
 
+        tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY, ++m->last_transaction_id);
+        if (!tr)
+                return -ENOMEM;
+
+        LOG_CONTEXT_PUSHF("TRANSACTION_ID=%" PRIu64, tr->id);
+
         log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
 
         type = job_type_collapse(type, unit);
 
-        tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
-        if (!tr)
-                return -ENOMEM;
-
         r = transaction_add_job_and_dependencies(
                         tr,
                         type,
@@ -2247,18 +2249,20 @@ int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name,
 }
 
 int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e) {
-        int r;
         _cleanup_(transaction_abort_and_freep) Transaction *tr = NULL;
+        int r;
 
         assert(m);
         assert(unit);
         assert(mode < _JOB_MODE_MAX);
         assert(mode != JOB_ISOLATE); /* Isolate is only valid for start */
 
-        tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
+        tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY, ++m->last_transaction_id);
         if (!tr)
                 return -ENOMEM;
 
+        LOG_CONTEXT_PUSHF("TRANSACTION_ID=%" PRIu64, tr->id);
+
         /* We need an anchor job */
         r = transaction_add_job_and_dependencies(tr, JOB_NOP, unit, NULL, TRANSACTION_IGNORE_REQUIREMENTS|TRANSACTION_IGNORE_ORDER, e);
         if (r < 0)
index b7ee766b05dca92ddb39f9a68de1793f0c75cf5a..d0855260bfcd3dc96ea2cc585bdc728fce3657e7 100644 (file)
@@ -236,6 +236,8 @@ typedef struct Manager {
         /* A set which contains all currently failed units */
         Set *failed_units;
 
+        uint64_t last_transaction_id;
+
         sd_event_source *run_queue_event_source;
 
         char *notify_socket;
index 016bbb1f97516dbcd531e3eab9b524af4ccf4f26..34a0faf5568baab46b65686030fb4dae6e32acda 100644 (file)
@@ -1235,20 +1235,24 @@ int transaction_add_triggering_jobs(Transaction *tr, Unit *u) {
         return 0;
 }
 
-Transaction* transaction_new(bool irreversible) {
-        Transaction *tr;
+Transaction* transaction_new(bool irreversible, uint64_t id) {
+        _cleanup_free_ Transaction *tr = NULL;
 
-        tr = new0(Transaction, 1);
+        assert(id != 0);
+
+        tr = new(Transaction, 1);
         if (!tr)
                 return NULL;
 
-        tr->jobs = hashmap_new(NULL);
+        *tr = (Transaction) {
+                .jobs = hashmap_new(NULL),
+                .irreversible = irreversible,
+                .id = id,
+        };
         if (!tr->jobs)
-                return mfree(tr);
-
-        tr->irreversible = irreversible;
+                return NULL;
 
-        return tr;
+        return TAKE_PTR(tr);
 }
 
 Transaction* transaction_free(Transaction *tr) {
index 4f5430d6d4a7c8dd49aede7edd21c135bd025800..275dc5984f8eec41a062c7ec9c8eaf01d8f15eaf 100644 (file)
@@ -8,9 +8,11 @@ typedef struct Transaction {
         Hashmap *jobs;        /* Unit object => Job object list 1:1 */
         Job *anchor_job;      /* The job the user asked for */
         bool irreversible;
+
+        uint64_t id;
 } Transaction;
 
-Transaction* transaction_new(bool irreversible);
+Transaction* transaction_new(bool irreversible, uint64_t id);
 Transaction* transaction_free(Transaction *tr);
 Transaction* transaction_abort_and_free(Transaction *tr);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Transaction*, transaction_abort_and_free);