ResourceOwner设计比较简单,这里做下总结,方便后面查询。
速查:
单SQL执行为例:
注意申请的两个ResourceOwner会有层次关系,最外层套的是TopTransaction,内层是Portal。
CurrentResourceOwner
|
|
v
{parent = 0x1996c58, firstchild = 0x0, nextchild = 0x0, name = 0xd47445 "Portal", ... }
| ^
| |
v |
{parent = 0x0, firstchild = 0x198a520, nextchild = 0x0, name = 0xbafcac "TopTransaction", ... }
itemsarr[k] holds an ID, for 0 <= k < nitems <= maxitems = capacity.
typedef struct ResourceArray
{
Datum *itemsarr; /* buffer for storing values */
Datum invalidval; /* value that is considered invalid */
uint32 capacity; /* allocated length of itemsarr[] */
uint32 nitems; /* how many items are stored in items array */
uint32 maxitems; /* current limit on nitems before enlarging */
uint32 lastidx; /* index of last item returned by GetAny */
} ResourceArray;
typedef struct ResourceOwnerData
{
ResourceOwner parent; /* NULL if no parent (toplevel owner) */
ResourceOwner firstchild; /* head of linked list of children */
ResourceOwner nextchild; /* next child of same parent */
const char *name; /* name (just for debugging) */
/* We have built-in support for remembering: */
ResourceArray bufferarr; /* owned buffers */
ResourceArray catrefarr; /* catcache references */
ResourceArray catlistrefarr; /* catcache-list pins */
ResourceArray relrefarr; /* relcache references */
ResourceArray planrefarr; /* plancache references */
ResourceArray tupdescarr; /* tupdesc references */
ResourceArray snapshotarr; /* snapshot references */
ResourceArray filearr; /* open temporary files */
ResourceArray dsmarr; /* dynamic shmem segments */
ResourceArray jitarr; /* JIT contexts */
ResourceArray cryptohasharr; /* cryptohash contexts */
ResourceArray hmacarr; /* HMAC contexts */
/* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
int nlocks; /* number of owned locks */
LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */
} ResourceOwnerData;
typedef struct ResourceArray
{
Datum *itemsarr; /* buffer for storing values */
Datum invalidval; /* value that is considered invalid */
uint32 capacity; /* allocated length of itemsarr[] */
uint32 nitems; // 指向当前数组使用位置
uint32 maxitems; /* current limit on nitems before enlarging */
uint32 lastidx; /* index of last item returned by GetAny */
} ResourceArray;
以记录Pin了哪些buffer为例:
in TopMemoryContext
(注意类型是Datum,可以存指针【引用】,也可以直接存值【值】)resarr->itemsarr[idx] = value
UnPin操作:
开放hash
static void
ResourceArrayAdd(ResourceArray *resarr, Datum value)
{
uint32 idx;
// resarr->capacity <= 64
if (RESARRAY_IS_ARRAY(resarr))
{
idx = resarr->nitems;
}
else
{
// 到这resarr->capacity最少为128
uint32 mask = resarr->capacity - 1;
// hash value 映射到 0 - 127的位置上
idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
for (;;)
{
if (resarr->itemsarr[idx] == resarr->invalidval)
break;
idx = (idx + 1) & mask;
}
}
resarr->lastidx = idx;
resarr->itemsarr[idx] = value;
resarr->nitems++;
}
锁比较特殊,没用ResourceArray数组,直接使用ResourceOwnerData中的locks数组。
typedef struct ResourceOwnerData
{
...
int nlocks; /* number of owned locks */
LOCALLOCK *locks[15]; /* list of owned locks */
} ResourceOwnerData;
记录常规锁:
ResourceOwnerRememberLock:记录Local常规锁,只记录15把锁,多了直接放弃。
删除记录常规锁:
ResourceOwnerForgetLock:删除记录Local常规锁,只记录15把锁,多了直接放弃。
递归,遍历当前owner同一层的所有owner,按child->nextchild来找;注意,不会释放parent的资源!
ResourceOwnerRelease
ResourceOwnerReleaseInternal
for (child = owner->firstchild; child != NULL; child = child->nextchild)
ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
..
..
【干活】
...
...
【干活】:
释放函数提供三种模式,释放不同资源:
typedef enum
{
RESOURCE_RELEASE_BEFORE_LOCKS,
RESOURCE_RELEASE_LOCKS,
RESOURCE_RELEASE_AFTER_LOCKS
} ResourceReleasePhase;
调用三次按顺序释放不同资源:
PortalDrop
...
ResourceOwnerRelease(portal->resowner,
RESOURCE_RELEASE_BEFORE_LOCKS,
isCommit, false);
ResourceOwnerRelease(portal->resowner,
RESOURCE_RELEASE_LOCKS,
isCommit, false);
ResourceOwnerRelease(portal->resowner,
RESOURCE_RELEASE_AFTER_LOCKS,
isCommit, false);
ResourceOwnerRelease具体工作:
每种资源调用自己的释放函数,都类似下面释放过程
...
while (ResourceArrayGetAny(&(owner->bufferarr), &foundres))
{
Buffer res = DatumGetBuffer(foundres);
ReleaseBuffer(res);
}
...
drop table table1;
create table table1(i int);
BEGIN;
INSERT INTO table1 VALUES (1);
-- s1
SAVEPOINT my_savepoint1;
INSERT INTO table1 VALUES (2);
-- s2
SAVEPOINT my_savepoint2;
INSERT INTO table1 VALUES (3);
...
...
两个检查点:两层子事务:
顶层:0x1996c58
p *CurrentResourceOwner->parent->parent
{parent = 0x0, firstchild = 0x198a520中层, nextchild = 0x0, name = 0xbafcac "TopTransaction"
中层:0x198a520
p *CurrentResourceOwner->parent
{parent = 0x1996c58顶层, firstchild = 0x19a2b40底层, nextchild = 0x0, name = 0xbafd01 "SubTransaction"
底层:0x19a2b40
p *CurrentResourceOwner
{parent = 0x198a520中层, firstchild = 0x0, nextchild = 0x0, name = 0xbafd01 "SubTransaction"