summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/resolve/resolved-dns-cache.c13
-rw-r--r--src/resolve/resolved-dns-packet.c5
-rw-r--r--src/resolve/resolved-dns-rr.c40
-rw-r--r--src/resolve/resolved-dns-rr.h4
4 files changed, 61 insertions, 1 deletions
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index 301f383809..fdb34d11df 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -247,6 +247,19 @@ static int dns_cache_link_item(DnsCache *c, DnsCacheItem *i) {
first = hashmap_get(c->by_key, i->key);
if (first) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
+
+ /* Keep a reference to the original key, while we manipulate the list. */
+ k = dns_resource_key_ref(first->key);
+
+ /* Now, try to reduce the number of keys we keep */
+ dns_resource_key_reduce(&first->key, &i->key);
+
+ if (first->rr)
+ dns_resource_key_reduce(&first->rr->key, &i->key);
+ if (i->rr)
+ dns_resource_key_reduce(&i->rr->key, &i->key);
+
LIST_PREPEND(by_key, first, i);
assert_se(hashmap_replace(c->by_key, first->key, first) >= 0);
} else {
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 57cfc1ab9b..0acbcfe261 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -2106,6 +2106,7 @@ int dns_packet_extract(DnsPacket *p) {
n = DNS_PACKET_RRCOUNT(p);
if (n > 0) {
+ DnsResourceRecord *previous = NULL;
bool bad_opt = false;
answer = dns_answer_new(n);
@@ -2122,6 +2123,10 @@ int dns_packet_extract(DnsPacket *p) {
if (r < 0)
goto finish;
+ /* Try to reduce memory usage a bit */
+ if (previous)
+ dns_resource_key_reduce(&rr->key, &previous->key);
+
if (rr->key->type == DNS_TYPE_OPT) {
bool has_rfc6975;
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 02c6b239d5..7273ef3825 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -334,6 +334,46 @@ int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
return 0;
}
+bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) {
+ assert(a);
+ assert(b);
+
+ /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
+ * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
+ * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
+ * superficial data. */
+
+ if (!*a)
+ return false;
+ if (!*b)
+ return false;
+
+ /* We refuse merging const keys */
+ if ((*a)->n_ref == (unsigned) -1)
+ return false;
+ if ((*b)->n_ref == (unsigned) -1)
+ return false;
+
+ /* Already the same? */
+ if (*a == *b)
+ return true;
+
+ /* Are they really identical? */
+ if (dns_resource_key_equal(*a, *b) <= 0)
+ return false;
+
+ /* Keep the one which already has more references. */
+ if ((*a)->n_ref > (*b)->n_ref) {
+ dns_resource_key_unref(*b);
+ *b = dns_resource_key_ref(*a);
+ } else {
+ dns_resource_key_unref(*a);
+ *a = dns_resource_key_ref(*b);
+ }
+
+ return true;
+}
+
DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
DnsResourceRecord *rr;
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 8ab53211a9..d9c31e81c5 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -81,7 +81,7 @@ enum {
};
struct DnsResourceKey {
- unsigned n_ref;
+ unsigned n_ref; /* (unsigned -1) for const keys, see below */
uint16_t class, type;
char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */
};
@@ -294,6 +294,8 @@ static inline bool dns_key_is_shared(const DnsResourceKey *key) {
return IN_SET(key->type, DNS_TYPE_PTR);
}
+bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b);
+
DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key);
DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name);
DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr);