]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: try to reduce number or DnsResourceKeys we keep around by merging them
authorLennart Poettering <lennart@poettering.net>
Fri, 15 Jan 2016 20:38:27 +0000 (21:38 +0100)
committerLennart Poettering <lennart@poettering.net>
Sun, 17 Jan 2016 19:47:46 +0000 (20:47 +0100)
Quite often we read the same RR key multiple times from the same message. Try to replace them by a single object when
we notice this. Do so again when we add things to the cache.

This should reduce memory consumption a tiny bit.

src/resolve/resolved-dns-cache.c
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-rr.h

index 301f383809c20bb5decc809bf2a5833151b9574c..fdb34d11df487c93a0615488a5c46ea4416c37bf 100644 (file)
@@ -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 {
index 57cfc1ab9b33464cce277bcab2774826d86c9056..0acbcfe261af1af4e5a54e3768518bc6c2df146c 100644 (file)
@@ -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;
 
index 02c6b239d59d935ad5fada2a524b0e9eb373c433..7273ef38255846dc47f6d2326ba567e930df93ee 100644 (file)
@@ -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;
 
index 8ab53211a992b6c0ae5086bc48878ea06529ccfd..d9c31e81c5b47e989f86b60f3db3103768337853 100644 (file)
@@ -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);