aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonan Pigott <ronan@rjp.ie>2024-03-15 13:52:30 -0700
committerLuca Boccassi <luca.boccassi@gmail.com>2024-03-18 11:10:11 +0000
commitce880172552534e7416ae3af697053c0df58b770 (patch)
treec1c453dc41c8dcee64c934ca93da0113f63f42e7
parentMerge pull request #31811 from yuwata/network-pin-persistent-storage (diff)
downloadsystemd-ce880172552534e7416ae3af697053c0df58b770.tar.xz
systemd-ce880172552534e7416ae3af697053c0df58b770.zip
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.
-rw-r--r--src/resolve/resolved-dns-query.c27
-rw-r--r--src/resolve/resolved-dns-transaction.c3
-rw-r--r--src/resolve/resolved-dns-transaction.h5
3 files changed, 34 insertions, 1 deletions
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index 801bbe8007e..14adb904bdf 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -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);
}
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 954841bb7c0..5af550bc592 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -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) &&
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index 6de4cdd7491..30d2167d645 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -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);