• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 14230500445

02 Apr 2025 01:53PM UTC coverage: 52.058% (-11.4%) from 63.455%
14230500445

push

github

web-flow
Merge pull request #15385 from rgacogne/ddist-enable-quiche-sni-tests

dnsdist: Enable the DoQ and DoH3 parts of the SNI tests in our CI

21502 of 68138 branches covered (31.56%)

Branch coverage included in aggregate %.

77059 of 121190 relevant lines covered (63.59%)

4345179.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.27
/pdns/auth-querycache.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-querycache.hh"
27
#include "logger.hh"
28
#include "statbag.hh"
29
#include "cachecleaner.hh"
30
extern StatBag S;
31

32
const unsigned int AuthQueryCache::s_mincleaninterval, AuthQueryCache::s_maxcleaninterval;
33

34
AuthQueryCache::AuthQueryCache(size_t mapsCount): d_maps(mapsCount), d_lastclean(time(nullptr))
35
{
11✔
36
  S.declare("query-cache-hit","Number of hits on the query cache");
11✔
37
  S.declare("query-cache-miss","Number of misses on the query cache");
11✔
38
  S.declare("query-cache-size", "Number of entries in the query cache", StatType::gauge);
11✔
39
  S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
11✔
40
  S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
11✔
41

42
  d_statnumhit=S.getPointer("query-cache-hit");
11✔
43
  d_statnummiss=S.getPointer("query-cache-miss");
11✔
44
  d_statnumentries=S.getPointer("query-cache-size");
11✔
45
}
11✔
46

47
void AuthQueryCache::MapCombo::reserve(size_t numberOfEntries)
48
{
21,504✔
49
#if BOOST_VERSION >= 105600
21,504✔
50
  d_map.write_lock()->get<HashTag>().reserve(numberOfEntries);
21,504✔
51
#endif /* BOOST_VERSION >= 105600 */
21,504✔
52
}
21,504✔
53

54
// called from ueberbackend
55
bool AuthQueryCache::getEntry(const DNSName &qname, const QType& qtype, vector<DNSZoneRecord>& value, int zoneID)
56
{
795,623✔
57
  cleanupIfNeeded();
795,623✔
58

59
  time_t now = time(nullptr);
795,623✔
60
  uint16_t qt = qtype.getCode();
795,623✔
61
  auto& mc = getMap(qname);
795,623✔
62
  {
795,623✔
63
    auto map = mc.d_map.try_read_lock();
795,623✔
64
    if (!map.owns_lock()) {
795,623✔
65
      S.inc("deferred-cache-lookup");
209✔
66
      return false;
209✔
67
    }
209✔
68

69
    return getEntryLocked(*map, qname, qt, value, zoneID, now);
795,414✔
70
  }
795,623✔
71
}
795,623✔
72

73
void AuthQueryCache::insert(const DNSName &qname, const QType& qtype, vector<DNSZoneRecord>&& value, uint32_t ttl, int zoneID)
74
{
1,599,806✔
75
  cleanupIfNeeded();
1,599,806✔
76

77
  if(!ttl)
1,599,806!
78
    return;
×
79

80
  time_t now = time(nullptr);
1,599,806✔
81
  CacheEntry val;
1,599,806✔
82
  val.ttd = now + ttl;
1,599,806✔
83
  val.qname = qname;
1,599,806✔
84
  val.qtype = qtype.getCode();
1,599,806✔
85
  val.drs = std::move(value);
1,599,806✔
86
  val.zoneID = zoneID;
1,599,806✔
87

88
  auto& mc = getMap(val.qname);
1,599,806✔
89

90
  {
1,599,806✔
91
    auto map = mc.d_map.try_write_lock();
1,599,806✔
92
    if (!map.owns_lock()) {
1,599,806✔
93
      S.inc("deferred-cache-inserts"); 
881✔
94
      return;
881✔
95
    }
881✔
96

97
    bool inserted;
1,598,925✔
98
    cmap_t::iterator place;
1,598,925✔
99
    std::tie(place, inserted) = map->insert(val);
1,598,925✔
100

101
    if (!inserted) {
1,598,925!
102
      map->replace(place, std::move(val));
×
103
      moveCacheItemToBack<SequencedTag>(*map, place);
×
104
    }
×
105
    else {
1,598,925✔
106
      if (*d_statnumentries >= d_maxEntries) {
1,598,925✔
107
        /* remove the least recently inserted or replaced entry */
108
        auto& sidx = map->get<SequencedTag>();
990,000✔
109
        sidx.pop_front();
990,000✔
110
      }
990,000✔
111
      else {
608,925✔
112
        (*d_statnumentries)++;
608,925✔
113
      }
608,925✔
114
    }
1,598,925✔
115
  }
1,598,925✔
116
}
1,598,925✔
117

118
bool AuthQueryCache::getEntryLocked(const cmap_t& map, const DNSName &qname, uint16_t qtype, vector<DNSZoneRecord>& value, int zoneID, time_t now)
119
{
795,469✔
120
  auto& idx = boost::multi_index::get<HashTag>(map);
795,469✔
121
  auto iter = idx.find(std::tie(qname, qtype, zoneID));
795,469✔
122

123
  if (iter == idx.end()) {
795,469✔
124
    (*d_statnummiss)++;
297,945✔
125
    return false;
297,945✔
126
  }
297,945✔
127

128
  if (iter->ttd < now) {
497,524!
129
    (*d_statnummiss)++;
×
130
    return false;
×
131
  }
×
132

133
  value = iter->drs;
497,524✔
134
  (*d_statnumhit)++;
497,524✔
135
  return true;
497,524✔
136
}
497,524✔
137

138
map<char,uint64_t> AuthQueryCache::getCounts()
139
{
×
140
  uint64_t queryCacheEntries=0, negQueryCacheEntries=0;
×
141

142
  for(auto& mc : d_maps) {
×
143
    auto map = mc.d_map.read_lock();
×
144
    
145
    for(const auto & iter : *map) {
×
146
      if(iter.drs.empty())
×
147
        negQueryCacheEntries++;
×
148
      else
×
149
        queryCacheEntries++;
×
150
    }
×
151
  }
×
152
  map<char,uint64_t> ret;
×
153

154
  ret['!']=negQueryCacheEntries;
×
155
  ret['Q']=queryCacheEntries;
×
156
  return ret;
×
157
}
×
158

159
/* clears the entire cache. */
160
uint64_t AuthQueryCache::purge()
161
{
26✔
162
  d_statnumentries->store(0);
26✔
163

164
  return purgeLockedCollectionsVector(d_maps);
26✔
165
}
26✔
166

167
uint64_t AuthQueryCache::purgeExact(const DNSName& qname)
168
{
101,000✔
169
  auto& mc = getMap(qname);
101,000✔
170
  uint64_t delcount = purgeExactLockedCollection<NameTag>(mc, qname);
101,000✔
171

172
  *d_statnumentries -= delcount;
101,000✔
173

174
  return delcount;
101,000✔
175
}
101,000✔
176

177
/* purges entries from the querycache. If match ends on a $, it is treated as a suffix */
178
uint64_t AuthQueryCache::purge(const string &match)
179
{
101,000✔
180
  uint64_t delcount = 0;
101,000✔
181

182
  if(boost::ends_with(match, "$")) {
101,000!
183
    delcount = purgeLockedCollectionsVector<NameTag>(d_maps, match);
×
184
    *d_statnumentries -= delcount;
×
185
  }
×
186
  else {
101,000✔
187
    delcount = purgeExact(DNSName(match));
101,000✔
188
  }
101,000✔
189

190
  return delcount;
101,000✔
191
}
101,000✔
192

193
void AuthQueryCache::cleanup()
194
{
10,368✔
195
  uint64_t totErased = pruneLockedCollectionsVector<SequencedTag>(d_maps);
10,368✔
196
  *d_statnumentries -= totErased;
10,368✔
197

198
  DLOG(g_log<<"Done with cache clean, cacheSize: "<<*d_statnumentries<<", totErased"<<totErased<<endl);
10,368✔
199
}
10,368✔
200

201
/* the logic:
202
   after d_nextclean operations, we clean. We also adjust the cleaninterval
203
   a bit so we slowly move it to a value where we clean roughly every 30 seconds.
204

205
   If d_nextclean has reached its maximum value, we also test if we were called
206
   within 30 seconds, and if so, we skip cleaning. This means that under high load,
207
   we will not clean more often than every 30 seconds anyhow.
208
*/
209

210
void AuthQueryCache::cleanupIfNeeded()
211
{
2,388,549✔
212
  if (d_ops++ == d_nextclean) {
2,388,549✔
213
    time_t now = time(nullptr);
12✔
214
    int timediff = max((int)(now - d_lastclean), 1);
12✔
215

216
    DLOG(g_log<<"cleaninterval: "<<d_cleaninterval<<", timediff: "<<timediff<<endl);
12✔
217

218
    if (d_cleaninterval == s_maxcleaninterval && timediff < 30) {
12!
219
      d_cleanskipped = true;
6✔
220
      d_nextclean += d_cleaninterval;
6✔
221

222
      DLOG(g_log<<"cleaning skipped, timediff: "<<timediff<<endl);
6✔
223

224
      return;
6✔
225
    }
6✔
226

227
    if(!d_cleanskipped) {
6!
228
      d_cleaninterval=(int)(0.6*d_cleaninterval)+(0.4*d_cleaninterval*(30.0/timediff));
6✔
229
      d_cleaninterval=std::max(d_cleaninterval, s_mincleaninterval);
6✔
230
      d_cleaninterval=std::min(d_cleaninterval, s_maxcleaninterval);
6✔
231

232
      DLOG(g_log<<"new cleaninterval: "<<d_cleaninterval<<endl);
6✔
233
    } else {
6✔
234
      d_cleanskipped = false;
×
235
    }
×
236

237
    d_nextclean += d_cleaninterval;
6✔
238
    d_lastclean=now;
6✔
239
    cleanup();
6✔
240
  }
6✔
241
}
2,388,549✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc