From ea17368c01cdfbd794b640796122c08d8df4127a Mon Sep 17 00:00:00 2001 From: Marek Vavrusa <marek.vavrusa@nic.cz> Date: Tue, 2 Apr 2013 12:21:28 +0200 Subject: [PATCH] Configurable number of parallel xfers (system.transfers). Updated documentation, cleanup. --- doc/reference.texi | 12 ++++++++- samples/knot.full.conf | 6 +++++ src/knot/conf/cf-lex.l | 1 + src/knot/conf/cf-parse.y | 2 ++ src/knot/conf/conf.c | 4 +++ src/knot/conf/conf.h | 2 ++ src/knot/ctl/remote.c | 8 +----- src/knot/server/xfr-handler.c | 46 +++++++++++------------------------ src/knot/server/xfr-handler.h | 7 ++++++ src/knot/server/zones.c | 4 ++- src/knot/server/zones.h | 1 + 11 files changed, 52 insertions(+), 41 deletions(-) diff --git a/doc/reference.texi b/doc/reference.texi index bb2bf39184..40488bcd35 100644 --- a/doc/reference.texi +++ b/doc/reference.texi @@ -42,8 +42,9 @@ else. [ @code{max-conn-idle} ( @kbd{integer} | @kbd{integer}(@code{s} | @code{m} | @code{h} | @code{d})@code{;} ) ] [ @code{max-conn-hs} ( @kbd{integer} | @kbd{integer}(@code{s} | @code{m} | @code{h} | @code{d})@code{;} ) ] [ @code{max-conn-reply} ( @kbd{integer} | @kbd{integer}(@code{s} | @code{m} | @code{h} | @code{d})@code{;} ) ] + [ @code{transfers} @kbd{integer}@code{;} ] [ @code{rate-limit} @kbd{integer}@code{;} ] - [ @code{rate-limit-size} ( @kbd{integer} | @kbd{integer}(@code{s} | @code{m} | @code{h} | @code{d})@code{;} ) ] + [ @code{rate-limit-size} @kbd{integer}@code{;} ] [ @code{rate-limit-slip} @kbd{integer}@code{;} ] @code{@}} @end example @@ -62,6 +63,7 @@ else. * max-conn-idle:: * max-conn-hs:: * max-conn-reply:: +* transfers:: * rate-limit:: * rate-limit-size:: * rate-limit-slip:: @@ -184,6 +186,14 @@ that already made at least 1 meaningful query. Maximum time to wait for a reply to an issued SOA query. +@node transfers +@subsubsection transfers +@vindex transfers + +Maximum parallel transfers, including pending SOA queries. +Lowest possible number is the number of CPUs. +Default is 10. + @node rate-limit @subsubsection rate-limit @vindex rate-limit diff --git a/samples/knot.full.conf b/samples/knot.full.conf index 8c02d3c11f..aabe334c38 100644 --- a/samples/knot.full.conf +++ b/samples/knot.full.conf @@ -61,6 +61,12 @@ system { # Default: 10s max-conn-reply 10s; + # Number of parallel transfers + # This number also includes pending SOA queries + # Minimal value is number of CPUs + # Default: 10 + transfers 10; + # Rate limit # in queries / second # Default: off (=0) diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l index 5a539179ad..0b0ddf88b1 100644 --- a/src/knot/conf/cf-lex.l +++ b/src/knot/conf/cf-lex.l @@ -98,6 +98,7 @@ max-conn-reply { lval.t = yytext; return MAX_CONN_REPLY; } rate-limit { lval.t = yytext; return RATE_LIMIT; } rate-limit-size { lval.t = yytext; return RATE_LIMIT_SIZE; } rate-limit-slip { lval.t = yytext; return RATE_LIMIT_SLIP; } +transfers { lval.t = yytext; return TRANSFERS; } 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 ff0097b21c..f6aa2b471f 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -299,6 +299,7 @@ static int conf_mask(void* scanner, int nval, int prefixlen) { %token <tok> RATE_LIMIT %token <tok> RATE_LIMIT_SIZE %token <tok> RATE_LIMIT_SLIP +%token <tok> TRANSFERS %token <tok> INTERFACES ADDRESS PORT %token <tok> IPA @@ -444,6 +445,7 @@ system: | system RATE_LIMIT_SIZE SIZE ';' { new_config->rrl_size = $3.l; } | system RATE_LIMIT_SIZE NUM ';' { new_config->rrl_size = $3.i; } | system RATE_LIMIT_SLIP NUM ';' { new_config->rrl_slip = $3.i; } + | system TRANSFERS NUM ';' { new_config->xfers = $3.i; } ; keys: diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index 31b380cf2f..f5104de4ee 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -178,6 +178,9 @@ static int conf_process(conf_t *conf) if (conf->rrl_size == 0) { conf->rrl_size = CONFIG_RRL_SIZE; } + + /* Default parallel transfers. */ + if (conf->xfers <= 0) conf->xfers = CONFIG_XFERS; // Postprocess zones int ret = KNOT_EOK; @@ -496,6 +499,7 @@ conf_t *conf_new(const char* path) c->ixfr_fslimit = -1; c->uid = -1; c->gid = -1; + c->xfers = -1; c->build_diffs = 0; /* Disable by default. */ /* ACLs. */ diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index 2c87b1da46..2f9f036da0 100644 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -52,6 +52,7 @@ #define CONFIG_IDLE_WD 60 /*!< [secs] of allowed inactivity between requests */ #define CONFIG_RRL_SLIP 2 /*!< Default slip value. */ #define CONFIG_RRL_SIZE 393241 /*!< Htable default size. */ +#define CONFIG_XFERS 10 /*! * \brief Configuration for the interface @@ -185,6 +186,7 @@ typedef struct conf_t { int rrl; /*!< Rate limit (in responses per second). */ size_t rrl_size; /*!< Rate limit htable size. */ int rrl_slip; /*!< Rate limit SLIP. */ + int xfers; /*!< Number of parallel transfers. */ /* * Log diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c index 8bb527ced6..a9c9fa5679 100644 --- a/src/knot/ctl/remote.c +++ b/src/knot/ctl/remote.c @@ -229,14 +229,8 @@ static int remote_c_zonestatus(server_t *s, remote_cmdargs_t* a) /* Evaluate zone state. */ char *when = NULL; -// int locked = pthread_mutex_trylock(&zd->xfr_in.lock); -// if (locked == 0) pthread_mutex_unlock(&zd->xfr_in.lock); - int locked = 0; - fprintf(stderr, "TODO: use something else\n"); - if (locked != 0) { + if (zd->xfr_in.state == XFR_PENDING) { when = strdup("pending"); -// } else if (zd->xfr_in.scheduled) { -// when = strdup("scheduled"); } else if (zd->xfr_in.timer) { struct timeval now, dif; gettimeofday(&now, 0); diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index 686877648e..54e6e558ae 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -45,7 +45,6 @@ /* Constants */ #define XFR_CHUNKLEN 3 /*! Number of requests assigned in a single pass. */ -#define XFR_QLEN 10 /*! Maximum pending transfers. \todo Configurable? */ #define XFR_SWEEP_INTERVAL 2 /*! [seconds] between sweeps. */ #define XFR_BUFFER_SIZE 65535 /*! Do not change this - maximum value for UDP packet length. */ #define XFR_MSG_DLTTR 9 /*! Index of letter differentiating IXFR/AXFR in log msg. */ @@ -473,12 +472,12 @@ static int xfr_task_process(xfrworker_t *w, knot_ns_xfr_t* rq, uint8_t *buf, siz switch(rq->type) { case XFR_TYPE_AIN: case XFR_TYPE_IIN: + zd->xfr_in.state = XFR_PENDING; rq->lookup_tree = hattrie_create(); if (ret != KNOT_EOK && ret != KNOT_EACCES) { if (zd != NULL && !knot_zone_contents(rq->zone)) { /* Reschedule request delay. */ - int tmr_s = AXFR_BOOTSTRAP_RETRY; - tmr_s += (int)((tmr_s) * tls_rand()); + int tmr_s = AXFR_BOOTSTRAP_RETRY * tls_rand(); event_t *ev = zd->xfr_in.timer; if (ev) { evsched_cancel(ev->parent, ev); @@ -705,7 +704,6 @@ static int xfr_task_xfer(xfrworker_t *w, knot_ns_xfr_t *rq) ret = xfr_task_finalize(w, rq); /* AXFR bootstrap timeout. */ - /*! \todo This is probably unneccesary. */ rcu_read_lock(); zonedata_t *zd = (zonedata_t *)knot_zone_data(rq->zone); if (ret != KNOT_EOK && !knot_zone_contents(rq->zone)) { @@ -941,9 +939,9 @@ int xfr_worker(dthread_t *thread) time_now(&next_sweep); next_sweep.tv_sec += XFR_SWEEP_INTERVAL; - unsigned thread_capacity = XFR_QLEN / w->master->unit->size; + unsigned thread_capacity = conf()->xfers / w->master->unit->size; w->pool.fds = fdset_new(); - w->pool.t = ahtable_create_n(XFR_QLEN); + w->pool.t = ahtable_create_n(conf()->xfers); w->pending = 0; /* Accept requests. */ @@ -952,7 +950,7 @@ int xfr_worker(dthread_t *thread) for (;;) { /* Populate pool with new requests. */ - if (w->pending < thread_capacity) { + if (w->pending <= thread_capacity) { pthread_mutex_lock(&xfr->mx); unsigned was_pending = w->pending; while (!EMPTY_LIST(xfr->queue)) { /* Take first request. */ @@ -1142,12 +1140,8 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *rq) rcu_read_lock(); int ret = knot_ns_init_xfr(ns, rq); - - int xfr_failed = (ret != KNOT_EOK); - const char *errstr = knot_strerror(ret); - // use the QNAME as the zone name to get names also for - // zones that are not in the server + /* Use the QNAME as the zone name. */ const knot_dname_t *qname = knot_packet_qname(rq->query); if (qname != NULL) { rq->zname = knot_dname_to_str(qname); @@ -1156,20 +1150,15 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *rq) } /* Check requested zone. */ - if (!xfr_failed) { - int zcheck_ret = zones_xfr_check_zone(rq, &rq->rcode); - xfr_failed = (zcheck_ret != KNOT_EOK); - errstr = knot_strerror(zcheck_ret); + if (ret == KNOT_EOK) { + ret = zones_xfr_check_zone(rq, &rq->rcode); } /* Check TSIG. */ char *keytag = NULL; - if (!xfr_failed && rq->tsig_key != NULL) { + if (ret == KNOT_EOK && rq->tsig_key != NULL) { ret = xfr_check_tsig(rq, &rq->rcode, &keytag); - xfr_failed = (ret != KNOT_EOK); - errstr = knot_strerror(ret); } - if (xfr_task_setmsg(rq, keytag) != KNOT_EOK) { rq->msg = strdup("XFR:"); } @@ -1207,7 +1196,7 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *rq) } /* Finally, answer AXFR/IXFR. */ - if (!xfr_failed) { + if (ret == KNOT_EOK) { switch(rq->type) { case XFR_TYPE_AOUT: ret = xfr_answer_axfr(ns, rq); @@ -1219,19 +1208,16 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *rq) ret = KNOT_ENOTSUP; break; } - - xfr_failed = (ret != KNOT_EOK); - errstr = knot_strerror(ret); } else { + /*! \todo Sign with TSIG for some errors. */ knot_ns_error_response_from_query(ns, rq->query, rq->rcode, rq->wire, &rq->wire_size); - /*! \todo Sign with TSIG for some errors. */ ret = rq->send(rq->session, &rq->addr, rq->wire, rq->wire_size); } /* Check results. */ - if (xfr_failed) { - log_server_notice("%s %s\n", rq->msg, errstr); + if (ret != KNOT_EOK) { + log_server_notice("%s %s\n", rq->msg, knot_strerror(ret)); } else { log_server_info("%s Finished.\n", rq->msg); } @@ -1244,11 +1230,7 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *rq) /* Free request. */ xfr_task_free(rq); rcu_read_unlock(); - if (xfr_failed) { - return KNOT_ERROR; - } - - return KNOT_EOK; + return ret; } knot_ns_xfr_t *xfr_task_create(knot_zone_t *z, int type, int flags) diff --git a/src/knot/server/xfr-handler.h b/src/knot/server/xfr-handler.h index 614281fe7c..e221834d50 100644 --- a/src/knot/server/xfr-handler.h +++ b/src/knot/server/xfr-handler.h @@ -36,6 +36,13 @@ struct xfrhandler_t; +/*! \brief Transfer state. */ +enum xfrstate_t { + XFR_IDLE = 0, + XFR_SCHED, + XFR_PENDING, +}; + /*! * \brief XFR worker structure. */ diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 45910abef4..1385698964 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -3227,6 +3227,7 @@ int zones_schedule_refresh(knot_zone_t *zone) /* Check XFR/IN master server. */ rcu_read_lock(); + zd->xfr_in.state = XFR_IDLE; if (zd->xfr_in.has_master) { /* Schedule REFRESH timer. */ @@ -3234,12 +3235,13 @@ int zones_schedule_refresh(knot_zone_t *zone) if (knot_zone_contents(zone)) { refresh_tmr = zones_jitter(zones_soa_refresh(zone)); } else { - refresh_tmr = AXFR_BOOTSTRAP_RETRY * tls_rand(); + refresh_tmr = zd->xfr_in.bootstrap_retry; } zd->xfr_in.timer = evsched_schedule_cb(sch, zones_refresh_ev, zone, refresh_tmr); dbg_zones("zone: REFRESH '%s' set to %u\n", zd->conf->name, refresh_tmr); + zd->xfr_in.state = XFR_SCHED; } rcu_read_unlock(); diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h index 2bc5d8b844..a0881e05b1 100644 --- a/src/knot/server/zones.h +++ b/src/knot/server/zones.h @@ -76,6 +76,7 @@ typedef struct zonedata_t struct event_t *expire; /*!< Timer for REFRESH. */ uint32_t bootstrap_retry; /*!< AXFR/IN bootstrap retry. */ int has_master; /*!< True if it has master set. */ + unsigned state; } xfr_in; /*! \brief Zone IXFR history. */ -- GitLab