]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/auth-zonecache.cc
Merge pull request #14032 from rgacogne/ddist-192-changelog-secpoll
[thirdparty/pdns.git] / pdns / auth-zonecache.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "auth-zonecache.hh"
27 #include "logger.hh"
28 #include "statbag.hh"
29 #include "arguments.hh"
30 #include "cachecleaner.hh"
31 extern StatBag S;
32
33 AuthZoneCache::AuthZoneCache(size_t mapsCount) :
34 d_maps(mapsCount)
35 {
36 S.declare("zone-cache-hit", "Number of zone cache hits");
37 S.declare("zone-cache-miss", "Number of zone cache misses");
38 S.declare("zone-cache-size", "Number of entries in the zone cache", StatType::gauge);
39
40 d_statnumhit = S.getPointer("zone-cache-hit");
41 d_statnummiss = S.getPointer("zone-cache-miss");
42 d_statnumentries = S.getPointer("zone-cache-size");
43 }
44
45 bool AuthZoneCache::getEntry(const DNSName& zone, int& zoneId)
46 {
47 auto& mc = getMap(zone);
48 bool found = false;
49 {
50 auto map = mc.d_map.read_lock();
51 auto iter = map->find(zone);
52 if (iter != map->end()) {
53 found = true;
54 zoneId = iter->second.zoneId;
55 }
56 }
57
58 if (found) {
59 (*d_statnumhit)++;
60 }
61 else {
62 (*d_statnummiss)++;
63 }
64 return found;
65 }
66
67 bool AuthZoneCache::isEnabled() const
68 {
69 return d_refreshinterval > 0;
70 }
71
72 void AuthZoneCache::clear()
73 {
74 purgeLockedCollectionsVector(d_maps);
75 }
76
77 void AuthZoneCache::replace(const vector<std::tuple<DNSName, int>>& zone_indices)
78 {
79 if (!d_refreshinterval)
80 return;
81
82 size_t count = zone_indices.size();
83 vector<cmap_t> newMaps(d_maps.size());
84
85 // build new maps
86 for (const std::tuple<DNSName, int>& tup : zone_indices) {
87 const DNSName& zone = std::get<0>(tup);
88 CacheValue val;
89 val.zoneId = std::get<1>(tup);
90 auto& mc = newMaps[getMapIndex(zone)];
91 auto iter = mc.find(zone);
92 if (iter != mc.end()) {
93 iter->second = std::move(val);
94 }
95 else {
96 mc.emplace(zone, val);
97 }
98 }
99
100 {
101 // process zone updates done while data collection for replace() was already in progress.
102 auto pending = d_pending.lock();
103 assert(pending->d_replacePending); // make sure we never forget to call setReplacePending()
104 for (const std::tuple<DNSName, int, bool>& tup : pending->d_pendingUpdates) {
105 const DNSName& zone = std::get<0>(tup);
106 CacheValue val;
107 val.zoneId = std::get<1>(tup);
108 bool insert = std::get<2>(tup);
109 auto& mc = newMaps[getMapIndex(zone)];
110 auto iter = mc.find(zone);
111 if (iter != mc.end()) {
112 if (insert) {
113 iter->second = std::move(val);
114 }
115 else {
116 mc.erase(iter);
117 count--;
118 }
119 }
120 else if (insert) {
121 mc.emplace(zone, val);
122 count++;
123 }
124 }
125
126 for (size_t mapIndex = 0; mapIndex < d_maps.size(); mapIndex++) {
127 auto& mc = d_maps[mapIndex];
128 auto map = mc.d_map.write_lock();
129 *map = std::move(newMaps[mapIndex]);
130 }
131
132 pending->d_pendingUpdates.clear();
133 pending->d_replacePending = false;
134
135 d_statnumentries->store(count);
136 }
137 }
138
139 void AuthZoneCache::add(const DNSName& zone, const int zoneId)
140 {
141 if (!d_refreshinterval)
142 return;
143
144 {
145 auto pending = d_pending.lock();
146 if (pending->d_replacePending) {
147 pending->d_pendingUpdates.emplace_back(zone, zoneId, true);
148 }
149 }
150
151 CacheValue val;
152 val.zoneId = zoneId;
153
154 int mapIndex = getMapIndex(zone);
155 {
156 auto& mc = d_maps[mapIndex];
157 auto map = mc.d_map.write_lock();
158 auto iter = map->find(zone);
159 if (iter != map->end()) {
160 iter->second = std::move(val);
161 }
162 else {
163 map->emplace(zone, val);
164 (*d_statnumentries)++;
165 }
166 }
167 }
168
169 void AuthZoneCache::remove(const DNSName& zone)
170 {
171 if (!d_refreshinterval)
172 return;
173
174 {
175 auto pending = d_pending.lock();
176 if (pending->d_replacePending) {
177 pending->d_pendingUpdates.emplace_back(zone, -1, false);
178 }
179 }
180
181 int mapIndex = getMapIndex(zone);
182 {
183 auto& mc = d_maps[mapIndex];
184 auto map = mc.d_map.write_lock();
185 if (map->erase(zone)) {
186 (*d_statnumentries)--;
187 }
188 }
189 }
190
191 void AuthZoneCache::setReplacePending()
192 {
193 if (!d_refreshinterval)
194 return;
195
196 {
197 auto pending = d_pending.lock();
198 pending->d_replacePending = true;
199 pending->d_pendingUpdates.clear();
200 }
201 }