]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Mesh design and preparatory cleanup.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 22 Jun 2007 10:09:21 +0000 (10:09 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 22 Jun 2007 10:09:21 +0000 (10:09 +0000)
      - 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

daemon/worker.c
doc/Changelog
iterator/iterator.c
iterator/iterator.h
services/mesh.c
services/mesh.h
util/data/msgreply.c
util/data/msgreply.h
util/rbtree.h

index 4070908a5417772018450c9db89f5080bf4dafb2..46c3e74fcadb99647d3080cab45f9c2679847032 100644 (file)
@@ -215,8 +215,7 @@ run_debug(struct module_qstate* p, int d)
        }
        buf[i++] = 'o';
        buf[i] = 0;
-       log_nametypeclass(VERB_ALGO, buf, p->qinfo.qname, p->qinfo.qtype, 
-               p->qinfo.qclass);
+       log_query_info(VERB_ALGO, buf, &p->qinfo);
        for(p = p->subquery_first; p; p = p->subquery_next) {
                run_debug(p, d+1);
        }
index f5e00da237ab0ed9947394825fd266deb8e25680..0710624b83809f211c2fc803e9c82941820797af 100644 (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
        - Fixup secondary buffer in case of error callback.
        - cleanup slumber list of runnable states.
index 2decfac198bb9ae5221606fed064baa94a5c0c8d..0c977b33731e6a042f2f78b2b345485cbbce43b7 100644 (file)
@@ -108,6 +108,7 @@ iter_new(struct module_qstate* qstate, int id)
        iq->num_current_queries = 0;
        iq->query_restart_count = 0;
        iq->referral_count = 0;
+       iq->priming = 0;
        iq->priming_stub = 0;
        iq->orig_qflags = qstate->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;
        /* suppress any target queries. */
        subiq->num_target_queries = 0; 
+       subiq->priming = 1;
        
        /* this module stops, our submodule starts, and does the query. */
        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, 
         * since stub hints never have missing targets.*/
        subiq->num_target_queries = 0; 
+       subiq->priming = 1;
        subiq->priming_stub = 1;
        
        /* 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;
        struct dns_msg* msg;
 
-       log_nametypeclass(VERB_DETAIL, "resolving", qstate->qinfo.qname, 
-               qstate->qinfo.qtype, qstate->qinfo.qclass);
+       log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo);
        /* check effort */
 
        /* 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,
        struct iter_env* ie, int id)
 {
-       log_nametypeclass(VERB_DETAIL, "resolving (init part 2): ", 
-               qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+       log_query_info(VERB_DETAIL, "resolving (init part 2): ", 
+               &qstate->qinfo);
 
        /* Check to see if we need to prime a stub zone. */
        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
 processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq)
 {
-       log_nametypeclass(VERB_DETAIL, "resolving (init part 3): ", 
-               qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+       log_query_info(VERB_DETAIL, "resolving (init part 3): ", 
+               &qstate->qinfo);
        /* If the RD flag wasn't set, then we just finish with the 
         * cached referral as the response. */
        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, 
         * more if some targets timeout or return throwaway answers. */
 
-       log_nametypeclass(VERB_DETAIL, "processQueryTargets:", 
-               qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+       log_query_info(VERB_DETAIL, "processQueryTargets:", &qstate->qinfo);
        verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, "
                "currentqueries %d", iq->num_target_queries, 
                iq->num_current_queries);
@@ -1001,6 +1002,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                        "number of referrrals with %d", iq->referral_count);
                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;
        if(iq->depth <= ie->max_dependency_depth) {
@@ -1088,8 +1096,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
        }
 
        /* We have a valid target. */
-       log_nametypeclass(VERB_DETAIL, "sending query:", qstate->qinfo.qname, 
-               qstate->qinfo.qtype, qstate->qinfo.qclass);
+       log_query_info(VERB_DETAIL, "sending query:", &qstate->qinfo);
        log_name_addr(VERB_DETAIL, "sending to target:", iq->dp->name, 
                &target->addr, target->addrlen);
        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);
        }
 
-       log_nametypeclass(VERB_DETAIL, "priming successful for", 
-               qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+       log_query_info(VERB_DETAIL, "priming successful for", &qstate->qinfo);
        delegpt_log(dp);
        foriq = (struct iter_qstate*)forq->minfo[id];
        foriq->dp = dp;
@@ -1400,8 +1406,8 @@ static int
 processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
        int id)
 {
-       log_nametypeclass(VERB_DETAIL, "finishing processing for", 
-               qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+       log_query_info(VERB_DETAIL, "finishing processing for", 
+               &qstate->qinfo);
 
        if(!iq->response) {
                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) {
                /* not interested */
                verbose(VERB_ALGO, "got subq error, but not interested");
-               log_nametypeclass(VERB_ALGO, "errname", 
-                       errinf.qname, errinf.qtype, errinf.qclass);
+               log_query_info(VERB_ALGO, "errname", &errinf);
                delegpt_log(iq->dp);
                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];
        verbose(VERB_DETAIL, "iterator[module %d] operate: extstate:%s event:%s", 
                id, strextstate(qstate->ext_state[id]), strmodulevent(event));
-       if(iq) log_nametypeclass(VERB_DETAIL, "iterator operate: query", 
-               qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+       if(iq) log_query_info(VERB_DETAIL, "iterator operate: query", 
+               &qstate->qinfo);
        if(ie->fwd_addrlen != 0) {
                perform_forward(qstate, event, id, outbound);
                return;
index 0535f7e75644d3704f33ddcdfd4067d601da9236..e79bb599e5bdb896b3573362cef4bc58129c6a10 100644 (file)
@@ -212,6 +212,12 @@ struct iter_qstate {
        /** the number of times this query as followed a referral. */
        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 
         * representing a stub priming query. It is meaningless unless 
index 3f5c6a0dde39c81f1ad108cbb57c7f84c0a92a44..d285b34f32d834b6b95c7bf67387392e6b1a1f11 100644 (file)
  */
 #include "config.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);
+}
index 798a65316cc2ad146fcdd903ad0929c498e821b1..b0883b24fe6034dd95620f3a3d4e95502b8e7966 100644 (file)
@@ -55,42 +55,49 @@ struct mesh_reply;
 struct worker;
 struct query_info;
 struct reply_info;
+struct outbound_entry;
 
 /** 
  * Mesh of query states
  */
-struct query_mesh {
+struct mesh_area {
        /** what worker this is a part of */
        struct worker* worker;
-       /** set of runnable queries (mesh_state_ref*) */
+       /** set of runnable queries (mesh_state.run_node) */
        rbtree_t run;
-       /** rbtree of all current queries */
+       /** rbtree of all current queries (mesh_state.node)*/
        rbtree_t all;
-       /** count of the number of mesh_reply entries */
-       size_t reply_count;
-       /** count of the number of mesh_states that have no mesh_replies
-        * i.e. are for internal use. */
-       size_t internal_count;
+
+       /** count of the total number of mesh_reply entries */
+       size_t num_reply_addrs;
+       /** count of the number of mesh_states that have mesh_replies 
+        * 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
- * Unique per qname, qtype, qclass.
+ * Unique per qname, qtype, qclass (from the qstate).
  * And RD flag; in case a client turns it off.
  * 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 {
-       /** node in query_mesh all tree, key is this struct */
+       /** node in mesh_area all tree, key is this struct */
        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;
-       /** unique identity for this mesh state: what is it for */
-       /* Note that qstate qinfo is changed by iterator */
-
-       /** if this is a priming query (with hints) */
+       /** if this is a (stub or root) priming query (with hints) */
        int is_priming;
-       
-       /** the query state */
+       /** the query state. Note that the qinfo and query_flags 
+        * may not change. */
        struct module_qstate* state;
        /** the list of replies to clients for the results */
        struct mesh_reply* reply_list;
@@ -123,38 +130,59 @@ struct mesh_reply {
        struct comm_reply query_reply;
        /** edns data from query */
        struct edns_data edns;
+       /** the time when request was entered */
+       struct timeval start_time;
        /** id of query, in network byteorder. */
        uint16_t qid;
        /** flags of query, for reply flags */
        uint16_t qflags;
 };
 
+/* ------------------- Functions for worker -------------------- */
+
 /**
  * Allocate mesh, to empty.
  * @param worker: what worker it is part of.
  * @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.
  * @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
  * 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 qinfo: query from client.
  * @param qflags: flags from client query.
  * @param edns: edns data from client query.
  * @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 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.
@@ -179,7 +207,7 @@ void mesh_detach_subs(struct module_qstate* qstate);
  *     the results from the new subquery.
  * @param qinfo: what to query for (copied).
  * @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,
  *     otherwise NULL is returned.
  * @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 (*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 */
index 312a2cb9aeef91c679e85a3471a5b6c3555dc954..c634b4e0b3ed047bc87d261d6667899f48f56ea8 100644 (file)
@@ -691,3 +691,10 @@ log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
        ldns_buffer_free(buf);
        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);
+}
index d301fb27d4d4637b58b35defe8ccad5b23a50f0d..04f471e215257fbf6dd74edd873d75386680775b 100644 (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, 
        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 */
index 401f2aa5bbb6212547633152cca65dce6053fab3..879804dd8600880aebc883a1b3a77e1949f9317d 100644 (file)
@@ -80,9 +80,6 @@ struct rbtree_t {
        /** The number of the nodes in the tree */
        size_t       count;
 
-       /** Current node for walks... */
-       rbnode_t    *_node;
-
        /** 
         * Key compare function. <0,0,>0 like strcmp. 
         * Return 0 on two NULL ptrs. 
@@ -169,14 +166,6 @@ rbnode_t *rbtree_next(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.
  * with type is the type of a pointer to that struct.