|
|
@ -244,6 +244,7 @@ struct stratum_instance { |
|
|
|
char address[INET6_ADDRSTRLEN]; |
|
|
|
char address[INET6_ADDRSTRLEN]; |
|
|
|
bool subscribed; |
|
|
|
bool subscribed; |
|
|
|
bool authorised; |
|
|
|
bool authorised; |
|
|
|
|
|
|
|
bool dropped; |
|
|
|
bool idle; |
|
|
|
bool idle; |
|
|
|
int reject; /* Indicator that this client is having a run of rejects
|
|
|
|
int reject; /* Indicator that this client is having a run of rejects
|
|
|
|
* or other problem and should be dropped lazily if |
|
|
|
* or other problem and should be dropped lazily if |
|
|
@ -285,6 +286,8 @@ struct stratifier_data { |
|
|
|
/* Serialises sends/receives to ckdb if possible */ |
|
|
|
/* Serialises sends/receives to ckdb if possible */ |
|
|
|
pthread_mutex_t ckdb_lock; |
|
|
|
pthread_mutex_t ckdb_lock; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool ckdb_offline; |
|
|
|
|
|
|
|
|
|
|
|
/* Variable length enonce1 always refers back to a u64 */ |
|
|
|
/* Variable length enonce1 always refers back to a u64 */ |
|
|
|
union { |
|
|
|
union { |
|
|
|
uint64_t u64; |
|
|
|
uint64_t u64; |
|
|
@ -1103,19 +1106,50 @@ static stratum_instance_t *ref_instance_by_id(sdata_t *sdata, int64_t id) |
|
|
|
return instance; |
|
|
|
return instance; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Decrease the reference count of instance. */ |
|
|
|
static void __drop_client(sdata_t *sdata, stratum_instance_t *client, user_instance_t *instance, |
|
|
|
static void __dec_instance_ref(stratum_instance_t *instance) |
|
|
|
int64_t id) |
|
|
|
{ |
|
|
|
{ |
|
|
|
instance->ref--; |
|
|
|
stratum_instance_t *old_client = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HASH_DEL(sdata->stratum_instances, client); |
|
|
|
|
|
|
|
if (instance) |
|
|
|
|
|
|
|
DL_DELETE(instance->instances, client); |
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
LOGNOTICE("Disconnecting client %ld %s %s", id, client->workername, |
|
|
|
|
|
|
|
client->dropped ? "lazily" : ""); |
|
|
|
|
|
|
|
HASH_ADD(hh, sdata->disconnected_instances, enonce1_64, sizeof(uint64_t), client); |
|
|
|
|
|
|
|
sdata->stats.disconnected++; |
|
|
|
|
|
|
|
client->disconnected_time = time(NULL); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (client->workername) |
|
|
|
|
|
|
|
LOGNOTICE("Dropping client %ld %s %s", id, client->workername, |
|
|
|
|
|
|
|
client->dropped ? "lazily" : ""); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
LOGINFO("Dropping workerless client %ld %s", id, client->dropped ? "lazily" : ""); |
|
|
|
|
|
|
|
__add_dead(sdata, client); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void dec_instance_ref(sdata_t *sdata, stratum_instance_t *instance) |
|
|
|
/* Decrease the reference count of instance. */ |
|
|
|
|
|
|
|
static void _dec_instance_ref(sdata_t *sdata, stratum_instance_t *instance, const char *file, |
|
|
|
|
|
|
|
const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ck_wlock(&sdata->instance_lock); |
|
|
|
ck_wlock(&sdata->instance_lock); |
|
|
|
__dec_instance_ref(instance); |
|
|
|
if (unlikely(--instance->ref < 0)) { |
|
|
|
|
|
|
|
LOGERR("Instance ref count dropped below zero from %s %s:%d", file, func, line); |
|
|
|
|
|
|
|
instance->ref = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* See if there are any instances that were dropped that could not be
|
|
|
|
|
|
|
|
* moved due to holding a reference and drop them now. */ |
|
|
|
|
|
|
|
if (unlikely(instance->dropped && !instance->ref)) |
|
|
|
|
|
|
|
__drop_client(sdata, instance, instance->user_instance, instance->id); |
|
|
|
ck_wunlock(&sdata->instance_lock); |
|
|
|
ck_wunlock(&sdata->instance_lock); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define dec_instance_ref(sdata, instance) _dec_instance_ref(sdata, instance, __FILE__, __func__, __LINE__) |
|
|
|
|
|
|
|
|
|
|
|
/* Enter with write instance_lock held */ |
|
|
|
/* Enter with write instance_lock held */ |
|
|
|
static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, int64_t id, int server) |
|
|
|
static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, int64_t id, int server) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -1260,33 +1294,18 @@ static void drop_client(sdata_t *sdata, int64_t id) |
|
|
|
|
|
|
|
|
|
|
|
ck_wlock(&sdata->instance_lock); |
|
|
|
ck_wlock(&sdata->instance_lock); |
|
|
|
client = __instance_by_id(sdata, id); |
|
|
|
client = __instance_by_id(sdata, id); |
|
|
|
if (client && likely(!client->ref)) { |
|
|
|
if (client) { |
|
|
|
stratum_instance_t *old_client = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instance = client->user_instance; |
|
|
|
instance = client->user_instance; |
|
|
|
if (client->authorised) { |
|
|
|
if (client->authorised) { |
|
|
|
dec = true; |
|
|
|
dec = true; |
|
|
|
client->authorised = false; |
|
|
|
|
|
|
|
ckp = client->ckp; |
|
|
|
ckp = client->ckp; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* If the client is still holding a reference, don't drop them
|
|
|
|
HASH_DEL(sdata->stratum_instances, client); |
|
|
|
* now but wait till the reference is dropped */ |
|
|
|
if (instance) |
|
|
|
if (likely(!client->ref)) |
|
|
|
DL_DELETE(instance->instances, client); |
|
|
|
__drop_client(sdata, client, instance, id); |
|
|
|
HASH_FIND(hh, sdata->disconnected_instances, &client->enonce1_64, sizeof(uint64_t), old_client); |
|
|
|
else |
|
|
|
/* Only keep around one copy of the old client in server mode */ |
|
|
|
client->dropped = true; |
|
|
|
if (!client->ckp->proxy && !old_client && client->enonce1_64 && dec) { |
|
|
|
|
|
|
|
LOGNOTICE("Disconnecting client %ld %s", client->id, client->workername); |
|
|
|
|
|
|
|
HASH_ADD(hh, sdata->disconnected_instances, enonce1_64, sizeof(uint64_t), client); |
|
|
|
|
|
|
|
sdata->stats.disconnected++; |
|
|
|
|
|
|
|
client->disconnected_time = time(NULL); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (client->workername) |
|
|
|
|
|
|
|
LOGNOTICE("Dropping client %ld %s", client->id, client->workername); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
LOGINFO("Dropping workerless client %ld", client->id); |
|
|
|
|
|
|
|
__add_dead(sdata, client); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Old disconnected instances will not have any valid shares so remove
|
|
|
|
/* Old disconnected instances will not have any valid shares so remove
|
|
|
@ -3309,9 +3328,33 @@ static void parse_ckdb_cmd(ckpool_t __maybe_unused *ckp, const char *cmd) |
|
|
|
json_decref(val); |
|
|
|
json_decref(val); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Test a value under lock and set it, returning the original value */ |
|
|
|
|
|
|
|
static bool test_and_set(bool *val, pthread_mutex_t *lock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bool ret; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutex_lock(lock); |
|
|
|
|
|
|
|
ret = *val; |
|
|
|
|
|
|
|
*val = true; |
|
|
|
|
|
|
|
mutex_unlock(lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool test_and_clear(bool *val, pthread_mutex_t *lock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bool ret; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutex_lock(lock); |
|
|
|
|
|
|
|
ret = *val; |
|
|
|
|
|
|
|
*val = false; |
|
|
|
|
|
|
|
mutex_unlock(lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void ckdbq_process(ckpool_t *ckp, char *msg) |
|
|
|
static void ckdbq_process(ckpool_t *ckp, char *msg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
static bool failed = false; |
|
|
|
|
|
|
|
sdata_t *sdata = ckp->data; |
|
|
|
sdata_t *sdata = ckp->data; |
|
|
|
char *buf = NULL; |
|
|
|
char *buf = NULL; |
|
|
|
|
|
|
|
|
|
|
@ -3321,18 +3364,15 @@ static void ckdbq_process(ckpool_t *ckp, char *msg) |
|
|
|
mutex_unlock(&sdata->ckdb_lock); |
|
|
|
mutex_unlock(&sdata->ckdb_lock); |
|
|
|
|
|
|
|
|
|
|
|
if (unlikely(!buf)) { |
|
|
|
if (unlikely(!buf)) { |
|
|
|
if (!failed) { |
|
|
|
if (!test_and_set(&sdata->ckdb_offline, &sdata->ckdb_lock)) |
|
|
|
failed = true; |
|
|
|
|
|
|
|
LOGWARNING("Failed to talk to ckdb, queueing messages"); |
|
|
|
LOGWARNING("Failed to talk to ckdb, queueing messages"); |
|
|
|
} |
|
|
|
|
|
|
|
sleep(5); |
|
|
|
sleep(5); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
free(msg); |
|
|
|
free(msg); |
|
|
|
if (failed) { |
|
|
|
if (test_and_clear(&sdata->ckdb_offline, &sdata->ckdb_lock)) |
|
|
|
failed = false; |
|
|
|
|
|
|
|
LOGWARNING("Successfully resumed talking to ckdb"); |
|
|
|
LOGWARNING("Successfully resumed talking to ckdb"); |
|
|
|
} |
|
|
|
|
|
|
|
/* TODO: Process any requests from ckdb that are heartbeat responses
|
|
|
|
/* TODO: Process any requests from ckdb that are heartbeat responses
|
|
|
|
* with specific requests. */ |
|
|
|
* with specific requests. */ |
|
|
|
if (likely(buf)) { |
|
|
|
if (likely(buf)) { |
|
|
@ -3467,6 +3507,11 @@ static void update_workerstats(ckpool_t *ckp, sdata_t *sdata) |
|
|
|
time_t now_t; |
|
|
|
time_t now_t; |
|
|
|
ts_t ts_now; |
|
|
|
ts_t ts_now; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sdata->ckdb_offline) { |
|
|
|
|
|
|
|
LOGDEBUG("Not queueing workerstats due to ckdb offline"); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (++sdata->stats.userstats_cycle > 0x1f) |
|
|
|
if (++sdata->stats.userstats_cycle > 0x1f) |
|
|
|
sdata->stats.userstats_cycle = 0; |
|
|
|
sdata->stats.userstats_cycle = 0; |
|
|
|
|
|
|
|
|
|
|
|