Browse Source

Merge branch 'master' of bitbucket.org:ckolivas/ckpool

master
Con Kolivas 10 years ago
parent
commit
6bedd54fed
  1. 218
      src/ckdb.c

218
src/ckdb.c

@ -49,7 +49,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "0.9.2" #define DB_VERSION "0.9.2"
#define CKDB_VERSION DB_VERSION"-0.302" #define CKDB_VERSION DB_VERSION"-0.303"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -802,6 +802,7 @@ enum cmd_values {
CMD_HOMEPAGE, CMD_HOMEPAGE,
CMD_GETATTS, CMD_GETATTS,
CMD_SETATTS, CMD_SETATTS,
CMD_EXPATTS,
CMD_DSP, CMD_DSP,
CMD_STATS, CMD_STATS,
CMD_PPLNS, CMD_PPLNS,
@ -3343,6 +3344,74 @@ unitem:
return NULL; return NULL;
} }
static bool useratts_item_expire(PGconn *conn, K_ITEM *ua_item, tv_t *cd)
{
ExecStatusType rescode;
bool conned = false;
K_TREE_CTX ctx[1];
PGresult *res;
K_ITEM *item;
USERATTS *useratts;
char *upd;
bool ok = false;
char *params[4 + HISTORYDATECOUNT];
int n, par = 0;
LOGDEBUG("%s(): add", __func__);
DATA_USERATTS(useratts, ua_item);
/* This is pointless if ua_item is part of the tree, however,
* it allows for if ua_item isn't already part of the tree */
K_RLOCK(useratts_free);
item = find_useratts(useratts->userid, useratts->attname);
K_RUNLOCK(useratts_free);
if (item) {
DATA_USERATTS(useratts, item);
if (!conn) {
conn = dbconnect();
conned = true;
}
upd = "update useratts set expirydate=$1 where userid=$2 and "
"attname=$3 and expirydate=$4";
par = 0;
params[par++] = tv_to_buf(cd, NULL, 0);
params[par++] = bigint_to_buf(useratts->userid, NULL, 0);
params[par++] = str_to_buf(useratts->attname, NULL, 0);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
PARCHKVAL(par, 4, params);
res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res);
if (!PGOK(rescode)) {
PGLOGERR("Update", rescode, conn);
goto unparam;
}
}
ok = true;
unparam:
if (par) {
PQclear(res);
if (conned)
PQfinish(conn);
for (n = 0; n < par; n++)
free(params[n]);
}
K_WLOCK(useratts_free);
if (ok && item) {
useratts_root = remove_from_ktree(useratts_root, item, cmp_useratts, ctx);
copy_tv(&(useratts->expirydate), cd);
useratts_root = add_to_ktree(useratts_root, item, cmp_useratts);
}
K_WUNLOCK(useratts_free);
return ok;
}
static bool useratts_fill(PGconn *conn) static bool useratts_fill(PGconn *conn)
{ {
ExecStatusType rescode; ExecStatusType rescode;
@ -10261,6 +10330,15 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id,
return buf; return buf;
} }
/* Return the list of useratts for the given username=value
* Format is attlist=attname.element,attname.element,...
* Replies will be attname.element=value
* The 2 date fields, date and date2, have a secondary element name
* dateexp and date2exp
* This will return Y or N depending upon if the date has expired as:
* attname.dateexp=N (or Y) and attname.date2exp=N (or Y)
* Expired means the date is <= now
*/
static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id, static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
tv_t *now, __maybe_unused char *by, tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet, __maybe_unused char *code, __maybe_unused char *inet,
@ -10274,7 +10352,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
USERS *users; USERS *users;
char *reason = NULL; char *reason = NULL;
char *answer = NULL; char *answer = NULL;
char *ptr, *comma, *dot; char *attlist = NULL, *ptr, *comma, *dot;
size_t len, off; size_t len, off;
bool first; bool first;
@ -10302,7 +10380,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
} }
APPEND_REALLOC_INIT(answer, off, len); APPEND_REALLOC_INIT(answer, off, len);
ptr = strdup(transfer_data(i_attlist)); attlist = ptr = strdup(transfer_data(i_attlist));
first = true; first = true;
while (ptr && *ptr) { while (ptr && *ptr) {
comma = strchr(ptr, ','); comma = strchr(ptr, ',');
@ -10310,7 +10388,6 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
*(comma++) = '\0'; *(comma++) = '\0';
dot = strchr(ptr, '.'); dot = strchr(ptr, '.');
if (!dot) { if (!dot) {
free(answer);
reason = "Missing element"; reason = "Missing element";
goto nuts; goto nuts;
} }
@ -10346,7 +10423,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
sizeof(num_buf)); sizeof(num_buf));
ans = ctv_buf; ans = ctv_buf;
} else if (strcmp(dot, "dateexp") == 0) { } else if (strcmp(dot, "dateexp") == 0) {
// Y/N if date is before now (not expired) // Y/N if date is <= now (expired)
if (tv_newer(&(useratts->attdate), now)) if (tv_newer(&(useratts->attdate), now))
ans = TRUE_STR; ans = TRUE_STR;
else else
@ -10357,13 +10434,12 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
sizeof(num_buf)); sizeof(num_buf));
ans = ctv_buf; ans = ctv_buf;
} else if (strcmp(dot, "date2exp") == 0) { } else if (strcmp(dot, "date2exp") == 0) {
// Y/N if date2 is before now (not expired) // Y/N if date2 is <= now (expired)
if (tv_newer(&(useratts->attdate2), now)) if (tv_newer(&(useratts->attdate2), now))
ans = TRUE_STR; ans = TRUE_STR;
else else
ans = FALSE_STR; ans = FALSE_STR;
} else { } else {
free(answer);
reason = "Unknown element"; reason = "Unknown element";
goto nuts; goto nuts;
} }
@ -10377,7 +10453,12 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
} }
} }
nuts: nuts:
if (attlist)
free(attlist);
if (reason) { if (reason) {
if (answer)
free(answer);
snprintf(reply, siz, "ERR.%s", reason); snprintf(reply, siz, "ERR.%s", reason);
LOGERR("%s.%s.%s", cmd, id, reply); LOGERR("%s.%s.%s", cmd, id, reply);
return strdup(reply); return strdup(reply);
@ -10403,6 +10484,21 @@ static void att_to_date(tv_t *date, char *data, tv_t *now)
} }
} }
/* Store useratts in the DB for the given username=value
* Format is 1 or more: ua_attname.element=value
* i.e. each starts with the constant "ua_"
* attname cannot contain Tab . or =
* element is per the coded list below, which also cannot contain Tab . or =
* Any matching useratts attnames found currently in the DB are expired
* Transfer will sort them so that any of the same attname
* will be next to each other
* thus will combine multiple elements for the same attname
* into one single useratts record (as is mandatory)
* The 2 date fields date and date2 require either epoch values sec,usec
* (usec is optional and defaults to 0) or one of: now or now+NNN
* now is the current epoch value and now+NNN is the epoch + NNN seconds
* See att_to_date() above
* */
static char *cmd_setatts(PGconn *conn, char *cmd, char *id, static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
tv_t *now, char *by, char *code, char *inet, tv_t *now, char *by, char *code, char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root) __maybe_unused tv_t *notcd, K_TREE *trf_root)
@ -10421,6 +10517,7 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
char *reason = NULL; char *reason = NULL;
char *dot, *data; char *dot, *data;
bool begun = false; bool begun = false;
int set = 0, db = 0;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@ -10439,12 +10536,6 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
goto bats; goto bats;
} else { } else {
DATA_USERS(users, u_item); DATA_USERS(users, u_item);
/* format is: ua_attname.element=value
* i.e. eash starts with the constant "ua_"
* transfer will sort them so that any of the same attname
* will be next to each other
* thus can combine multiple elements for the same attname
* into one single useratts record (as is mandatory) */
t_item = first_in_ktree(trf_root, ctx); t_item = first_in_ktree(trf_root, ctx);
while (t_item) { while (t_item) {
DATA_TRANSFER(transfer, t_item); DATA_TRANSFER(transfer, t_item);
@ -10475,9 +10566,10 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
} }
begun = true; begun = true;
} }
if (useratts_item_add(conn, ua_item, now, begun)) if (useratts_item_add(conn, ua_item, now, begun)) {
ua_item = NULL; ua_item = NULL;
else { db++;
} else {
res = PQexec(conn, "Rollback", CKPQ_WRITE); res = PQexec(conn, "Rollback", CKPQ_WRITE);
PQclear(res); PQclear(res);
reason = "DBERR"; reason = "DBERR";
@ -10495,18 +10587,25 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
HISTORYDATEINIT(useratts, now, by, code, inet); HISTORYDATEINIT(useratts, now, by, code, inet);
HISTORYDATETRANSFER(trf_root, useratts); HISTORYDATETRANSFER(trf_root, useratts);
} }
// List of valid element names for storage
if (strcmp(dot, "str") == 0) { if (strcmp(dot, "str") == 0) {
STRNCPY(useratts->attstr, data); STRNCPY(useratts->attstr, data);
set++;
} else if (strcmp(dot, "str2") == 0) { } else if (strcmp(dot, "str2") == 0) {
STRNCPY(useratts->attstr2, data); STRNCPY(useratts->attstr2, data);
set++;
} else if (strcmp(dot, "num") == 0) { } else if (strcmp(dot, "num") == 0) {
TXT_TO_BIGINT("num", data, useratts->attnum); TXT_TO_BIGINT("num", data, useratts->attnum);
set++;
} else if (strcmp(dot, "num2") == 0) { } else if (strcmp(dot, "num2") == 0) {
TXT_TO_BIGINT("num2", data, useratts->attnum2); TXT_TO_BIGINT("num2", data, useratts->attnum2);
set++;
} else if (strcmp(dot, "date") == 0) { } else if (strcmp(dot, "date") == 0) {
att_to_date(&(useratts->attdate), data, now); att_to_date(&(useratts->attdate), data, now);
set++;
} else if (strcmp(dot, "date2") == 0) { } else if (strcmp(dot, "date2") == 0) {
att_to_date(&(useratts->attdate2), data, now); att_to_date(&(useratts->attdate2), data, now);
set++;
} else { } else {
reason = "Unknown element"; reason = "Unknown element";
goto bats; goto bats;
@ -10537,6 +10636,7 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
reason = "DBERR"; reason = "DBERR";
goto bats; goto bats;
} }
db++;
res = PQexec(conn, "Commit", CKPQ_WRITE); res = PQexec(conn, "Commit", CKPQ_WRITE);
PQclear(res); PQclear(res);
} }
@ -10554,11 +10654,94 @@ bats:
LOGERR("%s.%s.%s", cmd, id, reply); LOGERR("%s.%s.%s", cmd, id, reply);
return strdup(reply); return strdup(reply);
} }
snprintf(reply, siz, "ok.set"); snprintf(reply, siz, "ok.set %d,%d", db, set);
LOGDEBUG("%s.%s", id, reply); LOGDEBUG("%s.%s", id, reply);
return strdup(reply); return strdup(reply);
} }
/* Expire the list of useratts for the given username=value
* Format is attlist=attname,attname,...
* Each matching DB attname record will have it's expirydate set to now
* thus an attempt to access it with getatts will not find it and
* return nothing for that attname
*/
static char *cmd_expatts(__maybe_unused PGconn *conn, char *cmd, char *id,
tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root)
{
K_ITEM *i_username, *i_attlist, *u_item, *ua_item;
char reply[1024] = "";
size_t siz = sizeof(reply);
USERATTS *useratts;
USERS *users;
char *reason = NULL;
char *attlist, *ptr, *comma;
int db = 0, mis = 0;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz);
if (!i_username) {
reason = "Missing username";
goto rats;
}
K_RLOCK(users_free);
u_item = find_users(transfer_data(i_username));
K_RUNLOCK(users_free);
if (!u_item) {
reason = "Unknown user";
goto rats;
} else {
DATA_USERS(users, u_item);
i_attlist = require_name(trf_root, "attlist", 1, NULL, reply, siz);
if (!i_attlist) {
reason = "Missing attlist";
goto rats;
}
attlist = ptr = strdup(transfer_data(i_attlist));
while (ptr && *ptr) {
comma = strchr(ptr, ',');
if (comma)
*(comma++) = '\0';
K_RLOCK(useratts_free);
ua_item = find_useratts(users->userid, ptr);
K_RUNLOCK(useratts_free);
if (!ua_item)
mis++;
else {
DATA_USERATTS(useratts, ua_item);
HISTORYDATEINIT(useratts, now, by, code, inet);
HISTORYDATETRANSFER(trf_root, useratts);
/* Since we are expiring records, don't bother
* with combining them all into a single
* transaction and don't abort on error
* Thus if an error is returned, retry would be
* necessary, but some may also have been
* expired successfully */
if (!useratts_item_expire(conn, ua_item, now))
reason = "DBERR";
else
db++;
}
ptr = comma;
}
free(attlist);
}
rats:
if (reason) {
snprintf(reply, siz, "ERR.%s", reason);
LOGERR("%s.%s.%s", cmd, id, reply);
return strdup(reply);
}
snprintf(reply, siz, "ok.exp %d,%d", db, mis);
LOGDEBUG("%s.%s.%s", cmd, id, reply);
return strdup(reply);
}
// order by userid asc // order by userid asc
static cmp_t cmp_mu(K_ITEM *a, K_ITEM *b) static cmp_t cmp_mu(K_ITEM *a, K_ITEM *b)
{ {
@ -11143,6 +11326,7 @@ static struct CMDS {
{ CMD_HOMEPAGE, "homepage", false, false, cmd_homepage, ACCESS_WEB }, { CMD_HOMEPAGE, "homepage", false, false, cmd_homepage, ACCESS_WEB },
{ CMD_GETATTS, "getatts", false, false, cmd_getatts, ACCESS_WEB }, { CMD_GETATTS, "getatts", false, false, cmd_getatts, ACCESS_WEB },
{ CMD_SETATTS, "setatts", false, false, cmd_setatts, ACCESS_WEB }, { CMD_SETATTS, "setatts", false, false, cmd_setatts, ACCESS_WEB },
{ CMD_EXPATTS, "expatts", false, false, cmd_expatts, ACCESS_WEB },
{ CMD_DSP, "dsp", false, false, cmd_dsp, ACCESS_SYSTEM }, { CMD_DSP, "dsp", false, false, cmd_dsp, ACCESS_SYSTEM },
{ CMD_STATS, "stats", true, false, cmd_stats, ACCESS_SYSTEM }, { CMD_STATS, "stats", true, false, cmd_stats, ACCESS_SYSTEM },
{ CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM }, { CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM },
@ -11994,6 +12178,7 @@ static void *socketer(__maybe_unused void *arg)
case CMD_USERSET: case CMD_USERSET:
case CMD_GETATTS: case CMD_GETATTS:
case CMD_SETATTS: case CMD_SETATTS:
case CMD_EXPATTS:
case CMD_BLOCKLIST: case CMD_BLOCKLIST:
case CMD_NEWID: case CMD_NEWID:
case CMD_STATS: case CMD_STATS:
@ -12230,6 +12415,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
case CMD_HOMEPAGE: case CMD_HOMEPAGE:
case CMD_GETATTS: case CMD_GETATTS:
case CMD_SETATTS: case CMD_SETATTS:
case CMD_EXPATTS:
case CMD_DSP: case CMD_DSP:
case CMD_STATS: case CMD_STATS:
case CMD_PPLNS: case CMD_PPLNS:

Loading…
Cancel
Save