diff --git a/src/backend/cdb/motion/ic_proxy.h b/src/backend/cdb/motion/ic_proxy.h index f827159c61a31c1d9e44a3ddaf3afc215f695053..66cc1b93543ed2c05307f376ab2675f0797e6d89 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 4962254af20ff0cca706d613801d5a137bfeb9f2..7949181944ae844e6c0988c60c2871c60c289b09 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 a3081a7e6fdb56ce8b700667efa1bd7e1ff6832b..80fcf862ffada3a317b3132f7b3fac198397cafa 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);