|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.218 2010/04/28 16:54:16 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.219 2010/05/26 19:52:52 sriggs Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -85,6 +85,7 @@ static TimestampTz timeout_start_time;
|
85 | 85 |
|
86 | 86 | /* statement_fin_time is valid only if statement_timeout_active is true */
|
87 | 87 | static TimestampTz statement_fin_time;
|
| 88 | +static TimestampTz statement_fin_time2; /* valid only in recovery */ |
88 | 89 |
|
89 | 90 |
|
90 | 91 | static void RemoveProcFromArray(int code, Datum arg);
|
@@ -1619,23 +1620,61 @@ handle_sig_alarm(SIGNAL_ARGS)
|
1619 | 1620 | * To avoid various edge cases, we must be careful to do nothing
|
1620 | 1621 | * when there is nothing to be done. We also need to be able to
|
1621 | 1622 | * reschedule the timer interrupt if called before end of statement.
|
| 1623 | + * |
| 1624 | + * We set either deadlock_timeout_active or statement_timeout_active |
| 1625 | + * or both. Interrupts are enabled if standby_timeout_active. |
1622 | 1626 | */
|
1623 | 1627 | bool
|
1624 |
| -enable_standby_sig_alarm(long delay_s, int delay_us, TimestampTz fin_time) |
| 1628 | +enable_standby_sig_alarm(TimestampTz now, TimestampTz fin_time, bool deadlock_only) |
1625 | 1629 | {
|
1626 |
| - struct itimerval timeval; |
1627 |
| - |
1628 |
| - Assert(delay_s >= 0 && delay_us >= 0); |
| 1630 | + TimestampTz deadlock_time = TimestampTzPlusMilliseconds(now, DeadlockTimeout); |
1629 | 1631 |
|
1630 |
| - statement_fin_time = fin_time; |
| 1632 | + if (deadlock_only) |
| 1633 | + { |
| 1634 | + /* |
| 1635 | + * Wake up at DeadlockTimeout only, then wait forever |
| 1636 | + */ |
| 1637 | + statement_fin_time = deadlock_time; |
| 1638 | + deadlock_timeout_active = true; |
| 1639 | + statement_timeout_active = false; |
| 1640 | + } |
| 1641 | + else if (fin_time > deadlock_time) |
| 1642 | + { |
| 1643 | + /* |
| 1644 | + * Wake up at DeadlockTimeout, then again at MaxStandbyDelay |
| 1645 | + */ |
| 1646 | + statement_fin_time = deadlock_time; |
| 1647 | + statement_fin_time2 = fin_time; |
| 1648 | + deadlock_timeout_active = true; |
| 1649 | + statement_timeout_active = true; |
| 1650 | + } |
| 1651 | + else |
| 1652 | + { |
| 1653 | + /* |
| 1654 | + * Wake only at MaxStandbyDelay because its fairly soon |
| 1655 | + */ |
| 1656 | + statement_fin_time = fin_time; |
| 1657 | + deadlock_timeout_active = false; |
| 1658 | + statement_timeout_active = true; |
| 1659 | + } |
1631 | 1660 |
|
1632 |
| - standby_timeout_active = true; |
| 1661 | + if (deadlock_timeout_active || statement_timeout_active) |
| 1662 | + { |
| 1663 | + long secs; |
| 1664 | + int usecs; |
| 1665 | + struct itimerval timeval; |
| 1666 | + TimestampDifference(now, statement_fin_time, |
| 1667 | + &secs, &usecs); |
| 1668 | + if (secs == 0 && usecs == 0) |
| 1669 | + usecs = 1; |
| 1670 | + MemSet(&timeval, 0, sizeof(struct itimerval)); |
| 1671 | + timeval.it_value.tv_sec = secs; |
| 1672 | + timeval.it_value.tv_usec = usecs; |
| 1673 | + if (setitimer(ITIMER_REAL, &timeval, NULL)) |
| 1674 | + return false; |
| 1675 | + standby_timeout_active = true; |
| 1676 | + } |
1633 | 1677 |
|
1634 |
| - MemSet(&timeval, 0, sizeof(struct itimerval)); |
1635 |
| - timeval.it_value.tv_sec = delay_s; |
1636 |
| - timeval.it_value.tv_usec = delay_us; |
1637 |
| - if (setitimer(ITIMER_REAL, &timeval, NULL)) |
1638 |
| - return false; |
1639 | 1678 | return true;
|
1640 | 1679 | }
|
1641 | 1680 |
|
@@ -1675,37 +1714,64 @@ static bool
|
1675 | 1714 | CheckStandbyTimeout(void)
|
1676 | 1715 | {
|
1677 | 1716 | TimestampTz now;
|
| 1717 | + bool reschedule = false; |
1678 | 1718 |
|
1679 | 1719 | standby_timeout_active = false;
|
1680 | 1720 |
|
1681 | 1721 | now = GetCurrentTimestamp();
|
1682 | 1722 |
|
| 1723 | + /* |
| 1724 | + * Reschedule the timer if its not time to wake yet, or if we |
| 1725 | + * have both timers set and the first one has just been reached. |
| 1726 | + */ |
1683 | 1727 | if (now >= statement_fin_time)
|
1684 |
| - SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); |
| 1728 | + { |
| 1729 | + if (deadlock_timeout_active) |
| 1730 | + { |
| 1731 | + /* |
| 1732 | + * We're still waiting when we reach DeadlockTimeout, so send out a request |
| 1733 | + * to have other backends check themselves for deadlock. Then continue |
| 1734 | + * waiting until MaxStandbyDelay. |
| 1735 | + */ |
| 1736 | + SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK); |
| 1737 | + deadlock_timeout_active = false; |
| 1738 | + |
| 1739 | + /* |
| 1740 | + * Begin second waiting period to MaxStandbyDelay if required. |
| 1741 | + */ |
| 1742 | + if (statement_timeout_active) |
| 1743 | + { |
| 1744 | + reschedule = true; |
| 1745 | + statement_fin_time = statement_fin_time2; |
| 1746 | + } |
| 1747 | + } |
| 1748 | + else |
| 1749 | + { |
| 1750 | + /* |
| 1751 | + * We've now reached MaxStandbyDelay, so ask all conflicts to leave, cos |
| 1752 | + * its time for us to press ahead with applying changes in recovery. |
| 1753 | + */ |
| 1754 | + SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); |
| 1755 | + } |
| 1756 | + } |
1685 | 1757 | else
|
| 1758 | + reschedule = true; |
| 1759 | + |
| 1760 | + if (reschedule) |
1686 | 1761 | {
|
1687 |
| - /* Not time yet, so (re)schedule the interrupt */ |
1688 | 1762 | long secs;
|
1689 | 1763 | int usecs;
|
1690 | 1764 | struct itimerval timeval;
|
1691 |
| - |
1692 | 1765 | TimestampDifference(now, statement_fin_time,
|
1693 | 1766 | &secs, &usecs);
|
1694 |
| - |
1695 |
| - /* |
1696 |
| - * It's possible that the difference is less than a microsecond; |
1697 |
| - * ensure we don't cancel, rather than set, the interrupt. |
1698 |
| - */ |
1699 | 1767 | if (secs == 0 && usecs == 0)
|
1700 | 1768 | usecs = 1;
|
1701 |
| - |
1702 |
| - standby_timeout_active = true; |
1703 |
| - |
1704 | 1769 | MemSet(&timeval, 0, sizeof(struct itimerval));
|
1705 | 1770 | timeval.it_value.tv_sec = secs;
|
1706 | 1771 | timeval.it_value.tv_usec = usecs;
|
1707 | 1772 | if (setitimer(ITIMER_REAL, &timeval, NULL))
|
1708 | 1773 | return false;
|
| 1774 | + standby_timeout_active = true; |
1709 | 1775 | }
|
1710 | 1776 |
|
1711 | 1777 | return true;
|
|
0 commit comments