Re: nsd name server generates high load during zone update on slave

2012-05-30 Thread Stuart Henderson
On 2012-05-29, Imre Oolberg i...@auul.pri.ee wrote:
 Hi!

 Thank you very much for quick answer! Tried it on 5.1 stable in the 
 spirit on applying bind patch i.e. saying

 # cd /usr/src
 # patch -p0  /usr/src/nsd.patch
 # cd usr.sbin/nsd
 # make -f Makefile.bsd-wrapper obj
 # make -f Makefile.bsd-wrapper depend
 # make -f Makefile.bsd-wrapper
 # make -f Makefile.bsd-wrapper install

 And restarting nsd.

 I specifically copied zone before and after several times and got 
 respectivele load and no load. Also checked that zone content is all 
 right after copying. At the same time i realize that my testing is not 
 thorough.

 Do you think it is safe for me to start using this patch in production 
 or your people do some more testing and eventually publish this patch as 
 002_nsd.patch for OpenBSD v. 5.1?

I think it's safe and would be a good candidate for the 5.1-stable tree,
but it's not in the class of bugs for which we usually release separate
patches (typically these are just for security/crash fixes).



Re: nsd name server generates high load during zone update on slave

2012-05-29 Thread Imre Oolberg

Hi!

Thank you very much for quick answer! Tried it on 5.1 stable in the 
spirit on applying bind patch i.e. saying


# cd /usr/src
# patch -p0  /usr/src/nsd.patch
# cd usr.sbin/nsd
# make -f Makefile.bsd-wrapper obj
# make -f Makefile.bsd-wrapper depend
# make -f Makefile.bsd-wrapper
# make -f Makefile.bsd-wrapper install

And restarting nsd.

I specifically copied zone before and after several times and got 
respectivele load and no load. Also checked that zone content is all 
right after copying. At the same time i realize that my testing is not 
thorough.


Do you think it is safe for me to start using this patch in production 
or your people do some more testing and eventually publish this patch as 
002_nsd.patch for OpenBSD v. 5.1?



Best regards,

Imre


On 05/28/12 23:12, Stuart Henderson wrote:

On 2012-05-28, Imre Oolbergi...@auul.pri.ee  wrote:

Hi!

I am having trouble on OpenBSD v. 5.1 using NSD nameserver.

When slave NSD name server receives zone update and reloads it into its
database high and sustained user load (about 1-2) is generated on cpu
depending on hardware from 3 minutes to 10 minutes. Also this kind on
load is observed when doing nsdc patch. It seems to happen only when
zone has many RRs, say 100k NS lines; using NSD with OpenBSD v. 4.8 from
packages does not have this issue, also not 5.1-current, but 5.1 does; i
have tried and got similar results on amd64 and i386, happens on
both; Normally this kind of reload and patch takes several seconds only.



I would be very thankful if somebody could have a look at it and confirm
this behaviour. And if really nsd on 5.1 is to blame may i add that
patch would be very much welcomed! :)


This is due to a bug introduced with NSD 3.2.9 and fixed shortly afterwards.
The _untested_ diff against -stable below may fix it.

Index: difffile.c
===
RCS file: /cvs/src/usr.sbin/nsd/difffile.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 difffile.c
--- difffile.c  29 Jan 2012 11:15:31 -  1.1.1.5
+++ difffile.c  28 May 2012 20:10:31 -
@@ -261,14 +261,43 @@ has_data_below(domain_type* top)
/* in the canonical ordering subdomains are after this name */
d = domain_next(d);
while(d != NULL  dname_is_subdomain(domain_dname(d), 
domain_dname(top))) {
-   if(d-is_existing)
+   if(d-is_existing) {
return 1;
+   }
d = domain_next(d);
}
return 0;
  }

-static void
+
+/* this routine makes empty terminals non-existent.
+ * @domain the lowest empty terminal
+ * @ce the closest encloser
+ */
+static domain_type*
+rrset_delete_empty_terminals(domain_type* domain, domain_type* ce)
+{
+   assert(domain);
+   if (domain-rrsets == 0) {
+   /* if there is no data below it, it becomes non existing.
+  also empty nonterminals above it become nonexisting */
+   /* check for data below this node. */
+   if(!has_data_below(domain)) {
+   /* nonexist this domain and all parent empty 
nonterminals */
+   domain_type* p = domain;
+   while(p != NULL  p-rrsets == 0) {
+   if(p == ce || has_data_below(p))
+   return p;
+   p-is_existing = 0;
+   p = p-parent;
+   }
+   }
+   }
+   return NULL;
+}
+
+
+static domain_type*
  rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
  {
int i;
@@ -279,7 +308,7 @@ rrset_delete(namedb_type* db, domain_typ
}
if(!*pp) {
/* rrset does not exist for domain */
-   return;
+   return NULL;
}
*pp = rrset-next;

@@ -320,23 +349,13 @@ rrset_delete(namedb_type* db, domain_typ
sizeof(rr_type) * rrset-rr_count);
region_recycle(db-region, rrset, sizeof(rrset_type));

+   rrset-rr_count = 0;
+
/* is the node now an empty node (completely deleted) */
-   if(domain-rrsets == 0) {
-   /* if there is no data below it, it becomes non existing.
-  also empty nonterminals above it become nonexisting */
-   /* check for data below this node. */
-   if(!has_data_below(domain)) {
-   /* nonexist this domain and all parent empty 
nonterminals */
-   domain_type* p = domain;
-   while(p != NULL  p-rrsets == 0) {
-   if(has_data_below(p))
-   break;
-   p-is_existing = 0;
-   p = p-parent;
-   }
-   }
+   if (domain-rrsets == 0) {
+   return domain;
}
-   rrset-rr_count = 0;

Re: nsd name server generates high load during zone update on slave

2012-05-28 Thread Stuart Henderson
On 2012-05-28, Imre Oolberg i...@auul.pri.ee wrote:
 Hi!

 I am having trouble on OpenBSD v. 5.1 using NSD nameserver.

 When slave NSD name server receives zone update and reloads it into its 
 database high and sustained user load (about 1-2) is generated on cpu 
 depending on hardware from 3 minutes to 10 minutes. Also this kind on 
 load is observed when doing nsdc patch. It seems to happen only when 
 zone has many RRs, say 100k NS lines; using NSD with OpenBSD v. 4.8 from 
 packages does not have this issue, also not 5.1-current, but 5.1 does; i 
 have tried and got similar results on amd64 and i386, happens on
 both; Normally this kind of reload and patch takes several seconds only.

 I would be very thankful if somebody could have a look at it and confirm 
 this behaviour. And if really nsd on 5.1 is to blame may i add that 
 patch would be very much welcomed! :)

This is due to a bug introduced with NSD 3.2.9 and fixed shortly afterwards.
The _untested_ diff against -stable below may fix it.

Index: difffile.c
===
RCS file: /cvs/src/usr.sbin/nsd/difffile.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 difffile.c
--- difffile.c  29 Jan 2012 11:15:31 -  1.1.1.5
+++ difffile.c  28 May 2012 20:10:31 -
@@ -261,14 +261,43 @@ has_data_below(domain_type* top)
/* in the canonical ordering subdomains are after this name */
d = domain_next(d);
while(d != NULL  dname_is_subdomain(domain_dname(d), 
domain_dname(top))) {
-   if(d-is_existing)
+   if(d-is_existing) {
return 1;
+   }
d = domain_next(d);
}
return 0;
 }
 
-static void
+
+/* this routine makes empty terminals non-existent.
+ * @domain the lowest empty terminal
+ * @ce the closest encloser
+ */
+static domain_type*
+rrset_delete_empty_terminals(domain_type* domain, domain_type* ce)
+{
+   assert(domain);
+   if (domain-rrsets == 0) {
+   /* if there is no data below it, it becomes non existing.
+  also empty nonterminals above it become nonexisting */
+   /* check for data below this node. */
+   if(!has_data_below(domain)) {
+   /* nonexist this domain and all parent empty 
nonterminals */
+   domain_type* p = domain;
+   while(p != NULL  p-rrsets == 0) {
+   if(p == ce || has_data_below(p))
+   return p;
+   p-is_existing = 0;
+   p = p-parent;
+   }
+   }
+   }
+   return NULL;
+}
+
+
+static domain_type*
 rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
 {
int i;
@@ -279,7 +308,7 @@ rrset_delete(namedb_type* db, domain_typ
}
if(!*pp) {
/* rrset does not exist for domain */
-   return;
+   return NULL;
}
*pp = rrset-next;
 
@@ -320,23 +349,13 @@ rrset_delete(namedb_type* db, domain_typ
sizeof(rr_type) * rrset-rr_count);
region_recycle(db-region, rrset, sizeof(rrset_type));
 
+   rrset-rr_count = 0;
+
/* is the node now an empty node (completely deleted) */
-   if(domain-rrsets == 0) {
-   /* if there is no data below it, it becomes non existing.
-  also empty nonterminals above it become nonexisting */
-   /* check for data below this node. */
-   if(!has_data_below(domain)) {
-   /* nonexist this domain and all parent empty 
nonterminals */
-   domain_type* p = domain;
-   while(p != NULL  p-rrsets == 0) {
-   if(has_data_below(p))
-   break;
-   p-is_existing = 0;
-   p = p-parent;
-   }
-   }
+   if (domain-rrsets == 0) {
+   return domain;
}
-   rrset-rr_count = 0;
+   return NULL;
 }
 
 static int
@@ -384,6 +403,7 @@ find_rr_num(rrset_type* rrset,
 static int
 delete_RR(namedb_type* db, const dname_type* dname,
uint16_t type, uint16_t klass,
+   domain_type* prevdomain,
buffer_type* packet, size_t rdatalen, zone_type *zone,
region_type* temp_region, int is_axfr)
 {
@@ -442,7 +462,11 @@ delete_RR(namedb_type* db, const dname_t
 
if(rrset-rr_count == 1) {
/* delete entire rrset */
-   rrset_delete(db, domain, rrset);
+   domain = rrset_delete(db, domain, rrset);
+   if (domain  !domain-nextdiff) {
+   /* this domain is not yet in the diff chain */
+