海山数据库(He3DB)源码详解:He3DB-CLOG日志管理器函数之clog_redo
处理事务日志重做过程中的一部分,专门用于处理clog记录。它负责处理两种类型的clog记录:ZEROPAGE和TRUNCATE,分别用于清零clog页面和截断事务控制信息的LRU缓存。
void
clog_redo(XLogReaderState *record)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
/* Backup blocks are not used in clog records */
Assert(!XLogRecHasAnyBlockRefs(record));
if (info == CLOG_ZEROPAGE)
{
int pageno;
int slotno;
memcpy(&pageno, XLogRecGetData(record), sizeof(int));
LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
slotno = ZeroCLOGPage(pageno, false);
SimpleLruWritePage(XactCtl, slotno);
Assert(!XactCtl->shared->page_dirty[slotno]);
LWLockRelease(XactSLRULock);
}
else if (info == CLOG_TRUNCATE)
{
xl_clog_truncate xlrec;
memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_clog_truncate));
AdvanceOldestClogXid(xlrec.oldestXact);
SimpleLruTruncate(XactCtl, xlrec.pageno);
}
else
elog(PANIC, "clog_redo: unknown op code %u", info);
}
void
clog_redo(XLogReaderState *record)
该函数接收一个指向XLogReaderState
结构体的指针record
。该结构体包含了当前正在处理的WAL记录的信息
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
使用XLogRecGetInfo
函数从record
中获取WAL记录的信息,并通过与~XLR_INFO_MASK
进行位与操作来清除一些不需要的位,结果存储在info
变量中
Assert(!XLogRecHasAnyBlockRefs(record));
确保当前的CLOG记录不使用备份块(Backup blocks)
备份块:为了保持数据的一致性,在更改实际数据之前先对其进行备份的块
然而,在clog记录的情况下,这种备份机制不是必需的,因为clog本身就是一种记录事务更改的机制
if (info == CLOG_ZEROPAGE)
{
int pageno;
int slotno;
memcpy(&pageno, XLogRecGetData(record), sizeof(int));
LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
slotno = ZeroCLOGPage(pageno, false);
SimpleLruWritePage(XactCtl, slotno);
Assert(!XactCtl->shared->page_dirty[slotno]);
LWLockRelease(XactSLRULock);
}
如果获取的info
为CLOG_ZEROPAGE
- 调用
memcpy
函数。将 WAL 记录中的数据部分(具体来说是一个整型值,即页面编号)复制到变量pageno
中。这样,pageno
就包含了需要从 WAL 记录中恢复的页面编号
&pageno
是目标内存地址,即变量pageno
的地址。XLogRecGetData(record)
是源内存地址,它返回一个指向 WAL 记录数据部分的指针。sizeof(int)
是要复制的字节数,这里是一个整型的大小。
- 获取排他锁
- 将指定页面号的CLOG页面清零,并返回该页面对应的槽位号,此过程不需要xlog记录(第二个参数false)
- 将修改后的
slotno
对应的页面写回LRU缓存 - 断言。确保
slotno
对应的页面在 LRU 缓存中不再被标记为脏页面,如果仍然是脏页面,说明前面有问题 - 释放锁
else if (info == CLOG_TRUNCATE)
{
xl_clog_truncate xlrec;
memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_clog_truncate));
AdvanceOldestClogXid(xlrec.oldestXact);
SimpleLruTruncate(XactCtl, xlrec.pageno);
}
xl_clog_truncate
定义了用于存储从 WAL记录中读取的截断信息的数据结构。包含要截断到的最旧事务ID(oldestXact
)和要截断的页面编号(pageno)等。
typedef struct xl_clog_truncate
{
int pageno;
TransactionId oldestXact;
Oid oldestXactDb;
} xl_clog_truncate;
- 使用
memcpy
函数从WAL记录的数据部分复制截断信息到xlrec
变量 - 更新最旧的事务ID,发生截断操作时,就知道小于或等于这个新最旧事务ID的事务都已经不再需要保留在日志中了
- 释放
xlrec.pageno
之后的所有页面
如果info
不是CLOG_ZEROPAGE
也不是CLOG_TRUNCATE
,则记录一个致命错误