From 029d75df1e4d3049df77fe5cf9825bcab7f00aa4 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 20 Sep 2024 17:12:04 +0200 Subject: [PATCH] OPTIM: cfgparse: speed up duplicate server detection Surprisingly, the duplicate server name detection has never made use of the names tree, so lookups were still in O(N^2). It took 1 second to validate 50k servers spread into 25 backends at 2k per backend. By simply using the tree (and since the current server already is in the tree), we just have to walk using ebpt_prev_dup to visit previous servers with the same name. We can then detect which ones conflict without having an ID set and error. The config check time is now 1/4 of the previous one for 2k servers per backend, and more importantly it will make it simpler to check for any duplicates later. --- src/cfgparse.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cfgparse.c b/src/cfgparse.c index 27c1119c0..83592556f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -3748,16 +3748,23 @@ out_uri_auth_compat: * in order to avoid combinatory explosion if all servers have the same * name. We do that only for servers which do not have an explicit ID, * because these IDs were made also for distinguishing them and we don't - * want to annoy people who correctly manage them. + * want to annoy people who correctly manage them. Since servers names + * are stored in a tree before landing here, we simply have to check for + * the current server's duplicates to spot conflicts. */ for (newsrv = curproxy->srv; newsrv; newsrv = newsrv->next) { struct server *other_srv; - if (newsrv->puid) + /* Note: internal servers are not always registered and + * they do not conflict. + */ + if (!newsrv->conf.name.node.leaf_p) continue; - for (other_srv = curproxy->srv; other_srv && other_srv != newsrv; other_srv = other_srv->next) { - if (!other_srv->puid && strcmp(other_srv->id, newsrv->id) == 0) { + for (other_srv = newsrv; + (other_srv = container_of_safe(ebpt_prev_dup(&other_srv->conf.name), + struct server, conf.name)); ) { + if (!newsrv->puid && !other_srv->puid) { ha_alert("parsing [%s:%d] : %s '%s', another server named '%s' was already defined at line %d, please use distinct names.\n", newsrv->conf.file, newsrv->conf.line, proxy_type_str(curproxy), curproxy->id,