📜  DBMS 中的时间戳和死锁预防方案介绍

📅  最后修改于: 2021-09-27 15:42:31             🧑  作者: Mango

当两个或多个事务的调度中的每个事务 T等待某个项目被集合中的某个其他事务 T 锁定时,就会发生死锁。因此,双方最终都处于死锁状态,等待对方释放对项目的锁。死锁是一个常见的问题,我们在通过引入锁解决并发控制的同时引入了这个问题。死锁避免是一个主要问题,建议使用一些协议来避免它们,例如保守 2-PL 和基于图形的协议,但仍然存在一些缺点。

在这里,我们将讨论交易时间戳 TS(T i )的新概念。时间戳是 DBMS 创建的唯一标识符,用于标识事务。它们通常按照提交到系统的顺序分配,因此时间戳可以被认为是事务开始时间。

可能有不同的生成时间戳的方法,例如

  • 一个简单的计数器,每次将其值分配给事务时都会增加。它们的编号可能是1、2、3…… 。尽管我们必须不时重置计数器以避免溢出。
  • 使用系统时钟的当前日期/时间。只要确保在同一个时钟滴答中没有两个事务被赋予相同的值,我们将始终获得唯一的时间戳。这种方法被广泛使用。

基于时间戳的死锁预防方案……

如前所述,时间戳是分配给每个事务的唯一标识符。它们基于事务启动的顺序。假设如果T 1在 T 2之前开始,那么TS(T 1 )将小于 (<) TS(T 2 )

有两种防止死锁的方案,称为“伤口等待”和“等待死亡” 。假设有两个事务T iT j ,现在说T i试图锁定一个项目X但项目X已经被某个T j锁定,现在在这种冲突的情况下,两种防止死锁的方案。我们很快就会用到这个上下文。

  • Wait_Die :允许较旧的事务等待较新的事务,而请求由较旧事务持有的项目的较新事务将中止并重新启动。
    从上面的上下文来看,如果TS(T i ) < TS(T j ) ,那么(T i比 T j早)T i被允许等待;否则中止 T i (T i小于 T j )并稍后使用相同的时间戳重新启动它。
  • Wound_Wait :它与 Wait_Die 技术正好相反。在这里,允许较年轻的事务等待较旧的事务,而如果较旧的事务请求较年轻的事务持有的项目,我们会通过中止它来抢占较年轻的事务。
    从上面的上下文来看,如果TS(T i ) < TS(T j ) ,那么(T i比 T j早)T j被中止(即,T i伤害了 T j )并稍后使用相同的时间戳重新启动它;否则(T i小于T j )T i被允许等待。

因此,这两种方案最终都会中止可能涉及死锁的两个事务中较年轻的一个。它是基于这样一个假设来完成的,即中止较新的事务将浪费更少的处理,这是合乎逻辑的。在这种情况下,不可能有循环,因为我们在这两种情况下都是线性等待的。
对于 GATE,这两种方法的理论就足够了,有关这方面的更多信息,您可以参考此处。

另一组防止死锁但不需要 Timestamps的协议。下面讨论它们:

  • 无等待算法:这遵循一个简单的方法,如果一个事务无法获得锁,它会立即中止,然后在一定时间延迟后重新启动,而不检查是否会发生死锁。在这里,没有事务等待,因此不可能发生死锁。
    这个方法有点不实用。它可能会导致事务中止并不必要地重新启动。
  • 谨慎等待:如果T i尝试锁定项目X但由于 X被某个T j锁定而无法做到。在这样的冲突中,如果T j没有等待某个其他锁定项,则允许 T i等待,否则中止T i

另一种处理死锁的方法是死锁检测,我们可以使用Wait-for-Graph。当我们在检查可序列化性的同时检查循环时,这使用了类似的方法。

饥饿:当我们使用锁定时可能出现的一个问题是饥饿,它发生在一个事务无限期地无法进行而系统中的其他事务继续正常进行时。如果锁定项目的等待方案不公平,将某些交易优先于其他交易,则可能会发生这种情况。我们可能有一些饥饿的解决方案。一种是使用先到先服务队列;事务可以按照它们最初请求锁定的顺序锁定项目。这是一种广泛使用的减少饥饿的机制。我们的并发控制管理器负责调度事务,因此它采用不同的方法来克服它们。你可以参考这里的详细解释。

试试这个问题:GATE | GATE-CS-2017(套装1)|第 46 题

接下来,我们将讨论著名的时间戳排序协议和 Thomas Write 规则。直到那时快乐学习!

参考:数据库系统概念,第五版 [Silberschatz、Korth、Sudarshan],第 16 章。