From 03e5c754568b3ea06aa7ccf7538a04a54612f82c Mon Sep 17 00:00:00 2001
From: Marek Vavrusa <marek.vavrusa@nic.cz>
Date: Wed, 18 Jul 2012 19:02:35 +0200
Subject: [PATCH] Implemented ixfr-from-differences in config.

refs #1949
---
 samples/knot.full.conf           | 10 ++++++++++
 src/knot/conf/cf-lex.l           |  1 +
 src/knot/conf/cf-parse.y         |  4 ++++
 src/knot/conf/conf.c             |  6 ++++++
 src/knot/conf/conf.h             |  2 ++
 src/knot/server/zones.c          | 22 ++++++++++++++++++++++
 src/libknot/updates/changesets.c |  2 +-
 src/libknot/zone/zone-diff.c     |  2 +-
 8 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/samples/knot.full.conf b/samples/knot.full.conf
index d9d9de79fe..a0ec438593 100644
--- a/samples/knot.full.conf
+++ b/samples/knot.full.conf
@@ -119,6 +119,11 @@ zones {
   # Shared options for all listed zones
   #
 
+  # Build differences from zone file changes
+  # Possible values: on|off
+  # Default value: off
+  ixfr-from-differences off;
+
   # Enable semantic checks for all zones (if 'on')
   # Possible values: on|off
   # Default value: off
@@ -161,6 +166,11 @@ zones {
     #   it is considered relative to the current directory from which the server
     #   was started.
     file "samples/example.com.zone";
+    
+    # Build differences from zone file changes
+    # Possible values: on|off
+    # Default value: off
+    ixfr-from-differences off;
 
     # Disable ANY type queries for authoritative answers (if 'on')
     # Possible values: on|off
diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l
index 16b0343860..58d1f4b961 100644
--- a/src/knot/conf/cf-lex.l
+++ b/src/knot/conf/cf-lex.l
@@ -90,6 +90,7 @@ notify-out      { lval.t = yytext; return NOTIFY_OUT; }
 workers         { lval.t = yytext; return WORKERS; }
 user            { lval.t = yytext; return USER; }
 pidfile         { lval.t = yytext; return PIDFILE; }
+ixfr-from-differences { lval.t = yytext; return BUILD_DIFFS; }
 
 interfaces      { lval.t = yytext; return INTERFACES; }
 address         { lval.t = yytext; return ADDRESS; }
diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
index fb6502674f..69a5415350 100644
--- a/src/knot/conf/cf-parse.y
+++ b/src/knot/conf/cf-parse.y
@@ -172,6 +172,7 @@ static void conf_zone_start(void *scanner, char *name) {
    this_zone->ixfr_fslimit = -1; // Default policy applies
    this_zone->dbsync_timeout = -1; // Default policy applies
    this_zone->disable_any = -1; // Default policy applies
+   this_zone->build_diffs = -1; // Default policy applies
 
    // Append mising dot to ensure FQDN
    size_t nlen = strlen(name);
@@ -266,6 +267,7 @@ static int conf_mask(void* scanner, int nval, int prefixlen) {
 %token <tok> XFR_OUT
 %token <tok> NOTIFY_IN
 %token <tok> NOTIFY_OUT
+%token <tok> BUILD_DIFFS
 
 %token <tok> INTERFACES ADDRESS PORT
 %token <tok> IPA
@@ -662,6 +664,7 @@ zone:
  | zone zone_acl '}'
  | zone zone_acl_list
  | zone FILENAME TEXT ';' { this_zone->file = $3.t; }
+ | zone BUILD_DIFFS BOOL ';' { this_zone->build_diffs = $3.i; }
  | zone SEMANTIC_CHECKS BOOL ';' { this_zone->enable_checks = $3.i; }
  | zone DISABLE_ANY BOOL ';' { this_zone->disable_any = $3.i; }
  | zone DBSYNC_TIMEOUT NUM ';' { this_zone->dbsync_timeout = $3.i; }
@@ -688,6 +691,7 @@ zones:
    ZONES '{'
  | zones zone '}'
  | zones DISABLE_ANY BOOL ';' { new_config->disable_any = $3.i; }
+ | zones BUILD_DIFFS BOOL ';' { new_config->build_diffs = $3.i; }
  | zones SEMANTIC_CHECKS BOOL ';' { new_config->zone_checks = $3.i; }
  | zones IXFR_FSLIMIT SIZE ';' { new_config->ixfr_fslimit = $3.l; }
  | zones IXFR_FSLIMIT NUM ';' { new_config->ixfr_fslimit = $3.i; }
diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
index edc2f1ad23..447f59a8aa 100644
--- a/src/knot/conf/conf.c
+++ b/src/knot/conf/conf.c
@@ -214,6 +214,11 @@ static int conf_process(conf_t *conf)
 		if (zone->dbsync_timeout < 0) {
 			zone->dbsync_timeout = conf->dbsync_timeout;
 		}
+		
+		// Default policy for ixfr-from-differences
+		if (zone->build_diffs < 0) {
+			zone->build_diffs = conf->build_diffs;
+		}
 
 		// Default policy for semantic checks
 		if (zone->enable_checks < 0) {
@@ -490,6 +495,7 @@ conf_t *conf_new(const char* path)
 	c->ixfr_fslimit = -1;
 	c->uid = -1;
 	c->gid = -1;
+	c->build_diffs = 0; /* Disable by default. */
 
 	return c;
 }
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
index 7e1b61ff8e..7921335cd8 100644
--- a/src/knot/conf/conf.h
+++ b/src/knot/conf/conf.h
@@ -96,6 +96,7 @@ typedef struct conf_zone_t {
 	int disable_any;          /*!< Disable ANY type queries for AA.*/
 	int notify_retries;       /*!< NOTIFY query retries. */
 	int notify_timeout;       /*!< Timeout for NOTIFY response (s). */
+	int build_diffs;          /*!< Calculate differences from changes. */
 	struct {
 		list xfr_in;      /*!< Remotes accepted for for xfr-in.*/
 		list xfr_out;     /*!< Remotes accepted for xfr-out.*/
@@ -197,6 +198,7 @@ typedef struct conf_t {
 	int notify_timeout; /*!< Timeout for NOTIFY response in seconds. */
 	int dbsync_timeout; /*!< Default interval between syncing to zonefile.*/
 	size_t ixfr_fslimit; /*!< File size limit for IXFR journal. */
+	int build_diffs;     /*!< Calculate differences from changes. */
 
 	/*
 	 * Implementation specifics
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index 81e1bf43c0..919c3fa5cb 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -1537,6 +1537,28 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst,
 
 			rcu_read_unlock();
 		}
+		
+		/* Calculate differences. */
+		rcu_read_lock();
+		knot_zone_t *z_old = knot_zonedb_find_zone(ns->zone_db,
+		                                              dname);
+		/* Ensure both new and old have zone contents. */
+		knot_zone_contents_t *zc = knot_zone_get_contents(zone);
+		knot_zone_contents_t *zc_old = knot_zone_get_contents(z_old);
+		if (z->build_diffs && zc != NULL && zc_old != NULL && zone_changed) {
+			int bd = zones_create_and_save_changesets(z_old, zone);
+			if (bd == KNOTD_ENODIFF) {
+				log_zone_warning("Zone file for '%s' changed, "
+				                 "but serial didn't - "
+				                 "won't create changesets.\n",
+				                 z->name);
+			} else if (bd != KNOTD_EOK) {
+				log_zone_warning("Failed to calculate differences"
+				                 " from the zone file update: "
+				                 "%s\n", knotd_strerror(bd));
+			}
+		}
+		rcu_read_unlock();
 	}
 
 	/* CLEANUP */
diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c
index 457ba93b2a..bd167897fc 100644
--- a/src/libknot/updates/changesets.c
+++ b/src/libknot/updates/changesets.c
@@ -206,7 +206,7 @@ int knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa,
 int knot_changesets_check_size(knot_changesets_t *changesets)
 {
 	/* Check if allocated is sufficient. */
-	if (changesets->count <= changesets->allocated) {
+	if (changesets->count < changesets->allocated) {
 		return KNOT_EOK;
 	}
 
diff --git a/src/libknot/zone/zone-diff.c b/src/libknot/zone/zone-diff.c
index 07817d4eb9..400f24f2a9 100644
--- a/src/libknot/zone/zone-diff.c
+++ b/src/libknot/zone/zone-diff.c
@@ -857,7 +857,7 @@ int knot_zone_diff_create_changesets(const knot_zone_contents_t *z1,
 		return ret;
 	}
 	
-	ret = knot_zone_contents_diff(z1, z2, &((*changesets)->sets[0]));
+	ret = knot_zone_contents_diff(z1, z2, (*changesets)->sets);
 	if (ret != KNOT_EOK) {
 		dbg_zonediff("zone_diff: create_changesets: "
 		             "Could not diff zones. "
-- 
GitLab