From 21427af360c9b90f8e57a3ea2e4896f41a598aab Mon Sep 17 00:00:00 2001 From: localvar Date: Wed, 13 Nov 2019 03:24:39 +0000 Subject: [PATCH] TBASE-306 enhance `taos_options` to support cocurrent calls. note it still a problem if one thread is modifying a global configuration while another thread is reading it. --- src/client/src/tscSystem.c | 91 +++++++++++++++++++++----------------- src/inc/tglobalcfg.h | 2 +- src/util/src/tglobalcfg.c | 13 +++--- 3 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/client/src/tscSystem.c b/src/client/src/tscSystem.c index 5e383c9d0b..2842754e40 100644 --- a/src/client/src/tscSystem.c +++ b/src/client/src/tscSystem.c @@ -182,51 +182,45 @@ void taos_init_imp() { void taos_init() { pthread_once(&tscinit, taos_init_imp); } -int taos_options(TSDB_OPTION option, const void *arg, ...) { - char * pStr = NULL; - SGlobalConfig *cfg_configDir = tsGetConfigOption("configDir"); - SGlobalConfig *cfg_activetimer = tsGetConfigOption("shellActivityTimer"); - SGlobalConfig *cfg_locale = tsGetConfigOption("locale"); - SGlobalConfig *cfg_charset = tsGetConfigOption("charset"); - SGlobalConfig *cfg_timezone = tsGetConfigOption("timezone"); - SGlobalConfig *cfg_socket = tsGetConfigOption("sockettype"); +static int taos_options_imp(TSDB_OPTION option, const char *pStr) { + SGlobalConfig *cfg = NULL; switch (option) { case TSDB_OPTION_CONFIGDIR: - pStr = (char *)arg; - if (cfg_configDir && cfg_configDir->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { + cfg = tsGetConfigOption("configDir"); + if (cfg && cfg->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { strncpy(configDir, pStr, TSDB_FILENAME_LEN); - cfg_configDir->cfgStatus = TSDB_CFG_CSTATUS_OPTION; + cfg->cfgStatus = TSDB_CFG_CSTATUS_OPTION; tscPrint("set config file directory:%s", pStr); } else { - tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg_configDir->option, pStr, - tsCfgStatusStr[cfg_configDir->cfgStatus], (char *)cfg_configDir->ptr); + tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg->option, pStr, + tsCfgStatusStr[cfg->cfgStatus], (char *)cfg->ptr); } break; case TSDB_OPTION_SHELL_ACTIVITY_TIMER: - if (cfg_activetimer && cfg_activetimer->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { - tsShellActivityTimer = atoi((char *)arg); + cfg = tsGetConfigOption("shellActivityTimer"); + if (cfg && cfg->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { + tsShellActivityTimer = atoi(pStr); if (tsShellActivityTimer < 1) tsShellActivityTimer = 1; if (tsShellActivityTimer > 3600) tsShellActivityTimer = 3600; - cfg_activetimer->cfgStatus = TSDB_CFG_CSTATUS_OPTION; + cfg->cfgStatus = TSDB_CFG_CSTATUS_OPTION; tscPrint("set shellActivityTimer:%d", tsShellActivityTimer); } else { - tscWarn("config option:%s, input value:%s, is configured by %s, use %d", cfg_activetimer->option, pStr, - tsCfgStatusStr[cfg_activetimer->cfgStatus], (int32_t *)cfg_activetimer->ptr); + tscWarn("config option:%s, input value:%s, is configured by %s, use %d", cfg->option, pStr, + tsCfgStatusStr[cfg->cfgStatus], (int32_t *)cfg->ptr); } break; case TSDB_OPTION_LOCALE: { // set locale - pStr = (char *)arg; - + cfg = tsGetConfigOption("locale"); size_t len = strlen(pStr); if (len == 0 || len > TSDB_LOCALE_LEN) { tscPrint("Invalid locale:%s, use default", pStr); return -1; } - if (cfg_locale && cfg_charset && cfg_locale->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { + if (cfg && cfg && cfg->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { char sep = '.'; if (strlen(tsLocale) == 0) { // locale does not set yet @@ -239,7 +233,7 @@ int taos_options(TSDB_OPTION option, const void *arg, ...) { if (locale != NULL) { tscPrint("locale set, prev locale:%s, new locale:%s", tsLocale, locale); - cfg_locale->cfgStatus = TSDB_CFG_CSTATUS_OPTION; + cfg->cfgStatus = TSDB_CFG_CSTATUS_OPTION; } else { // set the user-specified localed failed, use default LC_CTYPE as current locale locale = setlocale(LC_CTYPE, tsLocale); tscPrint("failed to set locale:%s, current locale:%s", pStr, tsLocale); @@ -261,7 +255,7 @@ int taos_options(TSDB_OPTION option, const void *arg, ...) { } strncpy(tsCharset, charset, tListLen(tsCharset)); - cfg_charset->cfgStatus = TSDB_CFG_CSTATUS_OPTION; + cfg->cfgStatus = TSDB_CFG_CSTATUS_OPTION; } else { tscPrint("charset:%s is not valid in locale, charset remains:%s", charset, tsCharset); @@ -272,23 +266,22 @@ int taos_options(TSDB_OPTION option, const void *arg, ...) { tscPrint("charset remains:%s", tsCharset); } } else { - tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg_locale->option, pStr, - tsCfgStatusStr[cfg_locale->cfgStatus], (char *)cfg_locale->ptr); + tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg->option, pStr, + tsCfgStatusStr[cfg->cfgStatus], (char *)cfg->ptr); } break; } case TSDB_OPTION_CHARSET: { /* set charset will override the value of charset, assigned during system locale changed */ - pStr = (char *)arg; - + cfg = tsGetConfigOption("charset"); size_t len = strlen(pStr); if (len == 0 || len > TSDB_LOCALE_LEN) { tscPrint("failed to set charset:%s", pStr); return -1; } - if (cfg_charset && cfg_charset->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { + if (cfg && cfg->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { if (taosValidateEncodec(pStr)) { if (strlen(tsCharset) == 0) { tscPrint("charset is set:%s", pStr); @@ -297,40 +290,41 @@ int taos_options(TSDB_OPTION option, const void *arg, ...) { } strncpy(tsCharset, pStr, tListLen(tsCharset)); - cfg_charset->cfgStatus = TSDB_CFG_CSTATUS_OPTION; + cfg->cfgStatus = TSDB_CFG_CSTATUS_OPTION; } else { tscPrint("charset:%s not valid", pStr); } } else { - tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg_charset->option, pStr, - tsCfgStatusStr[cfg_charset->cfgStatus], (char *)cfg_charset->ptr); + tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg->option, pStr, + tsCfgStatusStr[cfg->cfgStatus], (char *)cfg->ptr); } break; } case TSDB_OPTION_TIMEZONE: - pStr = (char *)arg; - if (cfg_timezone && cfg_timezone->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { + cfg = tsGetConfigOption("timezone"); + if (cfg && cfg->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { strcpy(tsTimezone, pStr); tsSetTimeZone(); - cfg_timezone->cfgStatus = TSDB_CFG_CSTATUS_OPTION; + cfg->cfgStatus = TSDB_CFG_CSTATUS_OPTION; tscTrace("timezone set:%s, input:%s by taos_options", tsTimezone, pStr); } else { - tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg_timezone->option, pStr, - tsCfgStatusStr[cfg_timezone->cfgStatus], (char *)cfg_timezone->ptr); + tscWarn("config option:%s, input value:%s, is configured by %s, use %s", cfg->option, pStr, + tsCfgStatusStr[cfg->cfgStatus], (char *)cfg->ptr); } break; case TSDB_OPTION_SOCKET_TYPE: - if (cfg_socket && cfg_socket->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { - if (strcasecmp(arg, TAOS_SOCKET_TYPE_NAME_UDP) != 0 && strcasecmp(arg, TAOS_SOCKET_TYPE_NAME_TCP) != 0) { + cfg = tsGetConfigOption("sockettype"); + if (cfg && cfg->cfgStatus <= TSDB_CFG_CSTATUS_OPTION) { + if (strcasecmp(pStr, TAOS_SOCKET_TYPE_NAME_UDP) != 0 && strcasecmp(pStr, TAOS_SOCKET_TYPE_NAME_TCP) != 0) { tscError("only 'tcp' or 'udp' allowed for configuring the socket type"); return -1; } - strncpy(tsSocketType, arg, tListLen(tsSocketType)); - cfg_socket->cfgStatus = TSDB_CFG_CSTATUS_OPTION; + strncpy(tsSocketType, pStr, tListLen(tsSocketType)); + cfg->cfgStatus = TSDB_CFG_CSTATUS_OPTION; tscPrint("socket type is set:%s", tsSocketType); } break; @@ -342,3 +336,20 @@ int taos_options(TSDB_OPTION option, const void *arg, ...) { return 0; } + + +int taos_options(TSDB_OPTION option, const void *arg, ...) { + static int32_t lock = 0; + + for (int i = 1; atomic_val_compare_exchange_32(&lock, 0, 1) != 0; ++i) { + if (i % 1000 == 0) { + tscPrint("haven't acquire lock after spin %d times.", i); + sched_yield(); + } + } + + int ret = taos_options_imp(option, (const char*)arg); + + atomic_store_32(&lock, 0); + return ret; +} \ No newline at end of file diff --git a/src/inc/tglobalcfg.h b/src/inc/tglobalcfg.h index 026d48ba08..09ced23c91 100644 --- a/src/inc/tglobalcfg.h +++ b/src/inc/tglobalcfg.h @@ -247,7 +247,7 @@ typedef struct { extern SGlobalConfig *tsGlobalConfig; extern int tsGlobalConfigNum; extern char * tsCfgStatusStr[]; -SGlobalConfig *tsGetConfigOption(char *option); +SGlobalConfig *tsGetConfigOption(const char *option); #define TSDB_CFG_MAX_NUM 110 #define TSDB_CFG_PRINT_LEN 23 diff --git a/src/util/src/tglobalcfg.c b/src/util/src/tglobalcfg.c index 586f329001..bac89db7e2 100644 --- a/src/util/src/tglobalcfg.c +++ b/src/util/src/tglobalcfg.c @@ -364,7 +364,7 @@ void tsReadLogOption(char *option, char *value) { } } -SGlobalConfig *tsGetConfigOption(char *option) { +SGlobalConfig *tsGetConfigOption(const char *option) { tsInitGlobalConfig(); for (int i = 0; i < tsGlobalConfigNum; ++i) { SGlobalConfig *cfg = tsGlobalConfig + i; @@ -374,7 +374,7 @@ SGlobalConfig *tsGetConfigOption(char *option) { return NULL; } -void tsReadConfigOption(char *option, char *value) { +void tsReadConfigOption(const char *option, char *value) { for (int i = 0; i < tsGlobalConfigNum; ++i) { SGlobalConfig *cfg = tsGlobalConfig + i; if (!(cfg->cfgType & TSDB_CFG_CTYPE_B_CONFIG)) continue; @@ -423,9 +423,7 @@ void tsInitConfigOption(SGlobalConfig *cfg, char *name, void *ptr, int8_t valTyp cfg->cfgStatus = TSDB_CFG_CSTATUS_NONE; } -void tsInitGlobalConfig() { - if (tsGlobalConfig != NULL) return; - +static void doInitGlobalConfig() { tsGlobalConfig = (SGlobalConfig *) malloc(sizeof(SGlobalConfig) * TSDB_CFG_MAX_NUM); memset(tsGlobalConfig, 0, sizeof(SGlobalConfig) * TSDB_CFG_MAX_NUM); @@ -783,6 +781,11 @@ void tsInitGlobalConfig() { tsGlobalConfigNum = (int)(cfg - tsGlobalConfig); } +static pthread_once_t initGlobalConfig = PTHREAD_ONCE_INIT; +void tsInitGlobalConfig() { + pthread_once(&initGlobalConfig, doInitGlobalConfig); +} + void tsReadGlobalLogConfig() { tsInitGlobalConfig(); -- GitLab