- 数据库体系
freeswitch默认使用sqlite3数据库,但也支持odbc使用其它数据库,或者PostgreSQL这是支持的三类数据库类型,从定义可以看出。
- typedef enum {
- SCDB_TYPE_CORE_DB,
- SCDB_TYPE_ODBC,
- SCDB_TYPE_PGSQL
- } switch_cache_db_handle_type_t;
switch_core_db.c实现sqlite核心数据库,switch_odbc.c实现例如MySQL的数据库,switch_pgsql.c实现PostgreSQL数据库。另外switch_core_sqldb.c是数据库抽象层,屏蔽调用具体的数据库API,向外提供统一的数据库操作API。
- typedef union {
- switch_core_db_t *core_db_dbh;
- switch_odbc_handle_t *odbc_dbh;
- switch_pgsql_handle_t *pgsql_dbh;
- } switch_cache_db_native_handle_t;
sqldb统一使用switch_cache_db_native_handle_t作为数据库实例,这是一个联合体。
- 初始化
- SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switch_bool_t console, const char **err)
- {
- runtime.max_db_handles = 50;
- runtime.db_handle_timeout = 5000000;
- runtime.dbname = "core";
- runtime.odbc_dbtype = DBTYPE_DEFAULT;
- runtime.dbname = NULL;
- if (sqlite3_initialize() != SQLITE_OK) {
- *err = "FATAL ERROR! Could not initialize SQLite\n";
- return SWITCH_STATUS_MEMERR;
- }
- if (switch_core_sqldb_start(runtime.memory_pool, switch_test_flag((&runtime), SCF_USE_SQL) ? SWITCH_TRUE : SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
- *err = "Error activating database";
- return SWITCH_STATUS_FALSE;
- }
- return SWITCH_STATUS_SUCCESS;
- }
在核心初始化的时候,调用了sqlite初始化核心数据库,然后调用sqldb_start启动数据库。
-
- 数据库管理者
- static struct {
- switch_memory_pool_t *memory_pool;
- switch_thread_t *db_thread;
- int db_thread_running;
- switch_bool_t manage;
- switch_mutex_t *io_mutex;
- switch_mutex_t *dbh_mutex;
- switch_mutex_t *ctl_mutex;
- switch_cache_db_handle_t *handle_pool;
- uint32_t total_handles;
- uint32_t total_used_handles;
- switch_cache_db_handle_t *dbh;
- switch_sql_queue_manager_t *qm;
- int paused;
- } sql_manager;
sql_manager管理所有的数据库,其中handle_pool是数据实例池,所以freeswitch同时支持多个不同的数据库,比如某个数据库使用sqlite,另一个数据库使用mysql,dbh则指向当前使用的数据库。qm是core.db使用的sql队列,sql的执行是在独立线程上执行的,其它数据库比如sip,需要使用自己的sql_queue。
-
- 启动数据库
启动数据库,初始化一些sql_manage的成员,然后通过switch_core_sqldb_start打开数据库,并重建表,最后启动数据库线程switch_core_sqldb_start_thread。
- switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_t manage)
- {
- switch_threadattr_t *thd_attr;
- sql_manager.memory_pool = pool;
- sql_manager.manage = manage;
- if (!sql_manager.manage) goto skip;
- top:
- /* 打开数据库 */
- if (switch_core_db_handle(&sql_manager.dbh) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n");
- return SWITCH_STATUS_FALSE;
- }
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening DB\n");
- //执行清空表、创建表等操作
- switch (sql_manager.dbh->type) {
- case SCDB_TYPE_PGSQL:
- case SCDB_TYPE_ODBC:
- break;
- case SCDB_TYPE_CORE_DB:
- {
- }
- break;
- }
- skip:
- if (sql_manager.manage) {
- switch_threadattr_create(&thd_attr, sql_manager.memory_pool);
- switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
- switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
- //启动数据库线程
- switch_core_sqldb_start_thread();
- switch_thread_create(&sql_manager.db_thread, thd_attr, switch_core_sql_db_thread, NULL, sql_manager.memory_pool);
- }
- switch_cache_db_release_db_handle(&sql_manager.dbh);
- return SWITCH_STATUS_SUCCESS;
- }
- 打开数据库
- switch_core_db_handle
- SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t **dbh, const char *file, const char *func, int line)
- {
- switch_status_t r;
- char *dsn;
- if (!sql_manager.manage) {
- return SWITCH_STATUS_FALSE;
- }
- if (!zstr(runtime.odbc_dsn)) {
- dsn = runtime.odbc_dsn;
- } else if (!zstr(runtime.dbname)) {
- dsn = runtime.dbname;
- } else {
- dsn = "core";
- }
- if ((r = _switch_cache_db_get_db_handle_dsn(dbh, dsn, file, func, line)) != SWITCH_STATUS_SUCCESS) {
- *dbh = NULL;
- }
- return r;
- }
打开数据库实际就是使用全局配置runtime.odbc_dsn作为路径,这个参数在解析配置的时候有讲过,这里不再说明,然后调用 _switch_cache_db_get_db_handle_dsn底层接口去打开数据库。
-
- _switch_cache_db_get_db_handle_dsn
- SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn(switch_cache_db_handle_t **dbh, const char *dsn,
- const char *file, const char *func, int line)
- {
- switch_cache_db_connection_options_t connection_options = { {0} };
- switch_cache_db_handle_type_t type;
- char tmp[256] = "";
- char *p;
- switch_status_t status = SWITCH_STATUS_FALSE;
- int i;
- if (!strncasecmp(dsn, "pgsql://", 8)) {
- type = SCDB_TYPE_PGSQL;
- connection_options.pgsql_options.dsn = (char *)(dsn + 8);
- } else if (!strncasecmp(dsn, "sqlite://", 9)) {
- type = SCDB_TYPE_CORE_DB;
- connection_options.core_db_options.db_path = (char *)(dsn + 9);
- } else if ((!(i = strncasecmp(dsn, "odbc://", 7))) || strchr(dsn+2, ':')) {
- type = SCDB_TYPE_ODBC;
- ...
- } else {
- type = SCDB_TYPE_CORE_DB;
- connection_options.core_db_options.db_path = (char *)dsn;
- }
- status = _switch_cache_db_get_db_handle(dbh, type, &connection_options, file, func, line);
- if (status != SWITCH_STATUS_SUCCESS) *dbh = NULL;
- return status;
- }
_switch_cache_db_get_db_handle_dsn接口解析dsn得到数据库类型,然后调用最底层接口去打开连接数据库_switch_cache_db_get_db_handle。
-
- _switch_cache_db_get_db_handle
- SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_handle_t **dbh, switch_cache_db_handle_type_t type, switch_cache_db_connection_options_t *connection_options, const char *file, const char *func, int line)
- {
- switch_cache_db_handle_t *new_dbh = NULL;
- //如果存在实例,直接使用,否则创建新实例
- if ((new_dbh = get_handle(db_str, db_callsite_str, thread_str))) {
- switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
- "Reuse Unused Cached DB handle %s [%s]\n", new_dbh->name, switch_cache_db_type_name(new_dbh->type));
- } else {
- switch_core_db_t *db = NULL;
- switch_odbc_handle_t *odbc_dbh = NULL;
- switch_pgsql_handle_t *pgsql_dbh = NULL;
- //根据类型,调用相关的NEW函数创建实例
- switch (type) {
- case SCDB_TYPE_PGSQL:
- {
- if ((pgsql_dbh = switch_pgsql_handle_new(connection_options->pgsql_options.dsn))) {
- if (switch_pgsql_handle_connect(pgsql_dbh) != SWITCH_PGSQL_SUCCESS) {
- switch_pgsql_handle_destroy(&pgsql_dbh);
- }
- }
- }
- break;
- case SCDB_TYPE_ODBC:
- {
- if ((odbc_dbh = switch_odbc_handle_new(connection_options->odbc_options.dsn,
- connection_options->odbc_options.user, connection_options->odbc_options.pass))) {
- if (switch_odbc_handle_connect(odbc_dbh) != SWITCH_ODBC_SUCCESS) {
- switch_odbc_handle_destroy(&odbc_dbh);
- }
- }
- }
- break;
- case SCDB_TYPE_CORE_DB:
- {
- db = switch_core_db_open_file(connection_options->core_db_options.db_path);
- }
- break;
- default:
- goto end;
- }
- //创建并添加操作实例
- new_dbh = create_handle(type);
- if (db) {
- new_dbh->native_handle.core_db_dbh = db;
- } else if (odbc_dbh) {
- new_dbh->native_handle.odbc_dbh = odbc_dbh;
- } else {
- new_dbh->native_handle.pgsql_dbh = pgsql_dbh;
- }
- add_handle(new_dbh, db_str, db_callsite_str, thread_str);
- }
- end:
- *dbh = new_dbh;
- return *dbh ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
- }
流程简化后如上,先看操作实例是否已经在池,没有再创建,创建的时候根据类型创建实例,然后添加到池。这里不同类型创建的实例类型不同,但是会统一到switch_cache_db_handle,
作为native_handle成员,这个数据结构才是sql管理层使用的。
- struct switch_cache_db_handle {
- char name[CACHE_DB_LEN];
- switch_cache_db_handle_type_t type;
- switch_cache_db_native_handle_t native_handle;
- time_t last_used;
- switch_mutex_t *mutex;
- switch_mutex_t *io_mutex;
- switch_memory_pool_t *pool;
- int32_t flags;
- unsigned long hash;
- unsigned long thread_hash;
- char creator[CACHE_DB_LEN];
- char last_user[CACHE_DB_LEN];
- uint32_t use_count;
- uint64_t total_used_count;
- struct switch_cache_db_handle *next;
- };
- 启动数据库线程
- switch_core_sqldb_start_thread
- static void switch_core_sqldb_start_thread(void)
- {
- switch_mutex_lock(sql_manager.ctl_mutex);
- if (sql_manager.manage) {
- if (!sql_manager.qm) {
- char *dbname = runtime.odbc_dsn;
- if (zstr(dbname)) {
- dbname = runtime.dbname;
- if (zstr(dbname)) {
- dbname = "core";
- }
- }
- switch_sql_queue_manager_init_name("CORE",
- &sql_manager.qm,
- 4,
- dbname,
- SWITCH_MAX_TRANS,
- runtime.core_db_pre_trans_execute,
- runtime.core_db_post_trans_execute,
- runtime.core_db_inner_pre_trans_execute,
- runtime.core_db_inner_post_trans_execute);
- }
- switch_sql_queue_manager_start(sql_manager.qm);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL is not enabled\n");
- }
- switch_mutex_unlock(sql_manager.ctl_mutex);
开始线程实质上是创建sql队列,这里需要绑定一组sql操作函数,pre_trans、post_trans等。调用switch_sql_queue_manager_init_name创建队列,然后调用switch_sql_queue_manager_start启动队列。注意,这里都是在创建core.db数据库,sip的数据库不是在这里。
-
- switch_sql_queue_manager_start
- SWITCH_DECLARE(switch_status_t) switch_sql_queue_manager_start(switch_sql_queue_manager_t *qm)
- {
- switch_threadattr_t *thd_attr;
- if (!qm->thread_running) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Starting SQL thread.\n", qm->name);
- switch_threadattr_create(&thd_attr, qm->pool);
- switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
- switch_threadattr_priority_set(thd_attr, SWITCH_PRI_NORMAL);
- switch_thread_create(&qm->thread, thd_attr, switch_user_sql_thread, qm, qm->pool);
- return SWITCH_STATUS_SUCCESS;
- }
- return SWITCH_STATUS_FALSE;
- }
这里会创建队列的线程,执行函数为switch_user_sql_thread。
-
- switch_user_sql_thread
switch_user_sql_thread@sql_manager.qm
{
do_trans
{
switch_queue_trypop(qm->sql_queue[i], &pop);
switch_cache_db_execute_sql
}
}
sql线程简化后,就是从队列里一直读sql,然后去执行。
- switch_core_sql_db_thread
启动数据库的时候,除了调用switch_core_sqldb_start_thread去创建队列外,还启动一条线程switch_core_sql_db_thread,注意这和switch_user_sql_thread是不一样的。
- static void *SWITCH_THREAD_FUNC switch_core_sql_db_thread(switch_thread_t *thread, void *obj)
- {
- int sec = 0, reg_sec = 0;;
- sql_manager.db_thread_running = 1;
- while (sql_manager.db_thread_running == 1) {
- if (++sec == SQL_CACHE_TIMEOUT) {
- sql_close(switch_epoch_time_now(NULL));
- sec = 0;
- }
- if (switch_test_flag((&runtime), SCF_USE_SQL) && ++reg_sec == SQL_REG_TIMEOUT) {
- switch_core_expire_registration(0);
- reg_sec = 0;
- }
- switch_yield(1000000);
- }
- return NULL;
- }
这条线程就是定时检查一些超时状态,没有特别重要的业务。