diff --git a/conf/autoload_configs/switch.conf.xml b/conf/autoload_configs/switch.conf.xml index 4f72c6a65d..d2500a6463 100644 --- a/conf/autoload_configs/switch.conf.xml +++ b/conf/autoload_configs/switch.conf.xml @@ -24,6 +24,11 @@ + + + + + diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index ab0777ed3b..0ef64d1079 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -249,6 +249,8 @@ struct switch_runtime { switch_dbtype_t odbc_dbtype; char hostname[256]; int multiple_registrations; + uint32_t max_db_handles; + uint32_t db_handle_timeout; }; extern struct switch_runtime runtime; diff --git a/src/switch_core.c b/src/switch_core.c index 50fe313f82..96e4b4ae27 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1283,7 +1283,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc memset(&runtime, 0, sizeof(runtime)); gethostname(runtime.hostname, sizeof(runtime.hostname)); - + runtime.max_db_handles = 50; + runtime.db_handle_timeout = 5000000;; + runtime.runlevel++; runtime.sql_buffer_len = 1024 * 32; runtime.max_sql_buffer_len = 1024 * 1024; @@ -1550,6 +1552,23 @@ static void switch_load_core_config(const char *file) if (tmp > -1 && tmp < 11) { switch_core_session_ctl(SCSC_DEBUG_LEVEL, &tmp); } + } else if (!strcasecmp(var, "max-db-handles")) { + long tmp = atol(val); + + if (tmp > 4 && tmp < 5001) { + runtime.max_db_handles = (uint32_t) tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "max-db-handles must be between 5 and 5000\n"); + } + } else if (!strcasecmp(var, "db-handle-timeout")) { + long tmp = atol(val); + + if (tmp > 0 && tmp < 5001) { + runtime.db_handle_timeout = (uint32_t) tmp * 1000000; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "db-handle-timeout must be between 1 and 5000\n"); + } + } else if (!strcasecmp(var, "multiple-registrations")) { runtime.multiple_registrations = switch_true(val); } else if (!strcasecmp(var, "sql-buffer-len")) { diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 8dbdd44895..a4ed5ca83c 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -66,8 +66,8 @@ static struct { switch_cache_db_handle_t *handle_pool; switch_thread_cond_t *cond; switch_mutex_t *cond_mutex; - int total_handles; - int total_used_handles; + uint32_t total_handles; + uint32_t total_used_handles; } sql_manager; @@ -273,11 +273,29 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h char db_callsite_str[CACHE_DB_LEN] = ""; switch_cache_db_handle_t *new_dbh = NULL; switch_ssize_t hlen = -1; + int waiting = 0; + uint32_t yield_len = 100000, total_yield = 0; const char *db_name = NULL; const char *db_user = NULL; const char *db_pass = NULL; + while(runtime.max_db_handles && sql_manager.total_handles >= runtime.max_db_handles && sql_manager.total_used_handles >= sql_manager.total_handles) { + if (!waiting++) { + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_WARNING, "Max handles %u exceeded, blocking....\n", + runtime.max_db_handles); + } + + switch_yield(yield_len); + total_yield += yield_len; + + if (runtime.db_handle_timeout && total_yield > runtime.db_handle_timeout) { + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Error connecting\n"); + *dbh = NULL; + return SWITCH_STATUS_FALSE; + } + } + switch (type) { case SCDB_TYPE_ODBC: {