From: Remi Gacogne Date: Fri, 17 Jan 2020 13:56:27 +0000 (+0100) Subject: auth: Enforce a strict maximum size for the packet and records caches X-Git-Tag: auth-4.3.0-beta1~19^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F8713%2Fhead;p=thirdparty%2Fpdns.git auth: Enforce a strict maximum size for the packet and records caches Before this change, both the query and packet caches in the authoritative server can exceed their maximum size by a lot, until the next cleaning cycle. This is particularly nasty since the current cleaning algorithm will never remove entries from the cache until they expire, as opposed to what we do in the recursor, for example, where we nuke the least-recently used entries, even if they are still valid, when the cache is full. This commit changes that by removing the least recently inserted or updated entry from the cache after inserting a new one when the cache is full, thus enforcing the maximum size more strictly. Note that this is really the least recently inserted/updated and not the least recently used one, as is done in the recursor. Having a proper LRU in the auth would require acquering a write lock for a simple lookup, instead of a potentially concurrent read-lock at the moment. We might want to consider changing that at some point, as a LRU might be fairer and the lock contention might be very small since the caches are sharded. --- diff --git a/pdns/auth-packetcache.cc b/pdns/auth-packetcache.cc index 48b937acf3..094c1f63ba 100644 --- a/pdns/auth-packetcache.cc +++ b/pdns/auth-packetcache.cc @@ -154,6 +154,7 @@ void AuthPacketCache::insert(DNSPacket& q, DNSPacket& r, unsigned int maxTTL) continue; } + moveCacheItemToBack(mc.d_map, iter); iter->value = entry.value; iter->ttd = now + ourttl; iter->created = now; @@ -162,7 +163,15 @@ void AuthPacketCache::insert(DNSPacket& q, DNSPacket& r, unsigned int maxTTL) /* no existing entry found to refresh */ mc.d_map.insert(entry); - (*d_statnumentries)++; + + if (*d_statnumentries >= d_maxEntries) { + /* remove the least recently inserted or replaced entry */ + auto& sidx = mc.d_map.get(); + sidx.pop_front(); + } + else { + (*d_statnumentries)++; + } } } diff --git a/pdns/auth-packetcache.hh b/pdns/auth-packetcache.hh index e0191dc950..91b41528bc 100644 --- a/pdns/auth-packetcache.hh +++ b/pdns/auth-packetcache.hh @@ -98,6 +98,8 @@ private: indexed_by < hashed_non_unique, member >, ordered_non_unique, member, CanonDNSNameCompare >, + /* Note that this sequence holds 'least recently inserted or replaced', not least recently used. + Making it a LRU would require taking a write-lock when fetching from the cache, making the RW-lock inefficient compared to a mutex */ sequenced> > > cmap_t; diff --git a/pdns/auth-querycache.cc b/pdns/auth-querycache.cc index 2dc8c3254b..e790e9e165 100644 --- a/pdns/auth-querycache.cc +++ b/pdns/auth-querycache.cc @@ -109,9 +109,17 @@ void AuthQueryCache::insert(const DNSName &qname, const QType& qtype, const vect if (!inserted) { mc.d_map.replace(place, val); + moveCacheItemToBack(mc.d_map, place); } else { - (*d_statnumentries)++; + if (*d_statnumentries >= d_maxEntries) { + /* remove the least recently inserted or replaced entry */ + auto& sidx = mc.d_map.get(); + sidx.pop_front(); + } + else { + (*d_statnumentries)++; + } } } } diff --git a/pdns/auth-querycache.hh b/pdns/auth-querycache.hh index 193f91bf92..2dd27c835d 100644 --- a/pdns/auth-querycache.hh +++ b/pdns/auth-querycache.hh @@ -80,6 +80,8 @@ private: member, member > > , ordered_non_unique, member, CanonDNSNameCompare >, + /* Note that this sequence holds 'least recently inserted or replaced', not least recently used. + Making it a LRU would require taking a write-lock when fetching from the cache, making the RW-lock inefficient compared to a mutex */ sequenced> > > cmap_t;