diff options
author | Internet Software Consortium, Inc <@isc.org> | 2012-10-29 07:26:33 -0600 |
---|---|---|
committer | Internet Software Consortium, Inc <@isc.org> | 2012-10-29 07:26:33 -0600 |
commit | 416b1db8df0cadcf29ec0f53d7ab1b8c6d0dbfaf (patch) | |
tree | 3f896f6a88eb1af9bcd0cdbb9b86ea5c712ed4a0 /lib | |
parent | 38f27ae0bdb4b0b53b00a160a2a4e370a3a1d506 (diff) | |
download | bind9-416b1db8df0cadcf29ec0f53d7ab1b8c6d0dbfaf.tar.gz |
9.9.1-P2
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dns/resolver.c | 5 | ||||
-rw-r--r-- | lib/dns/zone.c | 26 | ||||
-rw-r--r-- | lib/isc/include/isc/queue.h | 105 |
3 files changed, 98 insertions, 38 deletions
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index fb50360d..20b8de47 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -8448,6 +8448,7 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name, goto cleanup; bad->type = type; bad->hashval = hashval; + bad->expire = *expire; isc_buffer_init(&buffer, bad + 1, name->length); dns_name_init(&bad->name, NULL); dns_name_copy(name, &bad->name, &buffer); @@ -8459,8 +8460,8 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name, if (resolver->badcount < resolver->badhash * 2 && resolver->badhash > DNS_BADCACHE_SIZE) resizehash(resolver, &now, ISC_FALSE); - } - bad->expire = *expire; + } else + bad->expire = *expire; cleanup: UNLOCK(&resolver->lock); } diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 4451dc8c..99b540be 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -8525,13 +8525,14 @@ zone_maintenance(dns_zone_t *zone) { case dns_zone_slave: case dns_zone_key: case dns_zone_redirect: + case dns_zone_stub: LOCK_ZONE(zone); if (zone->masterfile != NULL && isc_time_compare(&now, &zone->dumptime) >= 0 && DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP)) { dumping = was_dumping(zone); - } else + } else dumping = ISC_TRUE; UNLOCK_ZONE(zone); if (!dumping) { @@ -8918,7 +8919,7 @@ zone_dump(dns_zone_t *zone, isc_boolean_t compact) { goto fail; } - if (compact) { + if (compact && zone->type != dns_zone_stub) { dns_zone_t *dummy = NULL; LOCK_ZONE(zone); zone_iattach(zone, &dummy); @@ -9824,7 +9825,7 @@ stub_callback(isc_task_t *task, isc_event_t *event) { dns_zone_t *zone = NULL; char master[ISC_SOCKADDR_FORMATSIZE]; char source[ISC_SOCKADDR_FORMATSIZE]; - isc_uint32_t nscnt, cnamecnt; + isc_uint32_t nscnt, cnamecnt, refresh, retry, expire; isc_result_t result; isc_time_t now; isc_boolean_t exiting = ISC_FALSE; @@ -9972,19 +9973,32 @@ stub_callback(isc_task_t *task, isc_event_t *event) { ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); if (zone->db == NULL) zone_attachdb(zone, stub->db); + result = zone_get_from_db(zone, zone->db, NULL, NULL, NULL, &refresh, + &retry, &expire, NULL, NULL); + if (result == ISC_R_SUCCESS) { + zone->refresh = RANGE(refresh, zone->minrefresh, + zone->maxrefresh); + zone->retry = RANGE(retry, zone->minretry, zone->maxretry); + zone->expire = RANGE(expire, zone->refresh + zone->retry, + DNS_MAX_EXPIRE); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); + } ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); dns_db_detach(&stub->db); - if (zone->masterfile != NULL) - zone_needdump(zone, 0); - dns_message_destroy(&msg); isc_event_free(&event); dns_request_destroy(&zone->request); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); isc_interval_set(&i, zone->expire, 0); DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); + + if (zone->masterfile != NULL) + zone_needdump(zone, 0); + zone_settimer(zone, &now); goto free_stub; diff --git a/lib/isc/include/isc/queue.h b/lib/isc/include/isc/queue.h index 5bf84c52..1bc9d5b4 100644 --- a/lib/isc/include/isc/queue.h +++ b/lib/isc/include/isc/queue.h @@ -14,12 +14,13 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id$ */ - /* * This is a generic implementation of a two-lock concurrent queue. * There are built-in mutex locks for the head and tail of the queue, * allowing elements to be safely added and removed at the same time. + * + * NULL is "end of list" + * -1 is "not linked" */ #ifndef ISC_QUEUE_H @@ -34,67 +35,111 @@ #define ISC_QLINK_INSIST(x) (void)0 #endif -#define ISC_QLINK(type) struct { void *next; isc_boolean_t linked; } +#define ISC_QLINK(type) struct { void *prev, *next; } + #define ISC_QLINK_INIT(elt, link) \ do { \ - (elt)->link.next = (void *)(-1); \ - (elt)->link.linked = ISC_FALSE; \ - } while (0) -#define ISC_QLINK_LINKED(elt, link) ((elt)->link.linked) + (elt)->link.next = (elt)->link.prev = (void *)(-1); \ + } while(0) + +#define ISC_QLINK_LINKED(elt, link) ((void*)(elt)->link.next != (void*)(-1)) #define ISC_QUEUE(type) struct { \ - type headnode; \ type *head, *tail; \ isc_mutex_t headlock, taillock; \ } #define ISC_QUEUE_INIT(queue, link) \ do { \ - isc_mutex_init(&(queue).headlock); \ isc_mutex_init(&(queue).taillock); \ - (queue).head = (void *) &((queue).headnode); \ - (queue).tail = (void *) &((queue).headnode); \ - ISC_QLINK_INIT((queue).head, link); \ + isc_mutex_init(&(queue).headlock); \ + (queue).tail = (queue).head = NULL; \ } while (0) -#define ISC_QUEUE_EMPTY(queue) ISC_TF((queue).head == (queue).tail) +#define ISC_QUEUE_EMPTY(queue) ISC_TF((queue).head == NULL) #define ISC_QUEUE_DESTROY(queue) \ do { \ ISC_QLINK_INSIST(ISC_QUEUE_EMPTY(queue)); \ - isc_mutex_destroy(&(queue).headlock); \ isc_mutex_destroy(&(queue).taillock); \ + isc_mutex_destroy(&(queue).headlock); \ } while (0) +/* + * queues are meant to separate the locks at either end. For best effect, that + * means keeping the ends separate - i.e. non-empty queues work best. + * + * a push to an empty queue has to take the pop lock to update + * the pop side of the queue. + * Popping the last entry has to take the push lock to update + * the push side of the queue. + * + * The order is (pop, push), because a pop is presumably in the + * latency path and a push is when we're done. + * + * We do an MT hot test in push to see if we need both locks, so we can + * acquire them in order. Hopefully that makes the case where we get + * the push lock and find we need the pop lock (and have to release it) rare. + * + * > 1 entry - no collision, push works on one end, pop on the other + * 0 entry - headlock race + * pop wins - return(NULL), push adds new as both head/tail + * push wins - updates head/tail, becomes 1 entry case. + * 1 entry - taillock race + * pop wins - return(pop) sets head/tail NULL, becomes 0 entry case + * push wins - updates {head,tail}->link.next, pop updates head + * with new ->link.next and doesn't update tail + * + */ #define ISC_QUEUE_PUSH(queue, elt, link) \ do { \ + isc_boolean_t headlocked = ISC_FALSE; \ ISC_QLINK_INSIST(!ISC_QLINK_LINKED(elt, link)); \ - (elt)->link.next = (void *)(-1); \ + if ((queue).head == NULL) { \ + LOCK(&(queue).headlock); \ + headlocked = ISC_TRUE; \ + } \ LOCK(&(queue).taillock); \ - (queue).tail->link.next = elt; \ - (queue).tail = elt; \ + if ((queue).tail == NULL && !headlocked) { \ + UNLOCK(&(queue).taillock); \ + LOCK(&(queue).headlock); \ + LOCK(&(queue).taillock); \ + headlocked = ISC_TRUE; \ + } \ + (elt)->link.prev = (queue).tail; \ + (elt)->link.next = NULL; \ + if ((queue).tail != NULL) \ + (queue).tail->link.next = (elt); \ + (queue).tail = (elt); \ UNLOCK(&(queue).taillock); \ - (elt)->link.linked = ISC_TRUE; \ + if (headlocked) { \ + if ((queue).head == NULL) \ + (queue).head = (elt); \ + UNLOCK(&(queue).headlock); \ + } \ } while (0) #define ISC_QUEUE_POP(queue, link, ret) \ do { \ LOCK(&(queue).headlock); \ - ret = (queue).head->link.next; \ - if (ret == (void *)(-1)) { \ - UNLOCK(&(queue).headlock); \ - ret = NULL; \ - } else { \ - (queue).head->link.next = ret->link.next; \ - if (ret->link.next == (void *)(-1)) { \ + ret = (queue).head; \ + while (ret != NULL) { \ + if (ret->link.next == NULL) { \ LOCK(&(queue).taillock); \ - (queue).tail = (queue).head; \ + if (ret->link.next == NULL) { \ + (queue).head = (queue).tail = NULL; \ + UNLOCK(&(queue).taillock); \ + break; \ + }\ UNLOCK(&(queue).taillock); \ } \ - UNLOCK(&(queue).headlock); \ - ret->link.next = (void *)(-1); \ - ret->link.linked = ISC_FALSE; \ + (queue).head = ret->link.next; \ + (queue).head->link.prev = NULL; \ + break; \ } \ - } while (0) + UNLOCK(&(queue).headlock); \ + if (ret != NULL) \ + (ret)->link.next = (ret)->link.prev = (void *)(-1); \ + } while(0) #endif /* ISC_QUEUE_H */ |