From c7dbb0114d8368ad113c865b1dcffcedd5da4afd Mon Sep 17 00:00:00 2001 From: ckolivas Date: Sat, 21 Mar 2015 10:53:45 +1100 Subject: [PATCH 1/4] Rework sessionid matching to not store client structure --- src/stratifier.c | 184 ++++++++++++++++++++--------------------------- 1 file changed, 79 insertions(+), 105 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 32123a6d..fc3fa50d 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -227,6 +227,7 @@ struct stratum_instance { uchar enonce1bin[16]; char enonce1var[12]; uint64_t enonce1_64; + int session_id; int64_t diff; /* Current diff */ int64_t old_diff; /* Previous diff */ @@ -278,6 +279,16 @@ struct share { typedef struct share share_t; +typedef struct session session_t; + +struct session { + UT_hash_handle hh; + int session_id; + uint64_t enonce1_64; + int64_t client_id; + time_t added; +}; + struct stratifier_data { char pubkeytxnbin[25]; char donkeytxnbin[25]; @@ -309,6 +320,7 @@ struct stratifier_data { int64_t workbase_id; int64_t blockchange_id; + int session_id; char lasthash[68]; char lastswaphash[68]; @@ -321,14 +333,12 @@ struct stratifier_data { int64_t user_instance_id; - /* Stratum_instances hashlist is stored by id, whereas disconnected_instances - * is sorted by enonce1_64. */ stratum_instance_t *stratum_instances; - stratum_instance_t *disconnected_instances; stratum_instance_t *recycled_instances; int stratum_generated; int disconnected_generated; + session_t *disconnected_sessions; user_instance_t *user_instances; @@ -938,13 +948,6 @@ static void __kill_instance(sdata_t *sdata, stratum_instance_t *client) DL_APPEND(sdata->recycled_instances, client); } -static void __del_disconnected(sdata_t *sdata, stratum_instance_t *client) -{ - HASH_DEL(sdata->disconnected_instances, client); - sdata->stats.disconnected--; - __kill_instance(sdata, client); -} - /* Called with instance_lock held. Note stats.users is protected by * instance lock to avoid recursive locking. */ static void __inc_worker(sdata_t *sdata, user_instance_t *instance) @@ -961,6 +964,35 @@ static void __dec_worker(sdata_t *sdata, user_instance_t *instance) sdata->stats.users--; } +static void __disconnect_session(sdata_t *sdata, const stratum_instance_t *client) +{ + time_t now_t = time(NULL); + session_t *session, *tmp; + + /* Opportunity to age old sessions */ + HASH_ITER(hh, sdata->disconnected_sessions, session, tmp) { + if (now_t - session->added > 600) { + HASH_DEL(sdata->disconnected_sessions, session); + dealloc(session); + sdata->stats.disconnected--; + } + } + + if (!client->enonce1_64) + return; + HASH_FIND_INT(sdata->disconnected_sessions, &client->session_id, session); + if (session) + return; + session = ckalloc(sizeof(session_t)); + session->enonce1_64 = client->enonce1_64; + session->session_id = client->session_id; + session->client_id = client->id; + session->added = now_t; + HASH_ADD_INT(sdata->disconnected_sessions, session_id, session); + sdata->stats.disconnected++; + sdata->disconnected_generated++; +} + /* Removes a client instance we know is on the stratum_instances list and from * the user client list if it's been placed on it */ static void __del_client(sdata_t *sdata, stratum_instance_t *client, user_instance_t *user) @@ -970,13 +1002,14 @@ static void __del_client(sdata_t *sdata, stratum_instance_t *client, user_instan DL_DELETE(user->clients, client); __dec_worker(sdata, user); } + } static void drop_allclients(ckpool_t *ckp) { stratum_instance_t *client, *tmp; - int disconnects = 0, kills = 0; sdata_t *sdata = ckp->data; + int kills = 0; char buf[128]; ck_wlock(&sdata->instance_lock); @@ -992,15 +1025,9 @@ static void drop_allclients(ckpool_t *ckp) sprintf(buf, "dropclient=%"PRId64, client_id); send_proc(ckp->connector, buf); } - HASH_ITER(hh, sdata->disconnected_instances, client, tmp) { - disconnects++; - __del_disconnected(sdata, client); - } sdata->stats.users = sdata->stats.workers = 0; ck_wunlock(&sdata->instance_lock); - if (disconnects) - LOGNOTICE("Disconnected %d instances", disconnects); if (kills) LOGNOTICE("Dropped %d instances", kills); } @@ -1223,56 +1250,26 @@ static stratum_instance_t *ref_instance_by_id(sdata_t *sdata, const int64_t id) return client; } -/* Has this client_id already been used and is now in one of the dropped lists */ -static bool __dropped_instance(sdata_t *sdata, const int64_t id) -{ - stratum_instance_t *client, *tmp; - bool ret = false; - - HASH_ITER(hh, sdata->disconnected_instances, client, tmp) { - if (unlikely(client->id == id)) { - ret = true; - goto out; - } - } -out: - return ret; -} - -/* Ret = 1 is disconnected, 2 is killed, 3 is workerless killed */ static void __drop_client(sdata_t *sdata, stratum_instance_t *client, user_instance_t *user, bool lazily, char **msg) { - stratum_instance_t *old_client = NULL; __del_client(sdata, client, user); - HASH_FIND(hh, sdata->disconnected_instances, &client->enonce1_64, sizeof(uint64_t), old_client); - /* Only keep around one copy of the old client in server mode */ - if (!client->ckp->proxy && !old_client && client->enonce1_64 && client->authorised) { - ASPRINTF(msg, "Client %"PRId64" %s %suser %s worker %s disconnected %s", - client->id, client->address, user->throttled ? "throttled " : "", - user->username, client->workername, lazily ? "lazily" : ""); - HASH_ADD(hh, sdata->disconnected_instances, enonce1_64, sizeof(uint64_t), client); - sdata->stats.disconnected++; - sdata->disconnected_generated++; - client->disconnected_time = time(NULL); - } else { - if (client->workername) { - if (user) { - ASPRINTF(msg, "Client %"PRId64" %s %suser %s worker %s dropped %s", - client->id, client->address, user->throttled ? "throttled " : "", - user->username, client->workername, lazily ? "lazily" : ""); - } else { - ASPRINTF(msg, "Client %"PRId64" %s no user worker %s dropped %s", - client->id, client->address, client->workername, - lazily ? "lazily" : ""); - } + if (client->workername) { + if (user) { + ASPRINTF(msg, "Client %"PRId64" %s %suser %s worker %s dropped %s", + client->id, client->address, user->throttled ? "throttled " : "", + user->username, client->workername, lazily ? "lazily" : ""); } else { - ASPRINTF(msg, "Workerless client %"PRId64" %s dropped %s", - client->id, client->address, lazily ? "lazily" : ""); + ASPRINTF(msg, "Client %"PRId64" %s no user worker %s dropped %s", + client->id, client->address, client->workername, + lazily ? "lazily" : ""); } - __kill_instance(sdata, client); + } else { + ASPRINTF(msg, "Workerless client %"PRId64" %s dropped %s", + client->id, client->address, lazily ? "lazily" : ""); } + __kill_instance(sdata, client); } /* Decrease the reference count of instance. */ @@ -1326,6 +1323,7 @@ static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, const int64_t i client = __recruit_stratum_instance(sdata); client->id = id; + client->session_id = ++sdata->session_id; strcpy(client->address, address); client->server = server; client->diff = client->old_diff = ckp->startdiff; @@ -1337,42 +1335,31 @@ static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, const int64_t i static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessionid, const int64_t id) { - stratum_instance_t *client, *tmp; - uint64_t enonce1_64 = 0, ret = 0; + int session_id, slen; + session_t *session; int64_t old_id = 0; - int slen; + uint64_t ret = 0; if (!sessionid) goto out; slen = strlen(sessionid) / 2; - if (slen < 1 || slen > 8) + if (slen < 1 || slen > 4) goto out; if (!validhex(sessionid)) goto out; - /* Number is in BE but we don't swap either of them */ - hex2bin(&enonce1_64, sessionid, slen); + sscanf(sessionid, "%x", &session_id); ck_wlock(&sdata->instance_lock); - HASH_ITER(hh, sdata->stratum_instances, client, tmp) { - if (client->id == id) - continue; - if (client->enonce1_64 == enonce1_64) { - /* Only allow one connected instance per enonce1 */ - goto out_unlock; - } - } - client = NULL; - HASH_FIND(hh, sdata->disconnected_instances, &enonce1_64, sizeof(uint64_t), client); - if (client) { - /* Delete the entry once we are going to use it since there - * will be a new instance with the enonce1_64 */ - old_id = client->id; - __del_disconnected(sdata, client); - - ret = enonce1_64; - } + HASH_FIND_INT(sdata->disconnected_sessions, &session_id, session); + if (!session) + goto out_unlock; + HASH_DEL(sdata->disconnected_sessions, session); + sdata->stats.disconnected--; + ret = session->enonce1_64; + old_id = session->client_id; + dealloc(session); out_unlock: ck_wunlock(&sdata->instance_lock); out: @@ -1444,11 +1431,9 @@ static void stratum_add_send(sdata_t *sdata, json_t *val, const int64_t client_i static void drop_client(sdata_t *sdata, const int64_t id) { - stratum_instance_t *client, *tmp; char_entry_t *entries = NULL; user_instance_t *user = NULL; - time_t now_t = time(NULL); - int aged = 0; + stratum_instance_t *client; char *msg; LOGINFO("Stratifier asked to drop client %"PRId64, id); @@ -1456,6 +1441,7 @@ static void drop_client(sdata_t *sdata, const int64_t id) ck_wlock(&sdata->instance_lock); client = __instance_by_id(sdata, id); if (client && !client->dropped) { + __disconnect_session(sdata, client); user = client->user_instance; /* If the client is still holding a reference, don't drop them * now but wait till the reference is dropped */ @@ -1465,21 +1451,9 @@ static void drop_client(sdata_t *sdata, const int64_t id) } else client->dropped = true; } - - /* Old disconnected instances will not have any valid shares so remove - * them from the disconnected instances list if they've been dead for - * more than 10 minutes */ - HASH_ITER(hh, sdata->disconnected_instances, client, tmp) { - if (now_t - client->disconnected_time < 600) - continue; - aged++; - __del_disconnected(sdata, client); - } ck_wunlock(&sdata->instance_lock); notice_msg_entries(&entries); - if (aged) - LOGINFO("Aged %d disconnected instances to dead", aged); } static void stratum_broadcast_message(sdata_t *sdata, const char *msg) @@ -1696,7 +1670,8 @@ static char *stratifier_stats(ckpool_t *ckp, sdata_t *sdata) objects = sdata->stats.disconnected; generated = sdata->disconnected_generated; - memsize = sizeof(stratum_instance_t) * sdata->stats.disconnected; + memsize = SAFE_HASH_OVERHEAD(sdata->disconnected_sessions); + memsize += sizeof(session_t) * sdata->stats.disconnected; JSON_CPACK(subval, "{si,si,si}", "count", objects, "memory", memsize, "generated", generated); json_set_object(val, "disconnected", subval); ck_runlock(&sdata->instance_lock); @@ -1978,6 +1953,7 @@ static json_t *parse_subscribe(stratum_instance_t *client, const int64_t client_ { sdata_t *sdata = client->ckp->data; bool old_match = false; + char sessionid[12]; int arr_size; json_t *ret; int n2len; @@ -2039,7 +2015,8 @@ static json_t *parse_subscribe(stratum_instance_t *client, const int64_t client_ n2len = sdata->workbases->enonce2varlen; else n2len = 8; - JSON_CPACK(ret, "[[[s,s]],s,i]", "mining.notify", client->enonce1, client->enonce1, + sprintf(sessionid, "%x", client->session_id); + JSON_CPACK(ret, "[[[s,s]],s,i]", "mining.notify", sessionid, client->enonce1, n2len); ck_runlock(&sdata->workbase_lock); @@ -3572,11 +3549,8 @@ static void srecv_process(ckpool_t *ckp, char *buf) client = __instance_by_id(sdata, msg->client_id); /* If client_id instance doesn't exist yet, create one */ if (unlikely(!client)) { - if (likely(!__dropped_instance(sdata, msg->client_id))) { - noid = true; - client = __stratum_add_instance(ckp, msg->client_id, address, server); - } else - dropped = true; + noid = true; + client = __stratum_add_instance(ckp, msg->client_id, address, server); } else if (unlikely(client->dropped)) dropped = true; if (likely(!dropped)) From 08622a4b617324b99c4785d56d867e4850fe0179 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 21 Mar 2015 11:56:01 +1100 Subject: [PATCH 2/4] Hand old sessionid to new client --- src/stratifier.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index fc3fa50d..5904b56a 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1333,12 +1333,13 @@ static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, const int64_t i return client; } -static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessionid, const int64_t id) +static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessionid, + int *session_id, const int64_t id) { - int session_id, slen; session_t *session; int64_t old_id = 0; uint64_t ret = 0; + int slen; if (!sessionid) goto out; @@ -1349,10 +1350,11 @@ static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessio if (!validhex(sessionid)) goto out; - sscanf(sessionid, "%x", &session_id); + sscanf(sessionid, "%x", session_id); + LOGDEBUG("Testing for sessionid %s %x", sessionid, *session_id); ck_wlock(&sdata->instance_lock); - HASH_FIND_INT(sdata->disconnected_sessions, &session_id, session); + HASH_FIND_INT(sdata->disconnected_sessions, session_id, session); if (!session) goto out_unlock; HASH_DEL(sdata->disconnected_sessions, session); @@ -1983,9 +1985,9 @@ static json_t *parse_subscribe(stratum_instance_t *client, const int64_t client_ /* This would be the session id for reconnect, it will * not work for clients on a proxied connection. */ buf = json_string_value(json_array_get(params_val, 1)); - LOGDEBUG("Found old session id %s", buf); + LOGWARNING("Found old session id %s", buf); /* Add matching here */ - if ((client->enonce1_64 = disconnected_sessionid_exists(sdata, buf, client_id))) { + if ((client->enonce1_64 = disconnected_sessionid_exists(sdata, buf, &client->session_id, client_id))) { sprintf(client->enonce1, "%016lx", client->enonce1_64); old_match = true; @@ -2015,7 +2017,7 @@ static json_t *parse_subscribe(stratum_instance_t *client, const int64_t client_ n2len = sdata->workbases->enonce2varlen; else n2len = 8; - sprintf(sessionid, "%x", client->session_id); + sprintf(sessionid, "%08x", client->session_id); JSON_CPACK(ret, "[[[s,s]],s,i]", "mining.notify", sessionid, client->enonce1, n2len); ck_runlock(&sdata->workbase_lock); From 6e41ff823f0f8ee897a9c4a64ba4e1419d4088cf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 21 Mar 2015 11:58:16 +1100 Subject: [PATCH 3/4] Demote debug --- src/stratifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stratifier.c b/src/stratifier.c index 5904b56a..35eba5bb 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1985,7 +1985,7 @@ static json_t *parse_subscribe(stratum_instance_t *client, const int64_t client_ /* This would be the session id for reconnect, it will * not work for clients on a proxied connection. */ buf = json_string_value(json_array_get(params_val, 1)); - LOGWARNING("Found old session id %s", buf); + LOGDEBUG("Found old session id %s", buf); /* Add matching here */ if ((client->enonce1_64 = disconnected_sessionid_exists(sdata, buf, &client->session_id, client_id))) { sprintf(client->enonce1, "%016lx", client->enonce1_64); From a8b7916829a55fff021e39fca8760a57e11b48b1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 21 Mar 2015 12:23:12 +1100 Subject: [PATCH 4/4] Fix memory leak --- src/stratifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stratifier.c b/src/stratifier.c index 35eba5bb..0562741a 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -4158,6 +4158,7 @@ static void *statsupdate(void *arg) char_t = ckalloc(sizeof(char_entry_t)); s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); ASPRINTF(&char_t->buf, "User %s:%s", user->username, s); + dealloc(s); DL_APPEND(char_list, char_t); } json_decref(val);