Date: Wed, 3 Oct 2007 21:23:28 GMT From: Fredrik Lindberg <fli@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 127147 for review Message-ID: <200710032123.l93LNS2B096898@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=127147 Change 127147 by fli@fli_nexus on 2007/10/03 21:22:36 - Follow changes to record subsystem. - Move query rescheduling into a function to remove duplicated code. - Better failure handling. - New debugging asserts. - Other minor fixes. Affected files ... .. //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.c#2 edit .. //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.h#2 edit Differences ... ==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.c#2 (text+ko) ==== @@ -35,6 +35,7 @@ #include "output_aggr.h" #include "threads.h" #include "queries.h" +#include "util.h" static void timeout_enqueue(struct queries *, struct query_cons *); static void timeout_dequeue(struct queries *, struct query_cons *); @@ -57,8 +58,11 @@ queries_init(struct queries *q, struct md_if *mif) { struct aq_func aqf; + int error; - records_init(&q->q_recs, mdns_c_in); + error = records_init(&q->q_recs); + if (error != 0) + goto queries_init_fail; MTX_INIT(q, q_mtx, NULL); TAILQ_INIT(&q->q_to_head); TAILQ_INIT(&q->q_ret_head); @@ -77,40 +81,22 @@ MDNS_INIT_SET(q, q_magic); dprintf(DEBUG_QUERY, "Initialized queries system q=%x mif=%x", q, mif); return (0); +queries_init_fail: + dprintf(DEBUG_QUERY, "Failed to initialize queries system mif=%x", mif); + return (-1); } /* - * Destroy callback, destroys a record and all its types - */ -static void -record_del_cb(struct record *r, void *arg) -{ - struct query_type *qt; - struct record_type *rt; - struct query_cons *qc, *qc2; - struct queries *q; - - q = arg; - record_foreach(rt, r) { - qt = record_type_getparent(rt); - ret_dequeue(q, qt); - TAILQ_FOREACH_SAFE(qc, &qt->qt_cons_list, qc_next, qc2) { - query_timeout_notify(q, qc); - } - } -} - -/* * Destroy a query system */ void queries_destroy(struct queries *q) { - MDNS_INIT_ASSERT(q, q_magic); MTX_LOCK(q, q_mtx); - records_foreach(&q->q_recs, record_del_cb, q); + records_destroy(&q->q_recs); + MTX_UNLOCK(q, q_mtx); MTX_DESTROY(q, q_mtx); MDNS_INIT_UNSET(q, q_magic); @@ -158,7 +144,6 @@ struct query_cons *qc; struct query_type *qt; struct record_type *rt; - struct record *r; q = arg.ptr; MDNS_INIT_ASSERT(q, q_magic); @@ -174,17 +159,12 @@ qt = qc->qc_qt; TAILQ_REMOVE(&qt->qt_cons_list, qc, qc_next); TAILQ_REMOVE(&q->q_to_head, qc, qc_to_next); + query_timeout_notify(q, qc); obj_free(OBJ_QCONS, qc); rt = &qt->qt_type; - r = rt->rt_record; - record_release(r); - if (record_type_refcnt(rt) == 1) { - destroy_query_type(q, qt); - } - else - record_type_release(rt); + record_type_release(rt); qc = TAILQ_FIRST(&q->q_to_head); if (qc == NULL) @@ -206,6 +186,7 @@ { struct query_cons *qc2, *qc3; + MDNS_INIT_ASSERT(q, q_magic); qc->qc_torel = qc->qc_timeout; qc2 = TAILQ_FIRST(&q->q_to_head); @@ -214,7 +195,7 @@ } else if (qc->qc_torel < qc2->qc_torel) { qc2->qc_torel -= qc->qc_torel; - TAILQ_INSERT_HEAD(&q->q_to_head, qc, qc_next); + TAILQ_INSERT_HEAD(&q->q_to_head, qc, qc_to_next); } else { while (qc->qc_torel >= qc2->qc_torel) { @@ -237,6 +218,7 @@ { struct query_cons *qc2; + MDNS_INIT_ASSERT(q, q_magic); qc2 = TAILQ_NEXT(qc, qc_to_next); if (qc2 != NULL) qc2->qc_torel += qc->qc_torel; @@ -253,6 +235,8 @@ struct query_type *qt2, *qt3; struct md_glob *g; + MDNS_INIT_ASSERT(q, q_magic); + qt->qt_retrel = qt->qt_retabs; qt2 = TAILQ_FIRST(&q->q_ret_head); @@ -294,6 +278,8 @@ struct query_type *qt2; struct md_glob *g; + MDNS_INIT_ASSERT(q, q_magic); + if (!(qt->qt_flags & QT_INRETQ)) return; @@ -361,36 +347,44 @@ { struct mdns_qset *qs; struct record *r; + struct record_class *rc; struct record_type *rt, *rt2; int range; + MDNS_INIT_ASSERT(q, q_magic); + if (qt->qt_flags & QT_SENT) return; rt = &qt->qt_type; - r = rt->rt_record; + rc = record_get_class(rt); + r = record_get_record(rc); /* * Check if a query exists on this record for T_ANY */ - record_type_get(r, &rt2, RECORD_NOINIT, mdns_in_any); + rt2 = record_type_find(&q->q_recs, REC_OBJCLASS, NULL, (uintptr_t)rc, + mdns_t_any); if (rt2 != NULL) { - record_type_release(rt2); if (rt2 != rt) return; } qs = mdns_pkg_getqset(); + if (qs == NULL) + return; mdns_qset_name_dup(qs, r->r_name); qs->q_type = rt->rt_type; - qs->q_class = mdns_c_in; /* XXX */ + qs->q_class = rc->rc_class; aq_enqueue(&q->q_aq4, qs, 20, 500); #ifdef INET6 qs = mdns_pkg_getqset(); + if (qs == NULL) + return; mdns_qset_name_dup(qs, r->r_name); qs->q_type = rt->rt_type; - qs->q_class = mdns_c_in; /* XXX */ + qs->q_class = rc->rc_class; aq_enqueue(&q->q_aq6, qs, 20, 500); #endif @@ -435,12 +429,9 @@ static void destroy_query_type(struct queries *q, struct query_type *qt) { - struct record_type *rt; struct query_cons *qc, *qc2; MDNS_INIT_ASSERT(qt, qt_magic); - rt = &qt->qt_type; - assert(record_type_refcnt(rt) == 1); if (qt->qt_flags & QT_INRETQ) ret_dequeue(q, qt); @@ -454,12 +445,27 @@ obj_free(OBJ_QCONS, qc); } - record_type_release(rt); MDNS_INIT_UNSET(qt, qt_magic); obj_free(OBJ_QTYPE, qt); } /* + * Callback from record sub-system when the last reference to a + * query_type {} is about to be released. + */ +static int +qt_del_cb(void *arg) +{ + struct query_type *qt = arg; + struct queries *q; + + MDNS_INIT_ASSERT(qt, qt_magic); + q = qt->qt_queries; + destroy_query_type(q, qt); + return (0); +} + +/* * Aggregation queue callback on packet chain intialization */ static void @@ -486,39 +492,47 @@ /* * Register a consumer with a query - * g - Global software state - * ifidx - Interface index to register query on (-1 equals all interfaces) + * q - Queries handle * qs - qset structure with query information * func - Callback function, called when a response comes in to the query * arg - Uniquely identifies the consumer, passed to func() * timeout - Specifies that timeout in seconds for oneshot queries, if * zero the query is treated as a continuous query. + * family - Address family */ int query_reg(struct queries *q, struct mdns_qset *qs, qc_cb func, void *arg, int timeout, int family) { struct record_type *rt; - struct record *r; struct query_type *qt; struct query_cons *qc, *qc2; + int error; + struct recpar rp; MDNS_INIT_ASSERT(q, q_magic); MTX_LOCK(q, q_mtx); - record_get(&q->q_recs, &r, 0, qs->q_name); - if (r == NULL) - goto out; - record_type_get(r, &rt, RECORD_NOINIT, qs->q_type); + error = record_type_get(&q->q_recs, &rt, REC_NOINIT, NULL, qs->q_name, + qs->q_class, qs->q_type); if (rt == NULL) { qt = obj_alloc(OBJ_QTYPE); + if (qt == NULL) + goto query_reg_fail; bzero(qt, sizeof(struct query_type)); + qt->qt_queries = q; MDNS_INIT_SET(qt, qt_magic); TAILQ_INIT(&qt->qt_cons_list); rt = &qt->qt_type; - record_type_get(r, &rt, RECORD_NOALLOC, qs->q_type); - record_type_setparent(rt, qt); + rp.rp_handle = qt; + rp.rp_del_cb = qt_del_cb; + error = record_type_get(&q->q_recs, &rt, REC_NOALLOC, &rp, + qs->q_name, qs->q_class, qs->q_type); + if (error != 0) { + obj_free(OBJ_QTYPE, qt); + goto query_reg_fail; + } } assert(rt != NULL); @@ -531,15 +545,15 @@ TAILQ_FOREACH(qc2, &qt->qt_cons_list, qc_next) { if (qc2->qc_arg != arg) continue; - record_type_release(rt); - record_release(r); - goto out; + goto query_reg_fail2; } /* TODO: send data from database record to client */ /* TODO: send data from cache to client */ qc = obj_alloc(OBJ_QCONS); + if (qc == NULL) + goto query_reg_fail2; qc->qc_func = func; qc->qc_arg = arg; qc->qc_timeout = timeout; @@ -553,9 +567,15 @@ timeout_enqueue(q, qc); MTX_UNLOCK(q, q_mtx); + dprintf(DEBUG_QUERY, "Registered query q=%p, qt=%p, consumer=%p", + q, qt, arg); return (0); -out: +query_reg_fail2: + record_type_release(rt); +query_reg_fail: MTX_UNLOCK(q, q_mtx); + dprintf(DEBUG_QUERY, "Failed to register query q=%p, consumer=%p", + q, arg); return (-1); } @@ -565,7 +585,6 @@ int query_dereg(struct queries *q, struct mdns_qset *qs, void *cons) { - struct record *r; struct record_type *rt; struct query_cons *qc; struct query_type *qt; @@ -573,42 +592,73 @@ MDNS_INIT_ASSERT(q, q_magic); MTX_LOCK(q, q_mtx); - record_get(&q->q_recs, &r, RECORD_NOINIT, qs->q_name); - if (r == NULL) - goto out1; + rt = record_type_find(&q->q_recs, 0, qs->q_name, qs->q_class, + qs->q_type); + if (rt == NULL) + goto query_dereg_fail; - record_type_get(r, &rt, RECORD_NOINIT, qs->q_type); - if (rt == NULL) - goto out2; - qt = record_type_getparent(rt); - TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) + TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) { if (qc->qc_arg == cons) break; + } if (qc != NULL) { if (qc->qc_timeout != 0) timeout_dequeue(q, qc); TAILQ_REMOVE(&qt->qt_cons_list, qc, qc_next); - record_release(r); record_type_release(rt); obj_free(OBJ_QCONS, qc); } - if (record_type_refcnt(rt) == 1) { - destroy_query_type(q, qt); - } - else - record_type_release(rt); -out2: - record_release(r); MTX_UNLOCK(q, q_mtx); + dprintf(DEBUG_QUERY, "De-registered consumer=%p from queries q=%p", + cons, q); return (0); -out1: +query_dereg_fail: MTX_UNLOCK(q, q_mtx); + dprintf(DEBUG_QUERY, "Failed to de-registered consumer=%p " + "from queries q=%p", cons, q); return (-1); } +/* Notify consumers */ +static inline void +notify_cons(struct query_type *qt, struct mdns_rrset *rs, int ifidx, int fam, + int trunc) +{ + struct query_cons *qc; + + TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) { + if (qc->qc_fam != AF_UNSPEC && qc->qc_fam != fam) + continue; + qc->qc_func(qc->qc_arg, rs, ifidx, fam, trunc); + } +} + +static inline void +reschedule_query(struct queries *q, struct query_type *qt, uint32_t ttl) +{ + int range; + + range = (random() % 3); + + /* Expired record, re-schedule transmission */ + if (ttl == 0) { + qt->qt_flags &= ~QT_RESP; + qt->qt_tries = 0; + qt->qt_retabs = 1; + } + else { + qt->qt_flags |= QT_RESP; + qt->qt_ttl = ttl; + qt->qt_tries = 80; /* next at 80% of ttl */ + qt->qt_retabs = (qt->qt_ttl * (qt->qt_tries + range)) / 100; + } + ret_enqueue(q, qt); +} + + /* * Notify callback, called to notify potential consumers about * new resource data. @@ -621,84 +671,62 @@ query_notify(struct queries *q, struct mdns_rrset *rs, int ifidx, int fam, int trunc) { - struct record *r; struct record_type *rt; - struct query_cons *qc; struct query_type *qt; - int range, sched = 0; + int sched = 0; MDNS_INIT_ASSERT(q, q_magic); + MTX_LOCK(q, q_mtx); - record_get(&q->q_recs, &r, RECORD_NOINIT, rs->r_name); - if (r == NULL) - goto out; + /* Clients waiting for C_ANY/T_ANY */ + rt = record_type_find(&q->q_recs, 0, rs->r_name, mdns_c_any, + mdns_t_any); + if (rt != NULL) { + qt = record_type_getparent(rt); + ret_dequeue(q, qt); + notify_cons(qt, rs, ifidx, fam, trunc); + reschedule_query(q, qt, rs->r_ttl); + sched = 1; + } - range = (random() % 3); - - /* - * Check for clients waiting on T_ANY - */ - record_type_get(r, &rt, RECORD_NOINIT, mdns_in_any); + /* Clients waiting for C_ANY */ + rt = record_type_find(&q->q_recs, 0, rs->r_name, mdns_c_any, + rs->r_type); if (rt != NULL) { qt = record_type_getparent(rt); - TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) { - if (qc->qc_fam != AF_UNSPEC && qc->qc_fam != fam) - continue; - qc->qc_func(qc->qc_arg, rs, ifidx, fam, trunc); + ret_dequeue(q, qt); + notify_cons(qt, rs, ifidx, fam, trunc); + if (!sched) { + reschedule_query(q, qt, rs->r_ttl); + sched++; } + } + /* Clients waiting for T_ANY */ + rt = record_type_find(&q->q_recs, 0, rs->r_name, rs->r_class, + mdns_t_any); + if (rt != NULL) { + qt = record_type_getparent(rt); ret_dequeue(q, qt); - - /* Expired record, re-schedule transmission */ - if (rs->r_ttl == 0) { - qt->qt_flags &= ~QT_RESP; - qt->qt_tries = 0; - qt->qt_retabs = 1; + notify_cons(qt, rs, ifidx, fam, trunc); + if (!sched) { + reschedule_query(q, qt, rs->r_ttl); + sched++; } - else { - qt->qt_flags |= QT_RESP; - qt->qt_ttl = rs->r_ttl; - qt->qt_tries = 80; /* next at 80% of ttl */ - qt->qt_retabs = - (qt->qt_ttl * (qt->qt_tries + range)) / 100; - } - sched = 1; - ret_enqueue(q, qt); - record_type_release(rt); } - record_type_get(r, &rt, RECORD_NOINIT, rs->r_type); + /* Exact match on class, type pair */ + rt = record_type_find(&q->q_recs, 0, rs->r_name, rs->r_class, + rs->r_type); if (rt != NULL) { qt = record_type_getparent(rt); - TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) { - if (qc->qc_fam != AF_UNSPEC && qc->qc_fam != fam) - continue; - qc->qc_func(qc->qc_arg, rs, ifidx, fam, trunc); - } - ret_dequeue(q, qt); - /* Expired record, re-schedule transmission */ - if (rs->r_ttl == 0) { - qt->qt_flags &= ~QT_RESP; - qt->qt_tries = 0; - qt->qt_retabs = 1; - } - else { - qt->qt_flags |= QT_RESP; - qt->qt_ttl = rs->r_ttl; - qt->qt_tries = 80; /* next at 80% of ttl */ - qt->qt_retabs = - (qt->qt_ttl * (qt->qt_tries + range)) / 100; - } + notify_cons(qt, rs, ifidx, fam, trunc); if (!sched) - ret_enqueue(q, qt); - - record_type_release(rt); + reschedule_query(q, qt, rs->r_ttl); } - record_release(r); -out: MTX_UNLOCK(q, q_mtx); } @@ -707,10 +735,8 @@ * any longer. */ static void -query_timeout_notify(struct queries *q, struct query_cons *qc) +query_timeout_notify(struct queries *q __unused, struct query_cons *qc) { - MTX_UNLOCK(q, q_mtx); qc->qc_func(qc->qc_arg, NULL, 0, 0, 0); - MTX_LOCK(q, q_mtx); } ==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.h#2 (text+ko) ==== @@ -75,6 +75,7 @@ MAGIC(qt_magic); struct record_type qt_type; TAILQ_HEAD(, query_cons) qt_cons_list; /* consumer list head */ + struct queries *qt_queries; int qt_flags; #define QT_INRETQ 0x01 /* scheduled for re-transmission */ #define QT_SENT 0x02 /* query sent */ @@ -83,7 +84,7 @@ int qt_retrel; /* relative re-transmit value (book keeping only) */ int qt_retabs; /* absolute re-transmission value */ int qt_tries; /* number of re-transmission retries */ - int qt_ttl; /* ttl from response */ + int qt_ttl; /* ttl from response */ }; int queries_init(struct queries *, struct md_if *);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200710032123.l93LNS2B096898>