Doc fix and work on prefetch feature.

git-svn-id: file:///svn/unbound/trunk@1951 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2010-01-07 14:38:18 +00:00
parent d11d56b0b3
commit 43d228c5bc
22 changed files with 1524 additions and 1353 deletions

View file

@ -738,6 +738,7 @@ load_msg(SSL* ssl, ldns_buffer* buf, struct worker* worker)
rep.flags = (uint16_t)flags;
rep.qdcount = (uint16_t)qdcount;
rep.ttl = (uint32_t)ttl;
rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
rep.security = (enum sec_status)security;
rep.an_numrrsets = (size_t)an;
rep.ns_numrrsets = (size_t)ns;

View file

@ -589,6 +589,24 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
return 1;
}
/** Reply to client and perform prefetch to keep cache up to date */
static void
reply_and_prefetch(struct worker* worker, struct query_info* qinfo,
uint16_t flags, struct comm_reply* repinfo)
{
/* first send answer to client to keep its latency
* as small as a cachereply */
comm_point_send_reply(repinfo);
/* account the prefetch (used to be part of the cache-reply count) */
/* TODO */
/* create the prefetch in the mesh as a normal lookup without
* client addrs waiting, which has the cache blacklisted (to bypass
* the cache and go to the network for the data). */
/* this (potentially) runs the mesh for the new query */
mesh_new_prefetch(worker->env.mesh, qinfo, flags);
}
/**
* Fill CH class answer into buffer. Keeps query.
* @param pkt: buffer
@ -836,6 +854,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
*(uint16_t*)ldns_buffer_begin(c->buffer),
ldns_buffer_read_u16_at(c->buffer, 2), repinfo,
&edns)) {
/* prefetch it if the prefetch TTL expired */
if(worker->env.cfg->prefetch && *worker->env.now >=
((struct reply_info*)e->data)->prefetch_ttl) {
lock_rw_unlock(&e->lock);
reply_and_prefetch(worker, &qinfo,
ldns_buffer_read_u16_at(c->buffer, 2),
repinfo);
return 0;
}
lock_rw_unlock(&e->lock);
return 1;
}

View file

@ -1,3 +1,7 @@
7 January 2010: Wouter
- Fixup python documentation (thanks Leo Vandewoestijne).
- Work on cache prefetch feature.
6 January 2010: Wouter
- iana portlist updated.
- bug#291: DNS wireformat max is 255. dname_valid allowed 256 length.

View file

@ -294,6 +294,9 @@ server:
# if no, localhost can be queried (for testing and debugging).
# do-not-query-localhost: yes
# if yes, perform prefetching of almost expired message cache entries.
# prefetch: no
# module configuration of the server. A string with identifiers
# separated by spaces. "iterator" or "validator iterator"
# module-config: "validator iterator"

View file

@ -503,6 +503,12 @@ If yes, localhost is added to the do\-not\-query\-address entries, both
IP6 ::1 and IP4 127.0.0.1/8. If no, then localhost can be used to send
queries to. Default is yes.
.TP
.B prefetch: \fI<yes or no>
If yes, message cache elements are prefetched before they expire to
keep the cache up to date. Default is no. Turning it on gives about
10 percent more traffic and load on the machine, but popular items do
not expire from the cache.
.TP
.B module\-config: \fI<"module names">
Module configuration, a list of module names separated by spaces, surround
the string with quotes (""). The modules can be validator, iterator.
@ -922,7 +928,7 @@ The
clause gives the settings for the \fIpython\fR(1) script module. This module
acts like the iterator and validator modules do, on queries and answers.
To enable the script module it has to be compiled into the daemon,
and the word "python" has to be put in the \fBmodule\-conf:\fR option
and the word "python" has to be put in the \fBmodule\-config:\fR option
(usually first, or between the validator and iterator).
.TP
.B python\-script: \fI<python file>\fR

View file

@ -672,6 +672,7 @@ reply_equal(struct reply_info* p, struct reply_info* q)
if(p->flags != q->flags ||
p->qdcount != q->qdcount ||
p->ttl != q->ttl ||
p->prefetch_ttl != q->prefetch_ttl ||
p->security != q->security ||
p->an_numrrsets != q->an_numrrsets ||
p->ns_numrrsets != q->ns_numrrsets ||

View file

@ -247,6 +247,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
FLAGS_SET_RCODE(err.flags, rcode);
err.qdcount = 1;
err.ttl = NORR_TTL;
err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl);
/* do not waste time trying to validate this servfail */
err.security = sec_status_indeterminate;
verbose(VERB_ALGO, "store error response in message cache");
@ -889,7 +890,9 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
if(verbosity >= VERB_ALGO) {
log_dns_msg("msg from cache lookup", &msg->qinfo,
msg->rep);
verbose(VERB_ALGO, "msg ttl is %d", (int)msg->rep->ttl);
verbose(VERB_ALGO, "msg ttl is %d, prefetch ttl %d",
(int)msg->rep->ttl,
(int)msg->rep->prefetch_ttl);
}
if(type == RESPONSE_TYPE_CNAME) {
@ -1996,6 +1999,8 @@ processClassResponse(struct module_qstate* qstate, int id,
to->rep->qdcount = from->rep->qdcount;
if(from->rep->ttl < to->rep->ttl) /* use smallest TTL */
to->rep->ttl = from->rep->ttl;
if(from->rep->prefetch_ttl < to->rep->prefetch_ttl)
to->rep->prefetch_ttl = from->rep->prefetch_ttl;
}
/* are we done? */
foriq->num_current_queries --;

View file

@ -345,6 +345,7 @@ struct reply_info {
uint16_t flags;
uint16_t qdcount;
uint32_t ttl;
uint32_t prefetch_ttl;
uint16_t authoritative;
enum sec_status security;

View file

@ -474,6 +474,9 @@ tomsg(struct module_env* env, struct msgreply_entry* e, struct reply_info* r,
msg->rep->flags = r->flags;
msg->rep->qdcount = r->qdcount;
msg->rep->ttl = r->ttl - now;
if(r->prefetch_ttl - now > 0)
msg->rep->prefetch_ttl = r->prefetch_ttl - now;
else msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(r->prefetch_ttl);
msg->rep->security = r->security;
msg->rep->an_numrrsets = r->an_numrrsets;
msg->rep->ns_numrrsets = r->ns_numrrsets;
@ -524,6 +527,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */
msg->rep->qdcount = 1;
msg->rep->ttl = d->ttl - now;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
msg->rep->security = sec_status_unchecked;
msg->rep->an_numrrsets = 1;
msg->rep->ns_numrrsets = 0;
@ -559,6 +563,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */
msg->rep->qdcount = 1;
msg->rep->ttl = d->ttl - now;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
msg->rep->security = sec_status_unchecked;
msg->rep->an_numrrsets = 1;
msg->rep->ns_numrrsets = 0;
@ -616,6 +621,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
packed_rrset_ptr_fixup(newd);
newd->rr_ttl[0] = newd->ttl;
msg->rep->ttl = newd->ttl;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(newd->ttl);
ldns_write_uint16(newd->rr_data[0], newlen);
memmove(newd->rr_data[0] + sizeof(uint16_t), newname, newlen);
msg->rep->an_numrrsets ++;

View file

@ -286,7 +286,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
/* see if it already exists, if not, create one */
if(!s) {
struct rbnode_t* n;
s = mesh_state_create(mesh->env,qinfo, qflags, 0);
s = mesh_state_create(mesh->env, qinfo, qflags, 0);
if(!s) {
log_err("mesh_state_create: out of memory; SERVFAIL");
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
@ -354,7 +354,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
/* see if it already exists, if not, create one */
if(!s) {
struct rbnode_t* n;
s = mesh_state_create(mesh->env,qinfo, qflags, 0);
s = mesh_state_create(mesh->env, qinfo, qflags, 0);
if(!s) {
return 0;
}
@ -388,6 +388,52 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
return 1;
}
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags)
{
struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags, 0);
struct rbnode_t* n;
/* already exists, and for a different purpose perhaps.
* if mesh_no_list, keep it that way. */
if(s) {
/* make it ignore the cache from now on */
if(!s->s.blacklist)
sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region);
return;
}
if(!mesh_make_new_space(mesh)) {
verbose(VERB_ALGO, "Too many queries. dropped prefetch.");
mesh->stats_dropped ++;
return;
}
s = mesh_state_create(mesh->env, qinfo, qflags, 0);
if(!s) {
log_err("prefetch mesh_state_create: out of memory");
return;
}
n = rbtree_insert(&mesh->all, &s->node);
log_assert(n != NULL);
/* set detached (it is now) */
mesh->num_detached_states++;
/* make it ignore the cache */
sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region);
if(s->list_select == mesh_no_list) {
/* move to either the forever or the jostle_list */
if(mesh->num_forever_states < mesh->max_forever_states) {
mesh->num_forever_states ++;
mesh_list_insert(s, &mesh->forever_first,
&mesh->forever_last);
s->list_select = mesh_forever_list;
} else {
mesh_list_insert(s, &mesh->jostle_first,
&mesh->jostle_last);
s->list_select = mesh_jostle_list;
}
}
mesh_run(mesh, s, module_event_new, NULL);
}
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
struct comm_reply* reply, int what)
{

View file

@ -286,6 +286,17 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, ldns_buffer* buf,
uint16_t qid, mesh_cb_func_t cb, void* cb_arg);
/**
* New prefetch message. Create new query state if needed.
* Will run the mesh area queries to process if a new query state is created.
*
* @param mesh: the mesh.
* @param qinfo: query from client.
* @param qflags: flags from client query.
*/
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags);
/**
* Handle new event from the wire. A serviced query has returned.
* The query state will be made runnable, and the mesh_area will process

View file

@ -144,6 +144,7 @@ print_option(struct config_file* cfg, const char* opt)
else O_MEM(opt, "so-rcvbuf", socket_rcvbuf)
else O_MEM(opt, "rrset-cache-size", rrset_cache_size)
else O_DEC(opt, "rrset-cache-slabs", rrset_cache_slabs)
else O_YNO(opt, "prefetch", prefetch)
else O_DEC(opt, "cache-max-ttl", max_ttl)
else O_DEC(opt, "infra-host-ttl", host_ttl)
else O_DEC(opt, "infra-lame-ttl", lame_ttl)

View file

@ -108,6 +108,7 @@ config_create()
cfg->bogus_ttl = 60;
cfg->min_ttl = 0;
cfg->max_ttl = 3600 * 24;
cfg->prefetch = 0;
cfg->infra_cache_slabs = 4;
cfg->infra_cache_numhosts = 10000;
cfg->infra_cache_lame_size = 10240; /* easily 40 or more entries */
@ -302,6 +303,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
} else if(strcmp(opt, "rrset-cache-slabs:") == 0) {
IS_POW2_NUMBER;
cfg->rrset_cache_slabs = (size_t)atoi(val);
} else if(strcmp(opt, "prefetch:") == 0) {
IS_YES_OR_NO;
cfg->prefetch = (strcmp(val, "yes") == 0);
} else if(strcmp(opt, "cache-max-ttl:") == 0) {
IS_NUMBER_OR_ZERO;
cfg->max_ttl = atoi(val);

View file

@ -164,6 +164,12 @@ struct config_file {
struct config_strlist* private_domain;
/** what threshold for unwanted action. */
size_t unwanted_threshold;
/** the number of seconds maximal TTL used for RRsets and messages */
int max_ttl;
/** the number of seconds minimum TTL used for RRsets and messages */
int min_ttl;
/** if prefetching of messages should be performed. */
int prefetch;
/** chrootdir, if not "" or chroot will be done */
char* chrootdir;
@ -208,10 +214,6 @@ struct config_file {
/** insecure domain list */
struct config_strlist* domain_insecure;
/** the number of seconds maximal TTL used for RRsets and messages */
int max_ttl;
/** the number of seconds minimum TTL used for RRsets and messages */
int min_ttl;
/** if not 0, this value is the validation date for RRSIGs */
int32_t val_date_override;
/** the minimum for signature clock skew */

File diff suppressed because it is too large Load diff

View file

@ -175,6 +175,7 @@ use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
unwanted-reply-threshold{COLON} { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) }
private-address{COLON} { YDVAR(1, VAR_PRIVATE_ADDRESS) }
private-domain{COLON} { YDVAR(1, VAR_PRIVATE_DOMAIN) }
prefetch{COLON} { YDVAR(1, VAR_PREFETCH) }
stub-zone{COLON} { YDVAR(0, VAR_STUB_ZONE) }
name{COLON} { YDVAR(1, VAR_NAME) }
stub-addr{COLON} { YDVAR(1, VAR_STUB_ADDR) }

File diff suppressed because it is too large Load diff

View file

@ -150,7 +150,8 @@
VAR_ADD_HOLDDOWN = 366,
VAR_DEL_HOLDDOWN = 367,
VAR_SO_RCVBUF = 368,
VAR_EDNS_BUFFER_SIZE = 369
VAR_EDNS_BUFFER_SIZE = 369,
VAR_PREFETCH = 370
};
#endif
/* Tokens. */
@ -266,6 +267,7 @@
#define VAR_DEL_HOLDDOWN 367
#define VAR_SO_RCVBUF 368
#define VAR_EDNS_BUFFER_SIZE 369
#define VAR_PREFETCH 370
@ -282,7 +284,7 @@ typedef union YYSTYPE
/* Line 1676 of yacc.c */
#line 286 "util/configparser.h"
#line 288 "util/configparser.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */

View file

@ -100,7 +100,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_DOMAIN_INSECURE VAR_PYTHON VAR_PYTHON_SCRIPT VAR_VAL_SIG_SKEW_MIN
%token VAR_VAL_SIG_SKEW_MAX VAR_CACHE_MIN_TTL VAR_VAL_LOG_LEVEL
%token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN
%token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE
%token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -153,7 +153,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_val_sig_skew_max | server_cache_min_ttl | server_val_log_level |
server_auto_trust_anchor_file | server_add_holddown |
server_del_holddown | server_keep_missing | server_so_rcvbuf |
server_edns_buffer_size
server_edns_buffer_size | server_prefetch
;
stubstart: VAR_STUB_ZONE
{
@ -742,6 +742,15 @@ server_private_domain: VAR_PRIVATE_DOMAIN STRING_ARG
yyerror("out of memory");
}
;
server_prefetch: VAR_PREFETCH STRING_ARG
{
OUTYY(("P(server_prefetch:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->prefetch = (strcmp($2, "yes")==0);
free($2);
}
;
server_unwanted_reply_threshold: VAR_UNWANTED_REPLY_THRESHOLD STRING_ARG
{
OUTYY(("P(server_unwanted_reply_threshold:%s)\n", $2));

View file

@ -78,8 +78,8 @@ parse_create_qinfo(ldns_buffer* pkt, struct msg_parse* msg,
/** constructor for replyinfo */
static struct reply_info*
construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
uint32_t ttl, size_t an, size_t ns, size_t ar, size_t total,
enum sec_status sec)
uint32_t ttl, uint32_t prettl, size_t an, size_t ns, size_t ar,
size_t total, enum sec_status sec)
{
struct reply_info* rep;
/* rrset_count-1 because the first ref is part of the struct. */
@ -94,6 +94,7 @@ construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
rep->flags = flags;
rep->qdcount = qd;
rep->ttl = ttl;
rep->prefetch_ttl = prettl;
rep->an_numrrsets = an;
rep->ns_numrrsets = ns;
rep->ar_numrrsets = ar;
@ -116,8 +117,8 @@ static int
parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
struct regional* region)
{
*rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
*rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
msg->rrset_count, sec_status_unchecked);
if(!*rep)
return 0;
@ -390,6 +391,7 @@ parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg,
pset = pset->rrset_all_next;
}
rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
return 1;
}
@ -466,6 +468,7 @@ reply_info_set_ttls(struct reply_info* rep, uint32_t timenow)
{
size_t i, j;
rep->ttl += timenow;
rep->prefetch_ttl += timenow;
for(i=0; i<rep->rrset_count; i++) {
struct packed_rrset_data* data = (struct packed_rrset_data*)
rep->ref[i].key->entry.data;
@ -654,8 +657,9 @@ reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
{
struct reply_info* cp;
cp = construct_reply_info_base(region, rep->flags, rep->qdcount,
rep->ttl, rep->an_numrrsets, rep->ns_numrrsets,
rep->ar_numrrsets, rep->rrset_count, rep->security);
rep->ttl, rep->prefetch_ttl, rep->an_numrrsets,
rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count,
rep->security);
if(!cp)
return NULL;
/* allocate ub_key structures special or not */

View file

@ -51,6 +51,10 @@ struct edns_data;
struct msg_parse;
struct rrset_parse;
/** calculate the prefetch TTL as 90% of original. Calculation
* without numerical overflow (uin32_t) */
#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10)
/**
* Structure to store query information that makes answers to queries
* different.
@ -119,6 +123,12 @@ struct reply_info {
*/
uint32_t ttl;
/**
* TTL for prefetch. After it has expired, a prefetch is suitable.
* Smaller than the TTL, otherwise the prefetch would not happen.
*/
uint32_t prefetch_ttl;
/**
* The security status from DNSSEC validation of this message.
*/

View file

@ -1916,6 +1916,8 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
}
vq->orig_msg->rep->ttl = ve->bogus_ttl;
vq->orig_msg->rep->prefetch_ttl =
PREFETCH_TTL_CALC(vq->orig_msg->rep->ttl);
if(qstate->env->cfg->val_log_level >= 1 &&
!qstate->env->cfg->val_log_squelch) {
if(qstate->env->cfg->val_log_level < 2)