为简化查询相关资源的管理(如pin和表级锁等),PG中引入了ResourceOwner对象
的概念。这些与查询相关的资源必须以某种可靠的方式被跟踪,以确保当查询结束后
被释放,甚至是查询由于错误被中止时资源被释放。相对于期望整个执行过程拥有牢
不可破的数据结构,PG更愿意采用单例模式去跟踪这些资源。
ResourceOwner的API建立在MemoryContext API之上,MemoryContext API已经
被证明是十分灵活的,并且在防止内存泄漏上十分有效。另外,ResourceOwner可以
有子对象(child ResourceOwner),可以形成对象树,当释放父对象(parent
ResourceOwner)时,所有直接和间接的子节点都将被释放。
(看起来十分具有诱惑力,统一ResourceOwner和MemoryContext到一个统一的对
象,但他们的使用方式差异很大,实际上并没有多大好处。)
PG中为每个事务、子事务以及每个Portal创建一个ResourceOwner。在Portal的
整个生命周期中,全局变量CurrentResourceOwner指向Portal的ResourceOwner,这
有助于类似这样的操作(如ReadBuffer、LockAcquire等)都可以记录所需的资源到这
个ResourceOwner中。
当Portal关闭时,任何未释放的资源(典型的主要是锁)成为当前事务的责任。这
体现在将Portal的ResourceOwner变成当前事务的ResourceOwner的子对象。
resowner.c中当释放子对象时,自动传输资源给父对象。同样,子事务的
ResourceOwner也是他们直接父对象的子对象。
PG既需要事务相关的ResourceOwner也需要Portal相关的ResourceOwner,因为事
务可能在尚未有Portal关联时进行要求资源的初始化工作(如查询分析query
parsing)。
API 一览
--------------------------------------------------
基本API:
* 创建ResourceOwner
* 资源关联或解除关联到ResourceOwner
* 释放ResourceOwner的拥有资源(释放所有拥有资源,但不包括对象自身)
* 删除ResourceOwner对象(包括子对象),所有拥有资源必须提前被释放掉
锁被特殊处理,因为在非错误情况下,无论是在子事务中或是Portal申请的锁,
锁的持有会直到事务结束。因此,当isCommit为true时,在子对象(child
ResourceOwner中的释放操作锁操作会将锁的所有权(lock ownership)传递给父对象
,而不是真的释放掉锁。
目前,ResourceOwner直接支持缓冲区pin、lgmr锁、catcache、relcache及
tupdesc引用等的属主关系维护,其它对象可通过记录所属ResourceOwner的指针与
ResourceOwner进行关联。在其它模块中有这样一个API,当ResourceOwner释放时会
得到控制权(get control),来扫描自己的数据以发现需要被删除的对象。
当unpin缓冲区、释放锁秋或cache引用时,当前CurrentResourceOwner必须指向
它们申请时相同的ResourceOwner。通过额外的记录可以放松这个限制,但目前来看
没有这个必要。
代码中,若有CurrentResourceOwner的暂时变化,应使用PG_TRY结构,以确保当
出现错误退出时,前一CurrentResourceOwner能正确恢复。
原文见postgresql源码中resowner目录的readme
原文链接:https://www.f2er.com/postgresql/196774.html