From 356310126e10488d576cc3f4fdebd47ecc41d0aa Mon Sep 17 00:00:00 2001 From: Daniel Salzman Date: Thu, 5 Dec 2019 15:25:42 +0100 Subject: [PATCH] server: abort possible open zone transaction when shutdown --- src/knot/server/server.c | 2 +- src/knot/zone/zonedb-load.c | 2 +- src/knot/zone/zonedb.c | 9 +++++--- src/knot/zone/zonedb.h | 3 ++- tests-extra/tests/ctl/shutdown/test.py | 32 ++++++++++++++++++++++++++ tests/knot/test_zonedb.c | 2 +- 6 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 tests-extra/tests/ctl/shutdown/test.py diff --git a/src/knot/server/server.c b/src/knot/server/server.c index ee7a72125..92998a714 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -458,7 +458,7 @@ void server_deinit(server_t *server) worker_pool_destroy(server->workers); /* Free zone database. */ - knot_zonedb_deep_free(&server->zone_db); + knot_zonedb_deep_free(&server->zone_db, true); /* Free remaining events. */ evsched_deinit(&server->sched); diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c index 59f16386b..790d7e0b6 100644 --- a/src/knot/zone/zonedb-load.c +++ b/src/knot/zone/zonedb-load.c @@ -317,7 +317,7 @@ static void remove_old_zonedb(conf_t *conf, knot_zonedb_t *db_old, knot_zonedb_iter_free(it); if (full) { - knot_zonedb_deep_free(&db_old); + knot_zonedb_deep_free(&db_old, false); } else { knot_zonedb_free(&db_old); } diff --git a/src/knot/zone/zonedb.c b/src/knot/zone/zonedb.c index 58b98f7bc..9d28fd0be 100644 --- a/src/knot/zone/zonedb.c +++ b/src/knot/zone/zonedb.c @@ -24,7 +24,7 @@ #include "contrib/ucw/mempool.h" /*! \brief Discard zone in zone database. */ -static void discard_zone(zone_t *zone) +static void discard_zone(zone_t *zone, bool abort_txn) { // Don't flush if removed zone (no previous configuration available). if (conf_rawid_exists(conf(), C_ZONE, zone->name, knot_dname_size(zone->name))) { @@ -39,6 +39,9 @@ static void discard_zone(zone_t *zone) } } + if (abort_txn) { + zone_control_clear(zone); + } zone_free(&zone); } @@ -155,12 +158,12 @@ void knot_zonedb_free(knot_zonedb_t **db) *db = NULL; } -void knot_zonedb_deep_free(knot_zonedb_t **db) +void knot_zonedb_deep_free(knot_zonedb_t **db, bool abort_txn) { if (db == NULL || *db == NULL) { return; } - knot_zonedb_foreach(*db, discard_zone); + knot_zonedb_foreach(*db, discard_zone, abort_txn); knot_zonedb_free(db); } diff --git a/src/knot/zone/zonedb.h b/src/knot/zone/zonedb.h index a162d6dfd..d35f9a0df 100644 --- a/src/knot/zone/zonedb.h +++ b/src/knot/zone/zonedb.h @@ -120,5 +120,6 @@ void knot_zonedb_free(knot_zonedb_t **db); * \brief Destroys and deallocates the whole zone database including the zones. * * \param db Zone database to be destroyed. + * \param abort_txn Indication that possible zone transactions are aborted. */ -void knot_zonedb_deep_free(knot_zonedb_t **db); +void knot_zonedb_deep_free(knot_zonedb_t **db, bool abort_txn); diff --git a/tests-extra/tests/ctl/shutdown/test.py b/tests-extra/tests/ctl/shutdown/test.py new file mode 100644 index 000000000..83629f5cf --- /dev/null +++ b/tests-extra/tests/ctl/shutdown/test.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +'''Test on server shutdown when a zone transaction is open.''' + +import psutil +from dnstest.libknot import libknot +from dnstest.test import Test +from dnstest.utils import * + +t = Test() + +knot = t.server("knot") +zone = t.zone("example.com.") +t.link(zone, knot) + +ctl = libknot.control.KnotCtl() + +t.start() + +ctl.connect(os.path.join(knot.dir, "knot.sock")) +ctl.send_block(cmd="zone-begin", zone=zone[0].name) +ctl.receive_block() +ctl.send(libknot.control.KnotCtlType.END) +ctl.close() + +knot.stop() +t.sleep(1) + +if psutil.pid_exists(knot.proc.pid): + set_err("Server still running") + +t.end() diff --git a/tests/knot/test_zonedb.c b/tests/knot/test_zonedb.c index 30beb9a03..3ef7632fe 100644 --- a/tests/knot/test_zonedb.c +++ b/tests/knot/test_zonedb.c @@ -110,6 +110,6 @@ int main(int argc, char *argv[]) ok(nr_passed == ZONE_COUNT, "zonedb: removed all zones"); cleanup: - knot_zonedb_deep_free(&db); + knot_zonedb_deep_free(&db, false); return 0; }