mirror of
https://github.com/systemd/systemd.git
synced 2025-01-18 10:04:04 +03:00
core/transaction: generate DOT graph of dependency cycle for easier debugging
This commit is contained in:
parent
66146f21c0
commit
d11e70d92f
@ -366,8 +366,12 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
|
|||||||
|
|
||||||
/* Have we seen this before? */
|
/* Have we seen this before? */
|
||||||
if (j->generation == generation) {
|
if (j->generation == generation) {
|
||||||
Job *k, *delete = NULL;
|
Job *k, *prev = NULL, *delete = NULL;
|
||||||
_cleanup_free_ char **array = NULL, *unit_ids = NULL;
|
_cleanup_free_ char **array = NULL, *unit_ids = NULL;
|
||||||
|
_cleanup_free_ char *dot = NULL;
|
||||||
|
|
||||||
|
if (!strextend(&dot, "digraph {"))
|
||||||
|
log_oom();
|
||||||
|
|
||||||
/* If the marker is NULL we have been here already and decided the job was loop-free from
|
/* If the marker is NULL we have been here already and decided the job was loop-free from
|
||||||
* here. Hence shortcut things and return right-away. */
|
* here. Hence shortcut things and return right-away. */
|
||||||
@ -382,6 +386,15 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
|
|||||||
/* For logging below */
|
/* For logging below */
|
||||||
if (strv_push_pair(&array, k->unit->id, (char*) job_type_to_string(k->type)) < 0)
|
if (strv_push_pair(&array, k->unit->id, (char*) job_type_to_string(k->type)) < 0)
|
||||||
log_oom();
|
log_oom();
|
||||||
|
/* Add edge to the graph when we already have part of it. */
|
||||||
|
else if (dot) {
|
||||||
|
r = strextendf(&dot, "\"%s\" -> \"%s\";", k->unit->id, prev ? prev->unit->id : j->unit->id);
|
||||||
|
if (r < 0) {
|
||||||
|
log_oom();
|
||||||
|
/* Dot output is not essential so let's get rid of it in case we ran into OOM. */
|
||||||
|
dot = mfree(dot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Mark every unit along the cycle */
|
/* Mark every unit along the cycle */
|
||||||
k->unit->was_on_dependency_cycle = true;
|
k->unit->was_on_dependency_cycle = true;
|
||||||
@ -393,8 +406,13 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
|
|||||||
/* Check if this in fact was the beginning of the cycle */
|
/* Check if this in fact was the beginning of the cycle */
|
||||||
if (k == j)
|
if (k == j)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
prev = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dot && !strextend(&dot, "}"))
|
||||||
|
log_oom();
|
||||||
|
|
||||||
unit_ids = merge_unit_ids(j->manager->unit_log_field, array); /* ignore error */
|
unit_ids = merge_unit_ids(j->manager->unit_log_field, array); /* ignore error */
|
||||||
|
|
||||||
STRV_FOREACH_PAIR(unit_id, job_type, array)
|
STRV_FOREACH_PAIR(unit_id, job_type, array)
|
||||||
@ -406,6 +424,12 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
|
|||||||
*unit_id, *job_type),
|
*unit_id, *job_type),
|
||||||
"%s", strna(unit_ids));
|
"%s", strna(unit_ids));
|
||||||
|
|
||||||
|
if (dot && IN_SET(log_get_target(), LOG_TARGET_AUTO, LOG_TARGET_JOURNAL, LOG_TARGET_JOURNAL_OR_KMSG)) {
|
||||||
|
log_struct(LOG_WARNING,
|
||||||
|
LOG_UNIT_MESSAGE(j->unit, "Ordering cycle generated, see TRANSACTION_CYCLE= for details. Note that each arc represents Before= dependency."),
|
||||||
|
"TRANSACTION_CYCLE=%s", dot);
|
||||||
|
}
|
||||||
|
|
||||||
if (delete) {
|
if (delete) {
|
||||||
const char *status;
|
const char *status;
|
||||||
/* logging for j not k here to provide a consistent narrative */
|
/* logging for j not k here to provide a consistent narrative */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user