nghttpx: Periodically remove expired DNS cache entries

This commit is contained in:
Tatsuhiro Tsujikawa 2016-12-11 10:42:54 +09:00
parent fd403a85c8
commit c487cd888f
2 changed files with 58 additions and 1 deletions

View File

@ -28,9 +28,21 @@
namespace shrpx {
DNSTracker::DNSTracker(struct ev_loop *loop) : loop_(loop) {}
namespace {
void gccb(struct ev_loop *loop, ev_timer *w, int revents) {
auto dns_tracker = static_cast<DNSTracker *>(w->data);
dns_tracker->gc();
}
} // namespace
DNSTracker::DNSTracker(struct ev_loop *loop) : loop_(loop) {
ev_timer_init(&gc_timer_, gccb, 0., 12_h);
gc_timer_.data = this;
}
DNSTracker::~DNSTracker() {
ev_timer_stop(loop_, &gc_timer_);
for (auto &p : ents_) {
auto &qlist = p.second.qlist;
while (!qlist.empty()) {
@ -94,6 +106,8 @@ int DNSTracker::resolve(Address *result, DNSQuery *dnsq) {
ents_.emplace(host, make_entry(nullptr, std::move(host_copy),
DNS_STATUS_ERROR, nullptr));
start_gc_timer();
return DNS_STATUS_ERROR;
}
@ -107,6 +121,8 @@ int DNSTracker::resolve(Address *result, DNSQuery *dnsq) {
ents_.emplace(host, make_entry(nullptr, std::move(host_copy),
DNS_STATUS_ERROR, nullptr));
start_gc_timer();
return DNS_STATUS_ERROR;
}
case DNS_STATUS_OK: {
@ -118,6 +134,8 @@ int DNSTracker::resolve(Address *result, DNSQuery *dnsq) {
ents_.emplace(host, make_entry(nullptr, std::move(host_copy),
DNS_STATUS_OK, result));
start_gc_timer();
return DNS_STATUS_OK;
}
case DNS_STATUS_RUNNING: {
@ -127,6 +145,8 @@ int DNSTracker::resolve(Address *result, DNSQuery *dnsq) {
make_entry(std::move(resolv), std::move(host_copy),
DNS_STATUS_RUNNING, nullptr));
start_gc_timer();
auto &ent = (*p.first).second;
add_to_qlist(ent, dnsq);
@ -260,4 +280,33 @@ void DNSTracker::cancel(DNSQuery *dnsq) {
dnsq->in_qlist = false;
}
void DNSTracker::start_gc_timer() {
if (ev_is_active(&gc_timer_)) {
return;
}
ev_timer_again(loop_, &gc_timer_);
}
void DNSTracker::gc() {
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Starting removing expired DNS cache entries";
}
auto now = ev_now(loop_);
for (auto it = std::begin(ents_); it != std::end(ents_);) {
auto &ent = (*it).second;
if (ent.expiry >= now) {
++it;
continue;
}
it = ents_.erase(it);
}
if (ents_.empty()) {
ev_timer_stop(loop_, &gc_timer_);
}
}
} // namespace shrpx

View File

@ -88,6 +88,10 @@ public:
int resolve(Address *result, DNSQuery *dnsq);
// Cancels name lookup requested by |dnsq|.
void cancel(DNSQuery *dnsq);
// Removes expired entries from ents_.
void gc();
// Starts GC timer.
void start_gc_timer();
private:
ResolverEntry make_entry(std::unique_ptr<DualDNSResolver> resolv,
@ -100,6 +104,10 @@ private:
void add_to_qlist(ResolverEntry &ent, DNSQuery *dnsq);
std::map<StringRef, ResolverEntry> ents_;
// Periodically iterates ents_, and removes expired entries to avoid
// excessive use of memory. Since only backend API can potentially
// increase memory consumption, interval could be very long.
ev_timer gc_timer_;
struct ev_loop *loop_;
};