diff --git a/src/gausskernel/storage/large_object/inv_api.cpp b/src/gausskernel/storage/large_object/inv_api.cpp index 1f69c5dc9..7f7d1c830 100644 --- a/src/gausskernel/storage/large_object/inv_api.cpp +++ b/src/gausskernel/storage/large_object/inv_api.cpp @@ -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(); // 提升命令计数器,以便后续事务中的元组更新可见 }