From f8cbf390afa873386bc85ba4c99ff1fd2c115d1e Mon Sep 17 00:00:00 2001 From: David Hankins Date: Thu, 28 Feb 2008 23:40:45 +0000 Subject: [PATCH] - There is now a default 1/4 of a second scheduled delay between delayed fsync()'s, it can be configured by the max-ack-delay configuration parameter. [ISC-Bugs #17679] --- RELNOTES | 4 ++++ includes/dhcpd.h | 11 +++++++++++ server/db.c | 4 ++-- server/dhcp.c | 42 ++++++++++++++++++++++++++++++++++-------- server/dhcpd.c | 16 ++++++++++++++++ server/dhcpd.conf.5 | 18 +++++++++++++----- server/stables.c | 1 + 7 files changed, 81 insertions(+), 15 deletions(-) diff --git a/RELNOTES b/RELNOTES index 3fe70bac..731881ea 100644 --- a/RELNOTES +++ b/RELNOTES @@ -57,6 +57,10 @@ work on other platforms. Please report any problems and suggested fixes to - ./configure was extended to cover many optional build features, such as failover, server tracing, debugging, and the execute() command. +- There is now a default 1/4 of a second scheduled delay between delayed + fsync()'s, it can be configured by the max-ack-delay configuration + parameter. + Changes since 4.0.0 (new features) - Added DHCPv6 rapid commit support. diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 489075c6..7b177093 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -624,6 +624,7 @@ struct lease_state { #define SV_LIMIT_ADDRS_PER_IA 56 #define SV_LIMIT_PREFS_PER_IA 57 #define SV_DELAYED_ACK 58 +#define SV_MAX_ACK_DELAY 59 #if !defined (DEFAULT_PING_TIMEOUT) # define DEFAULT_PING_TIMEOUT 1 @@ -633,6 +634,14 @@ struct lease_state { # define DEFAULT_DELAYED_ACK 28 /* default SO_SNDBUF size / 576 bytes */ #endif +#if !defined (DEFAULT_ACK_DELAY_SECS) +# define DEFAULT_ACK_DELAY_SECS 0 +#endif + +#if !defined (DEFAULT_ACK_DELAY_USECS) +# define DEFAULT_ACK_DELAY_USECS 250000 /* 1/4 of a second */ +#endif + #if !defined (DEFAULT_DEFAULT_LEASE_TIME) # define DEFAULT_DEFAULT_LEASE_TIME 43200 #endif @@ -1939,6 +1948,8 @@ int data_string_sprintfa(struct data_string *ds, const char *fmt, ...); /* dhcp.c */ extern int outstanding_pings; extern int max_outstanding_acks; +extern int max_ack_delay_secs; +extern int max_ack_delay_usecs; void dhcp PROTO ((struct packet *)); void dhcpdiscover PROTO ((struct packet *, int)); diff --git a/server/db.c b/server/db.c index e2af0a28..563a261c 100644 --- a/server/db.c +++ b/server/db.c @@ -1059,8 +1059,8 @@ int commit_leases () log_info ("commit_leases: unable to commit: %m"); return 0; } - - /* send out all deferred ACKs now*/ + + /* send out all deferred ACKs now */ flush_ackqueue(NULL); /* If we haven't rewritten the lease database in over an diff --git a/server/dhcp.c b/server/dhcp.c index 7376932e..756746fe 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -35,14 +35,19 @@ #include "dhcpd.h" #include #include +#include + +static void commit_leases_ackout(void *foo); int outstanding_pings; struct leasequeue *ackqueue_head, *ackqueue_tail; static struct leasequeue *free_ackqueue; -TIME next_fsync; +static struct timeval next_fsync; int outstanding_acks; int max_outstanding_acks = DEFAULT_DELAYED_ACK; +int max_ack_delay_secs = DEFAULT_ACK_DELAY_SECS; +int max_ack_delay_usecs = DEFAULT_ACK_DELAY_USECS; static char dhcp_message [256]; static int site_code_min; @@ -2836,6 +2841,7 @@ void delayed_ack_enqueue(struct lease *lease) { struct leasequeue *q; + if (!write_lease(lease)) return; if (free_ackqueue) { @@ -2861,21 +2867,41 @@ delayed_ack_enqueue(struct lease *lease) if (outstanding_acks > max_outstanding_acks) commit_leases(); - /* If neccessary, schedule a fsync in 1 second */ - /* - if (next_fsync < cur_time + 1) { - next_fsync = cur_time + 1; - add_timeout(next_fsync, commit_leases_readerdry, NULL, + /* If next_fsync is not set, schedule an fsync. */ + if (next_fsync.tv_sec == 0 && next_fsync.tv_usec == 0) { + next_fsync.tv_sec = cur_tv.tv_sec + max_ack_delay_secs; + next_fsync.tv_usec = cur_tv.tv_usec + max_ack_delay_usecs; + + if (next_fsync.tv_usec >= 1000000) { + next_fsync.tv_sec++; + next_fsync.tv_usec -= 1000000; + } + + add_timeout(&next_fsync, commit_leases_ackout, NULL, (tvref_t) NULL, (tvunref_t) NULL); } - */ } void commit_leases_readerdry(void *foo) { - if (outstanding_acks) + if (outstanding_acks) { commit_leases(); + + /* Reset next_fsync and cancel any pending timeout. */ + memset(&next_fsync, 0, sizeof(next_fsync)); + cancel_timeout(commit_leases_ackout, NULL); + } +} + +static void +commit_leases_ackout(void *foo) +{ + if (outstanding_acks) { + commit_leases(); + + memset(&next_fsync, 0, sizeof(next_fsync)); + } } /* CC: process the delayed ACK responses: diff --git a/server/dhcpd.c b/server/dhcpd.c index 3540e532..0f17ce41 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -1086,6 +1086,22 @@ void postconf_initialization (int quiet) data_string_forget(&db, MDL); } + oc = lookup_option(&server_universe, options, SV_MAX_ACK_DELAY); + if (oc && + evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, + &global_scope, oc, MDL)) { + u_int32_t timeval; + + if (db.len != 4) + log_fatal("invalid max ack delay configuration"); + + timeval = getULong(db.data); + max_ack_delay_secs = timeval / 1000000; + max_ack_delay_usecs = timeval % 1000000; + + data_string_forget(&db, MDL); + } + /* Don't need the options anymore. */ option_state_dereference (&options, MDL); diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index 221ce295..34257920 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -28,7 +28,7 @@ .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" -.\" $Id: dhcpd.conf.5,v 1.94 2008/02/20 12:45:53 fdupont Exp $ +.\" $Id: dhcpd.conf.5,v 1.95 2008/02/28 23:40:45 dhankins Exp $ .\" .TH dhcpd.conf 5 .SH NAME @@ -2069,14 +2069,17 @@ as the "valid lifetime" in DHCPv6). .PP The .I delayed-ack -statement +and +.I max-ack-delay +statements .RS 0.25i .PP -.B delayed-ack \fInumber\fR\fB;\fR +.B delayed-ack \fIcount\fR\fB;\fR +.B max-ack-delay \fImicroseconds\fR\fB;\fR .PP -.I Number +.I Count should be an integer value from zero to 2^16-1, and defaults to 28. The -number represents how many DHCPv4 replies maximum will be queued pending +count represents how many DHCPv4 replies maximum will be queued pending transmission until after a database commit event. If this number is reached, a database commit event (commonly resulting in fsync() and representing a performance penalty) will be made, and the reply packets @@ -2084,6 +2087,11 @@ will be transmitted in a batch afterwards. This preserves the RFC2131 direction that "stable storage" be updated prior to replying to clients. Should the DHCPv4 sockets "go dry" (select() returns immediately with no read sockets), the commit is made and any queued packets are transmitted. +.PP +Similarly, \fImicroseconds\fR indicates how many microseconds are permitted +to pass inbetween queuing a packet pending an fsync, and performing the +fsync. Valid values range from 0 to 2^32-1, and defaults to 250,000 (1/4 of +a second). .RE .PP The diff --git a/server/stables.c b/server/stables.c index abb96479..d2118166 100644 --- a/server/stables.c +++ b/server/stables.c @@ -240,6 +240,7 @@ static struct option server_options[] = { { "limit-addrs-per-ia", "L", &server_universe, 56, 1 }, { "limit-prefs-per-ia", "L", &server_universe, 57, 1 }, { "delayed-ack", "S", &server_universe, 58, 1 }, + { "max-ack-delay", "L", &server_universe, 59, 1 }, { NULL, NULL, NULL, 0, 0 } };