当前位置:   article > 正文

postgresql源码学习(六)—— 回滚(中止)与清理事务_nodejs pgsql回滚

nodejs pgsql回滚

一、 AbortTransaction

1. gdb测试

会话1

会话2

2. 具体代码与跟踪

调用栈如下

  1. static void
  2. AbortTransaction(void)
  3. {
  4. TransactionState s = CurrentTransactionState;
  5. TransactionId latestXid;
  6. bool is_parallel_worker;
  7. /* Prevent cancel/die interrupt while cleaning up,清理期间避免被中断 */
  8. HOLD_INTERRUPTS();
  9. /* Make sure we have a valid memory context and resource owner,确认我们有有效的内存上下文和资源管理器 */
  10. AtAbort_Memory();
  11. AtAbort_ResourceOwner();
  12. /*
  13. * 释放所有轻量锁,而常规锁则在完成abort后才释放
  14. */
  15. LWLockReleaseAll();
  16. /* Clear wait information and command progress indicator,清理等待信息和命令进度指示器 */
  17. pgstat_report_wait_end();
  18. pgstat_progress_end_command();
  19. /* Clean up buffer I/O and buffer context locks, too,清理buffer I/O和buffer上下文锁 */
  20. AbortBufferIO();
  21. UnlockBuffers();
  22. /* Reset WAL record construction state,重置WAL记录结构状态 */
  23. XLogResetInsertion();
  24. /* Cancel condition variable sleep,取消条件变量sleep */
  25. ConditionVariableCancelSleep();
  26. /*
  27. * Also clean up any open wait for lock, since the lock manager will choke
  28. * if we try to wait for another lock before doing this.清理所有在等待的锁,如果在这步前有在等待的锁,锁管理器将会抑制它
  29. */
  30. LockErrorCleanup();
  31. /*
  32. * If any timeout events are still active, make sure the timeout interrupt
  33. * is scheduled. This covers possible loss of a timeout interrupt due to
  34. * longjmp'ing out of the SIGINT handler (see notes in handle_sig_alarm).
  35. * We delay this till after LockErrorCleanup so that we don't uselessly
  36. * reschedule lock or deadlock check timeouts. 处理超时事件
  37. */
  38. reschedule_timeouts();
  39. /*
  40. * Re-enable signals, in case we got here by longjmp'ing out of a signal
  41. * handler. We do this fairly early in the sequence so that the timeout
  42. * infrastructure will be functional if needed while aborting.
  43. */
  44. PG_SETMASK(&UnBlockSig);

  1. /*
  2. * check the current transaction state,检查当前事务状态
  3. */
  4. is_parallel_worker = (s->blockState == TBLOCK_PARALLEL_INPROGRESS);
  5. if (s->state != TRANS_INPROGRESS && s->state != TRANS_PREPARE)
  6. elog(WARNING, "AbortTransaction while in %s state",
  7. TransStateAsString(s->state));
  8. Assert(s->parent == NULL);
  9. /*
  10. * set the current transaction state information appropriately during the
  11. * abort processing,状态设置
  12. */
  13. s->state = TRANS_ABORT;

  1. /*
  2. * Reset user ID which might have been changed transiently. We need this
  3. * to clean up in case control escaped out of a SECURITY DEFINER function
  4. * or other local change of CurrentUserId; therefore, the prior value of
  5. * SecurityRestrictionContext also needs to be restored.
  6. *
  7. * (Note: it is not necessary to restore session authorization or role
  8. * settings here because those can only be changed via GUC, and GUC will
  9. * take care of rolling them back if need be.)
  10. * 设置用户id和安全上下文
  11. */
  12. SetUserIdAndSecContext(s->prevUser, s->prevSecContext);
  13. /* Forget about any active REINDEX.,取消所有活跃的reindex操作 */
  14. ResetReindexState(s->nestingLevel);
  15. /* Reset logical streaming state.,重置逻辑stream状态 */
  16. ResetLogicalStreamingState();

   

  1. /* If in parallel mode, clean up workers and exit parallel mode.,如果是并行模式,清理并退出并行模式 */
  2. if (IsInParallelMode())
  3. {
  4. AtEOXact_Parallel(false);
  5. s->parallelModeLevel = 0;
  6. }
  7. /*
  8. * do abort processing,
  9. */
  10. AfterTriggerEndXact(false); /* 'false' means it's abort */
  11. AtAbort_Portals();
  12. smgrDoPendingSyncs(false, is_parallel_worker);
  13. AtEOXact_LargeObject(false);
  14. AtAbort_Notify();
  15. AtEOXact_RelationMap(false, is_parallel_worker);
  16. AtAbort_Twophase();

  1. /*
  2. * Advertise the fact that we aborted in pg_xact (assuming that we got as
  3. * far as assigning an XID to advertise). But if we're inside a parallel
  4. * worker, skip this; the user backend must be the one to write the abort record.
  5. * 非并行模式,要将abort操作记录到XLOG日志
  6. */
  7. if (!is_parallel_worker)
  8. latestXid = RecordTransactionAbort(false);
  9. else
  10. {
  11. latestXid = InvalidTransactionId;
  12. /*
  13. * Since the parallel leader won't get our value of XactLastRecEnd in
  14. * this case, we nudge WAL-writer ourselves in this case. See related
  15. * comments in RecordTransactionAbort for why this matters.
  16. */
  17. XLogSetAsyncXactLSN(XactLastRecEnd);
  18. }
  19. TRACE_POSTGRESQL_TRANSACTION_ABORT(MyProc->lxid);
  20. /*
  21. * Let others know about no transaction in progress by me. Note that this
  22. * must be done _before_ releasing locks we hold and _after_
  23. * RecordTransactionAbort.
  24. */
  25. ProcArrayEndTransaction(MyProc, latestXid);

   

  1. /*
  2. * Post-abort cleanup. See notes in CommitTransaction() concerning
  3. * ordering. We can skip all of it if the transaction failed before
  4. * creating a resource owner.
  5. */
  6. if (TopTransactionResourceOwner != NULL)
  7. {
  8. if (is_parallel_worker)
  9. CallXactCallbacks(XACT_EVENT_PARALLEL_ABORT);
  10. else
  11. CallXactCallbacks(XACT_EVENT_ABORT);
  12. ResourceOwnerRelease(TopTransactionResourceOwner,
  13. RESOURCE_RELEASE_BEFORE_LOCKS,
  14. false, true);
  15. AtEOXact_Buffers(false);
  16. AtEOXact_RelationCache(false);
  17. AtEOXact_Inval(false);
  18. AtEOXact_MultiXact();
  19. ResourceOwnerRelease(TopTransactionResourceOwner,
  20. RESOURCE_RELEASE_LOCKS,
  21. false, true);
  22. ResourceOwnerRelease(TopTransactionResourceOwner,
  23. RESOURCE_RELEASE_AFTER_LOCKS,
  24. false, true);
  25. smgrDoPendingDeletes(false);
  26. AtEOXact_GUC(false, 1);
  27. AtEOXact_SPI(false);
  28. AtEOXact_Enum();
  29. AtEOXact_on_commit_actions(false);
  30. AtEOXact_Namespace(false, is_parallel_worker);
  31. AtEOXact_SMgr();
  32. AtEOXact_Files(false);
  33. AtEOXact_ComboCid();
  34. AtEOXact_HashTables(false);
  35. AtEOXact_PgStat(false, is_parallel_worker);
  36. AtEOXact_ApplyLauncher(false);
  37. pgstat_report_xact_timestamp(0);
  38. }
  39. /*
  40. * State remains TRANS_ABORT until CleanupTransaction().
  41. */
  42. RESUME_INTERRUPTS();
  43. }

3. 主要流程图

二、 CleanupTransaction

  • 主要功能:释放事务所占用的内存资源
  • AbortTransaction的区别:该函数是终止事务退出时最后调用的函数,做最后的实际清理工作。而AbortTransaction没有实际释放相关资源,只是切换一些资源的状态,使其能够被其他事务获得。

1. gdb测试

会话1

会话2

2. 具体代码与跟踪

调用栈如下

  1. static void
  2. CleanupTransaction(void)
  3. {
  4. TransactionState s = CurrentTransactionState;
  5. /*
  6. * State should still be TRANS_ABORT from AbortTransaction().事务状态应该为TRANS_ABORT,因为本函数在AbortTransaction()之后调用
  7. */
  8. if (s->state != TRANS_ABORT)
  9. elog(FATAL, "CleanupTransaction: unexpected state %s",
  10. TransStateAsString(s->state));
  11. /*
  12. * do abort cleanup processing
  13. */
  14. AtCleanup_Portals(); /* now safe to release portal memory,安全地释放portal内存 */
  15. AtEOXact_Snapshot(false, true); /* and release the transaction's snapshots,释放事务快照 */
  16. CurrentResourceOwner = NULL; /* and resource owner */
  17. if (TopTransactionResourceOwner)
  18. ResourceOwnerDelete(TopTransactionResourceOwner);
  19. s->curTransactionOwner = NULL;
  20. CurTransactionResourceOwner = NULL;
  21. TopTransactionResourceOwner = NULL;
  22. AtCleanup_Memory(); /* and transaction memory */

  1. s->fullTransactionId = InvalidFullTransactionId;
  2. s->subTransactionId = InvalidSubTransactionId;
  3. s->nestingLevel = 0;
  4. s->gucNestLevel = 0;
  5. s->childXids = NULL;
  6. s->nChildXids = 0;
  7. s->maxChildXids = 0;
  8. s->parallelModeLevel = 0;
  9. XactTopFullTransactionId = InvalidFullTransactionId;
  10. nParallelCurrentXids = 0;
  11. /*
  12. * done with abort processing, set current transaction state back to
  13. * default
  14. */
  15. s->state = TRANS_DEFAULT;
  16. }

3. 主要流程图

 

参考:

《PostgreSQL技术内幕:事务处理深度探索》第1章

PostgreSQL数据库内核分析》第7章

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/135172
推荐阅读
相关标签
  

闽ICP备14008679号