Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1h3qmh-0000mz-Ad for pgsql-hackers@arkaria.postgresql.org; Tue, 12 Mar 2019 23:26:11 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1h3qlh-0001Td-0e for pgsql-hackers@arkaria.postgresql.org; Tue, 12 Mar 2019 23:25:09 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1h3qlg-0001TW-Pd for pgsql-hackers@lists.postgresql.org; Tue, 12 Mar 2019 23:25:08 +0000 Received: from smtp-fw-33001.amazon.com ([207.171.190.10]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1h3qlZ-0005KE-R0 for pgsql-hackers@postgresql.org; Tue, 12 Mar 2019 23:25:08 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1552433101; x=1583969101; h=date:from:to:subject:message-id:mime-version; bh=EpYpemW+2kB2qwPGP9O+7++yPBCRx5Co15zHo3dPS2c=; b=le1yr9TQhpAcTtoE1Xl/3a0Wog9VvzIHmbrOgZL93whvOXeZ+26xsT4L zKFRNm6zuHvjXSNxsPZEvJrAEohaX3ESiyn8CZxFgXT8tR7L22WOplRjj cYPuI75bJUCiDZ/f/V9dzf4Hf8Npg46dO4Kr4TEfpClIUVS8P+OP0bhci M=; X-Amazon-filename: 0001-Introduce-timeout-capability-for-ConditionVariableSleep-v1.patch X-IronPort-AV: E=Sophos;i="5.58,472,1544486400"; d="scan'208,223";a="788232315" Received: from sea3-co-svc-lb6-vlan2.sea.amazon.com (HELO email-inbound-relay-2a-119b4f96.us-west-2.amazon.com) ([10.47.22.34]) by smtp-border-fw-out-33001.sea14.amazon.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 12 Mar 2019 23:24:57 +0000 Received: from EX13MTAUWC001.ant.amazon.com (pdx1-ws-svc-p6-lb9-vlan2.pdx.amazon.com [10.236.137.194]) by email-inbound-relay-2a-119b4f96.us-west-2.amazon.com (8.14.7/8.14.7) with ESMTP id x2CNOukJ049321 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=FAIL) for ; Tue, 12 Mar 2019 23:24:57 GMT Received: from EX13D05UWC002.ant.amazon.com (10.43.162.92) by EX13MTAUWC001.ant.amazon.com (10.43.162.135) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Tue, 12 Mar 2019 23:24:56 +0000 Received: from f01898859afd.ant.amazon.com (10.43.160.36) by EX13D05UWC002.ant.amazon.com (10.43.162.92) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Tue, 12 Mar 2019 23:24:56 +0000 Date: Tue, 12 Mar 2019 16:24:54 -0700 From: Shawn Debnath To: "pgsql-hackers@postgresql.org" Subject: Introduce timeout capability for ConditionVariableSleep Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="wRRV7LY7NUeQGEoC" Content-Disposition: inline User-Agent: Microsoft-MacOutlook/10.10.7.190210 Thread-Topic: Introduce timeout capability for ConditionVariableSleep Thread-Index: AQHU2SMem6d/FdTVVUOLn5HtVpUzSw== X-Originating-IP: [10.43.160.36] X-ClientProxiedBy: EX13D17UWC002.ant.amazon.com (10.43.162.61) To EX13D05UWC002.ant.amazon.com (10.43.162.92) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --wRRV7LY7NUeQGEoC Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline Hello, Postgres today doesn't support waiting for a condition variable with a timeout, although the framework it relies upon, does. This change wraps the existing ConditionVariableSleep functionality and introduces a new API, ConditionVariableTimedSleep, to allow callers to specify a timeout value. A scenario that highlights this use case is a backend is waiting on status update from multiple workers but needs to time out if that signal doesn't arrive within a certain period. There was a workaround prior to aced5a92, but with that change, the semantics are now different. I chose to go with -1 instead of 0 for the return from ConditionVariableTimedSleep to indicate timeout error as it seems cleaner for this API. WaitEventSetWaitBlock returns -1 for timeout but WaitEventSetWait treats timeout as 0 (to represent 0 events indicating timeout). If there's an alternative, cleaner way to achieve this outcome, I am all ears. Thanks. -- Shawn Debnath Amazon Web Services (AWS) --wRRV7LY7NUeQGEoC Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="0001-Introduce-timeout-capability-for-ConditionVariableSleep-v1.patch" From c1b332826070de4782b12bbb577d66406d439c8d Mon Sep 17 00:00:00 2001 From: Shawn Debnath Date: Tue, 12 Mar 2019 23:21:41 +0000 Subject: [PATCH] Introduce timeout capability for ConditionVariableSleep This patch introduces ConditionVariableTimedSleep to enable timing out of waiting for a condition variable to get signalled. --- src/backend/storage/lmgr/condition_variable.c | 41 +++++++++++++++++++++++++-- src/include/storage/condition_variable.h | 2 ++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c index 58b7b51472..a0e14a5efa 100644 --- a/src/backend/storage/lmgr/condition_variable.c +++ b/src/backend/storage/lmgr/condition_variable.c @@ -121,9 +121,33 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv) */ void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info) +{ + (void) ConditionVariableTimedSleep(cv, -1 /* no timeout */, wait_event_info); +} + +/* + * Wait for the given condition variable to be signaled or till timeout. + * This should be called in a predicate loop that tests for a specific exit + * condition and otherwise sleeps, like so: + * + * ConditionVariablePrepareToSleep(cv); // optional + * while (condition for which we are waiting is not true) + * ConditionVariableSleep(cv, wait_event_info); + * ConditionVariableCancelSleep(); + * + * wait_event_info should be a value from one of the WaitEventXXX enums + * defined in pgstat.h. This controls the contents of pg_stat_activity's + * wait_event_type and wait_event columns while waiting. + * + * Returns 0 or -1 if timed out. + */ +int +ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, + uint32 wait_event_info) { WaitEvent event; bool done = false; + int ret; /* * If the caller didn't prepare to sleep explicitly, then do so now and @@ -143,7 +167,7 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info) if (cv_sleep_target != cv) { ConditionVariablePrepareToSleep(cv); - return; + return 0; } do @@ -154,12 +178,23 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info) * Wait for latch to be set. (If we're awakened for some other * reason, the code below will cope anyway.) */ - (void) WaitEventSetWait(cv_wait_event_set, -1, &event, 1, + ret = WaitEventSetWait(cv_wait_event_set, timeout, &event, 1, wait_event_info); /* Reset latch before examining the state of the wait list. */ ResetLatch(MyLatch); + /* Timeout */ + if (ret == 0 && timeout >= 0) + { + /* + * In the event of a timeout, we simply return and the caller + * calls ConditionVariableCancelSleep to remove themselves from the + * wait queue + */ + return -1; + } + /* * If this process has been taken out of the wait list, then we know * that it has been signaled by ConditionVariableSignal (or @@ -183,6 +218,8 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info) } SpinLockRelease(&cv->mutex); } while (!done); + + return 0; } /* diff --git a/src/include/storage/condition_variable.h b/src/include/storage/condition_variable.h index 2a0249392c..f62164e483 100644 --- a/src/include/storage/condition_variable.h +++ b/src/include/storage/condition_variable.h @@ -43,6 +43,8 @@ extern void ConditionVariableInit(ConditionVariable *cv); * the condition variable. */ extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info); +extern int ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, + uint32 wait_event_info); extern void ConditionVariableCancelSleep(void); /* -- 2.16.5 --wRRV7LY7NUeQGEoC--