bool old_contents_exist = (zone->contents != NULL), zone_in_journal_exists = false;
const char *zone_src = "zone file";
struct redisContext *db_ctx = NULL;
+ bool rdb_reload = false;
conf_val_t val = conf_zone_get(conf, C_JOURNAL_CONTENT, zone->name);
unsigned load_from = conf_opt(&val);
bool db_enabled = conf_zone_rdb_enabled(conf, zone->name, true, &db_instance);
if (db_enabled) {
zone_src = "database";
+ rdb_reload = zone_get_flag(zone, ZONE_RDB_RELOAD, false);
db_ctx = zone_redis_connect(conf, false);
}
// Attempt to load changes from database. If fails, load full zone from there later.
- if (db_enabled && (old_contents_exist || journal_conts != NULL) &&
+ if (db_enabled && !rdb_reload && (old_contents_exist || journal_conts != NULL) &&
zone->cat_members == NULL && EMPTY_LIST(zone->include_from) &&
zf_from != ZONEFILE_LOAD_DIFSE && !includes_configured) {
zone_redis_err_t err;
zone_schedule_notify(conf, zone, 0);
}
zone_redis_disconnect(db_ctx, true);
+ zone_unset_flag(zone, ZONE_RDB_RELOAD);
zone_skip_free(&skip);
zone->started = true;
switch (type) {
case RDB_EVENT_ZONE:
+ zone_set_flag(zone, ZONE_RDB_RELOAD);
+ // FALLTHROUGH
case RDB_EVENT_UPD:
log_zone_debug(zone->name, "rdb, event %s %s, serial %u",
since, (type == RDB_EVENT_ZONE ? "zone" : "update"), serial);
ZONE_USER_FLUSH = 1 << 8, /*!< User-triggered flush. */
ZONE_LAST_SIGN_OK = 1 << 9, /*!< Last full-sign event finished OK. */
ZONE_PREF_MASTER_2X = 1 << 10, /*!< Preferred master has been overwritten at least once. */
+ ZONE_RDB_RELOAD = 1 << 11, /*!< Full zone reload from database. */
ZONE_FLAG_MAX = 1 << 19, /*!< Maximal usable flag below purge_flag_t. */
ZONE_FLAG_TYPESIZE = 1 << 30, /*!< Enforces the compiler to use 32-bit variable for this enum. */
--- /dev/null
+$ORIGIN example.com.
+$TTL 3600
+
+@ SOA dns1 hostmaster 1 10800 3600 1209600 7200
+ NS dns1
+ NS dns2
+ MX 10 mail
+ TXT "version1"
+
+dns1 A 192.0.2.1
+ AAAA 2001:DB8::1
+
+dns2 A 192.0.2.2
+ AAAA 2001:DB8::2
+
+mail A 192.0.2.3
+ AAAA 2001:DB8::3
--- /dev/null
+$ORIGIN example.com.
+$TTL 3600
+
+@ SOA dns1 hostmaster 1 10800 3600 1209600 7200
+ NS dns1
+ NS dns2
+ MX 10 mail
+ TXT "version2"
+
+dns1 A 192.0.2.1
+ AAAA 2001:DB8::1
+
+dns2 A 192.0.2.2
+ AAAA 2001:DB8::2
+
+mail A 192.0.2.3
+ AAAA 2001:DB8::3
--- /dev/null
+#!/usr/bin/env python3
+
+'''Test for zone reload from Redis database.'''
+
+import random
+from dnstest.test import Test
+from dnstest.utils import *
+
+t = Test()
+
+hidden = t.server("knot")
+master = t.server("knot")
+slave = t.server("knot")
+
+zones = t.zone("example.com.", storage=".")
+
+t.link(zones, hidden, master)
+t.link(zones, master)
+t.link(zones, slave)
+
+tls = random.choice([True, False])
+redis_master = t.backend("redis", tls=tls)
+redis_slave = t.backend("redis", tls=tls)
+redis_slave.slave_of(redis_master)
+
+master.db_out(zones, [redis_master], 1)
+slave.db_in(zones, [redis_slave], 1)
+
+t.start()
+
+# Check initial zone contents.
+slave.zones_wait(zones)
+t.xfr_diff(hidden, slave, zones)
+resp = slave.dig("example.com", "TXT")
+resp.check_record(section="answer", rtype="TXT", rdata="version1")
+
+# Replace zone contents with serial unchanged.
+hidden.update_zonefile(zones[0], version=1)
+hidden.reload()
+master.ctl("zone-retransfer")
+
+# Check retransfered different zone contents with the same serial.
+t.sleep(4)
+t.xfr_diff(hidden, slave, zones)
+resp = slave.dig("example.com", "TXT")
+resp.check_record(section="answer", rtype="TXT", rdata="version2", nordata="version1")
+
+t.end()