From 4f327ee6eded45e7beb3c24f0212fcf0992d8de1 Mon Sep 17 00:00:00 2001 From: kanoi Date: Fri, 13 Mar 2015 20:58:20 +1100 Subject: [PATCH] ckdb - switch_state to allow code upgrades while running --- src/ckdb.c | 2 ++ src/ckdb.h | 23 ++++++++++++++++++++++- src/ckdb_cmd.c | 18 ++++++++++++++++++ src/ckdb_dbio.c | 24 +++++++++++++++++++++++- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/ckdb.c b/src/ckdb.c index ac39b470..ecf4af24 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -151,6 +151,8 @@ static char *restorefrom; // Only accessed in here static bool markersummary_auto; +int switch_state = SWITCH_STATE_ALL; + // disallow: '/' '.' '_' and FLDSEP const char *userpatt = "^[^/\\._"FLDSEPSTR"]*$"; const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.-]*[A-Za-z0-9]$"; diff --git a/src/ckdb.h b/src/ckdb.h index 830a7e9d..6893ecfa 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -55,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.030" +#define CKDB_VERSION DB_VERSION"-1.031" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -81,6 +81,27 @@ #define TRUE_CHR 'Y' #define FALSE_CHR 'N' +/* Set by cmd_setopts() and used by whatever code needs it + * It's loaded during startup but set to SWITCH_STATE_ALL if it's missing, + * meaning all switches are active + * The idea is that if you need to manually switch code over from one version + * up to the next version at an indeterminate time then you can do that by + * coding a switch_state test and then externally switch the code over via + * the cmd_setopts() socket interface + * It's not for coding runtime options into the code since that can be done + * using optioncontrol directly + * It's stored in optioncontrol so that it's value is permanent and + * activationdate and activationheight have their values overridden to + * disable using them + * N.B. optioncontrol_item_add() intercepts the change by name and updates + * switch_state but ONLY if the DB update succeeds */ +extern int switch_state; +#define SWITCH_STATE_NAME "SwitchState" +/* Each switch state must be higher than all previous + * so that future states don't undo old changes */ +#define SWITCH_STATE_AUTHWORKERS 1 +#define SWITCH_STATE_ALL 666666 + extern char *EMPTY; extern const char *userpatt; diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 3e73553c..93c42a69 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -2388,6 +2388,15 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by, setnow(&last_auth); ck_wunlock(&last_lock); + if (switch_state < SWITCH_STATE_AUTHWORKERS) { + snprintf(reply, siz, + "ok.authorise={\"secondaryuserid\":\"%s\"," + "\"difficultydefault\":%d}", + users->secondaryuserid, workers->difficultydefault); + LOGDEBUG("%s.%s", id, reply); + return strdup(reply); + } + APPEND_REALLOC_INIT(buf, off, len); snprintf(reply, siz, "ok.authorise={\"secondaryuserid\":\"%s\"," @@ -2493,6 +2502,15 @@ static char *cmd_addrauth_do(PGconn *conn, char *cmd, char *id, char *by, setnow(&last_auth); ck_wunlock(&last_lock); + if (switch_state < SWITCH_STATE_AUTHWORKERS) { + snprintf(reply, siz, + "ok.addrauth={\"secondaryuserid\":\"%s\"," + "\"difficultydefault\":%d}", + users->secondaryuserid, workers->difficultydefault); + LOGDEBUG("%s.%s", id, reply); + return strdup(reply); + } + APPEND_REALLOC_INIT(buf, off, len); snprintf(reply, siz, "ok.addrauth={\"secondaryuserid\":\"%s\"," diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index 91e43fd8..5b3c1544 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -2183,6 +2183,13 @@ K_ITEM *optioncontrol_item_add(PGconn *conn, K_ITEM *oc_item, tv_t *cd, bool beg DATA_OPTIONCONTROL(row, oc_item); + // Enforce the rule that switch_state isn't date/height controlled + if (strcmp(row->optionname, SWITCH_STATE_NAME) == 0) { + row->activationdate.tv_sec = date_begin.tv_sec; + row->activationdate.tv_usec = date_begin.tv_usec; + row->activationheight = OPTIONCONTROL_HEIGHT; + } + INIT_OPTIONCONTROL(&look); look.data = (void *)row; K_RLOCK(optioncontrol_free); @@ -2282,6 +2289,11 @@ nostart: } optioncontrol_root = add_to_ktree(optioncontrol_root, oc_item, cmp_optioncontrol); k_add_head(optioncontrol_store, oc_item); + if (strcmp(row->optionname, SWITCH_STATE_NAME) == 0) { + switch_state = atoi(row->optionvalue); + LOGWARNING("%s() set switch_state to %d", + __func__, switch_state); + } } K_WUNLOCK(optioncontrol_free); @@ -2320,7 +2332,7 @@ K_ITEM *optioncontrol_add(PGconn *conn, char *optionname, char *optionvalue, TXT_TO_INT("activationheight", activationheight, row->activationheight); } else - row->activationheight = 1; + row->activationheight = OPTIONCONTROL_HEIGHT; HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); @@ -2406,6 +2418,14 @@ bool optioncontrol_fill(PGconn *conn) optioncontrol_root = add_to_ktree(optioncontrol_root, item, cmp_optioncontrol); k_add_head(optioncontrol_store, item); + + // There should only be one CURRENT version of switch_state + if (CURRENT(&(row->expirydate)) && + strcmp(row->optionname, SWITCH_STATE_NAME) == 0) { + switch_state = atoi(row->optionvalue); + LOGWARNING("%s() set switch_state to %d", + __func__, switch_state); + } } if (!ok) { FREENULL(row->optionvalue); @@ -2418,6 +2438,8 @@ bool optioncontrol_fill(PGconn *conn) if (ok) { LOGDEBUG("%s(): built", __func__); LOGWARNING("%s(): loaded %d optioncontrol records", __func__, n); + LOGWARNING("%s() switch_state initially %d", + __func__, switch_state); } return ok;