diff --git a/src/knot/server/net.c b/src/knot/server/net.c index c1d061a8104a7ab641ba994cfec4bc6de7e20b41..5e2c8d63367a1b5702dff4b2c49f877d4dd3a90e 100644 --- a/src/knot/server/net.c +++ b/src/knot/server/net.c @@ -81,11 +81,6 @@ int net_bound_socket(int type, const struct sockaddr_storage *ss) int flag = 1; (void) setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); - /* Reuse port if available. */ -#if defined(SO_REUSEPORT) - (void) setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)); -#endif - /* Unlink UNIX socket if exists. */ if (ss->ss_family == AF_UNIX) { unlink(addr_str); diff --git a/src/knot/server/server.c b/src/knot/server/server.c index b9b3382a06b0be2c08d84cefd33f26652f9e33a3..4a0a0734408b0f132c0ad4b949f7f8d2ecf944d8 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -116,16 +116,12 @@ static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if) char addr_str[SOCKADDR_STRLEN] = {0}; sockaddr_tostr(&cfg_if->addr, addr_str, sizeof(addr_str)); -#if defined(SO_REUSEPORT) - /* Each thread binds own socket. */ - int sock = -1; -#else /* Create bound UDP socket. */ int sock = net_bound_socket(SOCK_DGRAM, &cfg_if->addr); if (sock < 0) { return sock; } -#endif + new_if->fd[IO_UDP] = sock; /* Create bound TCP socket. */ @@ -615,15 +611,26 @@ int server_update_zones(const struct conf_t *conf, void *data) { server_t *server = (server_t *)data; + /* Prevent new events on zones waiting to be replaced. */ + if (server->zone_db) { + knot_zonedb_foreach(server->zone_db, zone_events_freeze); + } + + /* Finish operations already in the queue. */ + worker_pool_wait(server->workers); + + /* Reload zone database and free old zones. */ int ret = zonedb_reload(conf, server); - if (ret != KNOT_EOK) { - return ret; + + /* Plan events on new zones. */ + if (server->zone_db) { + knot_zonedb_foreach(server->zone_db, zone_events_start); } /* Trim extra heap. */ mem_trim(); - return KNOT_EOK; + return ret; } ref_t *server_set_ifaces(server_t *s, fdset_t *fds, int type) diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index e0f8701035bc75bf0fed367d03de3aaf7a86ab2c..12dbf9269b8dd6c633c4bd0f164437b0f5c9fcb7 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -456,28 +456,33 @@ int udp_send_msg(int fd, const uint8_t *msg, size_t msglen, struct sockaddr *add return ret; } -static void unbind_ifaces(ifacelist_t *ifaces, fd_set *set, int maxfd) +/*! \brief Release the reference on the interface list and clear watched fdset. */ +static void forget_ifaces(ifacelist_t *ifaces, fd_set *set, int maxfd) { ref_release((ref_t *)ifaces); -#if defined(SO_REUSEPORT) - for (int fd = 0; fd <= maxfd; ++fd) { - if (FD_ISSET(fd, set)) { - close(fd); - } - } -#endif FD_ZERO(set); } -static int bind_iface(iface_t *iface, fd_set *set) +/*! \brief Add interface sockets to the watched fdset. */ +static int track_ifaces(ifacelist_t *ifaces, fd_set *set, int *maxfd, int *minfd) { -#if defined(SO_REUSEPORT) - int fd = net_bound_socket(SOCK_DGRAM, &iface->addr); -#else - int fd = iface->fd[IO_UDP]; -#endif - FD_SET(fd, set); - return fd; + FD_ZERO(set); + *maxfd = -1; + *minfd = 0; + + if (ifaces == NULL) { + return KNOT_EINVAL; + } + + iface_t *iface = NULL; + WALK_LIST(iface, ifaces->l) { + int fd = iface->fd[IO_UDP]; + *maxfd = MAX(fd, *maxfd); + *minfd = MIN(fd, *minfd); + FD_SET(fd, set); + } + + return KNOT_EOK; } int udp_master(dthread_t *thread) @@ -532,18 +537,9 @@ int udp_master(dthread_t *thread) udp.thread_id = handler->thread_id[thr_id]; rcu_read_lock(); - unbind_ifaces(ref, &fds, maxfd); - maxfd = 0; - minfd = INT_MAX; + forget_ifaces(ref, &fds, maxfd); ref = handler->server->ifaces; - if (ref) { - iface_t *i = NULL; - WALK_LIST(i, ref->l) { - int fd = bind_iface(i, &fds); - maxfd = MAX(fd, maxfd); - minfd = MIN(fd, minfd); - } - } + track_ifaces(ref, &fds, &maxfd, &minfd); rcu_read_unlock(); } @@ -575,7 +571,7 @@ int udp_master(dthread_t *thread) } _udp_deinit(rq); - unbind_ifaces(ref, &fds, maxfd); + forget_ifaces(ref, &fds, maxfd); mp_delete(udp.query_ctx.mm.ctx); return KNOT_EOK; } diff --git a/src/knot/worker/pool.c b/src/knot/worker/pool.c index d6d0cf046c1df9510943b4682ffe9bd7c9b6e2e9..42ff57217fe6875525511f4447bd3291fa09da31 100644 --- a/src/knot/worker/pool.c +++ b/src/knot/worker/pool.c @@ -36,8 +36,7 @@ struct worker_pool { pthread_mutex_t lock; pthread_cond_t wake; - bool suspended; - bool terminating; + bool terminating; /*!< Is the pool terminating? .*/ worker_queue_t tasks; }; @@ -63,11 +62,6 @@ static int worker_main(dthread_t *thread) break; } - if (pool->suspended) { - pthread_cond_wait(&pool->wake, &pool->lock); - continue; - } - task_t *task = worker_queue_dequeue(&pool->tasks); if (task == NULL) { pthread_cond_wait(&pool->wake, &pool->lock); @@ -80,6 +74,8 @@ static int worker_main(dthread_t *thread) pthread_mutex_unlock(&pool->lock); task->run(task); pthread_mutex_lock(&pool->lock); + + pthread_cond_broadcast(&pool->wake); } pthread_mutex_unlock(&pool->lock); @@ -166,26 +162,16 @@ void worker_pool_join(worker_pool_t *pool) dt_join(pool->threads); } -void worker_pool_suspend(worker_pool_t *pool) +void worker_pool_wait(worker_pool_t *pool) { if (!pool) { return; } pthread_mutex_lock(&pool->lock); - pool->suspended = true; - pthread_mutex_unlock(&pool->lock); -} - -void worker_pool_continue(worker_pool_t *pool) -{ - if (!pool) { - return; + while (!EMPTY_LIST(pool->tasks.list)) { + pthread_cond_wait(&pool->wake, &pool->lock); } - - pthread_mutex_lock(&pool->lock); - pool->suspended = false; - pthread_cond_broadcast(&pool->wake); pthread_mutex_unlock(&pool->lock); } @@ -197,9 +183,7 @@ void worker_pool_assign(worker_pool_t *pool, task_t *task) pthread_mutex_lock(&pool->lock); worker_queue_enqueue(&pool->tasks, task); - if (!pool->suspended) { - pthread_cond_signal(&pool->wake); - } + pthread_cond_signal(&pool->wake); pthread_mutex_unlock(&pool->lock); } diff --git a/src/knot/worker/pool.h b/src/knot/worker/pool.h index 171140983220e8edb85ca54067395ad6bac302e1..9ffa04d41fb0ed3054609bffbec9ae10186a2702 100644 --- a/src/knot/worker/pool.h +++ b/src/knot/worker/pool.h @@ -51,14 +51,10 @@ void worker_pool_stop(worker_pool_t *pool); void worker_pool_join(worker_pool_t *pool); /*! - * \brief Suspend execution of new tasks, existing task are not terminated. - */ -void worker_pool_suspend(worker_pool_t *pool); - -/*! - * \brief Continue execution of new tasks. + * \brief Wait till the number of pending tasks is zero. + * */ -void worker_pool_continue(worker_pool_t *pool); +void worker_pool_wait(worker_pool_t *pool); /*! * \brief Assign a task to be performed by a worker in the pool. diff --git a/src/knot/zone/events.c b/src/knot/zone/events.c index 91b63f0079af0704c78a11a554c07c1e7b18d208..e3a7fdaa801dc2740a66c122b480b5e83793e0db 100644 --- a/src/knot/zone/events.c +++ b/src/knot/zone/events.c @@ -609,7 +609,7 @@ static const event_info_t EVENT_INFO[] = { { ZONE_EVENT_RELOAD, event_reload, "reload" }, { ZONE_EVENT_REFRESH, event_refresh, "refresh" }, { ZONE_EVENT_XFER, event_xfer, "transfer" }, - { ZONE_EVENT_UPDATE, event_update, "UPDATE" }, + { ZONE_EVENT_UPDATE, event_update, "update" }, { ZONE_EVENT_EXPIRE, event_expire, "expiration" }, { ZONE_EVENT_FLUSH, event_flush, "journal flush" }, { ZONE_EVENT_NOTIFY, event_notify, "notify" }, @@ -734,7 +734,6 @@ void zone_events_deinit(zone_t *zone) evsched_cancel(zone->events.event); evsched_event_free(zone->events.event); - assert(zone->events.running == false); pthread_mutex_destroy(&zone->events.mx); memset(&zone->events, 0, sizeof(zone->events)); @@ -750,6 +749,12 @@ void zone_events_schedule_at(zone_t *zone, zone_event_type_t type, time_t time) pthread_mutex_lock(&events->mx); + /* Don't schedule new events if frozen. */ + if (events->frozen) { + pthread_mutex_unlock(&events->mx); + return; + } + time_t current = event_get_time(events, type); if (current == 0 || time == 0 || time < current) { event_set_time(events, type, time); @@ -772,7 +777,7 @@ void zone_events_cancel(zone_t *zone, zone_event_type_t type) zone_events_schedule_at(zone, type, 0); } -void zone_events_cancel_all(zone_t *zone) +void zone_events_freeze(zone_t *zone) { if (!zone) { return; @@ -781,10 +786,9 @@ void zone_events_cancel_all(zone_t *zone) zone_events_t *events = &zone->events; pthread_mutex_lock(&events->mx); - for (int i = 0; i < ZONE_EVENT_COUNT; i++) { - event_set_time(events, i, 0); - } - reschedule(events); + /* Cancel pending event and prevent new. */ + events->frozen = true; + evsched_cancel(events->event); pthread_mutex_unlock(&events->mx); } diff --git a/src/knot/zone/events.h b/src/knot/zone/events.h index f1638863367266d057c5ee9bbcceb8bb8b0f05c3..ebd7e7b5179d9404d2ead17f025c27ec07ece923 100644 --- a/src/knot/zone/events.h +++ b/src/knot/zone/events.h @@ -48,6 +48,7 @@ typedef enum zone_event_type { typedef struct zone_events { pthread_mutex_t mx; //!< Mutex protecting the struct. bool running; //!< Some zone event is being run. + bool frozen; //!< Terminated, don't schedule new events. event_t *event; //!< Scheduler event. worker_pool_t *pool; //!< Server worker pool. @@ -96,9 +97,9 @@ void zone_events_schedule(struct zone_t *zone, zone_event_type_t type, unsigned void zone_events_cancel(struct zone_t *zone, zone_event_type_t type); /*! - * \brief Cancel all zone events. + * \brief Freeze all zone events and prevent new events from running. */ -void zone_events_cancel_all(struct zone_t *zone); +void zone_events_freeze(struct zone_t *zone); /*! * \brief Start the events processing. diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c index cb89897047624b221835e7d28ca1ca347e538934..31d3ea03e23dcc43907578084dceef10624c9090 100644 --- a/src/knot/zone/zonedb-load.c +++ b/src/knot/zone/zonedb-load.c @@ -166,7 +166,7 @@ static zone_t *create_zone(conf_zone_t *conf, server_t *server, zone_t *old_zone * new. New zones are loaded. * * \param conf New server configuration. - * \param old_db Old zone database (can be NULL). + * \param server Server instance. * * \return New zone database. */ @@ -206,9 +206,9 @@ static knot_zonedb_t *create_zonedb(const conf_t *conf, server_t *server) } /*! - * \brief Remove old zones and zone database. + * \brief Schedule deletion of old zones, and free the zone db structure. * - * \note Zone may be preserved in the new zone database, in this case + * \note Zone content may be preserved in the new zone database, in this case * new and old zone share the contents. Shared content is not freed. * * \param db_new New zone database. @@ -234,7 +234,6 @@ static int remove_old_zonedb(const knot_zonedb_t *db_new, knot_zonedb_t *db_old) knot_zonedb_iter_next(&it); } - /* Delete all deprecated zones and delete the old database. */ knot_zonedb_deep_free(&db_old); return KNOT_EOK; @@ -252,12 +251,6 @@ int zonedb_reload(const conf_t *conf, struct server_t *server) return KNOT_EINVAL; } - /* Freeze zone timers. */ -#warning "Workers have to be suspended and unsuspended outside this function." - if (server->zone_db) { - //knot_zonedb_foreach(server->zone_db, zone_events_freeze); - } - /* Insert all required zones to the new zone DB. */ /*! \warning RCU must not be locked as some contents switching will be required. */ @@ -277,11 +270,6 @@ int zonedb_reload(const conf_t *conf, struct server_t *server) /* Wait for readers to finish reading old zone database. */ synchronize_rcu(); - /* Thaw zone events now that the database is published. */ - if (server->zone_db) { - knot_zonedb_foreach(server->zone_db, zone_events_start); - } - /* * Remove all zones present in the new DB from the old DB. * No new thread can access these zones in the old DB, as the diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c index 84304b84154ef8983118126ccb08283e01be579a..6ccac6651c901ad114187ec2052107afa2282035 100644 --- a/src/utils/dig/dig_exec.c +++ b/src/utils/dig/dig_exec.c @@ -653,7 +653,7 @@ static void process_query(const query_t *query) return; // SERVFAIL. } else if (ret == 1 && query->servfail_stop == true) { - WARN("failed to query server %s#%s(%s)\n", + WARN("failed to query server %s@%s(%s)\n", remote->name, remote->service, get_sockname(socktype)); net_clean(&net); @@ -663,7 +663,7 @@ static void process_query(const query_t *query) if (i < query->retries) { printf("\n"); - DBG("retrying server %s#%s(%s)\n", + DBG("retrying server %s@%s(%s)\n", remote->name, remote->service, get_sockname(socktype)); } @@ -671,7 +671,7 @@ static void process_query(const query_t *query) net_clean(&net); } - WARN("failed to query server %s#%s(%s)\n", + WARN("failed to query server %s@%s(%s)\n", remote->name, remote->service, get_sockname(socktype)); // If not last server, print separation. @@ -905,7 +905,7 @@ static void process_xfr(const query_t *query) } if (ret != 0) { - ERR("failed to query server %s#%s(%s)\n", + ERR("failed to query server %s@%s(%s)\n", remote->name, remote->service, get_sockname(socktype)); }