Locks
SpinLock
使用tas实现的自旋锁。
while (TAS_SPIN(lock))
{
perform_spin_delay(&delayStatus);
}
perform_spin_delay(SpinDelayStatus *status)
{
/* CPU-specific delay each time through the loop */
SPIN_DELAY();
/* Block the process every spins_per_delay tries */
if (++(status->spins) >= spins_per_delay)
{
if (++(status->delays) > NUM_DELAYS)
s_lock_stuck(status->file, status->line, status->func);
if (status->cur_delay == 0) /* first time to delay? */
status->cur_delay = MIN_DELAY_USEC;
pg_usleep(status->cur_delay);
/* increase delay by a random fraction between 1X and 2X */
status->cur_delay += (int) (status->cur_delay *
pg_prng_double(&pg_global_prng_state) + 0.5);
/* wrap back to minimum delay when max is exceeded */
if (status->cur_delay > MAX_DELAY_USEC)
status->cur_delay = MIN_DELAY_USEC;
status->spins = 0;
}
}
如果没有tas,则使用信号量实现,属于最底层的锁
LWLock
https://zhmin.github.io/posts/postgresql-lwlock/ 文档描述清楚
- lock状态保存在共享内存中
- 共享变量是在竞争lock失败之后尝试PGSemaphoreLock,此时sem是默认值为0,所以会等待
- 本质上lock是同一块内存,可以调试查看地址,只是对内存使用信号量进行控制
- LWLock会进行lock竞争,有等待队列,但是没有死锁检测
常规Locks
使用lw实现
- 共有下面8种,
#0 LockAcquireExtended (locktag=0x7ffe04c94b00, lockmode=5, sessionLock=false, dontWait=true, reportMemoryError=true, locallockp=0x7ffe04c94af8) at /home/esoye/postgres/src/backend/storage/lmgr/lock.c:1145
#1 0x00005563f316862d in ConditionalLockRelationOid (relid=16385, lockmode=5) at /home/esoye/postgres/src/backend/storage/lmgr/lmgr.c:160
#2 0x00005563f2da006e in RangeVarGetRelidExtended (relation=0x5563f3738618, lockmode=5, flags=2, callback=0x5563f2e9ae66 <RangeVarCallbackForLockTable>, callback_arg=0x5563f37386b8) at /home/esoye/postgres/src/backend/catalog/namespace.c:390
#3 0x00005563f2e9adb6 in LockTableCommand (lockstmt=0x5563f37386a8) at /home/esoye/postgres/src/backend/commands/lockcmds.c:55
#4 0x00005563f3190b97 in standard_ProcessUtility
#define AccessShareLock 1 /* SELECT */ // 可以正常访问,除非删表等操作才会阻塞,其他操作不阻塞,需要调研事务细节
#define RowShareLock 2 /* SELECT FOR UPDATE/FOR SHARE */ // for share,意向锁,实际上是锁tuple,只是为了避免某些操作可能需要遍历全表时对表加锁,目的是提前检测
#define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */ // 意向排他锁,正常数据变动会加这个锁。
#define ShareUpdateExclusiveLock 4 /* VACUUM (non-FULL), ANALYZE, CREATE INDEX CONCURRENTLY */
#define ShareLock 5 /* CREATE INDEX (WITHOUT CONCURRENTLY) */
#define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW SHARE */
#define ExclusiveLock 7 /* blocks ROW SHARE/SELECT...FOR UPDATE */
#define AccessExclusiveLock 8 /* ALTER TABLE, DROP TABLE, VACUUM FULL, and unqualified LOCK TABLE */
static const LOCKMASK LockConflicts[] = {
0,
/* AccessShareLock */
LOCKBIT_ON(AccessExclusiveLock),
/* RowShareLock */
LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
/* RowExclusiveLock */
LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
/* ShareUpdateExclusiveLock */
LOCKBIT_ON(ShareUpdateExclusiveLock) | LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
/* ShareLock */
LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) |
LOCKBIT_ON(ShareRowExclusiveLock) |
LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
/* ShareRowExclusiveLock */
LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) |
LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) |
LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
/* ExclusiveLock */
LOCKBIT_ON(RowShareLock) |
LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) |
LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) |
LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
/* AccessExclusiveLock */
LOCKBIT_ON(AccessShareLock) | LOCKBIT_ON(RowShareLock) |
LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) |
LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) |
LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock)
};
typedef enum LockTagType {
LOCKTAG_RELATION, /* whole relation */
LOCKTAG_RELATION_EXTEND, /* the right to extend a relation */
LOCKTAG_DATABASE_FROZEN_IDS, /* pg_database.datfrozenxid */
LOCKTAG_PAGE, /* one page of a relation */
LOCKTAG_TUPLE, /* one physical tuple */
LOCKTAG_TRANSACTION, /* transaction (for waiting for xact done) */
LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */
LOCKTAG_SPECULATIVE_TOKEN, /* speculative insertion Xid and token */
LOCKTAG_OBJECT, /* non-relation database object */
LOCKTAG_USERLOCK, /* reserved for old contrib/userlock code */
LOCKTAG_ADVISORY /* advisory user locks */
} LockTagType;
https://blog.csdn.net/hyman_c/article/details/119666570
- 普通共享锁普通排他锁 锁检测在LockAcquireExtended函数中
- 访问共享锁访问排他锁
- 直接select 的时候会在analyze阶段对表加
AccessShareLock
,此时会进行bind操作,所以会open relation
#0 0x00005563f2c95ec4 in relation_openrv_extended (relation=0x5563f3738708, lockmode=1, missing_ok=true) at /home/esoye/postgres/src/backend/access/common/relation.c:186
#1 0x00005563f2d32f35 in table_openrv_extended (relation=0x5563f3738708, lockmode=1, missing_ok=true) at /home/esoye/postgres/src/backend/access/table/table.c:108
#2 0x00005563f2e2d02e in parserOpenTable (pstate=0x5563f3738928, relation=0x5563f3738708, lockmode=1) at /home/esoye/postgres/src/backend/parser/parse_relation.c:1367
#3 0x00005563f2e2d29b in addRangeTableEntry (pstate=0x5563f3738928, relation=0x5563f3738708, alias=0x0, inh=true, inFromCl=true) at /home/esoye/postgres/src/backend/parser/parse_relation.c:1443
#4 0x00005563f2e0a17d in transformTableEntry (pstate=0x5563f3738928, r=0x5563f3738708) at /home/esoye/postgres/src/backend/parser/parse_clause.c:395
#5 0x00005563f2e0bc36 in transformFromClauseItem (pstate=0x5563f3738928, n=0x5563f3738708, top_nsitem=0x7ffe04c94d90, namespace=0x7ffe04c94d98) at /home/esoye/postgres/src/backend/parser/parse_clause.c:1066
#6 0x00005563f2e09a29 in transformFromClause (pstate=0x5563f3738928, frmList=0x5563f3738750) at /home/esoye/postgres/src/backend/parser/parse_clause.c:132
#7 0x00005563f2dd1175 in transformSelectStmt (pstate=0x5563f3738928, stmt=0x5563f37387b0) at /home/esoye/postgres/src/backend/parser/analyze.c:1313
#8 0x00005563f2dcf606 in transformStmt (pstate=0x5563f3738928, parseTree=0x5563f37387b0) at /home/esoye/postgres/src/backend/parser/analyze.c:365
#9 0x00005563f2dcf4ad in transformOptionalSelectInto (pstate=0x5563f3738928, parseTree=0x5563f37387b0) at /home/esoye/postgres/src/backend/parser/analyze.c:305
#10 0x00005563f2dcf3a3 in transformTopLevelStmt (pstate=0x5563f3738928, parseTree=0x5563f37388b8) at /home/esoye/postgres/src/backend/parser/analyze.c:255
#11 0x00005563f2dcf093 in parse_analyze_fixedparams (parseTree=0x5563f37388b8, sourceText=0x5563f3737c50 "select * from t1;", paramTypes=0x0, numParams=0, queryEnv=0x0) at /home/esoye/postgres/src/backend/parser/analyze.c:123
#12 0x00005563f3186c9d in pg_analyze_and_rewrite_fixedparams (parsetree=0x5563f37388b8, query_string=0x5563f3737c50 "select * from t1;", paramTypes=0x0, numParams=0, queryEnv=0x0) at /home/esoye/postgres/src/backend/tcop/postgres.c:643
#13 0x00005563f31874a7 in exec_simple_query (query_string=0x5563f3737c50 "select * from t1;") at /home/esoye/postgres/src/backend/tcop/postgres.c:1152
Read other posts