From 36c7141d53e96d9e6d93ef8c1c90a382842c6225 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Sun, 8 Feb 2015 11:17:20 -0500 Subject: [PATCH] change control_ng_stats into a hash and use locking and atomic ops --- daemon/aux.c | 10 ++++++++ daemon/aux.h | 11 +++++--- daemon/call.c | 3 +++ daemon/call.h | 4 ++- daemon/cli.c | 14 ++++++---- daemon/control_ng.c | 62 +++++++++++++++------------------------------ daemon/control_ng.h | 18 ++++++------- daemon/main.c | 2 -- 8 files changed, 62 insertions(+), 62 deletions(-) diff --git a/daemon/aux.c b/daemon/aux.c index c09d0c918..8856f7e76 100644 --- a/daemon/aux.c +++ b/daemon/aux.c @@ -192,3 +192,13 @@ void thread_create_detach(void (*f)(void *), void *d) { if (thread_create(thread_detach_func, dt, 1, NULL)) abort(); } + +unsigned int in6_addr_hash(const void *p) { + const struct in6_addr *a = p; + return a->s6_addr32[0] ^ a->s6_addr32[3]; +} + +int in6_addr_eq(const void *a, const void *b) { + const struct in6_addr *A = a, *B = b; + return !memcmp(A, B, sizeof(*A)); +} diff --git a/daemon/aux.h b/daemon/aux.h index 0c6b2b2c3..21bb0498b 100644 --- a/daemon/aux.h +++ b/daemon/aux.h @@ -144,7 +144,7 @@ INLINE u_int32_t in6_to_4(const struct in6_addr *a) { return a->s6_addr32[3]; } -INLINE void smart_ntop(char *o, struct in6_addr *a, size_t len) { +INLINE void smart_ntop(char *o, const struct in6_addr *a, size_t len) { const char *r; if (IN6_IS_ADDR_V4MAPPED(a)) @@ -156,7 +156,7 @@ INLINE void smart_ntop(char *o, struct in6_addr *a, size_t len) { *o = '\0'; } -INLINE char *smart_ntop_p(char *o, struct in6_addr *a, size_t len) { +INLINE char *smart_ntop_p(char *o, const struct in6_addr *a, size_t len) { int l; if (IN6_IS_ADDR_V4MAPPED(a)) { @@ -178,7 +178,7 @@ INLINE char *smart_ntop_p(char *o, struct in6_addr *a, size_t len) { } } -INLINE void smart_ntop_port(char *o, struct sockaddr_in6 *a, size_t len) { +INLINE void smart_ntop_port(char *o, const struct sockaddr_in6 *a, size_t len) { char *e; e = smart_ntop_p(o, &a->sin6_addr, len); @@ -483,4 +483,9 @@ INLINE void g_queue_append(GQueue *dst, const GQueue *src) { g_queue_push_tail(dst, l->data); } + + +unsigned int in6_addr_hash(const void *p); +int in6_addr_eq(const void *a, const void *b); + #endif diff --git a/daemon/call.c b/daemon/call.c index f484dfa4a..8c9beb260 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1426,6 +1426,9 @@ struct callmaster *callmaster_new(struct poller *p) { mutex_init(&c->totalstats_lock); c->totalstats.started = poller_now; + mutex_init(&c->cngs_lock); + c->cngs_hash = g_hash_table_new(in6_addr_hash, in6_addr_eq); + return c; fail: diff --git a/daemon/call.h b/daemon/call.h index ddd9e8778..8be512487 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -413,7 +413,9 @@ struct callmaster { mutex_t totalstats_lock; /* for both of them */ struct totalstats totalstats; struct totalstats totalstats_interval; - struct control_ng_stats* control_ng_stats; + /* control_ng_stats stuff */ + mutex_t cngs_lock; + GHashTable *cngs_hash; struct poller *poller; pcre *info_re; diff --git a/daemon/cli.c b/daemon/cli.c index 3b72cd6e7..dfa0c6744 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -60,15 +60,18 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m printlen = snprintf(replybuffer,(outbufend-replybuffer), " %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s \n", "Proxy", "Offer", "Answer", "Delete", "Ping", "List", "Query", "Errors"); ADJUSTLEN(printlen,outbufend,replybuffer); - struct control_ng_stats* cur = m->control_ng_stats; - if (!cur) { + mutex_lock(&m->cngs_lock); + GList *list = g_hash_table_get_values(m->cngs_hash); + + if (!list) { printlen = snprintf(replybuffer,(outbufend-replybuffer), "\n No proxies have yet tried to send data."); ADJUSTLEN(printlen,outbufend,replybuffer); } - while (cur) { + for (GList *l = list; l; l = l->next) { + struct control_ng_stats* cur = l->data; char buf[128]; memset(&buf,0,128); - smart_ntop_p(buf, &(cur->proxy.sin6_addr), sizeof(buf)); + smart_ntop_p(buf, &(cur->proxy), sizeof(buf)); printlen = snprintf(replybuffer,(outbufend-replybuffer), " %10s | %10u | %10u | %10u | %10u | %10u | %10u | %10u \n", buf, @@ -80,10 +83,11 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m cur->query, cur->errors); ADJUSTLEN(printlen,outbufend,replybuffer); - cur = cur->next; } printlen = snprintf(replybuffer,(outbufend-replybuffer), "\n\n"); ADJUSTLEN(printlen,outbufend,replybuffer); + mutex_unlock(&m->cngs_lock); + g_list_free(list); } static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { diff --git a/daemon/control_ng.c b/daemon/control_ng.c index ca42fc534..911479bea 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -56,41 +56,21 @@ static void pretty_print(bencode_item_t *el, GString *s) { } } -struct control_ng_stats* get_control_ng_stats(struct control_ng* c, struct sockaddr_in6* sin) { - - // seems to be the first address - if (!c->callmaster->control_ng_stats) { - c->callmaster->control_ng_stats = malloc(sizeof(struct control_ng_stats)); - memset(c->callmaster->control_ng_stats,0,sizeof(struct control_ng_stats)); - memcpy(&(c->callmaster->control_ng_stats->proxy),sin,sizeof(struct sockaddr_in6)); +struct control_ng_stats* get_control_ng_stats(struct control_ng* c, const struct in6_addr *addr) { + struct callmaster *m = c->callmaster; + struct control_ng_stats* cur; + + mutex_lock(&m->cngs_lock); + cur = g_hash_table_lookup(m->cngs_hash, addr); + if (!cur) { + cur = g_slice_alloc0(sizeof(struct control_ng_stats)); + cur->proxy = *addr; char buf[128]; memset(&buf,0,128); - smart_ntop_p(buf, &sin->sin6_addr, sizeof(buf)); - ilog(LOG_INFO,"Adding a first proxy for control ng stats:%s\n",buf); - return c->callmaster->control_ng_stats; - } - - struct control_ng_stats* cur = c->callmaster->control_ng_stats; - struct control_ng_stats* last; - - while (cur) { - last = cur; - if (memcmp((const void*)(&(cur->proxy.sin6_addr)),(const void*)(&(sin->sin6_addr)),sizeof(struct in6_addr))==0) { - ilog(LOG_DEBUG,"Already found proxy for control ng stats.\n"); - return cur; - } - cur = cur->next; + smart_ntop_p(buf, addr, sizeof(buf)); + ilog(LOG_DEBUG,"Adding a proxy for control ng stats:%s",buf); + g_hash_table_insert(m->cngs_hash, &cur->proxy, cur); } - - // add a new one - char buf[128]; memset(&buf,0,128); - smart_ntop_p(buf, &sin->sin6_addr, sizeof(buf)); - ilog(LOG_INFO,"Adding a new proxy for control ng stats:%s\n",buf); - - cur = malloc(sizeof(struct control_ng_stats)); - memset(cur,0,sizeof(struct control_ng_stats)); - memcpy(cur,sin,sizeof(struct sockaddr_in6)); - last->next = cur; - + mutex_unlock(&m->cngs_lock); return cur; } @@ -104,7 +84,7 @@ static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 * struct iovec iov[3]; GString *log_str; - struct control_ng_stats* cur = get_control_ng_stats(c,sin); + struct control_ng_stats* cur = get_control_ng_stats(c,&sin->sin6_addr); str_chr_str(&data, buf, ' '); if (!data.s || data.s == buf->s) { @@ -150,28 +130,28 @@ static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 * errstr = NULL; if (!str_cmp(&cmd, "ping")) { bencode_dictionary_add_string(resp, "result", "pong"); - cur->ping++; + g_atomic_int_inc(&cur->ping); } else if (!str_cmp(&cmd, "offer")) { errstr = call_offer_ng(dict, c->callmaster, resp, addr, sin); - cur->offer++; + g_atomic_int_inc(&cur->offer); } else if (!str_cmp(&cmd, "answer")) { errstr = call_answer_ng(dict, c->callmaster, resp); - cur->answer++; + g_atomic_int_inc(&cur->answer); } else if (!str_cmp(&cmd, "delete")) { errstr = call_delete_ng(dict, c->callmaster, resp); - cur->delete++; + g_atomic_int_inc(&cur->delete); } else if (!str_cmp(&cmd, "query")) { errstr = call_query_ng(dict, c->callmaster, resp); - cur->query++; + g_atomic_int_inc(&cur->query); } #if GLIB_CHECK_VERSION(2,16,0) else if (!str_cmp(&cmd, "list")) { errstr = call_list_ng(dict, c->callmaster, resp); - cur->list++; + g_atomic_int_inc(&cur->list); } #endif else @@ -186,7 +166,7 @@ err_send: ilog(LOG_WARNING, "Protocol error in packet from %s: %s ["STR_FORMAT"]", addr, errstr, STR_FMT(&data)); bencode_dictionary_add_string(resp, "result", "error"); bencode_dictionary_add_string(resp, "error-reason", errstr); - cur->errors++; + g_atomic_int_inc(&cur->errors); goto send_resp; send_resp: diff --git a/daemon/control_ng.h b/daemon/control_ng.h index 9851ac48a..611ab51e0 100644 --- a/daemon/control_ng.h +++ b/daemon/control_ng.h @@ -10,15 +10,14 @@ struct poller; struct callmaster; struct control_ng_stats { - struct sockaddr_in6 proxy; - u_int32_t ping; - u_int32_t offer; - u_int32_t answer; - u_int32_t delete; - u_int32_t query; - u_int32_t list; - u_int32_t errors; - struct control_ng_stats* next; + struct in6_addr proxy; + int ping; + int offer; + int answer; + int delete; + int query; + int list; + int errors; }; struct control_ng { @@ -30,5 +29,4 @@ struct control_ng { struct control_ng *control_ng_new(struct poller *, struct in6_addr, u_int16_t, struct callmaster *); - #endif diff --git a/daemon/main.c b/daemon/main.c index b03328e07..6958cf3e1 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -620,8 +620,6 @@ no_kernel: if (redis_restore(ctx->m, mc.redis)) die("Refusing to continue without working Redis database"); - - ZERO(ctx->m->control_ng_stats); } static void timer_loop(void *d) {