海山数据库(He3DB)源码详解:He3DB-CLOG日志管理器函数之CLOGShmemInit、ZeroCLOGPage
1 CLOGShmemInit源码解析
void CLOGShmemInit(void)
{
XactCtl->PagePrecedes = CLOGPagePrecedes;
SimpleLruInit(XactCtl, "Xact", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
SYNC_HANDLER_CLOG);
SlruPagePrecedesUnitTests(XactCtl, CLOG_XACTS_PER_PAGE);
}
XactCtl->PagePrecedes = CLOGPagePrecedes;
CLOGPagePrecedes
函数
static bool
CLOGPagePrecedes(int page1, int page2)
{
TransactionId xid1;
TransactionId xid2;
xid1 = ((TransactionId) page1) * CLOG_XACTS_PER_PAGE;
xid1 += FirstNormalTransactionId + 1;
xid2 = ((TransactionId) page2) * CLOG_XACTS_PER_PAGE;
xid2 += FirstNormalTransactionId + 1;
return (TransactionIdPrecedes(xid1, xid2) &&
TransactionIdPrecedes(xid1, xid2 + CLOG_XACTS_PER_PAGE - 1));
}
计算两个页面各自的起始xid
- 通过将page1强制转换为TransactionId类型(uint32)数据,并乘以每页事务数量CLOG_XACTS_PER_PAGE
- 再加上一个正常事务ID
通过TransactionIdPrecedes比较,来判断page1和page2哪个页面再截断过程(快速删除表中数据)中被认为是更旧的
若返回true,表示xid1在xid2之前,表示page1在截断过程中被认为更旧
截断过程(快速删除表中数据),相比于DELETE操作更快。
理解为:因为要初始化,所以要清空的操作。此外,判断两个页面的新旧,是为了SLRU算法服务
SimpleLruInit(XactCtl, "Xact", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
XactSLRULock, "pg_xact", LWTRANCHE_XACT_BUFFER,
SYNC_HANDLER_CLOG);
调用SimpleLruInit
函数初始化CLOG缓冲池,包括设置缓存的名称、缓冲区数量、每页LSN数量、锁定函数、文件名、锁事务号以及同步处理程序的标识符
SlruPagePrecedesUnitTests(XactCtl, CLOG_XACTS_PER_PAGE);
#define SlruPagePrecedesUnitTests(ctl, per_page) do {} while (0)
该函数是一个宏定义,但没有实质性操作,或许是未来要用于扩展单元测试代码
1.1 调用栈
该函数总体调用栈如图所示
1.1.1 被调关系
CLOGShmemInit
被CreateSharedMemoryAndSemaphores
函数调用,该函数用于创建和初始化共享内存以及信号量
1.1.2 调用关系
CLOGShmemBuffers
函数
Size
CLOGShmemBuffers(void)
{
LOG_FUNCTION_ENTRY();
LOG_FUNCTION_EXIT();
return Min(128, Max(4, NBuffers / 512));
}
用于计算CLOG缓存量buffers,采用的公式Min(128, Max(4, NBuffers / 512))
是一种合理的折衷方案,对于共享缓冲区(shared_buffers)值非常低的用户,CLOG 缓冲区数量也会相应减少,而其他用户将获得 128 个缓冲区。
SimpleLruInit
函数
用于初始化或连接到共享内存中的一个简单最近最少使用(LRU)缓存
void
SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
LWLock *ctllock, const char *subdir, int tranche_id,
SyncRequestHandler sync_handler)
{}
SlruPagePrecedesUnitTests
函数
用于对页面的前置关系函数进行单元测试
void
SlruPagePrecedesUnitTests(SlruCtl ctl, int per_page)
{
LOG_FUNCTION_ENTRY();
/* Test first, middle and last entries of a page. */
SlruPagePrecedesTestOffset(ctl, per_page, 0);
SlruPagePrecedesTestOffset(ctl, per_page, per_page / 2);
SlruPagePrecedesTestOffset(ctl, per_page, per_page - 1);
LOG_FUNCTION_EXIT();
return;
}
CLOGPagePrecedes
函数用于判断一个CLOG页面编号在截断操作中是否 “更旧”。
static bool
CLOGPagePrecedes(int page1, int page2)
{}
LOG_FUNCTION_ENTRY
以及LOG_FUNCTION_EXIT
用于记录函数开始和结束,用于调试定位
2 ZeroCLOGPage函数
注意:
-
缓冲池和页面槽号:
-
- 缓冲池是数据库管理系统用于缓存数据页面的内存区域。它允许数据库引擎在内存中操作数据,而不必每次都从磁盘读取。
-
- 缓冲池中的每个槽对应一个页面。槽号是用于标识页面在缓冲池中位置的索引。不同的槽号对应不同的页面。
static int ZeroCLOGPage(int pageno, bool writeXlog)
{
int slotno;
slotno = SimpleLruZeroPage(XactCtl, pageno);
if (writeXlog)
WriteZeroPageXlogRec(pageno);
return slotno;
}
- 函数参数含义
-
pageno
表示要初始化的页面编号
-
writeXlog
如果为真,则会记录一个 XLOG 记录
slotno = SimpleLruZeroPage(XactCtl, pageno);
- 根据
XactCtl
中的事务信息选择合适的页面槽号 - 将页面编号为
pageno
的CLOG页面设置为零,并返回一个新页面的槽号,赋值给slotno
if (writeXlog)
WriteZeroPageXlogRec(pageno);
如果writeXlog
为true,调用WriteZeroPageXlogRec
函数,在已经被设置为零且编号为 pageno
的页面记录一条XLOG记录
一个缓冲池中有许多CLOG页面,不同的槽号对应不同的CLOG页面,然后
WriteZeroPageXlogRec
函数是将XLOG记录写在编号为pageno
的CLOG页面上
最后,返回新页面的槽号
2.1 调用栈
3 总结
函数名 | 作用 |
---|---|
CLOGShmemInit | CLOG日式管理器的初始化,用于在共享内存中初始化CLOG缓冲池 |
ZeroCLOGPage | 将CLOG页面初始化或者重新初始化为零 |
CreateSharedMemoryAndSemaphores | 用于创建和初始化共享内存以及信号量 |
SimpleLruInit | 用于初始化或连接到共享内存中的一个简单最近最少使用(LRU)缓存 |
CLOGShmemBuffers | 用于计算CLOG缓存量buffers |
SlruPagePrecedesUnitTests | 用于对页面的前置关系函数进行单元测试 |
CLOGPagePrecedes | 函数用于判断一个CLOG页面编号在截断操作中是否 “更旧” |
LOG_FUNCTION_ENTRY | 用于记录函数开始 |
LOG_FUNCTION_EXIT | 用于记录函数结束 |
4 He3DB其余文章参考链接
海山数据库(He3DB)源码详解:He3DB-CLOG日志管理器函数之TransactionIdSetTreeStatus
海山数据库(He3DB)+AI(五):一种基于强化学习的数据库旋钮调优方法