Browse Source

ckdb/php - add code for future support of multiple payout addresses per user

master
kanoi 10 years ago
parent
commit
4c75fe3a27
  1. 12
      pool/db.php
  2. 8
      pool/page_settings.php
  3. 11
      src/ckdb.h
  4. 130
      src/ckdb_cmd.c
  5. 35
      src/ckdb_data.c
  6. 226
      src/ckdb_dbio.c

12
pool/db.php

@ -180,7 +180,17 @@ function userSettings($user, $email = null, $addr = null, $pass = null)
$flds['email'] = $email; $flds['email'] = $email;
if ($addr != null) if ($addr != null)
{ {
$flds['address'] = $addr; $rows = count($addr);
$i = 0;
foreach ($addr as $ar)
{
$flds['address:'.$i] = $ar['addr'];
// optional - missing = use default
if (isset($ar['ratio']))
$flds['ratio:'.$i] = $ar['ratio'];
$i++;
}
$flds['rows'] = $rows;
$tmo = 3; # 3x the timeout $tmo = 3; # 3x the timeout
} }
if ($pass != null) if ($pass != null)

8
pool/page_settings.php

@ -102,8 +102,9 @@ function dosettings($data, $user)
break; break;
case 'Address': case 'Address':
$addr = getparam('baddr', false); $addr = getparam('baddr', false);
$addrarr = array(array('addr' => $addr));
$pass = getparam('pass', false); $pass = getparam('pass', false);
$ans = userSettings($user, null, $addr, $pass); $ans = userSettings($user, null, $addrarr, $pass);
$check = true; $check = true;
break; break;
case 'Password': case 'Password':
@ -139,8 +140,9 @@ function dosettings($data, $user)
$email = $ans['email']; $email = $ans['email'];
else else
$email = ''; $email = '';
if (isset($ans['addr'])) // Use the first one - updating will expire all others
$addr = $ans['addr']; if (isset($ans['rows']) and $ans['rows'] > 0)
$addr = $ans['addr:0'];
else else
$addr = ''; $addr = '';
$pg = settings($data, $user, $email, $addr, $err); $pg = settings($data, $user, $email, $addr, $err);

11
src/ckdb.h

@ -52,7 +52,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "0.9.6" #define DB_VERSION "0.9.6"
#define CKDB_VERSION DB_VERSION"-0.731" #define CKDB_VERSION DB_VERSION"-0.740"
#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__
@ -751,17 +751,21 @@ typedef struct paymentaddresses {
char payaddress[TXT_BIG+1]; char payaddress[TXT_BIG+1];
int32_t payratio; int32_t payratio;
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
bool match; // Non-db field
} PAYMENTADDRESSES; } PAYMENTADDRESSES;
#define ALLOC_PAYMENTADDRESSES 1024 #define ALLOC_PAYMENTADDRESSES 1024
#define LIMIT_PAYMENTADDRESSES 0 #define LIMIT_PAYMENTADDRESSES 0
#define INIT_PAYMENTADDRESSES(_item) INIT_GENERIC(_item, paymentaddresses) #define INIT_PAYMENTADDRESSES(_item) INIT_GENERIC(_item, paymentaddresses)
#define DATA_PAYMENTADDRESSES(_var, _item) DATA_GENERIC(_var, _item, paymentaddresses, true) #define DATA_PAYMENTADDRESSES(_var, _item) DATA_GENERIC(_var, _item, paymentaddresses, true)
#define DATA_PAYMENTADDRESSES_NULL(_var, _item) DATA_GENERIC(_var, _item, paymentaddresses, false)
extern K_TREE *paymentaddresses_root; extern K_TREE *paymentaddresses_root;
extern K_LIST *paymentaddresses_free; extern K_LIST *paymentaddresses_free;
extern K_STORE *paymentaddresses_store; extern K_STORE *paymentaddresses_store;
#define PAYRATIODEF 1000000
// PAYMENTS // PAYMENTS
typedef struct payments { typedef struct payments {
int64_t paymentid; int64_t paymentid;
@ -1553,7 +1557,8 @@ extern K_ITEM *new_default_worker(PGconn *conn, bool update, int64_t userid, cha
char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root); char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root);
extern void dsp_paymentaddresses(K_ITEM *item, FILE *stream); extern void dsp_paymentaddresses(K_ITEM *item, FILE *stream);
extern cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_paymentaddresses(int64_t userid); extern K_ITEM *find_paymentaddresses(int64_t userid, K_TREE_CTX *ctx);
extern K_ITEM *find_one_payaddress(int64_t userid, char *payaddress, K_TREE_CTX *ctx);
extern cmp_t cmp_payments(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_payments(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_optioncontrol(char *optionname, tv_t *now); extern K_ITEM *find_optioncontrol(char *optionname, tv_t *now);
@ -1695,7 +1700,7 @@ extern bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault,
char *idlenotificationtime, char *by, char *code, char *idlenotificationtime, char *by, char *code,
char *inet, tv_t *cd, K_TREE *trf_root, bool check); char *inet, tv_t *cd, K_TREE *trf_root, bool check);
extern bool workers_fill(PGconn *conn); extern bool workers_fill(PGconn *conn);
extern K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress, extern bool paymentaddresses_set(PGconn *conn, int64_t userid, K_LIST *pa_store,
char *by, char *code, char *inet, tv_t *cd, char *by, char *code, char *inet, tv_t *cd,
K_TREE *trf_root); K_TREE *trf_root);
extern bool paymentaddresses_fill(PGconn *conn); extern bool paymentaddresses_fill(PGconn *conn);

130
src/ckdb_cmd.c

@ -161,16 +161,21 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
__maybe_unused char *code, __maybe_unused char *inet, __maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root) __maybe_unused tv_t *notcd, K_TREE *trf_root)
{ {
K_ITEM *i_username, *i_passwordhash, *i_address, *i_email, *u_item, *pa_item; K_ITEM *i_username, *i_passwordhash, *i_rows, *i_address, *i_ratio;
char *email, *address; K_ITEM *i_email, *u_item, *pa_item;
char *email;
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
char tmp[1024]; char tmp[1024];
PAYMENTADDRESSES *paymentaddresses; PAYMENTADDRESSES *paymentaddresses;
K_STORE *pa_store = NULL;
K_TREE_CTX ctx[1];
USERS *users; USERS *users;
char *reason = NULL; char *reason = NULL;
char *answer = NULL; char *answer = NULL;
size_t len, off; size_t len, off;
int32_t ratio;
int rows, i;
bool ok; bool ok;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@ -206,18 +211,35 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
APPEND_REALLOC(answer, off, len, tmp); APPEND_REALLOC(answer, off, len, tmp);
K_RLOCK(paymentaddresses_free); K_RLOCK(paymentaddresses_free);
pa_item = find_paymentaddresses(users->userid); pa_item = find_paymentaddresses(users->userid, ctx);
K_RUNLOCK(paymentaddresses_free);
if (pa_item) { if (pa_item) {
DATA_PAYMENTADDRESSES(paymentaddresses, pa_item); DATA_PAYMENTADDRESSES(paymentaddresses, pa_item);
snprintf(tmp, sizeof(tmp), "addr=%s", while (pa_item && CURRENT(&(paymentaddresses->expirydate)) &&
paymentaddresses->payaddress); paymentaddresses->userid == users->userid) {
snprintf(tmp, sizeof(tmp), "addr:%d=%s%c",
rows, paymentaddresses->payaddress, FLDSEP);
APPEND_REALLOC(answer, off, len, tmp); APPEND_REALLOC(answer, off, len, tmp);
} else { snprintf(tmp, sizeof(tmp), "ratio:%d=%d%c",
snprintf(tmp, sizeof(tmp), "addr="); rows, paymentaddresses->payratio, FLDSEP);
APPEND_REALLOC(answer, off, len, tmp); APPEND_REALLOC(answer, off, len, tmp);
rows++;
pa_item = prev_in_ktree(ctx);
DATA_PAYMENTADDRESSES_NULL(paymentaddresses, pa_item);
}
K_RUNLOCK(paymentaddresses_free);
} else {
K_RUNLOCK(paymentaddresses_free);
rows = 0;
} }
snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c",
rows, FLDSEP,
"addr,ratio", FLDSEP);
APPEND_REALLOC(answer, off, len, tmp);
snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s",
"PaymentAddresses", FLDSEP, "");
APPEND_REALLOC(answer, off, len, tmp);
} else { } else {
if (!check_hash(users, transfer_data(i_passwordhash))) { if (!check_hash(users, transfer_data(i_passwordhash))) {
reason = "Incorrect password"; reason = "Incorrect password";
@ -235,30 +257,84 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
} }
email = NULL; email = NULL;
} }
i_address = optional_name(trf_root, "address",
// address rows
i_rows = optional_name(trf_root, "rows",
1, (char *)intpatt,
reply, siz);
if (!i_rows && *reply) {
// Exists, but invalid
reason = "System error";
goto struckout;
}
if (i_rows) {
rows = atoi(transfer_data(i_rows));
if (rows < 0) {
reason = "System error";
goto struckout;
}
if (rows > 0) {
pa_store = k_new_store(paymentaddresses_free);
K_WLOCK(paymentaddresses_free);
for (i = 0; i < rows; i++) {
snprintf(tmp, sizeof(tmp), "ratio:%d", i);
i_ratio = optional_name(trf_root, tmp,
1, (char *)intpatt,
reply, siz);
if (*reply) {
K_WUNLOCK(paymentaddresses_free);
reason = "Invalid ratio";
goto struckout;
}
if (i_ratio)
ratio = atoi(transfer_data(i_ratio));
else
ratio = PAYRATIODEF;
/* 0 = expire/remove the address
* intpatt means it will be >= 0 */
if (ratio == 0)
continue;
snprintf(tmp, sizeof(tmp), "address:%d", i);
i_address = require_name(trf_root, tmp,
ADDR_MIN_LEN, ADDR_MIN_LEN,
(char *)addrpatt, (char *)addrpatt,
reply, siz); reply, siz);
if (i_address) if (!i_address) {
address = transfer_data(i_address); K_WUNLOCK(paymentaddresses_free);
else {
if (*reply) {
reason = "Invalid address"; reason = "Invalid address";
goto struckout; goto struckout;
} }
address = NULL; pa_item = k_unlink_head(paymentaddresses_free);
DATA_PAYMENTADDRESSES(paymentaddresses, pa_item);
bzero(paymentaddresses, sizeof(*paymentaddresses));
STRNCPY(paymentaddresses->payaddress,
transfer_data(i_address));
paymentaddresses->payratio = ratio;
k_add_head(pa_store, pa_item);
}
K_WUNLOCK(paymentaddresses_free);
} }
}
/* If all addresses have a ratio of zero
* pa_store->count will be 0 */
if ((email == NULL || *email == '\0') && if ((email == NULL || *email == '\0') &&
(address == NULL || *address == '\0')) { (pa_store == NULL || pa_store->count == 0)) {
reason = "Missing/Invalid value"; reason = "Missing/Invalid value";
goto struckout; goto struckout;
} }
if (address && *address) { if (pa_store && pa_store->count > 0) {
if (!btc_valid_address(address)) { pa_item = pa_store->head;
while (pa_item) {
DATA_PAYMENTADDRESSES(paymentaddresses, pa_item);
if (!btc_valid_address(paymentaddresses->payaddress)) {
reason = "Invalid BTC address"; reason = "Invalid BTC address";
goto struckout; goto struckout;
} }
pa_item = pa_item->next;
}
} }
if (email && *email) { if (email && *email) {
@ -274,9 +350,9 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
} }
} }
if (address && *address) { if (pa_store && pa_store->count > 0) {
ok = paymentaddresses_set(conn, users->userid, ok = paymentaddresses_set(conn, users->userid,
address, by, pa_store, by,
code, inet, code, inet,
now, trf_root); now, trf_root);
if (!ok) { if (!ok) {
@ -289,6 +365,15 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
} }
struckout: struckout:
if (pa_store) {
if (pa_store->count) {
K_WLOCK(paymentaddresses_free);
k_list_transfer_to_head(pa_store, paymentaddresses_free);
K_WUNLOCK(paymentaddresses_free);
}
k_free_store(pa_store);
pa_store = NULL;
}
if (reason) { if (reason) {
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);
@ -2988,7 +3073,7 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
int64_t ss_count, wm_count, ms_count; int64_t ss_count, wm_count, ms_count;
char tv_buf[DATE_BUFSIZ]; char tv_buf[DATE_BUFSIZ];
tv_t cd, begin_tv, block_tv, end_tv; tv_t cd, begin_tv, block_tv, end_tv;
K_TREE_CTX ctx[1], wm_ctx[1], ms_ctx[1]; K_TREE_CTX ctx[1], wm_ctx[1], ms_ctx[1], pay_ctx[1];
double ndiff, total_diff, elapsed; double ndiff, total_diff, elapsed;
double diff_times = 1.0; double diff_times = 1.0;
double diff_add = 0.0; double diff_add = 0.0;
@ -3276,7 +3361,8 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
PAYMENTADDRESSES *pa; PAYMENTADDRESSES *pa;
char *payaddress; char *payaddress;
pa_item = find_paymentaddresses(miningpayouts->userid); // TODO: handle multiple addresses for one user
pa_item = find_paymentaddresses(miningpayouts->userid, pay_ctx);
if (pa_item) { if (pa_item) {
DATA_PAYMENTADDRESSES(pa, pa_item); DATA_PAYMENTADDRESSES(pa, pa_item);
payaddress = pa->payaddress; payaddress = pa->payaddress;

35
src/ckdb_data.c

@ -1108,35 +1108,37 @@ void dsp_paymentaddresses(K_ITEM *item, FILE *stream)
} }
} }
// order by userid asc,expirydate desc,payaddress asc // order by expirydate asc,userid asc,payaddress asc
cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b) cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b)
{ {
PAYMENTADDRESSES *pa, *pb; PAYMENTADDRESSES *pa, *pb;
DATA_PAYMENTADDRESSES(pa, a); DATA_PAYMENTADDRESSES(pa, a);
DATA_PAYMENTADDRESSES(pb, b); DATA_PAYMENTADDRESSES(pb, b);
cmp_t c = CMP_BIGINT(pa->userid, pb->userid); cmp_t c = CMP_TV(pa->expirydate, pb->expirydate);
if (c == 0) { if (c == 0) {
c = CMP_TV(pb->expirydate, pa->expirydate); c = CMP_BIGINT(pa->userid, pb->userid);
if (c == 0) if (c == 0)
c = CMP_STR(pa->payaddress, pb->payaddress); c = CMP_STR(pa->payaddress, pb->payaddress);
} }
return c; return c;
} }
// Only one for now ... /* Find the last CURRENT paymentaddresses for the given userid
K_ITEM *find_paymentaddresses(int64_t userid) * N.B. there can be more than one
* any more will be prev_in_ktree(ctx): CURRENT and userid matches */
K_ITEM *find_paymentaddresses(int64_t userid, K_TREE_CTX *ctx)
{ {
PAYMENTADDRESSES paymentaddresses, *pa; PAYMENTADDRESSES paymentaddresses, *pa;
K_TREE_CTX ctx[1];
K_ITEM look, *item; K_ITEM look, *item;
paymentaddresses.userid = userid; paymentaddresses.expirydate.tv_sec = default_expiry.tv_sec;
paymentaddresses.expirydate.tv_usec = default_expiry.tv_usec;
paymentaddresses.userid = userid+1;
paymentaddresses.payaddress[0] = '\0'; paymentaddresses.payaddress[0] = '\0';
paymentaddresses.expirydate.tv_sec = DATE_S_EOT;
INIT_PAYMENTADDRESSES(&look); INIT_PAYMENTADDRESSES(&look);
look.data = (void *)(&paymentaddresses); look.data = (void *)(&paymentaddresses);
item = find_after_in_ktree(paymentaddresses_root, &look, cmp_paymentaddresses, ctx); item = find_before_in_ktree(paymentaddresses_root, &look, cmp_paymentaddresses, ctx);
if (item) { if (item) {
DATA_PAYMENTADDRESSES(pa, item); DATA_PAYMENTADDRESSES(pa, item);
if (pa->userid == userid && CURRENT(&(pa->expirydate))) if (pa->userid == userid && CURRENT(&(pa->expirydate)))
@ -1147,6 +1149,21 @@ K_ITEM *find_paymentaddresses(int64_t userid)
return NULL; return NULL;
} }
K_ITEM *find_one_payaddress(int64_t userid, char *payaddress, K_TREE_CTX *ctx)
{
PAYMENTADDRESSES paymentaddresses;
K_ITEM look;
paymentaddresses.expirydate.tv_sec = default_expiry.tv_sec;
paymentaddresses.expirydate.tv_usec = default_expiry.tv_usec;
paymentaddresses.userid = userid;
STRNCPY(paymentaddresses.payaddress, payaddress);
INIT_PAYMENTADDRESSES(&look);
look.data = (void *)(&paymentaddresses);
return find_in_ktree(paymentaddresses_root, &look, cmp_paymentaddresses, ctx);
}
// order by userid asc,paydate asc,payaddress asc,expirydate desc // order by userid asc,paydate asc,payaddress asc,expirydate desc
cmp_t cmp_payments(K_ITEM *a, K_ITEM *b) cmp_t cmp_payments(K_ITEM *a, K_ITEM *b)
{ {

226
src/ckdb_dbio.c

@ -1427,10 +1427,10 @@ bool workers_fill(PGconn *conn)
return ok; return ok;
} }
/* Whatever the current paymentaddresses are, replace them with this one /* Whatever the current paymentaddresses are, replace them with the list
* Code allows for zero, one or more current payment address * in pa_store
* even though there currently can only be zero or one */ * Code allows for zero, one or more current payment address */
K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress, bool paymentaddresses_set(PGconn *conn, int64_t userid, K_STORE *pa_store,
char *by, char *code, char *inet, tv_t *cd, char *by, char *code, char *inet, tv_t *cd,
K_TREE *trf_root) K_TREE *trf_root)
{ {
@ -1438,45 +1438,33 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
bool conned = false; bool conned = false;
PGresult *res; PGresult *res;
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
K_ITEM *item, *old, *this, look; K_ITEM *item, *match, *next, *prev;
PAYMENTADDRESSES *row, pa, *thispa; PAYMENTADDRESSES *row, *pa;
char *upd, *ins; char *upd = NULL, *ins;
bool ok = false; size_t len, off;
char *params[4 + HISTORYDATECOUNT]; bool ok = false, first;
int n, par = 0; char *params[1002]; // Limit of 999 addresses per user
char tmp[1024];
int n, par = 0, count, matches;
LOGDEBUG("%s(): add", __func__); LOGDEBUG("%s(): add", __func__);
K_WLOCK(paymentaddresses_free); // Quick early abort
item = k_unlink_head(paymentaddresses_free); if (pa_store->count > 999)
K_WUNLOCK(paymentaddresses_free); return false;
DATA_PAYMENTADDRESSES(row, item);
row->paymentaddressid = nextid(conn, "paymentaddressid", 1,
cd, by, code, inet);
if (row->paymentaddressid == 0)
goto unitem;
row->userid = userid;
STRNCPY(row->payaddress, payaddress);
row->payratio = 1000000;
HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row);
upd = "update paymentaddresses set expirydate=$1 where userid=$2 and expirydate=$3"; /* Since we are merging the changes in rather than just
par = 0; * replacing the db contents, lock the data for the duration
params[par++] = tv_to_buf(cd, NULL, 0); * of the update to ensure nothing else changes it */
params[par++] = bigint_to_buf(row->userid, NULL, 0); K_WLOCK(paymentaddresses_free);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
PARCHKVAL(par, 3, params);
if (conn == NULL) { if (conn == NULL) {
conn = dbconnect(); conn = dbconnect();
conned = true; conned = true;
} }
/* This means the nextid updates will rollback on an error, but also
* means that it will lock the nextid record for the whole update */
res = PQexec(conn, "Begin", CKPQ_WRITE); res = PQexec(conn, "Begin", CKPQ_WRITE);
rescode = PQresultStatus(res); rescode = PQresultStatus(res);
if (!PGOK(rescode)) { if (!PGOK(rescode)) {
@ -1485,6 +1473,64 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
} }
PQclear(res); PQclear(res);
// First step - DB expire all the old/changed records in RAM
LOGDEBUG("%s(): Step 1 userid=%"PRId64, __func__, userid);
count = matches = 0;
APPEND_REALLOC_INIT(upd, off, len);
APPEND_REALLOC(upd, off, len,
"update paymentaddresses set expirydate=$1 where "
"userid=$2 and expirydate=$3 and payaddress in (");
par = 0;
params[par++] = tv_to_buf(cd, NULL, 0);
params[par++] = bigint_to_buf(userid, NULL, 0);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
first = true;
item = find_paymentaddresses(userid, ctx);
DATA_PAYMENTADDRESSES_NULL(row, item);
while (item && CURRENT(&(row->expirydate)) && row->userid == userid) {
/* This is only possible if the DB was directly updated with
* more than 999 records then reloaded (or a code bug) */
if (++count > 999)
break;
// Find the RAM record in pa_store
match = pa_store->head;
while (match) {
DATA_PAYMENTADDRESSES(pa, match);
if (strcmp(pa->payaddress, row->payaddress) == 0 &&
pa->payratio == row->payratio) {
pa->match = true; // Don't store it
matches++;
break;
}
match = match->next;
}
if (!match) {
// No matching replacement, so expire 'row'
params[par++] = str_to_buf(row->payaddress, NULL, 0);
if (!first)
APPEND_REALLOC(upd, off, len, ",");
first = false;
snprintf(tmp, sizeof(tmp), "$%d", par);
APPEND_REALLOC(upd, off, len, tmp);
}
item = prev_in_ktree(ctx);
DATA_PAYMENTADDRESSES_NULL(row, item);
}
LOGDEBUG("%s(): Step 1 par=%d count=%d matches=%d first=%s", __func__,
par, count, matches, first ? "true" : "false");
// Too many, or none need expiring = don't do the update
if (count > 999 || first == true) {
for (n = 0; n < par; n++)
free(params[n]);
par = 0;
// Too many
if (count > 999)
goto rollback;
} else {
APPEND_REALLOC(upd, off, len, ")");
PARCHKVAL(par, par, params);
res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res); rescode = PQresultStatus(res);
PQclear(res); PQclear(res);
@ -1493,22 +1539,44 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
goto rollback; goto rollback;
} }
LOGDEBUG("%s(): Step 1 expired %d", __func__, par-3);
for (n = 0; n < par; n++) for (n = 0; n < par; n++)
free(params[n]); free(params[n]);
par = 0;
}
// Second step - add the non-matching records to the DB
LOGDEBUG("%s(): Step 2", __func__);
ins = "insert into paymentaddresses " ins = "insert into paymentaddresses "
"(paymentaddressid,userid,payaddress,payratio" "(paymentaddressid,userid,payaddress,payratio"
HISTORYDATECONTROL ") values (" PQPARAM9 ")"; HISTORYDATECONTROL ") values (" PQPARAM9 ")";
count = 0;
match = pa_store->head;
while (match) {
DATA_PAYMENTADDRESSES(row, match);
if (!row->match) {
row->paymentaddressid = nextid(conn, "paymentaddressid", 1,
cd, by, code, inet);
if (row->paymentaddressid == 0)
goto rollback;
row->userid = userid;
HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row);
par = 0; par = 0;
params[par++] = bigint_to_buf(row->paymentaddressid, NULL, 0); params[par++] = bigint_to_buf(row->paymentaddressid, NULL, 0);
params[par++] = bigint_to_buf(row->userid, NULL, 0); params[par++] = bigint_to_buf(row->userid, NULL, 0);
params[par++] = str_to_buf(row->payaddress, NULL, 0); params[par++] = str_to_buf(row->payaddress, NULL, 0);
params[par++] = int_to_buf(row->payratio, NULL, 0); params[par++] = int_to_buf(row->payratio, NULL, 0);
HISTORYDATEPARAMS(params, par, row); HISTORYDATEPARAMS(params, par, row);
PARCHK(par, params); PARCHKVAL(par, 9, params); // As per PQPARAM9 above
res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); res = PQexecParams(conn, ins, par, NULL, (const char **)params,
NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res); rescode = PQresultStatus(res);
PQclear(res); PQclear(res);
if (!PGOK(rescode)) { if (!PGOK(rescode)) {
@ -1516,6 +1584,16 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
goto rollback; goto rollback;
} }
for (n = 0; n < par; n++)
free(params[n]);
par = 0;
count++;
}
match = match->next;
}
LOGDEBUG("%s(): Step 2 inserted %d", __func__, count);
ok = true; ok = true;
rollback: rollback:
if (ok) if (ok)
@ -1529,46 +1607,62 @@ unparam:
PQfinish(conn); PQfinish(conn);
for (n = 0; n < par; n++) for (n = 0; n < par; n++)
free(params[n]); free(params[n]);
unitem: FREENULL(upd);
K_WLOCK(paymentaddresses_free); // Third step - do step 1 and 2 to the RAM version of the DB
if (!ok) LOGDEBUG("%s(): Step 3, ok=%s", __func__, ok ? "true" : "false");
k_add_head(paymentaddresses_free, item); matches = count = n = 0;
if (ok) {
// Change the expiry on all records that we expired in the DB
item = find_paymentaddresses(userid, ctx);
DATA_PAYMENTADDRESSES_NULL(row, item);
while (item && CURRENT(&(row->expirydate)) && row->userid == userid) {
prev = prev_in_ktree(ctx);
// Find the RAM record in pa_store
match = pa_store->head;
while (match) {
DATA_PAYMENTADDRESSES(pa, match);
if (strcmp(pa->payaddress, row->payaddress) == 0 &&
pa->payratio == row->payratio) {
break;
}
match = match->next;
}
if (match)
matches++;
else { else {
// Change the expiry on all the old ones // It wasn't a match, thus it was expired
pa.userid = userid; n++;
pa.expirydate.tv_sec = DATE_S_EOT; paymentaddresses_root = remove_from_ktree(paymentaddresses_root, item,
pa.payaddress[0] = '\0';
INIT_PAYMENTADDRESSES(&look);
look.data = (void *)(&pa);
// Tree order is expirydate desc
old = find_after_in_ktree(paymentaddresses_root, &look,
cmp_paymentaddresses, ctx);
while (old) {
this = old;
DATA_PAYMENTADDRESSES(thispa, this);
if (thispa->userid != userid)
break;
old = next_in_ktree(ctx);
/* Tree remove+add below doesn't matter since
* this test will avoid reprocessing */
if (CURRENT(&(thispa->expirydate))) {
paymentaddresses_root = remove_from_ktree(paymentaddresses_root, this,
cmp_paymentaddresses); cmp_paymentaddresses);
copy_tv(&(thispa->expirydate), cd); copy_tv(&(row->expirydate), cd);
paymentaddresses_root = add_to_ktree(paymentaddresses_root, this, paymentaddresses_root = add_to_ktree(paymentaddresses_root, item,
cmp_paymentaddresses); cmp_paymentaddresses);
} }
item = prev;
DATA_PAYMENTADDRESSES_NULL(row, item);
} }
paymentaddresses_root = add_to_ktree(paymentaddresses_root, item,
// Add in all the non-matching ps_store
match = pa_store->head;
while (match) {
next = match->next;
DATA_PAYMENTADDRESSES(pa, match);
if (!pa->match) {
paymentaddresses_root = add_to_ktree(paymentaddresses_root, match,
cmp_paymentaddresses); cmp_paymentaddresses);
k_add_head(paymentaddresses_store, item); k_unlink_item(pa_store, match);
k_add_head(paymentaddresses_store, match);
count++;
}
match = next;
} }
}
LOGDEBUG("%s(): Step 3, untouched %d expired %d added %d", __func__, matches, n, count);
K_WUNLOCK(paymentaddresses_free); K_WUNLOCK(paymentaddresses_free);
if (ok) // Calling function must clean up anything left in pa_store
return item; return ok;
else
return NULL;
} }
bool paymentaddresses_fill(PGconn *conn) bool paymentaddresses_fill(PGconn *conn)

Loading…
Cancel
Save