From 689c8aae88c8240b6d0532a489ebe1bc9cedb431 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 6 Nov 2020 14:04:14 +1030 Subject: [PATCH] fixup! plugin: sort topological candidates by specified order. --- lightningd/plugin_hook.c | 97 +++++++++++++--------------------------- 1 file changed, 32 insertions(+), 65 deletions(-) diff --git a/lightningd/plugin_hook.c b/lightningd/plugin_hook.c index b25fcd574edb..d506f2c65731 100644 --- a/lightningd/plugin_hook.c +++ b/lightningd/plugin_hook.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -401,25 +402,8 @@ void plugin_hook_add_deps(struct plugin_hook *hook, add_deps(&h->after, buffer, after); } -/* From https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm - * (https://creativecommons.org/licenses/by-sa/3.0/): - * L ← Empty list that will contain the sorted elements - * S ← Set of all nodes with no incoming edge - * - * while S is not empty do - * remove a node n from S - * add n to L - * for each node m with an edge e from n to m do - * remove edge e from the graph - * if m has no other incoming edges then - * insert m into S - * - * if graph has edges then - * return error (graph has at least one cycle) - * else - * return L (a topologically sorted order) - */ struct hook_node { + bool finished; struct hook_instance *hook; size_t num_incoming; struct hook_node **outgoing; @@ -434,31 +418,33 @@ static struct hook_node *find_hook(struct hook_node *graph, const char *name) return NULL; } -/* We maintain load order for ready-to-be-added hooks. */ -static void add_to_s(struct hook_node ***s, struct hook_node *n) +/* Sometimes naive is best. */ +static struct hook_node *get_best_candidate(struct hook_node *graph) { - size_t pos, s_num; + struct hook_node *best = NULL; - s_num = tal_count(*s); - for (pos = 0; pos < s_num; pos++) { - if ((*s)[pos]->hook->plugin->index > n->hook->plugin->index) - break; + for (size_t i = 0; i < tal_count(graph); i++) { + if (graph[i].finished) + continue; + if (graph[i].num_incoming != 0) + continue; + if (!best + || best->hook->plugin->index > graph[i].hook->plugin->index) + best = &graph[i]; } - tal_resize(s, s_num + 1); - memmove(*s + pos+1, *s + pos, sizeof(**s) * (s_num - pos)); - (*s)[pos] = n; + return best; } static struct plugin **plugin_hook_make_ordered(const tal_t *ctx, struct plugin_hook *hook) { - struct hook_node *graph; - struct hook_node **l, **s; - struct plugin **ret; + struct hook_node *graph, *n; + struct hook_instance **done; /* Populate graph nodes */ graph = tal_arr(tmpctx, struct hook_node, tal_count(hook->hooks)); for (size_t i = 0; i < tal_count(graph); i++) { + graph[i].finished = false; graph[i].hook = hook->hooks[i]; graph[i].num_incoming = 0; graph[i].outgoing = tal_arr(graph, struct hook_node *, 0); @@ -496,45 +482,26 @@ static struct plugin **plugin_hook_make_ordered(const tal_t *ctx, } } - /* Populate array of ready-to-go nodes. */ - s = tal_arr(graph, struct hook_node *, 0); - for (size_t i = 0; i < tal_count(graph); i++) { - if (graph[i].num_incoming == 0) - add_to_s(&s, &graph[i]); + done = tal_arr(tmpctx, struct hook_instance *, 0); + while ((n = get_best_candidate(graph)) != NULL) { + tal_arr_expand(&done, n->hook); + n->finished = true; + for (size_t i = 0; i < tal_count(n->outgoing); i++) + n->outgoing[i]->num_incoming--; } - l = tal_arr(graph, struct hook_node *, 0); - while (tal_count(s)) { - struct hook_node *n = s[0]; - tal_arr_expand(&l, n); - tal_arr_remove(&s, 0); - - /* for each node m with an edge e from n to m do - * remove edge e from the graph - * if m has no other incoming edges then - * insert m into S - */ - for (size_t i = 0; i < tal_count(n->outgoing); i++) { - if (--n->outgoing[i]->num_incoming == 0) - add_to_s(&s, n->outgoing[i]); + if (tal_count(done) != tal_count(hook->hooks)) { + struct plugin **ret = tal_arr(ctx, struct plugin *, 0); + for (size_t i = 0; i < tal_count(graph); i++) { + if (!graph[i].finished) + tal_arr_expand(&ret, graph[i].hook->plugin); } - } - - /* Check for any left over: these cannot be loaded. */ - ret = tal_arr(ctx, struct plugin *, 0); - for (size_t i = 0; i < tal_count(graph); i++) { - if (graph[i].num_incoming) - tal_arr_expand(&ret, graph[i].hook->plugin); - } - if (tal_count(ret) != 0) return ret; + } - /* Success! Write them back in order. */ - assert(tal_count(l) == tal_count(hook->hooks)); - for (size_t i = 0; i < tal_count(hook->hooks); i++) - hook->hooks[i] = l[i]->hook; - - return tal_free(ret); + /* Success! Copy ordered hooks back. */ + memcpy(hook->hooks, done, tal_bytelen(hook->hooks)); + return NULL; } /* Plugins could fail due to multiple hooks, but only add once. */