blob: d0da71dfae29091864a2c4d6c1e878c89a0be0c4 [file]
/*-------------------------------------------------------------------------
*
* idle_resource_cleaner.c
*
* Portions Copyright (c) 2005-2008, Greenplum inc
* Portions Copyright (c) 2012-Present VMware, Inc. or its affiliates.
*
*
* IDENTIFICATION
* src/backend/tcop/idle_resource_cleaner.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <signal.h>
#include "cdb/cdbgang.h"
#include "commands/async.h"
#include "storage/sinval.h"
#include "tcop/idle_resource_cleaner.h"
#include "utils/timeout.h"
int IdleSessionGangTimeout = 18000;
static volatile sig_atomic_t clientWaitTimeoutInterruptEnabled = 0;
static volatile sig_atomic_t idle_gang_timeout_occurred;
/*
* We want to check to see if our session goes "idle" (nobody sending us work to
* do). We decide this is true if after waiting a while, we don't get a message
* from the client.
* We can then free resources. Currently, we only free gangs on the segDBs.
*
* We want the time value to be long enough so we don't free gangs prematurely.
* This means giving the end user enough time to type in the next SQL statement
*/
void
StartIdleResourceCleanupTimers()
{
if (IdleSessionGangTimeout <= 0 || !cdbcomponent_qesExist())
return;
enable_timeout_after(GANG_TIMEOUT, IdleSessionGangTimeout);
}
void
CancelIdleResourceCleanupTimers()
{
disable_timeout(GANG_TIMEOUT, false);
}
void
EnableClientWaitTimeoutInterrupt(void)
{
clientWaitTimeoutInterruptEnabled = 1;
/* If a timeout occurred while the interrupt was disabled, process it now */
if (idle_gang_timeout_occurred)
IdleGangTimeoutHandler();
/*
* NOTE: This is simpler than the corresponding notify and catchup
* interrupt code, because we don't expect the idle timeouts to fire again
* during the same client wait.
*/
}
bool
DisableClientWaitTimeoutInterrupt(void)
{
bool result = (clientWaitTimeoutInterruptEnabled != 0);
clientWaitTimeoutInterruptEnabled = 0;
return result;
}
/*
* Called when a session has been idle for a while (waiting for the client
* to send us SQL to execute). The idea is to consume less resources while
* sitting idle, so we can support more sessions being logged on.
*
* The expectation is that if the session is logged on, but nobody is sending us
* work to do, we want to free up whatever resources we can. Usually it means
* there is a human being at the other end of the connection, and that person
* has walked away from their terminal, or just hasn't decided what to do next.
* We could be idle for a very long time (many hours).
*
* Of course, freeing gangs means that the next time the user does send in an
* SQL statement, we need to allocate gangs (at least the writer gang) to do
* anything. This entails extra work, so we don't want to do this if we don't
* think the session has gone idle.
*
* PS: Is there anything we can free up on the master (QD) side? I can't
* think of anything.
*/
void
IdleGangTimeoutHandler(void)
{
if (clientWaitTimeoutInterruptEnabled)
{
idle_gang_timeout_occurred = 0;
DisconnectAndDestroyUnusedQEs();
}
else
idle_gang_timeout_occurred = 1;
}