From: Witold Kręcicki Date: Wed, 5 Jun 2019 20:07:50 +0000 (+0200) Subject: In dns_zonemgr_unreachable use atomics to avoid unnecessary X-Git-Tag: v9.15.2~55^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=68eb9a7c6a0b03545c003d82f4258b9530d2f508;p=thirdparty%2Fbind9.git In dns_zonemgr_unreachable use atomics to avoid unnecessary write locking. Unreachable cache in zonemgr is realized as an static LRU list. When we 'use' an entry we need to update the last-used time, we can use atomics to do so without the necessity to upgrading read-lock to write-lock. --- diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 6681446a7a5..f1ef2fc0951 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -501,7 +501,7 @@ struct dns_zone { #define DNS_ZONELOADFLAG_THAW 0x00000002U /* Thaw the zone on successful load. */ -#define UNREACH_CHACHE_SIZE 10U +#define UNREACH_CACHE_SIZE 10U #define UNREACH_HOLD_TIME 600 /* 10 minutes */ #define CHECK(op) \ @@ -512,9 +512,9 @@ struct dns_zone { struct dns_unreachable { isc_sockaddr_t remote; isc_sockaddr_t local; - uint32_t expire; - uint32_t last; - uint32_t count; + atomic_uint_fast32_t expire; + atomic_uint_fast32_t last; + uint32_t count; }; struct dns_zonemgr { @@ -557,7 +557,7 @@ struct dns_zonemgr { /* Locked by urlock. */ /* LRU cache */ - struct dns_unreachable unreachable[UNREACH_CHACHE_SIZE]; + struct dns_unreachable unreachable[UNREACH_CACHE_SIZE]; }; /*% @@ -17339,30 +17339,24 @@ dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, isc_sockaddr_t *local, isc_time_t *now) { unsigned int i; - isc_rwlocktype_t locktype; - isc_result_t result; uint32_t seconds = isc_time_seconds(now); uint32_t count = 0; REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - locktype = isc_rwlocktype_read; - RWLOCK(&zmgr->urlock, locktype); - for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + RWLOCK(&zmgr->urlock, isc_rwlocktype_read); + for (i = 0; i < UNREACH_CACHE_SIZE; i++) { if (zmgr->unreachable[i].expire >= seconds && isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { - result = isc_rwlock_tryupgrade(&zmgr->urlock); - if (result == ISC_R_SUCCESS) { - locktype = isc_rwlocktype_write; - zmgr->unreachable[i].last = seconds; - count = zmgr->unreachable[i].count; - } + atomic_store_relaxed(&zmgr->unreachable[i].last, + seconds); + count = zmgr->unreachable[i].count; break; } } - RWUNLOCK(&zmgr->urlock, locktype); - return (i < UNREACH_CHACHE_SIZE && count > 1U); + RWUNLOCK(&zmgr->urlock, isc_rwlocktype_read); + return (i < UNREACH_CACHE_SIZE && count > 1U); } void @@ -17370,9 +17364,6 @@ dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, isc_sockaddr_t *local) { unsigned int i; - isc_rwlocktype_t locktype; - isc_result_t result; - char master[ISC_SOCKADDR_FORMATSIZE]; char source[ISC_SOCKADDR_FORMATSIZE]; @@ -17381,27 +17372,15 @@ dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - locktype = isc_rwlocktype_read; - RWLOCK(&zmgr->urlock, locktype); - for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + RWLOCK(&zmgr->urlock, isc_rwlocktype_read); + for (i = 0; i < UNREACH_CACHE_SIZE; i++) { if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { - if (zmgr->unreachable[i].expire == 0) - break; - result = isc_rwlock_tryupgrade(&zmgr->urlock); - if (result == ISC_R_SUCCESS) { - locktype = isc_rwlocktype_write; - zmgr->unreachable[i].expire = 0; - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_ZONE, ISC_LOG_INFO, - "master %s (source %s) deleted " - "from unreachable cache", - master, source); - } + atomic_store_relaxed(&zmgr->unreachable[i].expire, 0); break; } } - RWUNLOCK(&zmgr->urlock, locktype); + RWUNLOCK(&zmgr->urlock, isc_rwlocktype_read); } void @@ -17410,54 +17389,55 @@ dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, { uint32_t seconds = isc_time_seconds(now); uint32_t last = seconds; - unsigned int i, slot = UNREACH_CHACHE_SIZE, oldest = 0; - + unsigned int i, slot = UNREACH_CACHE_SIZE, oldest = 0; REQUIRE(DNS_ZONEMGR_VALID(zmgr)); RWLOCK(&zmgr->urlock, isc_rwlocktype_write); - for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + for (i = 0; i < UNREACH_CACHE_SIZE; i++) { /* Existing entry? */ if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) break; /* Empty slot? */ - if (zmgr->unreachable[i].expire < seconds) + if (atomic_load_relaxed(&zmgr->unreachable[i].expire) < seconds) { slot = i; + } /* Least recently used slot? */ - if (zmgr->unreachable[i].last < last) { - last = zmgr->unreachable[i].last; + if (atomic_load_relaxed(&zmgr->unreachable[i].last) < last) { + last = atomic_load_relaxed(&zmgr->unreachable[i].last); oldest = i; } } - if (i < UNREACH_CHACHE_SIZE) { + if (i < UNREACH_CACHE_SIZE) { /* * Found a existing entry. Update the expire timer and * last usage timestamps. */ - zmgr->unreachable[i].expire = seconds + UNREACH_HOLD_TIME; - zmgr->unreachable[i].last = seconds; - if (zmgr->unreachable[i].expire < seconds) + if (atomic_load_relaxed(&zmgr->unreachable[i].expire) + < seconds) { zmgr->unreachable[i].count = 1; - else + } else { zmgr->unreachable[i].count++; - } else if (slot != UNREACH_CHACHE_SIZE) { + } + atomic_store_relaxed(&zmgr->unreachable[i].expire, + seconds + UNREACH_HOLD_TIME); + atomic_store_relaxed(&zmgr->unreachable[i].last, seconds); + } else { /* - * Found a empty slot. Add a new entry to the cache. + * We need to write a new entry. */ - zmgr->unreachable[slot].expire = seconds + UNREACH_HOLD_TIME; - zmgr->unreachable[slot].last = seconds; + if (slot == UNREACH_CACHE_SIZE) { + /* + * We don't have an empty slot, use the oldest one. + */ + slot = oldest; + } + atomic_store_relaxed(&zmgr->unreachable[slot].expire, + seconds + UNREACH_HOLD_TIME); + atomic_store_relaxed(&zmgr->unreachable[slot].last, seconds); + zmgr->unreachable[slot].count = 1; zmgr->unreachable[slot].remote = *remote; zmgr->unreachable[slot].local = *local; - zmgr->unreachable[slot].count = 1; - } else { - /* - * Replace the least recently used entry in the cache. - */ - zmgr->unreachable[oldest].expire = seconds + UNREACH_HOLD_TIME; - zmgr->unreachable[oldest].last = seconds; - zmgr->unreachable[oldest].remote = *remote; - zmgr->unreachable[oldest].local = *local; - zmgr->unreachable[oldest].count = 1; } RWUNLOCK(&zmgr->urlock, isc_rwlocktype_write); }