Update inv_api.cpp

This commit is contained in:
Auweafan 2023-10-04 18:47:53 +08:00
parent 9124cc9411
commit f6ddcc93b3
1 changed files with 282 additions and 257 deletions

View File

@ -62,121 +62,135 @@ static void open_lo_relation(void)
if (t_thrd.storage_cxt.lo_heap_r && t_thrd.storage_cxt.lo_index_r)
return; /* already open in current xact */
/* Arrange for the top xact to own these relation references */
/* 获取当前的资源拥有者 */
currentOwner = t_thrd.utils_cxt.CurrentResourceOwner;
PG_TRY();
{
/* 将顶层事务的资源拥有者设置为当前资源拥有者 */
t_thrd.utils_cxt.CurrentResourceOwner = t_thrd.utils_cxt.TopTransactionResourceOwner;
/* Use RowExclusiveLock since we might either read or write */
/* 使用RowExclusiveLock因为我们可能需要读取或写入 */
if (t_thrd.storage_cxt.lo_heap_r == NULL)
/* 打开LargeObjectRelationId对应的heap关系并使用RowExclusiveLock */
t_thrd.storage_cxt.lo_heap_r = heap_open(LargeObjectRelationId, RowExclusiveLock);
if (t_thrd.storage_cxt.lo_index_r == NULL)
/* 打开LargeObjectLOidPNIndexId对应的index关系并使用RowExclusiveLock */
t_thrd.storage_cxt.lo_index_r = index_open(LargeObjectLOidPNIndexId, RowExclusiveLock);
}
PG_CATCH();
{
/* Ensure CurrentResourceOwner is restored on error */
/* 在错误发生时恢复CurrentResourceOwner的值 */
t_thrd.utils_cxt.CurrentResourceOwner = currentOwner;
PG_RE_THROW();
}
PG_END_TRY();
/* 恢复CurrentResourceOwner的值 */
t_thrd.utils_cxt.CurrentResourceOwner = currentOwner;
}
/*
* Clean up at main transaction end
*/
void close_lo_relation(bool isCommit)
{
if (t_thrd.storage_cxt.lo_heap_r || t_thrd.storage_cxt.lo_index_r) {
if (t_thrd.storage_cxt.lo_heap_r || t_thrd.storage_cxt.lo_index_r) { // 如果lo_heap_r或lo_index_r不为空
/*
* Only bother to close if committing; else abort cleanup will handle
* it
*
*/
if (isCommit) {
ResourceOwner currentOwner;
if (isCommit) { // 如果是提交事务
ResourceOwner currentOwner; // 当前资源拥有者
currentOwner = t_thrd.utils_cxt.CurrentResourceOwner;
PG_TRY();
currentOwner = t_thrd.utils_cxt.CurrentResourceOwner; // 保存当前资源拥有者
PG_TRY(); // 尝试执行以下代码块
{
t_thrd.utils_cxt.CurrentResourceOwner = t_thrd.utils_cxt.TopTransactionResourceOwner;
t_thrd.utils_cxt.CurrentResourceOwner =
t_thrd.utils_cxt.TopTransactionResourceOwner; // 设置当前资源拥有者为顶级事务资源拥有者
if (t_thrd.storage_cxt.lo_index_r)
index_close(t_thrd.storage_cxt.lo_index_r, NoLock);
if (t_thrd.storage_cxt.lo_heap_r)
heap_close(t_thrd.storage_cxt.lo_heap_r, NoLock);
if (t_thrd.storage_cxt.lo_index_r) // 如果lo_index_r不为空
index_close(t_thrd.storage_cxt.lo_index_r, NoLock); // 关闭索引关系
if (t_thrd.storage_cxt.lo_heap_r) // 如果lo_heap_r不为空
heap_close(t_thrd.storage_cxt.lo_heap_r, NoLock); // 关闭堆关系
}
PG_CATCH();
PG_CATCH(); // 捕获异常
{
/* Ensure CurrentResourceOwner is restored on error */
t_thrd.utils_cxt.CurrentResourceOwner = currentOwner;
PG_RE_THROW();
/* 确保错误时恢复CurrentResourceOwner */
t_thrd.utils_cxt.CurrentResourceOwner = currentOwner; // 恢复当前资源拥有者
PG_RE_THROW(); // 重新抛出异常
}
PG_END_TRY();
t_thrd.utils_cxt.CurrentResourceOwner = currentOwner;
t_thrd.utils_cxt.CurrentResourceOwner = currentOwner; // 恢复当前资源拥有者
}
t_thrd.storage_cxt.lo_heap_r = NULL;
t_thrd.storage_cxt.lo_index_r = NULL;
t_thrd.storage_cxt.lo_heap_r = NULL; // 将lo_heap_r置为NULL
t_thrd.storage_cxt.lo_index_r = NULL; // 将lo_index_r置为NULL
}
}
/*
* Same as pg_largeobject.c's LargeObjectExists(), except snapshot to
* read with can be specified.
*/
static bool myLargeObjectExists(Oid loid, Snapshot snapshot)
{
Relation pg_lo_meta;
ScanKeyData skey[1];
SysScanDesc sd;
HeapTuple tuple;
bool retval = false;
Relation pg_lo_meta; // LargeObjectMetadataRelationId 对应的关系
ScanKeyData skey[1]; // 扫描键
SysScanDesc sd; // 系统扫描描述符
HeapTuple tuple; // 堆元组
bool retval = false; // 返回值默认为false
// 初始化扫描键设置ObjectIdAttributeNumber对象ID属性编号等于loid
ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(loid));
// 打开LargeObjectMetadataRelationId对应的heap关系并使用AccessShareLock进行锁定
pg_lo_meta = heap_open(LargeObjectMetadataRelationId, AccessShareLock);
// 开始对pg_lo_meta关系进行系统扫描使用LargeObjectMetadataOidIndexId对应的索引
// 忽略无效元组指定快照为snapshot扫描键数量为1扫描键为skey
sd = systable_beginscan(pg_lo_meta, LargeObjectMetadataOidIndexId, true, snapshot, 1, skey);
// 获取下一个堆元组
tuple = systable_getnext(sd);
if (HeapTupleIsValid(tuple))
retval = true;
retval = true; // 如果堆元组有效则将retval设为true
// 结束系统扫描
systable_endscan(sd);
// 关闭pg_lo_meta关系释放AccessShareLock锁定的资源
heap_close(pg_lo_meta, AccessShareLock);
return retval;
return retval; // 返回retval值
}
/*
* Extract data field from a pg_largeobject tuple, detoasting if needed
* and verifying that the length is sane. Returns data pointer (a bytea *),
* data length, and an indication of whether to pfree the data pointer.
*/
static void getdatafield(Form_pg_largeobject tuple, bytea** pdatafield, int* plen, bool* pfreeit)
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
{
bytea* datafield = NULL;
int len;
bool freeit = false;
bytea *datafield = NULL; // 数据域指针
int len; // 数据域长度
bool freeit = false; // 是否需要释放数据域
datafield = &(tuple->data); /* see note at top of file */
if (VARATT_IS_EXTENDED(datafield)) {
datafield = (bytea*)heap_tuple_untoast_attr((struct varlena*)datafield);
freeit = true;
datafield = &(tuple->data); /* 见文件顶部的注释 */
if (VARATT_IS_EXTENDED(datafield)) { // 如果数据域使用扩展存储
datafield =
(bytea *)heap_tuple_untoast_attr((struct varlena *)datafield); // 将扩展存储的数据域解压成栈上数据域
freeit = true; // 设置需要释放数据域
}
len = VARSIZE(datafield) - VARHDRSZ;
if (len < 0 || len > LOBLKSIZE)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("pg_largeobject entry for OID %u, page %d has invalid data field size %d",
tuple->loid,
tuple->pageno,
len)));
*pdatafield = datafield;
*plen = len;
*pfreeit = freeit;
len = VARSIZE(datafield) - VARHDRSZ; // 获取数据域长度
if (len < 0 || len > LOBLKSIZE) // 如果数据域长度不正确
ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),
errmsg("pg_largeobject entry for OID %u, page %d has invalid data field size %d", tuple->loid,
tuple->pageno, len)));
*pdatafield = datafield; // 返回数据域指针
*plen = len; // 返回数据域长度
*pfreeit = freeit; // 返回是否需要释放数据域
}
/*
@ -197,6 +211,7 @@ Oid inv_create(Oid lobjId)
/*
* Create a new largeobject with empty data pages
largeobject型对象
*/
lobjId_new = LargeObjectCreate(lobjId);
@ -230,51 +245,62 @@ Oid inv_create(Oid lobjId)
* and subsidiary data are allocated in the specified memory context,
* which must be suitably long-lived for the caller's purposes.
*/
LargeObjectDesc* inv_open(Oid lobjId, int flags, MemoryContext mcxt)
LargeObjectDesc *inv_open(Oid lobjId, int flags, MemoryContext mcxt)
{
LargeObjectDesc* retval = NULL;
LargeObjectDesc *retval = NULL; // 返回的LargeObjectDesc型对象描述符指针
retval = (LargeObjectDesc*)MemoryContextAlloc(mcxt, sizeof(LargeObjectDesc));
retval =
(LargeObjectDesc *)MemoryContextAlloc(mcxt, sizeof(LargeObjectDesc)); // 分配内存空间用于存储LargeObjectDesc型对象描述符
retval->id = lobjId;
retval->subid = GetCurrentSubTransactionId();
retval->offset = 0;
retval->id = lobjId; // 设置LargeObjectDesc型对象的OID
retval->subid = GetCurrentSubTransactionId(); // 设置当前子事务ID
retval->offset = 0; // 设置偏移量
if (flags & INV_WRITE) {
retval->snapshot = SnapshotNow;
retval->flags = IFS_WRLOCK | IFS_RDLOCK;
} else if (flags & INV_READ) {
if (flags & INV_WRITE) { // 如果标志包含INV_WRITE表示以写模式打开LargeObjectDesc型对象
retval->snapshot = SnapshotNow; // 使用当前快照
retval->flags = IFS_WRLOCK | IFS_RDLOCK; // 设置写锁和读锁标志
} else if (flags & INV_READ) { // 如果标志包含INV_READ表示以读模式打开LargeObjectDesc型对象
/*
* We must register the snapshot in TopTransaction's resowner, because
* it must stay alive until the LO is closed rather than until the
* current portal shuts down.
* TopTransaction的资源拥有者中注册快照
* LO关闭之前保持活动状态portal关闭时
*/
retval->snapshot = RegisterSnapshotOnOwner(GetActiveSnapshot(), t_thrd.utils_cxt.TopTransactionResourceOwner);
retval->flags = IFS_RDLOCK;
} else
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid flags: %d", flags)));
retval->snapshot = RegisterSnapshotOnOwner(
GetActiveSnapshot(), t_thrd.utils_cxt.TopTransactionResourceOwner); // 在资源拥有者中注册快照
retval->flags = IFS_RDLOCK; // 设置读锁标志
} else {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid flags: %d", flags))); // 抛出错误,标志无效
}
/* Can't use LargeObjectExists here because it always uses SnapshotNow */
if (!myLargeObjectExists(lobjId, retval->snapshot))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("large object %u does not exist", lobjId)));
// 不能使用LargeObjectExists因为它总是使用SnapshotNow
if (!myLargeObjectExists(lobjId, retval->snapshot)) { // 如果大型对象不存在
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("large object %u does not exist", lobjId))); // 抛出错误,大型对象不存在
}
return retval;
return retval; // 返回LargeObjectDesc型对象描述符指针
}
/*
* Closes a large object descriptor previously made by inv_open(), and
* releases the long-term memory used by it.
*/
void inv_close(LargeObjectDesc* obj_desc)
void inv_close(LargeObjectDesc *obj_desc)
{
Assert(PointerIsValid(obj_desc));
/*
* obj_desc是否有效
*/
if (obj_desc->snapshot != SnapshotNow)
UnregisterSnapshotFromOwner(obj_desc->snapshot, t_thrd.utils_cxt.TopTransactionResourceOwner);
/*
* obj_desc的内存空间
*/
pfree(obj_desc);
}
/*
* Destroys an existing large object (not to be confused with a descriptor!)
*
@ -287,18 +313,19 @@ int inv_drop(Oid lobjId)
/*
* Delete any comments and dependencies on the large object
*/
object.classId = LargeObjectRelationId;
object.objectId = lobjId;
object.objectSubId = 0;
performDeletion(&object, DROP_CASCADE, 0);
object.classId = LargeObjectRelationId; // 设置对象类别为大型对象
object.objectId = lobjId; // 设置对象ID为目标大型对象的OID
object.objectSubId = 0; // 设置对象子ID为0
performDeletion(&object, DROP_CASCADE, 0); // 执行删除操作,级联删除依赖项
/*
* Advance command counter so that tuple removal will be seen by later
* large-object operations in this transaction.
* 便
*/
CommandCounterIncrement();
CommandCounterIncrement();// 提升命令计数器
return 1;
return 1;// 返回1表示删除成功
}
/*
@ -314,14 +341,24 @@ static uint32 inv_getsize(LargeObjectDesc* obj_desc)
SysScanDesc sd;
HeapTuple tuple;
/*
* obj_desc是否有效
*/
Assert(PointerIsValid(obj_desc));
/* 打开pg_largeobject关系 */
open_lo_relation();
/*
*
*/
ScanKeyInit(&skey[0], Anum_pg_largeobject_loid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(obj_desc->id));
sd = systable_beginscan_ordered(
t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 1, skey);
/*
* pg_largeobject索引
*/
sd = systable_beginscan_ordered(t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 1,
skey);
/*
* Because the pg_largeobject index is on both loid and pageno, but we
@ -336,136 +373,152 @@ static uint32 inv_getsize(LargeObjectDesc* obj_desc)
int len;
bool pfreeit = false;
/* 如果存在null值则错误 */
if (HeapTupleHasNulls(tuple)) /* paranoia */
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("null field found in pg_largeobject")));
/* 获取元组中的数据 */
data = (Form_pg_largeobject)GETSTRUCT(tuple);
getdatafield(data, &datafield, &len, &pfreeit);
/* 计算最后一个字节的位置 */
lastbyte = data->pageno * LOBLKSIZE + len;
/* 释放datafield指向的内存空间 */
if (pfreeit)
pfree(datafield);
}
/*
*
*/
systable_endscan_ordered(sd);
return lastbyte;
}
int inv_seek(LargeObjectDesc* obj_desc, int offset, int whence)
int inv_seek(LargeObjectDesc *obj_desc, int offset, int whence)
{
Assert(PointerIsValid(obj_desc));
Assert(PointerIsValid(obj_desc)); // 断言大型对象描述符指针有效
switch (whence) {
case SEEK_SET:
if (offset < 0)
case SEEK_SET: // 从文件开头开始计算offset
if (offset < 0) // 如果offset为负数则抛出错误
ereport(ERROR, (errcode_for_file_access(), errmsg("invalid seek offset: %d", offset)));
obj_desc->offset = offset;
obj_desc->offset = offset; // 设置偏移量为offset
break;
case SEEK_CUR:
if (offset < 0 && obj_desc->offset < ((uint32)(-offset)))
case SEEK_CUR: // 相对于当前位置计算offset
if (offset < 0 &&
obj_desc->offset < ((uint32)(-offset))) // 如果offset为负数且偏移量小于(-offset),则抛出错误
ereport(ERROR, (errcode_for_file_access(), errmsg("invalid seek offset: %d", offset)));
obj_desc->offset += offset;
obj_desc->offset += offset; // 偏移量增加offset
break;
case SEEK_END: {
uint32 size = inv_getsize(obj_desc);
if (offset < 0 && size < ((uint32)(-offset)))
case SEEK_END: { // 相对于文件末尾计算offset
uint32 size = inv_getsize(obj_desc); // 获取大型对象的大小
if (offset < 0 && size < ((uint32)(-offset))) // 如果offset为负数且对象大小小于(-offset),则抛出错误
ereport(ERROR, (errcode_for_file_access(), errmsg("invalid seek offset: %d", offset)));
obj_desc->offset = size + offset;
obj_desc->offset = size + offset; // 偏移量设置为对象大小加offset
} break;
default:
ereport(ERROR, (errcode_for_file_access(), errmsg("invalid whence: %d", whence)));
ereport(ERROR, (errcode_for_file_access(),
errmsg("invalid whence: %d", whence))); // 如果whence参数无效则抛出错误
}
return obj_desc->offset; // 返回当前偏移量
}
int inv_tell(LargeObjectDesc *obj_desc)
{
// 检查obj_desc是否有效
Assert(PointerIsValid(obj_desc));
// 返回obj_desc中的offset字段值
return obj_desc->offset;
}
int inv_tell(LargeObjectDesc* obj_desc)
{
Assert(PointerIsValid(obj_desc));
return obj_desc->offset;
}
int inv_read(LargeObjectDesc* obj_desc, char* buf, int nbytes)
int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
{
Assert(PointerIsValid(obj_desc));
int nread = 0;
Assert(PointerIsValid(obj_desc)); // 断言大型对象描述符指针有效
int nread = 0; // 已读取的字节数
int n;
int off;
int len;
int32 pageno = (int32)(obj_desc->offset / LOBLKSIZE);
int32 pageno = (int32)(obj_desc->offset / LOBLKSIZE); // 根据偏移量计算页号
uint32 pageoff;
ScanKeyData skey[2];
SysScanDesc sd;
HeapTuple tuple;
errno_t rc = EOK;
Assert(buf != NULL);
Assert(buf != NULL); // 断言缓冲区指针有效
if (nbytes <= 0) {
if (nbytes <= 0) { // 如果要读取的字节数小于等于0则直接返回0
return 0;
}
open_lo_relation();
open_lo_relation(); // 打开大型对象关系表
// 初始化扫描键值
ScanKeyInit(&skey[0], Anum_pg_largeobject_loid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(obj_desc->id));
ScanKeyInit(&skey[1], Anum_pg_largeobject_pageno, BTGreaterEqualStrategyNumber, F_INT4GE, Int32GetDatum(pageno));
sd = systable_beginscan_ordered(
t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 2, skey);
// 开始有序扫描大型对象索引表
sd = systable_beginscan_ordered(t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 2,
skey);
while ((tuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL) {
Form_pg_largeobject data;
bytea* datafield = NULL;
bytea *datafield = NULL;
bool pfreeit = false;
if (HeapTupleHasNulls(tuple)) /* paranoia */
if (HeapTupleHasNulls(tuple)) // 如果元组有空字段,抛出错误
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("null field found in pg_largeobject")));
data = (Form_pg_largeobject)GETSTRUCT(tuple);
data = (Form_pg_largeobject)GETSTRUCT(tuple); // 获取大型对象元组的数据
/*
* We expect the indexscan will deliver pages in order. However,
* there may be missing pages if the LO contains unwritten "holes". We
* want missing sections to read out as zeroes.
*/
pageoff = ((uint32)data->pageno) * LOBLKSIZE;
if (pageoff > obj_desc->offset) {
pageoff = ((uint32)data->pageno) * LOBLKSIZE; // 计算页的偏移量
if (pageoff > obj_desc->offset) { // 如果页的偏移量大于当前偏移量,则说明存在缺失的部分,将其读出为零
n = pageoff - obj_desc->offset;
n = (n <= (nbytes - nread)) ? n : (nbytes - nread);
rc = memset_s(buf + nread, n, '\0', n);
rc = memset_s(buf + nread, n, '\0', n); // 将buf中的一部分置为零
securec_check(rc, "", "");
nread += n;
obj_desc->offset += n;
}
if (nread < nbytes) {
off = (int)(obj_desc->offset - pageoff);
if (off < 0 || off >= LOBLKSIZE) {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid offset num:%d", off)));
off = (int)(obj_desc->offset - pageoff); // 计算在当前页内的偏移量
if (off < 0 || off >= LOBLKSIZE) { // 如果偏移量不合法,抛出错误
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid offset num:%d", off)));
}
getdatafield(data, &datafield, &len, &pfreeit);
if (len > off) {
getdatafield(data, &datafield, &len, &pfreeit); // 获取大型对象数据字段
if (len > off) { // 如果数据字段内有足够的数据可供读取
n = len - off;
n = (n <= (nbytes - nread)) ? n : (nbytes - nread);
rc = memcpy_s(buf + nread, n, VARDATA(datafield) + off, n);
rc = memcpy_s(buf + nread, n, VARDATA(datafield) + off, n); // 将数据复制到buf中
securec_check(rc, "", "");
nread += n;
obj_desc->offset += n;
}
if (pfreeit)
pfree(datafield);
pfree(datafield); // 释放大型对象数据字段的内存
}
if (nread >= nbytes)
break;
}
systable_endscan_ordered(sd);
systable_endscan_ordered(sd); // 结束扫描
return nread;
return nread; // 返回已读取的字节数
}
void check_obj_desc(const LargeObjectDesc* obj_desc)
{
/* enforce writability because snapshot is probably wrong otherwise */
@ -480,56 +533,57 @@ void check_obj_desc(const LargeObjectDesc* obj_desc)
ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("large object %u was already dropped", obj_desc->id)));
}
int inv_write(LargeObjectDesc* obj_desc, const char* buf, int nbytes)
int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
{
if (nbytes <= 0) {
return 0;
}
int nwritten = 0;
int n;
int off;
int len;
int32 pageno;
ScanKeyData skey[2];
SysScanDesc sd;
HeapTuple oldtuple = NULL;
Form_pg_largeobject olddata = NULL;
bool neednextpage = true;
bytea* datafield = NULL;
bool pfreeit = false;
int nwritten = 0; // 已写入的字节数
int n; // 当前写入的字节数
int off; // 偏移量,表示当前写入的位置在页面中的偏移量
int len; // 旧页中的有效数据长度
int32 pageno; // 页面号
ScanKeyData skey[2]; // 扫描键
SysScanDesc sd; // 系统扫描描述符
HeapTuple oldtuple = NULL; // 旧元组
Form_pg_largeobject olddata = NULL; // 旧的pg_largeobject元组
bool neednextpage = true; // 是否需要获取下一个已存在的页面
bytea *datafield = NULL; // 数据字段
bool pfreeit = false; // 是否需要释放datafield
struct {
bytea hdr;
char data[LOBLKSIZE]; /* make struct big enough */
int32 align_it; /* ensure struct is aligned well enough */
} workbuf;
char* workb = VARDATA(&workbuf.hdr);
HeapTuple newtup;
Datum values[Natts_pg_largeobject];
bool nulls[Natts_pg_largeobject];
bool replace[Natts_pg_largeobject];
CatalogIndexState indstate;
char data[LOBLKSIZE]; /* make struct big enough */
int32 align_it; /* ensure struct is aligned well enough */
} workbuf; // 工作缓冲区
char *workb = VARDATA(&workbuf.hdr); // 缓冲区数据部分的指针
HeapTuple newtup; // 新元组
Datum values[Natts_pg_largeobject]; // 插入的值
bool nulls[Natts_pg_largeobject]; // 是否为NULL
bool replace[Natts_pg_largeobject]; // 是否替换
CatalogIndexState indstate; // 目录索引状态
errno_t rc;
if (unlikely(!PointerIsValid(obj_desc))) {
return 0;
}
pageno = (int32)(obj_desc->offset / LOBLKSIZE);
pageno = (int32)(obj_desc->offset / LOBLKSIZE); // 计算页面号
rc = memset_s(&workbuf, sizeof(workbuf), 0, sizeof(workbuf));
rc = memset_s(&workbuf, sizeof(workbuf), 0, sizeof(workbuf)); // 清零工作缓冲区
securec_check(rc, "\0", "\0");
Assert(buf != NULL);
Assert(buf != NULL); // 断言buf不为空
check_obj_desc(obj_desc);
open_lo_relation();
check_obj_desc(obj_desc); // 检查对象描述符
open_lo_relation(); // 打开large object关系
indstate = CatalogOpenIndexes(t_thrd.storage_cxt.lo_heap_r);
indstate = CatalogOpenIndexes(t_thrd.storage_cxt.lo_heap_r); // 打开目录索引
// 初始化扫描键
ScanKeyInit(&skey[0], Anum_pg_largeobject_loid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(obj_desc->id));
ScanKeyInit(&skey[1], Anum_pg_largeobject_pageno, BTGreaterEqualStrategyNumber, F_INT4GE, Int32GetDatum(pageno));
sd = systable_beginscan_ordered(
t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 2, skey);
// 开始有序扫描
sd = systable_beginscan_ordered(t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 2,
skey);
while (nwritten < nbytes) {
/*
@ -556,8 +610,8 @@ int inv_write(LargeObjectDesc* obj_desc, const char* buf, int nbytes)
*
* First, load old data into workbuf
*/
getdatafield(olddata, &datafield, &len, &pfreeit);
rc = memcpy_s(workb, len, VARDATA(datafield), len);
getdatafield(olddata, &datafield, &len, &pfreeit); // 获取旧数据
rc = memcpy_s(workb, len, VARDATA(datafield), len); // 拷贝旧数据到工作缓冲区
securec_check(rc, "", "");
if (pfreeit)
pfree(datafield);
@ -565,25 +619,25 @@ int inv_write(LargeObjectDesc* obj_desc, const char* buf, int nbytes)
/*
* Fill any hole
*/
off = (int)(obj_desc->offset % LOBLKSIZE);
off = (int)(obj_desc->offset % LOBLKSIZE); // 计算偏移量
if (off > len) {
rc = memset_s(workb + len, off - len, '\0', off - len);
rc = memset_s(workb + len, off - len, '\0', off - len); // 填充空洞
securec_check(rc, "", "");
}
/*
* Insert appropriate portion of new data
*/
n = LOBLKSIZE - off;
n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
rc = memcpy_s(workb + off, n, buf + nwritten, n);
n = LOBLKSIZE - off; // 可写入的长度
n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten); // 取较小的长度
rc = memcpy_s(workb + off, n, buf + nwritten, n); // 拷贝数据到工作缓冲区
securec_check(rc, "", "");
nwritten += n;
obj_desc->offset += n;
nwritten += n; // 更新已写入的字节数
obj_desc->offset += n; // 更新偏移量
off += n;
/* compute valid length of new page */
len = (len >= off) ? len : off;
SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ); // 设置新页的长度
/*
* Form and insert updated tuple
@ -596,11 +650,11 @@ int inv_write(LargeObjectDesc* obj_desc, const char* buf, int nbytes)
securec_check(rc, "", "");
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
replace[Anum_pg_largeobject_data - 1] = true;
newtup =
heap_modify_tuple(oldtuple, RelationGetDescr(t_thrd.storage_cxt.lo_heap_r), values, nulls, replace);
simple_heap_update(t_thrd.storage_cxt.lo_heap_r, &newtup->t_self, newtup);
CatalogIndexInsert(indstate, newtup);
heap_freetuple(newtup);
newtup = heap_modify_tuple(oldtuple, RelationGetDescr(t_thrd.storage_cxt.lo_heap_r), values, nulls,
replace); // 修改元组
simple_heap_update(t_thrd.storage_cxt.lo_heap_r, &newtup->t_self, newtup); // 更新堆中的元组
CatalogIndexInsert(indstate, newtup); // 在索引中插入元组
heap_freetuple(newtup); // 释放新元组
/*
* We're done with this old page.
@ -614,24 +668,24 @@ int inv_write(LargeObjectDesc* obj_desc, const char* buf, int nbytes)
*
* First, fill any hole
*/
off = (int)(obj_desc->offset % LOBLKSIZE);
off = (int)(obj_desc->offset % LOBLKSIZE); // 计算偏移量
if (off > 0) {
rc = memset_s(workb, off, '\0', off);
rc = memset_s(workb, off, '\0', off); // 填充空洞
securec_check(rc, "", "");
}
/*
* Insert appropriate portion of new data
*/
n = LOBLKSIZE - off;
n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
rc = memcpy_s(workb + off, n, buf + nwritten, n);
n = LOBLKSIZE - off; // 可写入的长度
n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten); // 取较小的长度
rc = memcpy_s(workb + off, n, buf + nwritten, n); // 拷贝数据到工作缓冲区
securec_check(rc, "", "");
nwritten += n;
obj_desc->offset += n;
nwritten += n; // 更新已写入的字节数
obj_desc->offset += n; // 更新偏移量
/* compute valid length of new page */
len = off + n;
SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ); // 设置新页的长度
/*
* Form and insert updated tuple
@ -643,171 +697,142 @@ int inv_write(LargeObjectDesc* obj_desc, const char* buf, int nbytes)
values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
newtup = heap_form_tuple(t_thrd.storage_cxt.lo_heap_r->rd_att, values, nulls);
(void)simple_heap_insert(t_thrd.storage_cxt.lo_heap_r, newtup);
CatalogIndexInsert(indstate, newtup);
heap_freetuple(newtup);
newtup = heap_form_tuple(t_thrd.storage_cxt.lo_heap_r->rd_att, values, nulls); // 创建新元组
(void)simple_heap_insert(t_thrd.storage_cxt.lo_heap_r, newtup); // 插入新元组
CatalogIndexInsert(indstate, newtup); // 在索引中插入元组
heap_freetuple(newtup); // 释放新元组
}
pageno++;
}
systable_endscan_ordered(sd);
systable_endscan_ordered(sd); // 结束有序扫描
CatalogCloseIndexes(indstate);
CatalogCloseIndexes(indstate); // 关闭目录索引
/*
* Advance command counter so that my tuple updates will be seen by later
* large-object operations in this transaction.
*/
CommandCounterIncrement();
CommandCounterIncrement(); // 提升命令计数器,以确保后续事务可以看到我更新的元组
return nwritten;
}
void inv_truncate(LargeObjectDesc* obj_desc, int len)
void inv_truncate(LargeObjectDesc *obj_desc, int len)
{
int32 pageno = (int32)(len / LOBLKSIZE);
int32 pageno = (int32)(len / LOBLKSIZE); // 计算页号
int off;
ScanKeyData skey[2];
SysScanDesc sd;
HeapTuple oldtuple;
Form_pg_largeobject olddata;
struct {
bytea hdr;
char data[LOBLKSIZE]; /* make struct big enough */
int32 align_it; /* ensure struct is aligned well enough */
char data[LOBLKSIZE]; // 用于存储数据的缓冲区
int32 align_it;
} workbuf;
char* workb = VARDATA(&workbuf.hdr);
char *workb = VARDATA(&workbuf.hdr);
HeapTuple newtup;
Datum values[Natts_pg_largeobject] = {0, 0, 0};
bool nulls[Natts_pg_largeobject] = {false, false, false};
bool nulls[Natts_pg_largeobject] = {false, false, false};
bool replace[Natts_pg_largeobject] = {false, false, false};
CatalogIndexState indstate;
errno_t rc;
rc = memset_s(&workbuf, sizeof(workbuf), 0, sizeof(workbuf));
securec_check(rc, "\0", "\0");
Assert(PointerIsValid(obj_desc));
check_obj_desc(obj_desc);
open_lo_relation();
rc = memset_s(&workbuf, sizeof(workbuf), 0, sizeof(workbuf)); // 将workbuf缓冲区清零
securec_check(rc, "\0", "\0"); // 检查内存操作是否成功
indstate = CatalogOpenIndexes(t_thrd.storage_cxt.lo_heap_r);
Assert(PointerIsValid(obj_desc)); // 检查obj_desc指针是否有效
/*
* Set up to find all pages with desired loid and pageno >= target
*/
check_obj_desc(obj_desc); // 检查obj_desc的描述是否有效
open_lo_relation(); // 打开大型对象关系表
indstate = CatalogOpenIndexes(t_thrd.storage_cxt.lo_heap_r); // 打开索引
/* 设置扫描键查找指定loid和pageno大于等于目标的所有页 */
ScanKeyInit(&skey[0], Anum_pg_largeobject_loid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(obj_desc->id));
ScanKeyInit(&skey[1], Anum_pg_largeobject_pageno, BTGreaterEqualStrategyNumber, F_INT4GE, Int32GetDatum(pageno));
sd = systable_beginscan_ordered(
t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 2, skey);
sd = systable_beginscan_ordered(t_thrd.storage_cxt.lo_heap_r, t_thrd.storage_cxt.lo_index_r, obj_desc->snapshot, 2,
skey); // 开始有序扫描
/*
* If possible, get the page the truncation point is in. The truncation
* point may be beyond the end of the LO or in a hole.
*/
olddata = NULL;
if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL) {
if (HeapTupleHasNulls(oldtuple)) /* paranoia */
if (HeapTupleHasNulls(oldtuple)) // 检查旧元组是否有空值(出于谨慎)
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("null field found in pg_largeobject")));
olddata = (Form_pg_largeobject)GETSTRUCT(oldtuple);
Assert(olddata->pageno >= pageno);
Assert(olddata->pageno >= pageno); // 检查pageno是否大于等于目标页号
}
/*
* If we found the page of the truncation point we need to truncate the
* data in it. Otherwise if we're in a hole, we need to create a page to
* mark the end of data.
*/
if (olddata != NULL && olddata->pageno == pageno) {
/* First, load old data into workbuf */
bytea* datafield = NULL;
bytea *datafield = NULL;
bool pfreeit = false;
int pagelen;
/* 将旧数据加载到workbuf中 */
getdatafield(olddata, &datafield, &pagelen, &pfreeit);
rc = memcpy_s(workb, pagelen, VARDATA(datafield), pagelen);
securec_check(rc, "", "");
if (pfreeit)
pfree(datafield);
/*
* Fill any hole
*/
off = len % LOBLKSIZE;
/* 填充任何空隙 */
if (off > pagelen) {
rc = memset_s(workb + pagelen, off - pagelen, '\0', off - pagelen);
securec_check(rc, "", "");
}
/* compute length of new page */
SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ); // 计算新页的长度
/*
* Form and insert updated tuple
*/
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
replace[Anum_pg_largeobject_data - 1] = true;
newtup = heap_modify_tuple(oldtuple, RelationGetDescr(t_thrd.storage_cxt.lo_heap_r), values, nulls, replace);
simple_heap_update(t_thrd.storage_cxt.lo_heap_r, &newtup->t_self, newtup);
CatalogIndexInsert(indstate, newtup);
heap_freetuple(newtup);
newtup = heap_modify_tuple(oldtuple, RelationGetDescr(t_thrd.storage_cxt.lo_heap_r), values, nulls,
replace); // 修改旧的元组
simple_heap_update(t_thrd.storage_cxt.lo_heap_r, &newtup->t_self, newtup); // 更新堆上的元组
CatalogIndexInsert(indstate, newtup); // 插入索引
heap_freetuple(newtup); // 释放元组内存
} else {
/*
* If the first page we found was after the truncation point, we're in
* a hole that we'll fill, but we need to delete the later page
* because the loop below won't visit it again.
*/
if (olddata != NULL) {
Assert(olddata->pageno > pageno);
simple_heap_delete(t_thrd.storage_cxt.lo_heap_r, &oldtuple->t_self);
simple_heap_delete(t_thrd.storage_cxt.lo_heap_r, &oldtuple->t_self); // 删除后续页面
}
/*
* Write a brand new page.
*
* Fill the hole up to the truncation point
*/
off = len % LOBLKSIZE;
/* 填充空隙 */
if (off > 0) {
rc = memset_s(workb, off, '\0', off);
securec_check(rc, "", "");
}
/* compute length of new page */
SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ); // 计算新页的长度
/*
* Form and insert new tuple
*/
/* 插入新的元组 */
values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
newtup = heap_form_tuple(t_thrd.storage_cxt.lo_heap_r->rd_att, values, nulls);
(void)simple_heap_insert(t_thrd.storage_cxt.lo_heap_r, newtup);
CatalogIndexInsert(indstate, newtup);
heap_freetuple(newtup);
(void)simple_heap_insert(t_thrd.storage_cxt.lo_heap_r, newtup); // 在堆上插入元组
CatalogIndexInsert(indstate, newtup); // 插入索引
heap_freetuple(newtup); // 释放元组内存
}
/*
* Delete any pages after the truncation point. If the initial search
* didn't find a page, then of course there's nothing more to do.
*/
if (olddata != NULL) {
while ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL) {
simple_heap_delete(t_thrd.storage_cxt.lo_heap_r, &oldtuple->t_self);
simple_heap_delete(t_thrd.storage_cxt.lo_heap_r, &oldtuple->t_self); // 删除截断点后的页面
}
}
systable_endscan_ordered(sd);
systable_endscan_ordered(sd); // 结束有序扫描
CatalogCloseIndexes(indstate);
CatalogCloseIndexes(indstate); // 关闭索引
/*
* Advance command counter so that tuple updates will be seen by later
* large-object operations in this transaction.
*/
CommandCounterIncrement();
CommandCounterIncrement(); // 提升命令计数器,以便后续事务中的元组更新可见
}