Add enable_timeout_every() to fire the same timeout repeatedly.
enable_timeout_at() and enable_timeout_after() can still be used when you want to fire a timeout just once. Patch by me, per a suggestion from Tom Lane. Discussion: http://postgr.es/m/2992585.1632938816@sss.pgh.pa.us Discussion: http://postgr.es/m/CA+TgmoYqSF5sCNrgTom9r3Nh=at4WmYFD=gsV-omStZ60S0ZUQ@mail.gmail.com
This commit is contained in:
parent
902a2c2800
commit
732e6677a6
@ -36,6 +36,7 @@ typedef struct timeout_params
|
|||||||
|
|
||||||
TimestampTz start_time; /* time that timeout was last activated */
|
TimestampTz start_time; /* time that timeout was last activated */
|
||||||
TimestampTz fin_time; /* time it is, or was last, due to fire */
|
TimestampTz fin_time; /* time it is, or was last, due to fire */
|
||||||
|
int interval_in_ms; /* time between firings, or 0 if just once */
|
||||||
} timeout_params;
|
} timeout_params;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -153,7 +154,8 @@ remove_timeout_index(int index)
|
|||||||
* Enable the specified timeout reason
|
* Enable the specified timeout reason
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
|
enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time,
|
||||||
|
int interval_in_ms)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -188,6 +190,7 @@ enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
|
|||||||
all_timeouts[id].indicator = false;
|
all_timeouts[id].indicator = false;
|
||||||
all_timeouts[id].start_time = now;
|
all_timeouts[id].start_time = now;
|
||||||
all_timeouts[id].fin_time = fin_time;
|
all_timeouts[id].fin_time = fin_time;
|
||||||
|
all_timeouts[id].interval_in_ms = interval_in_ms;
|
||||||
|
|
||||||
insert_timeout(id, i);
|
insert_timeout(id, i);
|
||||||
}
|
}
|
||||||
@ -399,6 +402,29 @@ handle_sig_alarm(SIGNAL_ARGS)
|
|||||||
/* And call its handler function */
|
/* And call its handler function */
|
||||||
this_timeout->timeout_handler();
|
this_timeout->timeout_handler();
|
||||||
|
|
||||||
|
/* If it should fire repeatedly, re-enable it. */
|
||||||
|
if (this_timeout->interval_in_ms > 0)
|
||||||
|
{
|
||||||
|
TimestampTz new_fin_time;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To guard against drift, schedule the next instance of
|
||||||
|
* the timeout based on the intended firing time rather
|
||||||
|
* than the actual firing time. But if the timeout was so
|
||||||
|
* late that we missed an entire cycle, fall back to
|
||||||
|
* scheduling based on the actual firing time.
|
||||||
|
*/
|
||||||
|
new_fin_time =
|
||||||
|
TimestampTzPlusMilliseconds(this_timeout->fin_time,
|
||||||
|
this_timeout->interval_in_ms);
|
||||||
|
if (new_fin_time < now)
|
||||||
|
new_fin_time =
|
||||||
|
TimestampTzPlusMilliseconds(now,
|
||||||
|
this_timeout->interval_in_ms);
|
||||||
|
enable_timeout(this_timeout->index, now, new_fin_time,
|
||||||
|
this_timeout->interval_in_ms);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The handler might not take negligible time (CheckDeadLock
|
* The handler might not take negligible time (CheckDeadLock
|
||||||
* for instance isn't too cheap), so let's update our idea of
|
* for instance isn't too cheap), so let's update our idea of
|
||||||
@ -449,6 +475,7 @@ InitializeTimeouts(void)
|
|||||||
all_timeouts[i].timeout_handler = NULL;
|
all_timeouts[i].timeout_handler = NULL;
|
||||||
all_timeouts[i].start_time = 0;
|
all_timeouts[i].start_time = 0;
|
||||||
all_timeouts[i].fin_time = 0;
|
all_timeouts[i].fin_time = 0;
|
||||||
|
all_timeouts[i].interval_in_ms = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
all_timeouts_initialized = true;
|
all_timeouts_initialized = true;
|
||||||
@ -532,7 +559,29 @@ enable_timeout_after(TimeoutId id, int delay_ms)
|
|||||||
/* Queue the timeout at the appropriate time. */
|
/* Queue the timeout at the appropriate time. */
|
||||||
now = GetCurrentTimestamp();
|
now = GetCurrentTimestamp();
|
||||||
fin_time = TimestampTzPlusMilliseconds(now, delay_ms);
|
fin_time = TimestampTzPlusMilliseconds(now, delay_ms);
|
||||||
enable_timeout(id, now, fin_time);
|
enable_timeout(id, now, fin_time, 0);
|
||||||
|
|
||||||
|
/* Set the timer interrupt. */
|
||||||
|
schedule_alarm(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable the specified timeout to fire periodically, with the specified
|
||||||
|
* delay as the time between firings.
|
||||||
|
*
|
||||||
|
* Delay is given in milliseconds.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
enable_timeout_every(TimeoutId id, TimestampTz fin_time, int delay_ms)
|
||||||
|
{
|
||||||
|
TimestampTz now;
|
||||||
|
|
||||||
|
/* Disable timeout interrupts for safety. */
|
||||||
|
disable_alarm();
|
||||||
|
|
||||||
|
/* Queue the timeout at the appropriate time. */
|
||||||
|
now = GetCurrentTimestamp();
|
||||||
|
enable_timeout(id, now, fin_time, delay_ms);
|
||||||
|
|
||||||
/* Set the timer interrupt. */
|
/* Set the timer interrupt. */
|
||||||
schedule_alarm(now);
|
schedule_alarm(now);
|
||||||
@ -555,7 +604,7 @@ enable_timeout_at(TimeoutId id, TimestampTz fin_time)
|
|||||||
|
|
||||||
/* Queue the timeout at the appropriate time. */
|
/* Queue the timeout at the appropriate time. */
|
||||||
now = GetCurrentTimestamp();
|
now = GetCurrentTimestamp();
|
||||||
enable_timeout(id, now, fin_time);
|
enable_timeout(id, now, fin_time, 0);
|
||||||
|
|
||||||
/* Set the timer interrupt. */
|
/* Set the timer interrupt. */
|
||||||
schedule_alarm(now);
|
schedule_alarm(now);
|
||||||
@ -590,11 +639,17 @@ enable_timeouts(const EnableTimeoutParams *timeouts, int count)
|
|||||||
case TMPARAM_AFTER:
|
case TMPARAM_AFTER:
|
||||||
fin_time = TimestampTzPlusMilliseconds(now,
|
fin_time = TimestampTzPlusMilliseconds(now,
|
||||||
timeouts[i].delay_ms);
|
timeouts[i].delay_ms);
|
||||||
enable_timeout(id, now, fin_time);
|
enable_timeout(id, now, fin_time, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TMPARAM_AT:
|
case TMPARAM_AT:
|
||||||
enable_timeout(id, now, timeouts[i].fin_time);
|
enable_timeout(id, now, timeouts[i].fin_time, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TMPARAM_EVERY:
|
||||||
|
fin_time = TimestampTzPlusMilliseconds(now,
|
||||||
|
timeouts[i].delay_ms);
|
||||||
|
enable_timeout(id, now, fin_time, timeouts[i].delay_ms);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -48,14 +48,15 @@ typedef void (*timeout_handler_proc) (void);
|
|||||||
typedef enum TimeoutType
|
typedef enum TimeoutType
|
||||||
{
|
{
|
||||||
TMPARAM_AFTER,
|
TMPARAM_AFTER,
|
||||||
TMPARAM_AT
|
TMPARAM_AT,
|
||||||
|
TMPARAM_EVERY
|
||||||
} TimeoutType;
|
} TimeoutType;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
TimeoutId id; /* timeout to set */
|
TimeoutId id; /* timeout to set */
|
||||||
TimeoutType type; /* TMPARAM_AFTER or TMPARAM_AT */
|
TimeoutType type; /* TMPARAM_AFTER or TMPARAM_AT */
|
||||||
int delay_ms; /* only used for TMPARAM_AFTER */
|
int delay_ms; /* only used for TMPARAM_AFTER/EVERY */
|
||||||
TimestampTz fin_time; /* only used for TMPARAM_AT */
|
TimestampTz fin_time; /* only used for TMPARAM_AT */
|
||||||
} EnableTimeoutParams;
|
} EnableTimeoutParams;
|
||||||
|
|
||||||
@ -75,6 +76,8 @@ extern void reschedule_timeouts(void);
|
|||||||
|
|
||||||
/* timeout operation */
|
/* timeout operation */
|
||||||
extern void enable_timeout_after(TimeoutId id, int delay_ms);
|
extern void enable_timeout_after(TimeoutId id, int delay_ms);
|
||||||
|
extern void enable_timeout_every(TimeoutId id, TimestampTz fin_time,
|
||||||
|
int delay_ms);
|
||||||
extern void enable_timeout_at(TimeoutId id, TimestampTz fin_time);
|
extern void enable_timeout_at(TimeoutId id, TimestampTz fin_time);
|
||||||
extern void enable_timeouts(const EnableTimeoutParams *timeouts, int count);
|
extern void enable_timeouts(const EnableTimeoutParams *timeouts, int count);
|
||||||
extern void disable_timeout(TimeoutId id, bool keep_indicator);
|
extern void disable_timeout(TimeoutId id, bool keep_indicator);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user