数据库恢复
正如数据库恢复页面中所解释的那样,SmartEDB 提供了“嗅探器”实用程序,以允许 C 和 C++ 应用程序检测并移除“死”连接。
使用嗅探器
由于没有独立于系统的检测进程失败的方法,因此提供了“嗅探器” API mco_db_sniffer()
。通常,mco_db_sniffer()
会在单独的线程中定期调用,或者从应用程序中的特定位置调用,以检查“死”连接。然后,mco_db_sniffer()
会调用用户提供的回调函数,以实际检测给定的连接是否“存活”,如果不存活则终止它。
为了执行此检查,通常会使用如下代码将一些标识信息(通常是进程标识符)添加到每个连接上下文中:
int pid ;
#ifdef _WIN32
pid = GetCurrentProcessId();
#else
pid = getpid();
#endif
...
mco_db_connect_ctx(dbName, &pid, &db);
注意,还需要在传递给的数据库参数中指定此连接上下文的大小mco_db_open_dev()
. 例如:
db_params.connection_context_size = sizeof(int);
回调函数
“嗅探器” 回调函数可以这样实现:
MCO_RET sniffer_callback(
mco_db_h db,
void* context,
mco_trans_counter_t trans_no)
{
int pid = *(int*)context;
#ifdef _WIN32
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (h != NULL)
{
CloseHandle(h);
return MCO_S_OK;
}
#else
if (kill(pid, 0) == 0)
{
return MCO_S_OK;
}
#endif
printf("Process %d is crashed\n", pid);
return MCO_S_DEAD_CONNECTION;
}
回调函数的参数如下:
db:有效的数据库连接句柄。
context:用户定义的连接上下文。通过函数
mco_db_connect_ctx()
提供的大小为MCO_CFG_CONNECTION_CONEXT_SIZE
的不透明数据。trans_no:当前活动事务的数量(若无活动事务则为 0)。这是有助于检测可能表明连接已断开的挂起事务的附加信息。
如果用户回调函数返回MCO_S_DEAD_CONNECTION
,则将对该连接执行恢复。现在mco_db_sniffer()
遍历数据库连接,并将根据指定的策略(第三个参数)调用用户回调函数。该策略参数的取值范围如下:
- MCO_SNIFFER_INSPECT_ACTIVE_CONNECTIONS:对于所有活动连接;
- MCO_SNIFFER_INSPECT_ACTIVE_TRANSACTIONS:用于所有具有活动事务的连接;
- MCO_SNIFFER_INSPECT_HANGED_TRANSACTIONS:用于与活动事务的连接。其事务编号自上次调用
mco_db_sniffer()
以来未发生变化的连接被认为处于挂起状态,用户有责任正确指定并强制执行连续调用mco_db_sniffer()
之间的间隔,以避免错误检测到挂起的事务。
“看门狗”线程
可以在应用程序中按如下方式实现一个“看门狗”线程:
THREAD_PROC_DEFINE(sniffer_loop, arg)
{
mco_db_h db;
int pid = get_pid();
mco_db_connect_ctx(dbName, &pid, &db));
while (1)
{
mco_db_sniffer(db, sniffer_callback,
MCO_SNIFFER_INSPECT_ACTIVE_CONNECTIONS));
sleep(SNIFFER_INTERRVAL);
}
mco_db_disconnect(db);
THREAD_RETURN(0);
}
恢复实际上包含两个阶段:
- 第一阶段,获取已断开的连接。每个连接都有由进程指定的私有指针。这些指针必须进行调整,以便在执行恢复操作的进程上下文中使用。
- 第二阶段,调用内部函数来回滚可能正在进行的任何事务,并释放已断开连接的数据结构。
参阅SDK示例 samples/core/19_recovery_sniffer 提供了一个嗅探器实现。
NVRAM数据库支持和恢复
SmartEDB 允许 C 和 C++ 应用程序在系统重启或类似活动后重新连接到在非易失性内存(NVRAM 或电池支持的 RAM)中创建的数据库。数据库可以在常规内存或共享内存中创建。如果数据库遭到损坏,SmartEDB 运行时会根据调用 mco_db_open_dev()
时指定的内存缓冲区的内容尝试恢复数据库。
为了重新连接到 NVRAM 中的数据库,应用程序需要向 mco_db_open_dev()
指定内存设备,并将选项 MCO_DB_OPEN_EXISTING
作为参数(在 mco_db_params_t.mode_mask
参数中)进行设置。
例如:
mco_db_params_t db_params;
...
mco_db_params_init(&db_params);
...
if (...)
{
db_params.mode_mask |= MCO_DB_OPEN_EXISTING;
}
...
rc = mco_db_open_dev(db_name... , &db_params);
数据库运行时会执行必要的步骤以确保数据库元数据和数据库内容的一致性。如果 mco_db_open_dev()
返回 MCO_S_OK
,应用程序就可以通过调用 mco_db_connect()
正常连接到数据库。
在某些情况下,例如应用程序错误导致数据库运行时元数据损坏,数据库恢复可能会失败。此时mco_db_open_dev()
将返回错误代码。
请参阅 SDK 示例 02-open_nvram 以获取示例。
持久数据库恢复
在发生系统故障时,可能需要持久的数据库恢复。当调用mco_db_open_dev()
时,SmartEDB运行时使用事务日志文件自动执行恢复。日志类型在mco_db_params_t.db_log_type
中指定。例如:
mco_db_params_t db_params;
...
mco_db_params_init ( &db_params ); /* 用默认值初始化参数 */
// Set log file type
db_params.db_log_type = UNDO_LOG; /* NO_LOG | REDO_LOG | UNDO_LOG */
对于自动恢复,重要的是在系统故障发生时,在更新数据库的进程中,RedoLog
(默认)或UndoLog
日志文件类型是活跃的。如果崩溃进程中的日志文件类型为NoLog
,则不可能进行恢复。自动恢复无需应用程序执行额外的 API 调用或操作。