Commit 58721528 authored by Jan Včelák's avatar Jan Včelák 🚀

events: allow to schedule multiple events at once

parent a18232de
......@@ -15,6 +15,7 @@
*/
#include <assert.h>
#include <stdarg.h>
#include <time.h>
#include <urcu.h>
......@@ -71,6 +72,28 @@ static time_t time_until(time_t planned)
return now < planned ? (planned - now) : 0;
}
/*!
* \brief Set time of a given event type.
*/
static void event_set_time(zone_events_t *events, zone_event_type_t type, time_t time)
{
assert(events);
assert(valid_event(type));
events->time[type] = time;
}
/*!
* \brief Get time of a given event type.
*/
static time_t event_get_time(zone_events_t *events, zone_event_type_t type)
{
assert(events);
assert(valid_event(type));
return events->time[type];
}
/*!
* \brief Find next scheduled zone event.
*
......@@ -103,25 +126,12 @@ static zone_event_type_t get_next_event(zone_events_t *events)
}
/*!
* \brief Set time of a given event type.
* \brief Fined time of next scheduled event.
*/
static void event_set_time(zone_events_t *events, zone_event_type_t type, time_t time)
static time_t get_next_time(zone_events_t *events)
{
assert(events);
assert(valid_event(type));
events->time[type] = time;
}
/*!
* \brief Get time of a given event type.
*/
static time_t event_get_time(zone_events_t *events, zone_event_type_t type)
{
assert(events);
assert(valid_event(type));
return events->time[type];
zone_event_type_t type = get_next_event(events);
return valid_event(type) ? event_get_time(events, type) : 0;
}
/*!
......@@ -266,21 +276,38 @@ void zone_events_deinit(zone_t *zone)
memset(&zone->events, 0, sizeof(zone->events));
}
void zone_events_schedule_at(zone_t *zone, zone_event_type_t type, time_t time)
void _zone_events_schedule_at(zone_t *zone, ...)
{
if (!zone || !valid_event(type)) {
return;
}
zone_events_t *events = &zone->events;
va_list args;
va_start(args, zone);
pthread_mutex_lock(&events->mx);
time_t current = event_get_time(events, type);
if (time == 0 || current == 0 || time < current) {
event_set_time(events, type, time);
time_t old_next = get_next_time(events);
// update timers
for (int type = va_arg(args, int); valid_event(type); type = va_arg(args, int)) {
time_t planned = va_arg(args, time_t);
if (planned < 0) {
continue;
}
time_t current = event_get_time(events, type);
if (planned == 0 || current == 0 || planned < current) {
event_set_time(events, type, planned);
}
}
// reschedule if changed
time_t next = get_next_time(events);
if (old_next != next) {
reschedule(events);
}
pthread_mutex_unlock(&events->mx);
va_end(args);
}
bool zone_events_is_scheduled(zone_t *zone, zone_event_type_t type)
......@@ -310,13 +337,7 @@ void zone_events_enqueue(zone_t *zone, zone_event_type_t type)
pthread_mutex_unlock(&events->mx);
/* Execute as soon as possible. */
zone_events_schedule(zone, type, ZONE_EVENT_NOW);
}
void zone_events_schedule(zone_t *zone, zone_event_type_t type, unsigned dt)
{
time_t abstime = time(NULL) + dt;
zone_events_schedule_at(zone, type, abstime);
zone_events_schedule_at(zone, type, time(NULL));
}
void zone_events_cancel(zone_t *zone, zone_event_type_t type)
......
......@@ -25,9 +25,6 @@
#include "knot/worker/pool.h"
#include "libknot/db/db.h"
/* Timer special values. */
#define ZONE_EVENT_NOW 0
struct zone;
typedef enum zone_event_type {
......@@ -101,44 +98,26 @@ void zone_events_deinit(struct zone *zone);
void zone_events_enqueue(struct zone *zone, zone_event_type_t type);
/*!
* \brief Schedule new zone event to absolute time.
* \brief Schedule new zone event.
*
* If the event is already scheduled, the new time will be set only if the
* new time is earlier than the currently scheduled one. An exception is
* a zero time, which causes event cancellation.
*
* \param zone Zone to schedule new event for.
* \param type Type of event.
* \param time Absolute time.
*/
void zone_events_schedule_at(struct zone *zone, zone_event_type_t type, time_t time);
/*!
* \brief Schedule new zone event using relative time to current time.
*
* The function internally uses \ref zone_events_schedule_at.
* The function allows to set multiple events at once. The
*
* \param zone Zone to schedule new event for.
* \param type Type of event.
* \param dt Relative time.
* \param ... Sequence of zone_event_type_t and time_t terminated with
* ZONE_EVENT_INVALID.
*/
void zone_events_schedule(struct zone *zone, zone_event_type_t type, unsigned dt);
void _zone_events_schedule_at(struct zone *zone, ...);
/*!
* \brief Check if zone event is scheduled.
*
* \param zone Zone to check event of.
* \param type Type of event.
*/
bool zone_events_is_scheduled(struct zone *zone, zone_event_type_t type);
#define zone_events_schedule_at(zone, events...) \
_zone_events_schedule_at(zone, events, ZONE_EVENT_INVALID)
#define zone_events_schedule_now(zone, type) \
zone_events_schedule_at(zone, type, time(NULL))
/*!
* \brief Cancel one zone event.
*
* \param zone Zone to cancel event in.
* \param type Type of event to cancel.
*/
void zone_events_cancel(struct zone *zone, zone_event_type_t type);
/*!
* \brief Freeze all zone events and prevent new events from running.
......
......@@ -34,7 +34,7 @@ static void test_scheduling(zone_t *zone)
// scheduling
zone_events_schedule(zone, ZONE_EVENT_EXPIRE, offset);
zone_events_schedule_at(zone, ZONE_EVENT_EXPIRE, now + offset);
zone_events_schedule_at(zone, ZONE_EVENT_FLUSH, now + (offset / 2));
for (int i = 0; i < ZONE_EVENT_COUNT; i++) {
......@@ -51,12 +51,12 @@ static void test_scheduling(zone_t *zone)
timestamp = zone_events_get_next(zone, &event);
ok(timestamp >= now + (offset / 2) && event == ZONE_EVENT_FLUSH, "flush is next");
zone_events_cancel(zone, ZONE_EVENT_FLUSH);
zone_events_schedule_at(zone, ZONE_EVENT_FLUSH, 0);
timestamp = zone_events_get_next(zone, &event);
ok(timestamp >= now + offset && event == ZONE_EVENT_EXPIRE, "expire is next");
zone_events_cancel(zone, ZONE_EVENT_EXPIRE);
zone_events_schedule_at(zone, ZONE_EVENT_EXPIRE, 0);
timestamp = zone_events_get_next(zone, &event);
ok(timestamp < 0 && event == ZONE_EVENT_INVALID, "nothing planned");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment