2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <boost/version.hpp>
27 #include "namespaces.hh"
29 #include <boost/multi_index_container.hpp>
30 #include <boost/multi_index/ordered_index.hpp>
31 #include <boost/multi_index/hashed_index.hpp>
32 #include <boost/multi_index/sequenced_index.hpp>
33 #include <boost/multi_index/key_extractors.hpp>
34 using namespace ::boost::multi_index;
37 #include "dnspacket.hh"
40 class AuthQueryCache : public boost::noncopyable
43 AuthQueryCache(size_t mapsCount=1024);
45 void insert(const DNSName &qname, const QType& qtype, vector<DNSZoneRecord>&& content, uint32_t ttl, int zoneID);
47 bool getEntry(const DNSName &qname, const QType& qtype, vector<DNSZoneRecord>& entry, int zoneID);
49 size_t size() { return *d_statnumentries; } //!< number of entries in the cache
50 void cleanup(); //!< force the cache to preen itself from expired queries
52 uint64_t purge(const std::string& match); // could be $ terminated. Is not a dnsname!
53 uint64_t purgeExact(const DNSName& qname); // no wildcard matching here
55 map<char,uint64_t> getCounts();
57 void setMaxEntries(uint64_t maxEntries)
59 d_maxEntries = maxEntries;
60 for (auto& shard : d_maps) {
61 shard.reserve(maxEntries / d_maps.size());
69 mutable vector<DNSZoneRecord> drs;
70 mutable time_t ttd{0};
77 struct SequencedTag{};
78 typedef multi_index_container<
81 hashed_unique<tag<HashTag>, composite_key<CacheEntry,
82 member<CacheEntry,DNSName,&CacheEntry::qname>,
83 member<CacheEntry,uint16_t,&CacheEntry::qtype>,
84 member<CacheEntry,int, &CacheEntry::zoneID> > > ,
85 ordered_non_unique<tag<NameTag>, member<CacheEntry,DNSName,&CacheEntry::qname>, CanonDNSNameCompare >,
86 /* Note that this sequence holds 'least recently inserted or replaced', not least recently used.
87 Making it a LRU would require taking a write-lock when fetching from the cache, making the RW-lock inefficient compared to a mutex */
88 sequenced<tag<SequencedTag>>
96 ~MapCombo() = default;
97 MapCombo(const MapCombo &) = delete;
98 MapCombo & operator=(const MapCombo &) = delete;
100 void reserve(size_t numberOfEntries);
102 SharedLockGuarded<cmap_t> d_map;
105 vector<MapCombo> d_maps;
106 MapCombo& getMap(const DNSName& qname)
108 return d_maps[qname.hash() % d_maps.size()];
111 bool getEntryLocked(const cmap_t& map, const DNSName &content, uint16_t qtype, vector<DNSZoneRecord>& entry, int zoneID, time_t now);
112 void cleanupIfNeeded();
114 AtomicCounter d_ops{0};
115 AtomicCounter *d_statnumhit;
116 AtomicCounter *d_statnummiss;
117 AtomicCounter *d_statnumentries;
119 uint64_t d_maxEntries{0};
120 time_t d_lastclean; // doesn't need to be atomic
121 unsigned long d_nextclean{4096};
122 unsigned int d_cleaninterval{4096};
123 bool d_cleanskipped{false};
125 static const unsigned int s_mincleaninterval=1000, s_maxcleaninterval=300000;