【问题标题】:Can page level locks cause a deadlock between 2 transactions trying to lock 2 different rows on the same page?页面级锁会导致尝试锁定同一页上的 2 个不同行的 2 个事务之间的死锁吗?
【发布时间】:2020-09-01 11:18:26
【问题描述】:

根据postgres docs section 13.3.2

除了表和行锁,页级共享/排他锁 用于控制对共享表页的读/写访问 缓冲池。这些锁在一行被释放后立即释放 获取或更新。应用程序开发人员通常不需要 与页级锁有关,但在这里提到它们是为了 完整性。

我的理解是,我不必担心我的事务是否足够大,以至于它们可能会锁定足够长的行,以至于会发生以下情况:T1 在 P1 上锁定了 R1,并希望在 P2 上锁定 R2,但不能这样做因为 T2 在 P2 上的 R3 上有一个锁,直到它在 P1 上的 R4 上获得一个锁才会释放它。

T -> 交易
P -> 页面
R -> 行

这个假设是否正确,或者我应该使我的事务足够短以降低发生这种锁定的可能性?

【问题讨论】:

  • 我的理解是,当页面数据被访问在内存中时,这些页面锁只会在很短的时间内被持有。它们不会在交易期间保留,也不会应用于磁盘上的块。
  • 根据您的回复和@Laurenz Albe 的回复,我非常有信心是这种情况,但现在我有兴趣找到更多关于这些页面锁如何工作的信息,除了代码本身之外,似乎没有官方资源。你们有谁知道我可以检查的任何内部设计规范吗?

标签: postgresql postgresql-9.6


【解决方案1】:

无论您的事务需要多长时间,页面级别的锁总是会保持很短的时间。与其他锁不同,它们在提交之前释放,在不再需要时立即释放。

此外,页锁总是以它们不能参与死锁的方式进行的(除非 PostgreSQL 有错误)。

详情:

使用src/backend/storage/lmgr/lmgr.c 中的LockPage 函数获取页面锁定。目前,它们仅在索引清理期间与 GIN 索引一起使用,当挂起列表集成到主索引中时(src/backend/access/gin/ginfast.c 中的函数 ginInsertCleanup):锁定元页以防止函数并发执行。

【讨论】:

  • 你知道关于 postgres 官方文档/规范的任何声明吗?我正在寻找它,但看不到任何参考,而且我引用的部分似乎相当模糊......
猜你喜欢
  • 2023-01-08
  • 1970-01-01
  • 1970-01-01
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
相关资源
最近更新 更多