1-timeout-framework-v21.patch
text/x-patch
Filename: 1-timeout-framework-v21.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v21
| File | + | − |
|---|---|---|
| src/backend/port/ipc_test.c | 4 | 4 |
| src/backend/port/posix_sema.c | 8 | 2 |
| src/backend/port/sysv_sema.c | 8 | 2 |
| src/backend/port/win32_sema.c | 8 | 2 |
| src/backend/storage/lmgr/deadlock.c | 4 | 0 |
| src/backend/storage/lmgr/lmgrtimeout.c | 121 | 0 |
| src/backend/storage/lmgr/lock.c | 3 | 2 |
| src/backend/storage/lmgr/lwlock.c | 2 | 2 |
| src/backend/storage/lmgr/Makefile | 1 | 1 |
| src/backend/storage/lmgr/proc.c | 25 | 14 |
| src/backend/utils/init/postinit.c | 28 | 0 |
| src/include/storage/lmgrtimeout.h | 36 | 0 |
| src/include/storage/pg_sema.h | 4 | 1 |
| src/include/storage/proc.h | 1 | 0 |
diff -durpN postgresql/src/backend/port/ipc_test.c postgresql.1/src/backend/port/ipc_test.c
--- postgresql/src/backend/port/ipc_test.c 2012-04-16 19:57:22.437915477 +0200
+++ postgresql.1/src/backend/port/ipc_test.c 2012-08-21 15:53:50.059329927 +0200
@@ -240,7 +240,7 @@ main(int argc, char **argv)
printf("Testing Lock ... ");
fflush(stdout);
- PGSemaphoreLock(&storage->sem, false);
+ PGSemaphoreLock(&storage->sem, false, NULL);
printf("OK\n");
@@ -262,8 +262,8 @@ main(int argc, char **argv)
PGSemaphoreUnlock(&storage->sem);
PGSemaphoreUnlock(&storage->sem);
- PGSemaphoreLock(&storage->sem, false);
- PGSemaphoreLock(&storage->sem, false);
+ PGSemaphoreLock(&storage->sem, false, NULL);
+ PGSemaphoreLock(&storage->sem, false, NULL);
printf("OK\n");
@@ -311,7 +311,7 @@ main(int argc, char **argv)
printf("Waiting for child (should wait 3 sec here) ... ");
fflush(stdout);
- PGSemaphoreLock(&storage->sem, false);
+ PGSemaphoreLock(&storage->sem, false, NULL);
printf("OK\n");
diff -durpN postgresql/src/backend/port/posix_sema.c postgresql.1/src/backend/port/posix_sema.c
--- postgresql/src/backend/port/posix_sema.c 2012-04-16 19:57:22.438915489 +0200
+++ postgresql.1/src/backend/port/posix_sema.c 2012-08-21 15:49:26.215579665 +0200
@@ -236,9 +236,11 @@ PGSemaphoreReset(PGSemaphore sema)
* Lock a semaphore (decrement count), blocking if count would be < 0
*/
void
-PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
+PGSemaphoreLock(PGSemaphore sema, bool interruptOK,
+ PGSemaphoreCondition condition_checker)
{
int errStatus;
+ bool condition = false;
/*
* See notes in sysv_sema.c's implementation of PGSemaphoreLock. Just as
@@ -252,8 +254,12 @@ PGSemaphoreLock(PGSemaphore sema, bool i
CHECK_FOR_INTERRUPTS();
errStatus = sem_wait(PG_SEM_REF(sema));
ImmediateInterruptOK = false;
- } while (errStatus < 0 && errno == EINTR);
+ if (condition_checker)
+ condition = condition_checker();
+ } while (errStatus < 0 && errno == EINTR && !condition);
+ if (condition)
+ return;
if (errStatus < 0)
elog(FATAL, "sem_wait failed: %m");
}
diff -durpN postgresql/src/backend/port/sysv_sema.c postgresql.1/src/backend/port/sysv_sema.c
--- postgresql/src/backend/port/sysv_sema.c 2012-05-14 08:20:56.284830580 +0200
+++ postgresql.1/src/backend/port/sysv_sema.c 2012-08-21 15:49:26.991584804 +0200
@@ -358,9 +358,11 @@ PGSemaphoreReset(PGSemaphore sema)
* Lock a semaphore (decrement count), blocking if count would be < 0
*/
void
-PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
+PGSemaphoreLock(PGSemaphore sema, bool interruptOK,
+ PGSemaphoreCondition condition_checker)
{
int errStatus;
+ bool condition = false;
struct sembuf sops;
sops.sem_op = -1; /* decrement */
@@ -414,8 +416,12 @@ PGSemaphoreLock(PGSemaphore sema, bool i
CHECK_FOR_INTERRUPTS();
errStatus = semop(sema->semId, &sops, 1);
ImmediateInterruptOK = false;
- } while (errStatus < 0 && errno == EINTR);
+ if (condition_checker)
+ condition = condition_checker();
+ } while (errStatus < 0 && errno == EINTR && !condition);
+ if (condition)
+ return;
if (errStatus < 0)
elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
}
diff -durpN postgresql/src/backend/port/win32_sema.c postgresql.1/src/backend/port/win32_sema.c
--- postgresql/src/backend/port/win32_sema.c 2012-06-11 06:22:48.137921483 +0200
+++ postgresql.1/src/backend/port/win32_sema.c 2012-08-21 15:49:24.921571070 +0200
@@ -116,10 +116,12 @@ PGSemaphoreReset(PGSemaphore sema)
* Serve the interrupt if interruptOK is true.
*/
void
-PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
+PGSemaphoreLock(PGSemaphore sema, bool interruptOK,
+ PGSemaphoreCondition condition_checker)
{
DWORD ret;
HANDLE wh[2];
+ bool condition = false;
/*
* Note: pgwin32_signal_event should be first to ensure that it will be
@@ -158,8 +160,12 @@ PGSemaphoreLock(PGSemaphore sema, bool i
errno = EIDRM;
ImmediateInterruptOK = false;
- } while (errno == EINTR);
+ if (condition_checker)
+ condition = condition_checker();
+ } while (errno == EINTR && !condition);
+ if (condition)
+ return;
if (errno != 0)
ereport(FATAL,
(errmsg("could not lock semaphore: error code %lu", GetLastError())));
diff -durpN postgresql/src/backend/storage/lmgr/deadlock.c postgresql.1/src/backend/storage/lmgr/deadlock.c
--- postgresql/src/backend/storage/lmgr/deadlock.c 2012-07-27 10:19:36.932331508 +0200
+++ postgresql.1/src/backend/storage/lmgr/deadlock.c 2012-08-21 15:08:16.728428766 +0200
@@ -31,6 +31,7 @@
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "utils/memutils.h"
+#include "utils/timeout.h"
/* One edge in the waits-for graph */
@@ -897,6 +898,9 @@ DeadLockReport(void)
StringInfoData locktagbuf;
int i;
+ if (!DeadLockTimeoutCondition())
+ return;
+
initStringInfo(&clientbuf);
initStringInfo(&logbuf);
initStringInfo(&locktagbuf);
diff -durpN postgresql/src/backend/storage/lmgr/lmgrtimeout.c postgresql.1/src/backend/storage/lmgr/lmgrtimeout.c
--- postgresql/src/backend/storage/lmgr/lmgrtimeout.c 1970-01-01 01:00:00.000000000 +0100
+++ postgresql.1/src/backend/storage/lmgr/lmgrtimeout.c 2012-08-21 13:05:19.214992078 +0200
@@ -0,0 +1,121 @@
+/*-------------------------------------------------------------------------
+ *
+ * lmgrtimeout.c
+ * routines to manage lock manager timeout sources
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/storage/lmgr/lmgrtimeout.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "storage/lmgrtimeout.h"
+
+/*
+ * Linked set of lock manager timeout functions
+ */
+static LmgrTimeoutFunctions *CurrentLmgrTimeoutFunctions = NULL;
+
+/*
+ * Register a set of functions for an lock manager timeout
+ */
+void
+RegisterLmgrTimeout(LmgrTimeoutFunctions *functions)
+{
+ Assert(functions != NULL);
+ Assert(functions->enable != NULL);
+ Assert(functions->disable != NULL);
+ Assert(functions->condition != NULL);
+ Assert(functions->reporter != NULL);
+
+ functions->next = CurrentLmgrTimeoutFunctions;
+ CurrentLmgrTimeoutFunctions = functions;
+}
+
+/*
+ * Enable registered lock manager timeouts
+ */
+void
+EnableLmgrTimeouts(void)
+{
+ LmgrTimeoutFunctions *ptr = CurrentLmgrTimeoutFunctions;
+
+ while (ptr)
+ {
+ ptr->enable();
+ ptr = ptr->next;
+ }
+}
+
+/*
+ * Disable registered lock manager timeouts
+ */
+void
+DisableLmgrTimeouts(void)
+{
+ LmgrTimeoutFunctions *ptr = CurrentLmgrTimeoutFunctions;
+
+ while (ptr)
+ {
+ ptr->disable();
+ ptr = ptr->next;
+ }
+}
+
+/*
+ * Call the timeout indicator functions in the order of registration
+ */
+static bool
+DoLmgrTimeoutCondition(LmgrTimeoutFunctions *ptr)
+{
+ if (ptr)
+ {
+ if (ptr->next)
+ if (DoLmgrTimeoutCondition(ptr->next))
+ return true;
+ if (ptr->condition())
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Call the timeout indicator and return if any one of them is set
+ */
+bool
+LmgrTimeoutCondition(void)
+{
+ return DoLmgrTimeoutCondition(CurrentLmgrTimeoutFunctions);
+}
+
+/*
+ * Call the timeout error reporter functions in the order of registration
+ */
+static void
+DoReportLmgrTimeoutError(LmgrTimeoutFunctions *ptr)
+{
+ if (ptr)
+ {
+ if (ptr->next)
+ DoReportLmgrTimeoutError(ptr->next);
+
+ /* This may not return because of calling ereport() */
+ ptr->reporter();
+ }
+}
+
+/*
+ * Call the timeout error reporter if set
+ */
+void
+ReportLmgrTimeoutError(void)
+{
+ DoReportLmgrTimeoutError(CurrentLmgrTimeoutFunctions);
+}
diff -durpN postgresql/src/backend/storage/lmgr/lock.c postgresql.1/src/backend/storage/lmgr/lock.c
--- postgresql/src/backend/storage/lmgr/lock.c 2012-06-26 09:10:21.280759421 +0200
+++ postgresql.1/src/backend/storage/lmgr/lock.c 2012-08-21 16:01:33.095488150 +0200
@@ -38,6 +38,7 @@
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
+#include "storage/lmgrtimeout.h"
#include "storage/proc.h"
#include "storage/sinvaladt.h"
#include "storage/spin.h"
@@ -1512,9 +1513,9 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
/*
* Now that we aren't holding the partition lock, we can give an
- * error report including details about the detected deadlock.
+ * error report on the timeout condition that triggered.
*/
- DeadLockReport();
+ ReportLmgrTimeoutError();
/* not reached */
}
}
diff -durpN postgresql/src/backend/storage/lmgr/lwlock.c postgresql.1/src/backend/storage/lmgr/lwlock.c
--- postgresql/src/backend/storage/lmgr/lwlock.c 2012-06-27 07:41:33.603316276 +0200
+++ postgresql.1/src/backend/storage/lmgr/lwlock.c 2012-08-21 15:54:39.410667067 +0200
@@ -477,7 +477,7 @@ LWLockAcquire(LWLockId lockid, LWLockMod
for (;;)
{
/* "false" means cannot accept cancel/die interrupt here. */
- PGSemaphoreLock(&proc->sem, false);
+ PGSemaphoreLock(&proc->sem, false, NULL);
if (!proc->lwWaiting)
break;
extraWaits++;
@@ -682,7 +682,7 @@ LWLockAcquireOrWait(LWLockId lockid, LWL
for (;;)
{
/* "false" means cannot accept cancel/die interrupt here. */
- PGSemaphoreLock(&proc->sem, false);
+ PGSemaphoreLock(&proc->sem, false, NULL);
if (!proc->lwWaiting)
break;
extraWaits++;
diff -durpN postgresql/src/backend/storage/lmgr/Makefile postgresql.1/src/backend/storage/lmgr/Makefile
--- postgresql/src/backend/storage/lmgr/Makefile 2012-04-16 19:57:22.458915722 +0200
+++ postgresql.1/src/backend/storage/lmgr/Makefile 2012-08-21 13:05:00.254861812 +0200
@@ -12,7 +12,7 @@ subdir = src/backend/storage/lmgr
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = lmgr.o lock.o proc.o deadlock.o lwlock.o spin.o s_lock.o predicate.o
+OBJS = lmgr.o lmgrtimeout.o lock.o proc.o deadlock.o lwlock.o spin.o s_lock.o predicate.o
include $(top_srcdir)/src/backend/common.mk
diff -durpN postgresql/src/backend/storage/lmgr/proc.c postgresql.1/src/backend/storage/lmgr/proc.c
--- postgresql/src/backend/storage/lmgr/proc.c 2012-07-27 10:19:36.933331515 +0200
+++ postgresql.1/src/backend/storage/lmgr/proc.c 2012-08-21 15:56:36.948469452 +0200
@@ -43,6 +43,7 @@
#include "replication/syncrep.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
+#include "storage/lmgrtimeout.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
@@ -640,8 +641,11 @@ LockErrorCleanup(void)
if (lockAwaited == NULL)
return;
- /* Turn off the deadlock timer, if it's still running (see ProcSleep) */
- disable_timeout(DEADLOCK_TIMEOUT, false);
+ /*
+ * Turn off the lock manager timers if they are still running
+ * (see ProcSleep)
+ */
+ DisableLmgrTimeouts();
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
@@ -1028,15 +1032,9 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
deadlock_state = DS_NOT_YET_CHECKED;
/*
- * Set timer so we can wake up after awhile and check for a deadlock. If a
- * deadlock is detected, the handler releases the process's semaphore and
- * sets MyProc->waitStatus = STATUS_ERROR, allowing us to know that we
- * must report failure rather than success.
- *
- * By delaying the check until we've waited for a bit, we can avoid
- * running the rather expensive deadlock-check code in most cases.
+ * Set the timer for registered lock manager timeouts
*/
- enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout);
+ EnableLmgrTimeouts();
/*
* If someone wakes us between LWLockRelease and PGSemaphoreLock,
@@ -1057,7 +1055,7 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
*/
do
{
- PGSemaphoreLock(&MyProc->sem, true);
+ PGSemaphoreLock(&MyProc->sem, true, LmgrTimeoutCondition);
/*
* waitStatus could change from STATUS_WAITING to something else
@@ -1203,9 +1201,9 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
} while (myWaitStatus == STATUS_WAITING);
/*
- * Disable the timer, if it's still running
+ * Disable the timers, if they are still running
*/
- disable_timeout(DEADLOCK_TIMEOUT, false);
+ DisableLmgrTimeouts();
/*
* Re-acquire the lock table's partition lock. We have to do this to hold
@@ -1451,6 +1449,19 @@ check_done:
/*
+ * DeadLockTimeoutCondition
+ * Indicate whether deadlock was detected
+ */
+bool
+DeadLockTimeoutCondition(void)
+{
+ if (deadlock_state == DS_NOT_YET_CHECKED)
+ return false;
+ return get_timeout_indicator(DEADLOCK_TIMEOUT) && (deadlock_state != DS_NO_DEADLOCK);
+}
+
+
+/*
* ProcWaitForSignal - wait for a signal from another backend.
*
* This can share the semaphore normally used for waiting for locks,
@@ -1464,7 +1475,7 @@ check_done:
void
ProcWaitForSignal(void)
{
- PGSemaphoreLock(&MyProc->sem, true);
+ PGSemaphoreLock(&MyProc->sem, true, NULL);
}
/*
diff -durpN postgresql/src/backend/utils/init/postinit.c postgresql.1/src/backend/utils/init/postinit.c
--- postgresql/src/backend/utils/init/postinit.c 2012-07-22 16:48:48.525857751 +0200
+++ postgresql.1/src/backend/utils/init/postinit.c 2012-08-21 16:14:31.026731931 +0200
@@ -41,6 +41,7 @@
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
+#include "storage/lmgrtimeout.h"
#include "storage/procarray.h"
#include "storage/procsignal.h"
#include "storage/proc.h"
@@ -65,11 +66,17 @@ static void PerformAuthentication(Port *
static void CheckMyDatabase(const char *name, bool am_superuser);
static void InitCommunication(void);
static void ShutdownPostgres(int code, Datum arg);
+static void EnableDeadLockTimeout(void);
+static void DisableDeadLockTimeout(void);
static void StatementTimeoutHandler(void);
static bool ThereIsAtLeastOneRole(void);
static void process_startup_options(Port *port, bool am_superuser);
static void process_settings(Oid databaseid, Oid roleid);
+static LmgrTimeoutFunctions DeadLockTimeoutFunctions = {
+ EnableDeadLockTimeout, DisableDeadLockTimeout,
+ DeadLockTimeoutCondition, DeadLockReport
+};
/*** InitPostgres support ***/
@@ -501,6 +508,7 @@ InitPostgres(const char *in_dbname, Oid
if (!bootstrap)
{
RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLock);
+ RegisterLmgrTimeout(&DeadLockTimeoutFunctions);
RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler);
}
@@ -982,6 +990,26 @@ ShutdownPostgres(int code, Datum arg)
LockReleaseAll(USER_LOCKMETHOD, true);
}
+static void
+EnableDeadLockTimeout(void)
+{
+ /*
+ * Set timer so we can wake up after awhile and check for a deadlock. If a
+ * deadlock is detected, the handler releases the process's semaphore and
+ * sets MyProc->waitStatus = STATUS_ERROR, allowing us to know that we
+ * must report failure rather than success.
+ *
+ * By delaying the check until we've waited for a bit, we can avoid
+ * running the rather expensive deadlock-check code in most cases.
+ */
+ enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout);
+}
+
+static void
+DisableDeadLockTimeout(void)
+{
+ disable_timeout(DEADLOCK_TIMEOUT, true);
+}
/*
* STATEMENT_TIMEOUT handler: trigger a query-cancel interrupt.
diff -durpN postgresql/src/include/storage/lmgrtimeout.h postgresql.1/src/include/storage/lmgrtimeout.h
--- postgresql/src/include/storage/lmgrtimeout.h 1970-01-01 01:00:00.000000000 +0100
+++ postgresql.1/src/include/storage/lmgrtimeout.h 2012-08-21 13:30:43.050291053 +0200
@@ -0,0 +1,36 @@
+/*-------------------------------------------------------------------------
+ *
+ * lmgrtimeout.h
+ * POSTGRES lock manager timeout definitions.
+ *
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/storage/lmgrtimeout.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef LMGRTIMEOUT_H
+#define LMGRTIMEOUT_H
+
+/* callback function signatures for lock manager timeouts */
+typedef void (*LmgrTimeoutCallback)(void);
+typedef bool (*LmgrTimeoutConditionCallback)(void);
+
+typedef struct LmgrTimeoutFunctions {
+ LmgrTimeoutCallback enable;
+ LmgrTimeoutCallback disable;
+ LmgrTimeoutConditionCallback condition;
+ LmgrTimeoutCallback reporter;
+ struct LmgrTimeoutFunctions *next;
+} LmgrTimeoutFunctions;
+
+/* register and handle lock manager timeouts */
+extern void RegisterLmgrTimeout(LmgrTimeoutFunctions *functions);
+extern void EnableLmgrTimeouts(void);
+extern void DisableLmgrTimeouts(void);
+extern bool LmgrTimeoutCondition(void);
+extern void ReportLmgrTimeoutError(void);
+
+#endif /* LMGRTIMEOUT_H */
diff -durpN postgresql/src/include/storage/pg_sema.h postgresql.1/src/include/storage/pg_sema.h
--- postgresql/src/include/storage/pg_sema.h 2012-04-16 19:57:22.672918205 +0200
+++ postgresql.1/src/include/storage/pg_sema.h 2012-08-21 15:44:06.655459333 +0200
@@ -62,6 +62,8 @@ typedef HANDLE PGSemaphoreData;
typedef PGSemaphoreData *PGSemaphore;
+typedef bool (*PGSemaphoreCondition)(void);
+
/* Module initialization (called during postmaster start or shmem reinit) */
extern void PGReserveSemaphores(int maxSemas, int port);
@@ -72,7 +74,8 @@ extern void PGSemaphoreCreate(PGSemaphor
extern void PGSemaphoreReset(PGSemaphore sema);
/* Lock a semaphore (decrement count), blocking if count would be < 0 */
-extern void PGSemaphoreLock(PGSemaphore sema, bool interruptOK);
+extern void PGSemaphoreLock(PGSemaphore sema, bool interruptOK,
+ PGSemaphoreCondition condition);
/* Unlock a semaphore (increment count) */
extern void PGSemaphoreUnlock(PGSemaphore sema);
diff -durpN postgresql/src/include/storage/proc.h postgresql.1/src/include/storage/proc.h
--- postgresql/src/include/storage/proc.h 2012-07-22 16:48:48.548857900 +0200
+++ postgresql.1/src/include/storage/proc.h 2012-08-21 15:10:38.641347523 +0200
@@ -244,6 +244,7 @@ extern int ProcSleep(LOCALLOCK *localloc
extern PGPROC *ProcWakeup(PGPROC *proc, int waitStatus);
extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock);
extern void CheckDeadLock(void);
+extern bool DeadLockTimeoutCondition(void);
extern bool IsWaitingForLock(void);
extern void LockErrorCleanup(void);