Mesh design and preparatory cleanup.

- removed unused _node iterator value from rbtree_t. Takes up space.
      - iterator can handle querytargets state without a delegation point
        set, so that a priming(stub) subquery error can be handled.
      - iterator stores if it is priming or not.
      - log_query_info() neater logging.


git-svn-id: file:///svn/unbound/trunk@418 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-06-22 10:09:21 +00:00
parent b2deaa21ba
commit fcd489a12a
9 changed files with 173 additions and 54 deletions

View file

@ -215,8 +215,7 @@ run_debug(struct module_qstate* p, int d)
} }
buf[i++] = 'o'; buf[i++] = 'o';
buf[i] = 0; buf[i] = 0;
log_nametypeclass(VERB_ALGO, buf, p->qinfo.qname, p->qinfo.qtype, log_query_info(VERB_ALGO, buf, &p->qinfo);
p->qinfo.qclass);
for(p = p->subquery_first; p; p = p->subquery_next) { for(p = p->subquery_first; p; p = p->subquery_next) {
run_debug(p, d+1); run_debug(p, d+1);
} }

View file

@ -1,3 +1,10 @@
22 June 2007: Wouter
- removed unused _node iterator value from rbtree_t. Takes up space.
- iterator can handle querytargets state without a delegation point
set, so that a priming(stub) subquery error can be handled.
- iterator stores if it is priming or not.
- log_query_info() neater logging.
21 June 2007: Wouter 21 June 2007: Wouter
- Fixup secondary buffer in case of error callback. - Fixup secondary buffer in case of error callback.
- cleanup slumber list of runnable states. - cleanup slumber list of runnable states.

View file

@ -108,6 +108,7 @@ iter_new(struct module_qstate* qstate, int id)
iq->num_current_queries = 0; iq->num_current_queries = 0;
iq->query_restart_count = 0; iq->query_restart_count = 0;
iq->referral_count = 0; iq->referral_count = 0;
iq->priming = 0;
iq->priming_stub = 0; iq->priming_stub = 0;
iq->orig_qflags = qstate->query_flags; iq->orig_qflags = qstate->query_flags;
/* remove all weird bits from the query flags */ /* remove all weird bits from the query flags */
@ -554,6 +555,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq,
subiq->dp = dp; subiq->dp = dp;
/* suppress any target queries. */ /* suppress any target queries. */
subiq->num_target_queries = 0; subiq->num_target_queries = 0;
subiq->priming = 1;
/* this module stops, our submodule starts, and does the query. */ /* this module stops, our submodule starts, and does the query. */
qstate->ext_state[id] = module_wait_subquery; qstate->ext_state[id] = module_wait_subquery;
@ -608,6 +610,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq,
/* suppress any target queries -- although there wouldn't be anyway, /* suppress any target queries -- although there wouldn't be anyway,
* since stub hints never have missing targets.*/ * since stub hints never have missing targets.*/
subiq->num_target_queries = 0; subiq->num_target_queries = 0;
subiq->priming = 1;
subiq->priming_stub = 1; subiq->priming_stub = 1;
/* this module stops, our submodule starts, and does the query. */ /* this module stops, our submodule starts, and does the query. */
@ -641,8 +644,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
size_t delnamelen; size_t delnamelen;
struct dns_msg* msg; struct dns_msg* msg;
log_nametypeclass(VERB_DETAIL, "resolving", qstate->qinfo.qname, log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo);
qstate->qinfo.qtype, qstate->qinfo.qclass);
/* check effort */ /* check effort */
/* We enforce a maximum number of query restarts. This is primarily a /* We enforce a maximum number of query restarts. This is primarily a
@ -801,8 +803,8 @@ static int
processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
struct iter_env* ie, int id) struct iter_env* ie, int id)
{ {
log_nametypeclass(VERB_DETAIL, "resolving (init part 2): ", log_query_info(VERB_DETAIL, "resolving (init part 2): ",
qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); &qstate->qinfo);
/* Check to see if we need to prime a stub zone. */ /* Check to see if we need to prime a stub zone. */
if(prime_stub(qstate, iq, ie, id, qstate->qinfo.qname, if(prime_stub(qstate, iq, ie, id, qstate->qinfo.qname,
@ -828,8 +830,8 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
static int static int
processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq) processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq)
{ {
log_nametypeclass(VERB_DETAIL, "resolving (init part 3): ", log_query_info(VERB_DETAIL, "resolving (init part 3): ",
qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); &qstate->qinfo);
/* If the RD flag wasn't set, then we just finish with the /* If the RD flag wasn't set, then we just finish with the
* cached referral as the response. */ * cached referral as the response. */
if(!(qstate->query_flags & BIT_RD)) { if(!(qstate->query_flags & BIT_RD)) {
@ -987,8 +989,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
* needs to send a query to. That is, at least one per referral, * needs to send a query to. That is, at least one per referral,
* more if some targets timeout or return throwaway answers. */ * more if some targets timeout or return throwaway answers. */
log_nametypeclass(VERB_DETAIL, "processQueryTargets:", log_query_info(VERB_DETAIL, "processQueryTargets:", &qstate->qinfo);
qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, " verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, "
"currentqueries %d", iq->num_target_queries, "currentqueries %d", iq->num_target_queries,
iq->num_current_queries); iq->num_current_queries);
@ -1002,6 +1003,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
} }
/* Make sure we have a delegation point, otherwise priming failed
* or another failure occurred */
if(!iq->dp) {
verbose(VERB_DETAIL, "Failed to get a delegation, giving up");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
tf_policy = 0; tf_policy = 0;
if(iq->depth <= ie->max_dependency_depth) { if(iq->depth <= ie->max_dependency_depth) {
tf_policy = ie->target_fetch_policy[iq->depth]; tf_policy = ie->target_fetch_policy[iq->depth];
@ -1088,8 +1096,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
} }
/* We have a valid target. */ /* We have a valid target. */
log_nametypeclass(VERB_DETAIL, "sending query:", qstate->qinfo.qname, log_query_info(VERB_DETAIL, "sending query:", &qstate->qinfo);
qstate->qinfo.qtype, qstate->qinfo.qclass);
log_name_addr(VERB_DETAIL, "sending to target:", iq->dp->name, log_name_addr(VERB_DETAIL, "sending to target:", iq->dp->name,
&target->addr, target->addrlen); &target->addr, target->addrlen);
outq = (*qstate->env->send_query)( outq = (*qstate->env->send_query)(
@ -1291,8 +1298,7 @@ processPrimeResponse(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
} }
log_nametypeclass(VERB_DETAIL, "priming successful for", log_query_info(VERB_DETAIL, "priming successful for", &qstate->qinfo);
qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
delegpt_log(dp); delegpt_log(dp);
foriq = (struct iter_qstate*)forq->minfo[id]; foriq = (struct iter_qstate*)forq->minfo[id];
foriq->dp = dp; foriq->dp = dp;
@ -1400,8 +1406,8 @@ static int
processFinished(struct module_qstate* qstate, struct iter_qstate* iq, processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
int id) int id)
{ {
log_nametypeclass(VERB_DETAIL, "finishing processing for", log_query_info(VERB_DETAIL, "finishing processing for",
qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); &qstate->qinfo);
if(!iq->response) { if(!iq->response) {
verbose(VERB_ALGO, "No response is set, servfail"); verbose(VERB_ALGO, "No response is set, servfail");
@ -1603,8 +1609,7 @@ process_subq_error(struct module_qstate* qstate, struct iter_qstate* iq,
if(!dpns) { if(!dpns) {
/* not interested */ /* not interested */
verbose(VERB_ALGO, "got subq error, but not interested"); verbose(VERB_ALGO, "got subq error, but not interested");
log_nametypeclass(VERB_ALGO, "errname", log_query_info(VERB_ALGO, "errname", &errinf);
errinf.qname, errinf.qtype, errinf.qclass);
delegpt_log(iq->dp); delegpt_log(iq->dp);
return; return;
} }
@ -1623,8 +1628,8 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id]; struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
verbose(VERB_DETAIL, "iterator[module %d] operate: extstate:%s event:%s", verbose(VERB_DETAIL, "iterator[module %d] operate: extstate:%s event:%s",
id, strextstate(qstate->ext_state[id]), strmodulevent(event)); id, strextstate(qstate->ext_state[id]), strmodulevent(event));
if(iq) log_nametypeclass(VERB_DETAIL, "iterator operate: query", if(iq) log_query_info(VERB_DETAIL, "iterator operate: query",
qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); &qstate->qinfo);
if(ie->fwd_addrlen != 0) { if(ie->fwd_addrlen != 0) {
perform_forward(qstate, event, id, outbound); perform_forward(qstate, event, id, outbound);
return; return;

View file

@ -212,6 +212,12 @@ struct iter_qstate {
/** the number of times this query as followed a referral. */ /** the number of times this query as followed a referral. */
int referral_count; int referral_count;
/**
* This flag, if true, means that this event is a priming query.
* In that case priming stub may be set as well.
*/
int priming;
/** /**
* This is flag that, if true, means that this event is * This is flag that, if true, means that this event is
* representing a stub priming query. It is meaningless unless * representing a stub priming query. It is meaningless unless

View file

@ -44,4 +44,62 @@
*/ */
#include "config.h" #include "config.h"
#include "services/mesh.h" #include "services/mesh.h"
#include "util/log.h"
#include "util/net_help.h"
#include "util/module.h"
#include "util/region-allocator.h"
/** compare two mesh_states */
static int
mesh_state_compare(const void* ap, const void* bp)
{
struct mesh_state* a = (struct mesh_state*)ap;
struct mesh_state* b = (struct mesh_state*)bp;
if(a->is_priming && !b->is_priming)
return -1;
if(!a->is_priming && b->is_priming)
return 1;
if((a->state->query_flags&BIT_RD) && !(b->state->query_flags&BIT_RD))
return -1;
if(!(a->state->query_flags&BIT_RD) && (b->state->query_flags&BIT_RD))
return 1;
return query_info_compare(&a->state->qinfo, &b->state->qinfo);
}
/** compare two mesh references */
static int
mesh_state_ref_compare(const void* ap, const void* bp)
{
struct mesh_state_ref* a = (struct mesh_state_ref*)ap;
struct mesh_state_ref* b = (struct mesh_state_ref*)bp;
return mesh_state_compare(a->s, b->s);
}
struct mesh_area*
mesh_create(struct worker* worker)
{
struct mesh_area* mesh = calloc(1, sizeof(struct mesh_area));
if(!mesh) {
log_err("mesh area alloc: out of memory");
return NULL;
}
mesh->worker = worker;
rbtree_init(&mesh->run, &mesh_state_compare);
rbtree_init(&mesh->all, &mesh_state_compare);
mesh->num_reply_addrs = 0;
mesh->num_reply_states = 0;
mesh->num_detached_states = 0;
return mesh;
}
void
mesh_delete(struct mesh_area* mesh)
{
if(!mesh)
return;
/* free all query states */
free(mesh);
}

View file

@ -55,42 +55,49 @@ struct mesh_reply;
struct worker; struct worker;
struct query_info; struct query_info;
struct reply_info; struct reply_info;
struct outbound_entry;
/** /**
* Mesh of query states * Mesh of query states
*/ */
struct query_mesh { struct mesh_area {
/** what worker this is a part of */ /** what worker this is a part of */
struct worker* worker; struct worker* worker;
/** set of runnable queries (mesh_state_ref*) */ /** set of runnable queries (mesh_state.run_node) */
rbtree_t run; rbtree_t run;
/** rbtree of all current queries */ /** rbtree of all current queries (mesh_state.node)*/
rbtree_t all; rbtree_t all;
/** count of the number of mesh_reply entries */
size_t reply_count; /** count of the total number of mesh_reply entries */
/** count of the number of mesh_states that have no mesh_replies size_t num_reply_addrs;
* i.e. are for internal use. */ /** count of the number of mesh_states that have mesh_replies
size_t internal_count; * Because a state can send results to multiple reply addresses,
* this number must be equal or lower than num_reply_addrs. */
size_t num_reply_states;
/** number of mesh_states that have no mesh_replies, and also
* an empty set of super-states, thus are 'toplevel' or detached
* internal opportunistic queries */
size_t num_detached_states;
}; };
/** /**
* A mesh query state * A mesh query state
* Unique per qname, qtype, qclass. * Unique per qname, qtype, qclass (from the qstate).
* And RD flag; in case a client turns it off. * And RD flag; in case a client turns it off.
* And priming queries are different from ordinary queries (because of hints). * And priming queries are different from ordinary queries (because of hints).
*
* The entire structure is allocated in a region, this region is the qstate
* region. All parts (rbtree nodes etc) are also allocated in the region.
*/ */
struct mesh_state { struct mesh_state {
/** node in query_mesh all tree, key is this struct */ /** node in mesh_area all tree, key is this struct */
rbnode_t node; rbnode_t node;
/** node in query_mesh runnable tree, key is this struct */ /** node in mesh_area runnable tree, key is this struct */
rbnode_t run_node; rbnode_t run_node;
/** unique identity for this mesh state: what is it for */ /** if this is a (stub or root) priming query (with hints) */
/* Note that qstate qinfo is changed by iterator */
/** if this is a priming query (with hints) */
int is_priming; int is_priming;
/** the query state. Note that the qinfo and query_flags
/** the query state */ * may not change. */
struct module_qstate* state; struct module_qstate* state;
/** the list of replies to clients for the results */ /** the list of replies to clients for the results */
struct mesh_reply* reply_list; struct mesh_reply* reply_list;
@ -123,38 +130,59 @@ struct mesh_reply {
struct comm_reply query_reply; struct comm_reply query_reply;
/** edns data from query */ /** edns data from query */
struct edns_data edns; struct edns_data edns;
/** the time when request was entered */
struct timeval start_time;
/** id of query, in network byteorder. */ /** id of query, in network byteorder. */
uint16_t qid; uint16_t qid;
/** flags of query, for reply flags */ /** flags of query, for reply flags */
uint16_t qflags; uint16_t qflags;
}; };
/* ------------------- Functions for worker -------------------- */
/** /**
* Allocate mesh, to empty. * Allocate mesh, to empty.
* @param worker: what worker it is part of. * @param worker: what worker it is part of.
* @return mesh: the new mesh or NULL on error. * @return mesh: the new mesh or NULL on error.
*/ */
struct query_mesh* mesh_create(struct worker* worker); struct mesh_area* mesh_create(struct worker* worker);
/** /**
* Delete mesh, and all query states and replies in it. * Delete mesh, and all query states and replies in it.
* @param mesh: the mesh to delete. * @param mesh: the mesh to delete.
*/ */
void mesh_delete(struct query_mesh* mesh); void mesh_delete(struct mesh_area* mesh);
/** /**
* New query incoming from clients. Create new query state if needed, and * New query incoming from clients. Create new query state if needed, and
* add mesh_reply to it. Returns error to client on malloc failures. * add mesh_reply to it. Returns error to client on malloc failures.
* Will run the mesh area queries to process if a new query state is created.
*
* @param mesh: the mesh. * @param mesh: the mesh.
* @param qinfo: query from client. * @param qinfo: query from client.
* @param qflags: flags from client query. * @param qflags: flags from client query.
* @param edns: edns data from client query. * @param edns: edns data from client query.
* @param rep: where to reply to. * @param rep: where to reply to.
* @param id: query id to reply with. * @param qid: query id to reply with.
*/ */
void mesh_new_client(struct query_mesh* mesh, struct query_info* qinfo, void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, struct comm_reply* rep, uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
uint16_t id); uint16_t qid);
/**
* Handle new event from the wire. A serviced query has returned.
* The query state will be made runnable, and the mesh_area will process
* query states until processing is complete.
*
* @param mesh: the query mesh.
* @param e: outbound entry, with query state to run and reply pointer.
* @param is_ok: if true, reply is OK, otherwise a timeout happened.
* @param reply: the comm point reply info.
*/
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
int is_ok, struct comm_reply* reply);
/* ------------------- Functions for module environment --------------- */
/** /**
* Detach-subqueries. * Detach-subqueries.
@ -179,7 +207,7 @@ void mesh_detach_subs(struct module_qstate* qstate);
* the results from the new subquery. * the results from the new subquery.
* @param qinfo: what to query for (copied). * @param qinfo: what to query for (copied).
* @param qflags: what flags to use (RD flag or not). * @param qflags: what flags to use (RD flag or not).
* @param prime: if it is a priming query. * @param prime: if it is a (stub) priming query.
* @param newq: If the new subquery needs initialisation, it is returned, * @param newq: If the new subquery needs initialisation, it is returned,
* otherwise NULL is returned. * otherwise NULL is returned.
* @return: false on error, true if success (and init may be needed). * @return: false on error, true if success (and init may be needed).
@ -221,4 +249,15 @@ void mesh_query_done(struct module_qstate* qstate, int rcode,
void mesh_walk_supers(struct module_qstate* qstate, int id, int rcode, void mesh_walk_supers(struct module_qstate* qstate, int id, int rcode,
void (*cb)(struct module_qstate*, int, struct module_qstate*, int)); void (*cb)(struct module_qstate*, int, struct module_qstate*, int));
/* ------------------- Functions for mesh -------------------- */
/**
* Create and initialize a new mesh state and its query state
*/
/**
* Cleanup a mesh state and its query state. Does not do rbtree or
* reference cleanup.
*/
#endif /* SERVICES_MESH_H */ #endif /* SERVICES_MESH_H */

View file

@ -691,3 +691,10 @@ log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
ldns_buffer_free(buf); ldns_buffer_free(buf);
region_destroy(region); region_destroy(region);
} }
void
log_query_info(enum verbosity_value v, const char* str,
struct query_info* qinf)
{
log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
}

View file

@ -309,4 +309,13 @@ struct ub_packed_rrset_key* reply_find_answer_rrset(struct query_info* qinfo,
void log_dns_msg(const char* str, struct query_info* qinfo, void log_dns_msg(const char* str, struct query_info* qinfo,
struct reply_info* rep); struct reply_info* rep);
/**
* Print string with neat domain name, type, class from query info.
* @param v: at what verbosity level to print this.
* @param str: string of message.
* @param qinf: query info structure with name, type and class.
*/
void log_query_info(enum verbosity_value v, const char* str,
struct query_info* qinf);
#endif /* UTIL_DATA_MSGREPLY_H */ #endif /* UTIL_DATA_MSGREPLY_H */

View file

@ -80,9 +80,6 @@ struct rbtree_t {
/** The number of the nodes in the tree */ /** The number of the nodes in the tree */
size_t count; size_t count;
/** Current node for walks... */
rbnode_t *_node;
/** /**
* Key compare function. <0,0,>0 like strcmp. * Key compare function. <0,0,>0 like strcmp.
* Return 0 on two NULL ptrs. * Return 0 on two NULL ptrs.
@ -169,14 +166,6 @@ rbnode_t *rbtree_next(rbnode_t *rbtree);
*/ */
rbnode_t *rbtree_previous(rbnode_t *rbtree); rbnode_t *rbtree_previous(rbnode_t *rbtree);
/**
* Macro to walk through the tree, sets k to key, d to data, for every element.
*/
#define RBTREE_WALK(rbtree, k, d) \
for((rbtree)->_node = rbtree_first(rbtree);\
(rbtree)->_node != RBTREE_NULL && ((k) = (rbtree)->_node->key) && \
((d) = (void *) (rbtree)->_node); (rbtree)->_node = rbtree_next((rbtree)->_node))
/** /**
* Call with node=variable of struct* with rbnode_t as first element. * Call with node=variable of struct* with rbnode_t as first element.
* with type is the type of a pointer to that struct. * with type is the type of a pointer to that struct.