Skip to content

Commit 022655c

Browse files
committed
C
1 parent f327db5 commit 022655c

File tree

5 files changed

+91
-0
lines changed

5 files changed

+91
-0
lines changed

src/backend/access/heap/heapam.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,6 +2759,67 @@ xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
27592759
return false;
27602760
}
27612761

2762+
/**
2763+
关于crosscheck参数:
2764+
经常用Estate结构中的来填入
2765+
Snapshot es_crosscheck_snapshot; // crosscheck time qual for RI
2766+
注释中的 RI 是 Referential Integrity(引用完整性)的缩写
2767+
2768+
在 PostgreSQL 的 `heap_delete` 函数中,`crosscheck` 参数是一个可选的快照(`Snapshot`),用于在删除元组时执行额外的可见性检查。它的主要作用是确保删除操作符合某些特定的约束条件,通常与外键约束或其他复杂的事务逻辑相关。
2769+
2770+
---
2771+
2772+
### 1. **`crosscheck` 参数的作用**
2773+
`crosscheck` 参数的主要功能是提供一个额外的快照,用于验证元组是否在该快照中可见。
2774+
如果元组在 `crosscheck` 快照中不可见,则删除操作会被拒绝,并返回 `TM_Updated` 状态。这种机制通常用于确保事务一致性,避免删除操作破坏其他事务的逻辑。
2775+
2776+
---
2777+
2778+
### 2. **典型使用场景**
2779+
#### **(1) 外键约束的级联删除**
2780+
在外键约束的级联删除(`ON DELETE CASCADE`)中,`crosscheck` 参数可以用来确保引用的父表元组在删除时仍然符合外键约束的可见性规则。例如:
2781+
- 当删除父表中的一行时,子表中的引用行可能需要被级联删除。
2782+
- 在这种情况下,`crosscheck` 快照可以用来验证父表的元组是否仍然符合外键约束的可见性要求。
2783+
2784+
#### **(2) 事务隔离级别的验证**
2785+
在某些事务隔离级别(如可重复读或序列化)下,`crosscheck` 参数可以确保删除操作不会破坏其他事务的视图。例如:
2786+
- 如果另一个事务已经修改了目标元组,使其在 `crosscheck` 快照中不可见,则当前事务的删除操作会被拒绝。
2787+
2788+
#### **(3) 复杂的业务逻辑**
2789+
在某些复杂的业务逻辑中,`crosscheck` 参数可以用来确保删除操作符合特定的业务规则。例如:
2790+
- 在多表联动操作中,`crosscheck` 快照可以用来验证元组是否符合某些特定的条件。
2791+
2792+
---
2793+
2794+
### 3. **`crosscheck` 的工作机制**
2795+
在 `heap_delete` 函数中,当 `crosscheck` 参数不为 `InvalidSnapshot` 时,会对目标元组执行额外的可见性检查:
2796+
- 调用 `HeapTupleSatisfiesVisibility` 函数,使用 `crosscheck` 快照验证元组的可见性。
2797+
- 如果元组在 `crosscheck` 快照中不可见,则删除操作会返回 `TM_Updated` 状态,表示元组已被其他事务更新或删除。
2798+
2799+
代码片段如下:
2800+
```c
2801+
if (crosscheck != InvalidSnapshot && result == TM_Ok)
2802+
{
2803+
if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
2804+
result = TM_Updated;
2805+
}
2806+
```
2807+
2808+
---
2809+
2810+
### 4. **返回值的处理**
2811+
如果 `crosscheck` 检查失败,`heap_delete` 函数会返回 `TM_Updated`,并填充 `TM_FailureData` 结构体,提供有关失败的详细信息:
2812+
- **`ctid`**: 指向元组的链式更新目标。
2813+
- **`xmax`**: 表示删除元组的事务 ID。
2814+
- **`cmax`**: 表示最后修改元组的命令 ID(仅在 `TM_SelfModified` 情况下可用)。
2815+
2816+
调用者可以根据返回值和失败数据决定如何处理,例如重试操作或回滚事务。
2817+
2818+
---
2819+
2820+
### 5. **总结**
2821+
`crosscheck` 参数在 `heap_delete` 中提供了一种灵活的机制,用于在删除元组时执行额外的可见性检查。它的典型应用场景包括外键约束的级联删除、事务隔离级别的验证以及复杂的业务逻辑。通过结合 `crosscheck` 快照,PostgreSQL 能够确保删除操作的正确性和一致性,同时避免破坏其他事务的逻辑。
2822+
*/
27622823
/*
27632824
* heap_delete - delete a tuple
27642825
*

src/backend/access/heap/heapam_handler.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,11 @@ heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot,
356356
return result;
357357
}
358358

359+
/**
360+
加行锁(LockTupleMode 4类),场景
361+
- 更新或删除操作: 在执行 UPDATE 或 DELETE 操作时,需要对目标行加锁,以防止其他事务同时修改或删除该行。
362+
- 显式行锁: 当用户通过 SELECT ... FOR UPDATE 或 SELECT ... FOR SHARE 等语句显式请求行锁时,底层会调用类似 heapam_tuple_lock 的函数来实现加锁。
363+
*/
359364
static TM_Result
360365
heapam_tuple_lock(Relation relation, ItemPointer tid, Snapshot snapshot,
361366
TupleTableSlot *slot, CommandId cid, LockTupleMode mode,

src/backend/catalog/heap.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,13 @@ SystemAttributeByName(const char *attname)
270270
* XXX END OF UGLY HARD CODED BADNESS XXX
271271
* ---------------------------------------------------------------- */
272272

273+
/**
274+
总结
275+
- heap_create_with_catalog 是一个高层次的函数,负责创建一个完整的、带有系统目录条目的关系。它会调用 heap_create 来完成物理存储的创建,并在系统目录中注册元数据。
276+
- heap_create 是一个底层函数,专注于创建关系的物理存储,不涉及系统目录的操作。
273277
278+
(这里的系统目录指的就是catalog那些系统表)
279+
*/
274280
/* ----------------------------------------------------------------
275281
* heap_create - Create an uncataloged heap relation
276282
*

src/backend/executor/nodeModifyTable.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,11 @@ ExecInsert(ModifyTableContext *context,
10931093
*/
10941094
specToken = SpeculativeInsertionLockAcquire(GetCurrentTransactionId());
10951095

1096+
/**
1097+
推测性插入通常用于实现 INSERT ... ON CONFLICT 的逻辑。
1098+
在这种情况下,系统需要先尝试插入元组,然后检查是否存在冲突(例如违反唯一性约束)。
1099+
如果没有冲突,插入操作会被确认;如果有冲突,系统可以选择更新现有元组或放弃插入。
1100+
*/
10961101
/* insert the tuple, with the speculative token */
10971102
table_tuple_insert_speculative(resultRelationDesc, slot,
10981103
estate->es_output_cid,

src/include/access/tableam.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ typedef enum ScanOptions
7272
SO_NEED_TUPLES = 1 << 10,
7373
} ScanOptions;
7474

75+
/**
76+
Result codes for table_{update,delete,lock_tuple}
77+
update/delete/lock,它们都很相似,都需要考虑到时间上的绝对因素
78+
*/
7579
/*
7680
* Result codes for table_{update,delete,lock_tuple}, and for visibility
7781
* routines inside table AMs.
@@ -1276,6 +1280,10 @@ extern bool table_index_fetch_tuple_check(Relation rel,
12761280
*/
12771281

12781282

1283+
/**
1284+
根据指定的 tid(元组标识符)从表中获取元组,并将其存储到 slot(元组槽)中
1285+
一般在modifytable(update操作)中被调用
1286+
*/
12791287
/*
12801288
* Fetch tuple at `tid` into `slot`, after doing a visibility test according to
12811289
* `snapshot`. If a tuple was found and passed the visibility test, returns
@@ -1440,6 +1448,12 @@ table_tuple_complete_speculative(Relation rel, TupleTableSlot *slot,
14401448
succeeded);
14411449
}
14421450

1451+
1452+
/**
1453+
该函数的主要功能是将多个元组批量插入到指定的表中。
1454+
通过批量操作,它能够减少对同一页面的多次锁定和解锁操作,同时将多个插入操作的日志(WAL,Write-Ahead Logging)合并为一条记录。
1455+
这种优化显著提高了插入性能,特别是在需要插入大量数据的场景下(如copy,临时表等)。
1456+
*/
14431457
/*
14441458
* Insert multiple tuples into a table.
14451459
*

0 commit comments

Comments
 (0)