From 854c4b849fd0296b67bbe00ffe4f3e35307f46ca Mon Sep 17 00:00:00 2001 From: Ning Yu Date: Wed, 21 Oct 2020 12:16:50 +0800 Subject: [PATCH] ic-proxy: classify peer addresses The peer addresses are specified with the GUC gp_interconnect_proxy_addresses, it can be reloaded on SIGHUP, we used to only care about the newly added ones, however it is also possible for the user to modify them, or even remove some of them. So now we add the logic to classify the addresses after parsing the GUC, we can tell whether an address is added, removed, or modified. The handling of the classified addresses will be done in the next commit. --- src/backend/cdb/motion/ic_proxy.h | 33 +++++++ src/backend/cdb/motion/ic_proxy_addr.c | 132 ++++++++++++++++++++++--- src/backend/cdb/motion/ic_proxy_addr.h | 7 ++ 3 files changed, 159 insertions(+), 13 deletions(-) diff --git a/src/backend/cdb/motion/ic_proxy.h b/src/backend/cdb/motion/ic_proxy.h index f827159c61..66cc1b9354 100644 --- a/src/backend/cdb/motion/ic_proxy.h +++ b/src/backend/cdb/motion/ic_proxy.h @@ -55,4 +55,37 @@ ic_proxy_build_server_sock_path(char *buf, size_t bufsize) PostPortNumber, PostmasterPid); } +/* + * Free a list. + * + * The difference with list_free() is we always return NIL. + */ +static inline List * +ic_proxy_list_free(List *list) +{ + list_free(list); + return NIL; +} + +/* + * Free a list and the cells. + * + * The cells must be allocated with the ic_proxy_alloc() / ic_proxy_new() + * allocators. + * + * Always return NIL. + */ +static inline List * +ic_proxy_list_free_deep(List *list) +{ + ListCell *cell; + + foreach(cell, list) + { + ic_proxy_free(lfirst(cell)); + } + + return ic_proxy_list_free(list); +} + #endif /* IC_PROXY_H */ diff --git a/src/backend/cdb/motion/ic_proxy_addr.c b/src/backend/cdb/motion/ic_proxy_addr.c index 4962254af2..7949181944 100644 --- a/src/backend/cdb/motion/ic_proxy_addr.c +++ b/src/backend/cdb/motion/ic_proxy_addr.c @@ -28,10 +28,32 @@ /* - * List, the addresses list. + * List, the current addresses list. */ List *ic_proxy_addrs = NIL; +/* + * List, the previous addresses list. + * + * It holds the memory of all the addresses, so the classified lists can only + * hold a ref. + */ +List *ic_proxy_prev_addrs = NIL; + +/* + * List, the classified addresses lists. + * + * - if an address is removed from the GUC gp_interconnect_proxy_addresses, + * it is put in the "removed" list; + * - if an address is newly added to the GUC, it is in the "added" list; + * - if an address is updated, it is in both the "removed" and "added" lists; + * + * The addresses of these lists must not be freed, they are actually held by + * ic_proxy_addrs or ic_proxy_prev_addrs. + */ +List *ic_proxy_removed_addrs = NIL; +List *ic_proxy_added_addrs = NIL; + /* * List, the addresses list that are being resolved. */ @@ -42,6 +64,87 @@ static List *ic_proxy_unknown_addrs = NIL; */ static ICProxyAddr *ic_proxy_my_addr = NULL; +static int +ic_proxy_addr_compare_dbid(const void *a, const void *b, void *arg) +{ + const ICProxyAddr *addr1 = a; + const ICProxyAddr *addr2 = b; + + return addr1->dbid - addr2->dbid; +} + +/* + * Classify the addrs as added, deleted, updated and unchanged. + * + * Both the old and new lists must be sorted by dbid, the caller is responsible + * to ensure this. + */ +static void +ic_proxy_classify_addresses(List *oldaddrs, List *newaddrs) +{ + ListCell *lcold; + ListCell *lcnew; + + ic_proxy_added_addrs = ic_proxy_list_free(ic_proxy_added_addrs); + ic_proxy_removed_addrs = ic_proxy_list_free(ic_proxy_removed_addrs); + + lcold = list_head(oldaddrs); + lcnew = list_head(newaddrs); + while (lcold && lcnew) + { + ICProxyAddr *old = lfirst(lcold); + ICProxyAddr *new = lfirst(lcnew); + + if (old->dbid < new->dbid) + { + /* the address is removed */ + ic_proxy_removed_addrs = lappend(ic_proxy_removed_addrs, old); + lcold = lnext(lcold); + } + else if (old->dbid > new->dbid) + { + /* the address is newly added */ + ic_proxy_added_addrs = lappend(ic_proxy_added_addrs, new); + lcnew = lnext(lcnew); + } + /* + * note that the new->sockaddr is not filled yet, so we must compare + * with the hostname and service as strings. + */ + else if (strcmp(old->service, new->service) || + strcmp(old->hostname, new->hostname)) + { + /* the address is updated */ + ic_proxy_removed_addrs = lappend(ic_proxy_removed_addrs, old); + ic_proxy_added_addrs = lappend(ic_proxy_added_addrs, new); + lcold = lnext(lcold); + lcnew = lnext(lcnew); + } + else + { + /* the address is unchanged */ + lcold = lnext(lcold); + lcnew = lnext(lcnew); + } + } + + /* all the addresses remaining in the old list are removed */ + for ( ; lcold; lcold = lnext(lcold)) + { + ICProxyAddr *old = lfirst(lcold); + + ic_proxy_removed_addrs = lappend(ic_proxy_removed_addrs, old); + } + + /* all the addresses remaining in the new list are newly added */ + for ( ; lcnew; lcnew = lnext(lcnew)) + { + ICProxyAddr *new = lfirst(lcnew); + + ic_proxy_added_addrs = lappend(ic_proxy_added_addrs, new); + } +} + /* * Resolved one address. */ @@ -122,18 +225,13 @@ ic_proxy_addr_on_getaddrinfo(uv_getaddrinfo_t *req, void ic_proxy_reload_addresses(uv_loop_t *loop) { - /* reset the old addresses */ - { - ListCell *cell; - - foreach(cell, ic_proxy_addrs) - { - ic_proxy_free(lfirst(cell)); - } - - list_free(ic_proxy_addrs); - ic_proxy_addrs = NIL; - } + /* + * save the old addresses to the "prev" list, it is used to know the diffs + * of the addresses. + */ + ic_proxy_prev_addrs = ic_proxy_list_free_deep(ic_proxy_prev_addrs); + ic_proxy_prev_addrs = ic_proxy_addrs; + ic_proxy_addrs = NULL; /* cancel any unfinished getaddrinfo reqs */ { @@ -203,6 +301,14 @@ ic_proxy_reload_addresses(uv_loop_t *loop) fclose(f); ic_proxy_free(buf); } + + /* sort the new addrs so it's easy to diff */ + ic_proxy_unknown_addrs = list_qsort(ic_proxy_unknown_addrs, + ic_proxy_addr_compare_dbid, NULL); + + /* the last thing is to classify the addrs */ + ic_proxy_classify_addresses(ic_proxy_prev_addrs /* oldaddrs */, + ic_proxy_unknown_addrs /* newaddrs */); } /* diff --git a/src/backend/cdb/motion/ic_proxy_addr.h b/src/backend/cdb/motion/ic_proxy_addr.h index a3081a7e6f..80fcf862ff 100644 --- a/src/backend/cdb/motion/ic_proxy_addr.h +++ b/src/backend/cdb/motion/ic_proxy_addr.h @@ -43,6 +43,13 @@ struct ICProxyAddr * List */ extern List *ic_proxy_addrs; +extern List *ic_proxy_prev_addrs; + +/* + * List + */ +extern List *ic_proxy_removed_addrs; +extern List *ic_proxy_added_addrs; extern void ic_proxy_reload_addresses(uv_loop_t *loop); -- GitLab