resolved: wait to gc transactions if they might still give an answer

In some cases when a query completes there are still pending
transactions that are no longer useful to answer the query. But if this
query is repeated in the future and we don't have the answers cached,
we're going to ask and ignore the answer again.

Instead of purging these superfluous transactions, let's wait and see if
they produce an answer, since we already asked the question, and use it
to fill our cache.
This commit is contained in:
Ronan Pigott 2024-03-15 13:52:30 -07:00 committed by Luca Boccassi
parent 48570c9273
commit ce88017255
3 changed files with 34 additions and 1 deletions

View file

@ -57,6 +57,21 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
}
}
static void dns_query_candidate_abandon(DnsQueryCandidate *c) {
DnsTransaction *t;
assert(c);
/* Abandon all the DnsTransactions attached to this query */
while ((t = set_steal_first(c->transactions))) {
t->wait_for_answer = true;
set_remove(t->notify_query_candidates, c);
set_remove(t->notify_query_candidates_done, c);
dns_transaction_gc(t);
}
}
static DnsQueryCandidate* dns_query_candidate_unlink(DnsQueryCandidate *c) {
assert(c);
@ -354,6 +369,16 @@ static void dns_query_stop(DnsQuery *q) {
dns_query_candidate_stop(c);
}
static void dns_query_abandon(DnsQuery *q) {
assert(q);
/* Thankfully transactions have their own timeouts */
event_source_disable(q->timeout_event_source);
LIST_FOREACH(candidates_by_query, c, q->candidates)
dns_query_candidate_abandon(c);
}
static void dns_query_unlink_candidates(DnsQuery *q) {
assert(q);
@ -591,7 +616,7 @@ void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
(void) manager_monitor_send(q->manager, q);
dns_query_stop(q);
dns_query_abandon(q);
if (q->complete)
q->complete(q);
}

View file

@ -181,6 +181,9 @@ DnsTransaction* dns_transaction_gc(DnsTransaction *t) {
if (t->block_gc > 0)
return t;
if (t->wait_for_answer && IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING))
return t;
if (set_isempty(t->notify_query_candidates) &&
set_isempty(t->notify_query_candidates_done) &&
set_isempty(t->notify_zone_items) &&

View file

@ -136,6 +136,11 @@ struct DnsTransaction {
unsigned block_gc;
/* Set when we're willing to let this transaction live beyond it's usefulness for the original query,
* for caching purposes. This blocks gc while there is still a chance we might still receive an
* answer. */
bool wait_for_answer;
LIST_FIELDS(DnsTransaction, transactions_by_scope);
LIST_FIELDS(DnsTransaction, transactions_by_stream);
LIST_FIELDS(DnsTransaction, transactions_by_key);