正文

PostgreSQL事务回卷实战案例详析(postcard造句)一篇读懂

文章摘要

这篇文章主要讨论了一个事务ID管理的函数SetTransactionIdLimit,用于计算事务ID的限制值(如xidWrapLimit、xidStopLimit、xidWarnLimit和xidVacLimit)。这些限制值用于确保事务ID在正常运行中不会溢出,从而避免数据丢失或系统崩溃。代码还涉及事务ID的同步、错误报告以及警告信息的输出,特别是在事务ID超过阈值时,会触发VACUUM操作以清理旧事务ID。此外,文章还提到了如何判断事务ID是否超过设定限制(TransactionIdFollowsOrEquals函数),以及生成新的事务ID(GetNewTransactionId函数)。总体来看,文章聚焦于事务ID的管理机制及其错误处理策略。

void SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid) { TransactionId xidVacLimit; TransactionId xidWarnLimit; TransactionId xidStopLimit; TransactionId xidWrapLimit; TransactionId curXid; Assert(TransactionIdIsNormal(oldest_datfrozenxid)); xidWrapLimit=oldest_datfrozenxid + (MaxTransactionId >> 1); if (xidWrapLimit < FirstNormalTransactionId) xidWrapLimit +=FirstNormalTransactionId; xidStopLimit=xidWrapLimit – 1000000; if (xidStopLimit < FirstNormalTransactionId) xidStopLimit -=FirstNormalTransactionId; xidWarnLimit=xidStopLimit – 10000000; if (xidWarnLimit < FirstNormalTransactionId) xidWarnLimit -=FirstNormalTransactionId; xidVacLimit=oldest_datfrozenxid + autovacuum_freeze_max_age; if (xidVacLimit < FirstNormalTransactionId) xidVacLimit +=FirstNormalTransactionId; LWLockAcquire(XidGenLock, LW_EXCLUSIVE); ShmemVariableCache->oldestXid=oldest_datfrozenxid; ShmemVariableCache->xidVacLimit=xidVacLimit; ShmemVariableCache->xidWarnLimit=xidWarnLimit; ShmemVariableCache->xidStopLimit=xidStopLimit; ShmemVariableCache->xidWrapLimit=xidWrapLimit; ShmemVariableCache->oldestXidDB=oldest_datoid; curXid=XidFromFullTransactionId(ShmemVariableCache->nextFullXid); LWLockRelease(XidGenLock); ereport(DEBUG1, (errmsg(“transaction ID wrap limit is %u, limited by database with OID %u”, xidWrapLimit, oldest_datoid))); if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) && IsUnderPostmaster && !InRecovery) SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER); if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit) && !InRecovery) { char *oldest_datname; if (IsTransactionState()) oldest_datname=get_database_name(oldest_datoid); else oldest_datname=NULL; if (oldest_datname) ereport(WARNING, (errmsg(“database “%s” must be vacuumed within %u transactions”, oldest_datname, xidWrapLimit – curXid), errhint(“To avoid a database shutdown, execute a database-wide VACUUM in that database.\n” “You might also need to commit or roll back old prepared transactions, or drop stale replication slots.”))); else ereport(WARNING, (errmsg(“database with OID %u must be vacuumed within %u transactions”, oldest_datoid, xidWrapLimit – curXid), errhint(“To avoid a database shutdown, execute a database-wide VACUUM in that database.\n” “You might also need to commit or roll back old prepared transactions, or drop stale replication slots.”))); } } bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2) { int32 diff; if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2)) return (id1 >=id2); diff=(int32) (id1 – id2); return (diff >=0); } FullTransactionId GetNewTransactionId(bool isSubXact) { full_xid=ShmemVariableCache->nextFullXid; xid=XidFromFullTransactionId(full_xid); if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidVacLimit)) { TransactionId xidWarnLimit=ShmemVariableCache->xidWarnLimit; TransactionId xidStopLimit=ShmemVariableCache->xidStopLimit; TransactionId xidWrapLimit=ShmemVariableCache->xidWrapLimit; Oid oldest_datoid=ShmemVariableCache->oldestXidDB; if (IsUnderPostmaster && TransactionIdFollowsOrEquals(xid, xidStopLimit)) { char *oldest_datname=get_database_name(oldest_datoid); if (oldest_datname) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg(“database is not accepting commands to avoid wraparound data loss in database “%s””, oldest_datname), errhint(“Stop the postmaster and vacuum that database in single-user mode.\n” “You might also need to commit or roll back old prepared transactions, or drop stale replication slots.”))); } } }