]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
cache: cache glue records instead of refetching
authorMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 5 Jan 2015 00:14:14 +0000 (01:14 +0100)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 5 Jan 2015 12:06:30 +0000 (13:06 +0100)
lib/cache.c
lib/layer/iterate.c
lib/layer/itercache.c

index d9fc2ec590b49bfd835dc94db390069a72dd2c6d..7b7db6891830806de92358bb04f0569f064fdba1 100644 (file)
@@ -104,7 +104,7 @@ int kr_cache_query(namedb_txn_t *txn, knot_rrset_t *rr, uint32_t *timestamp)
                knot_dname_to_str(name_str, rr->owner, sizeof(name_str));
                char type_str[16];
                knot_rrtype_to_string(rr->type, type_str, sizeof(type_str));
-               DEBUG_MSG("query '%s %s' => %u RRs\n", name_str, type_str, found_rr->count);
+               DEBUG_MSG("read '%s %s' => %u RRs\n", name_str, type_str, found_rr->count);
 #endif
                /* Assign data and return success. */
                rr->rrs.rr_count = found_rr->count;
@@ -149,7 +149,7 @@ int kr_cache_insert(namedb_txn_t *txn, const knot_rrset_t *rr, uint32_t timestam
        knot_dname_to_str(name_str, rr->owner, sizeof(name_str));
        char type_str[16];
        knot_rrtype_to_string(rr->type, type_str, sizeof(type_str));
-       DEBUG_MSG("insert '%s %s' => %u RRs (key=%zuB,data=%zuB)\n", name_str, type_str, rr->rrs.rr_count, key.len, val.len);
+       DEBUG_MSG("write '%s %s' => %u RRs (key=%zuB,data=%zuB)\n", name_str, type_str, rr->rrs.rr_count, key.len, val.len);
 #endif
 
        int ret = db_api->insert(txn, &key, &val, 0);
index 51c1b56566236f9c0fa87eff07bbd41f80949756..eac4921025b5b6f31a7d7f966db9ae555814aad6 100644 (file)
@@ -56,13 +56,14 @@ static int set_zone_cut(struct kr_rplan *rplan, knot_pkt_t *pkt, const knot_rrse
                /* Find address in the additionals (optional). */
                int ret = glue_ns_addr(pkt, &rplan->zone_cut.addr, ns_name, type_list[i]);
                if (ret == KNOT_EOK) {
-                       break;
+                       return KNOT_EOK;
                }
        }
 
-       /* Query for address records to get it in the cache. */
-       (void) kr_rplan_push(rplan, rplan->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_A);
-       (void) kr_rplan_push(rplan, rplan->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA);
+       /* Query for address records (if not glue). */
+       for (unsigned i = 0; i < sizeof(type_list)/sizeof(uint16_t); ++i) {
+               (void) kr_rplan_push(rplan, rplan->zone_cut.ns, KNOT_CLASS_IN, type_list[i]);
+       }
 
        return KNOT_EOK;
 }
index 3bd97c42816a700fdc1cc1461511d09a22a3dcc2..07b31d7e8617de59641ef483597b4b347c4bc42c 100644 (file)
@@ -31,7 +31,7 @@ static int begin(knot_layer_t *ctx, void *module_param)
        return ctx->state;
 }
 
-static int query_cache_append(knot_pkt_t *answer, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
+static int read_cache_append(knot_pkt_t *answer, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
 {
        unsigned drift = timestamp;
 
@@ -65,7 +65,7 @@ static int query_cache_append(knot_pkt_t *answer, namedb_txn_t *txn, knot_rrset_
        return KNOT_EOK;
 }
 
-static int query_cache_zonecut(struct kr_zonecut *cut, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
+static int read_cache_zonecut(struct kr_zonecut *cut, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
 {
        /* Query cache for requested record */
        if (kr_cache_query(txn, cache_rr, &timestamp) != KNOT_EOK) {
@@ -83,7 +83,7 @@ static int query_cache_zonecut(struct kr_zonecut *cut, namedb_txn_t *txn, knot_r
        }
 }
 
-static int query_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
+static int read_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
 {
        assert(pkt && ctx);
        struct kr_layer_param *param = ctx->data;
@@ -100,7 +100,7 @@ static int query_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
 
        /* Check if updating current zone cut. */
        if (cur != kr_rplan_last(param->rplan)) {
-               ret = query_cache_zonecut(&param->rplan->zone_cut, txn, &cache_rr, timestamp);
+               ret = read_cache_zonecut(&param->rplan->zone_cut, txn, &cache_rr, timestamp);
                if (ret == KNOT_EOK) {
                        kr_rplan_pop(param->rplan, cur);
                        return KNOT_NS_PROC_DONE;
@@ -111,7 +111,7 @@ static int query_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
 
        /* Try to find a CNAME/DNAME chain first. */
        cache_rr.type = KNOT_RRTYPE_CNAME;
-       ret = query_cache_append(param->answer, txn, &cache_rr, timestamp);
+       ret = read_cache_append(param->answer, txn, &cache_rr, timestamp);
        if (ret == KNOT_EOK) {
                if (cur->stype != KNOT_RRTYPE_CNAME) {
                        const knot_dname_t *cname = knot_cname_name(&cache_rr.rrs);
@@ -125,7 +125,7 @@ static int query_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
 
        /* Try to find expected record then. */
        cache_rr.type = cur->stype;
-       ret = query_cache_append(param->answer, txn, &cache_rr, timestamp);
+       ret = read_cache_append(param->answer, txn, &cache_rr, timestamp);
        if (ret == KNOT_EOK) {
                kr_rplan_pop(param->rplan, cur);
                return KNOT_NS_PROC_DONE;
@@ -149,7 +149,6 @@ static int merge_cache_rr(knot_rrset_t *cache_rr, const knot_rrset_t *rr, mm_ctx
 static int merge_in_section(knot_rrset_t *cache_rr, const knot_pktsection_t *section, unsigned from, mm_ctx_t *pool)
 {
        int ret = KNOT_EOK;
-
        for (unsigned i = from; i < section->count; ++i) {
                ret = merge_cache_rr(cache_rr, knot_pkt_rr(section, i), pool);
                if (ret != KNOT_EOK) {
@@ -157,102 +156,87 @@ static int merge_in_section(knot_rrset_t *cache_rr, const knot_pktsection_t *sec
                }
        }
 
+       if (cache_rr->rrs.rr_count == 0) {
+               return KNOT_ENOENT;
+       }
        return ret;
 }
 
 /*! \brief Cache direct answer. */
-static int update_cache_answer(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+static int write_cache_rr(const knot_pktsection_t *section, knot_rrset_t *rr, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
 {
-       const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
-       knot_dname_t name_buf[KNOT_DNAME_MAXLEN];
-       knot_dname_to_wire(name_buf, knot_pkt_qname(pkt), sizeof(name_buf));
-
-       /* Cache only direct answer. */
-       knot_rrset_t cache_rr;
-       knot_rrset_init(&cache_rr, name_buf, KNOT_RRTYPE_CNAME, knot_pkt_qclass(pkt));
-       int ret = merge_in_section(&cache_rr, an, 0, pool);
-       if (ret != KNOT_EOK) {
-               return ret;
-       }
-
        /* Cache CNAME chain. */
-       while(cache_rr.rrs.rr_count > 0) {
-               /* Cache the merged RRSet (may fail) */
-               (void) kr_cache_insert(txn, &cache_rr, timestamp);
-               /* Follow the chain */
-               knot_dname_to_wire(name_buf, knot_ns_name(&cache_rr.rrs, 0), sizeof(name_buf));
-               knot_rdataset_clear(&cache_rr.rrs, pool);
-               ret = merge_in_section(&cache_rr, an, 0, pool);
+       int ret = KNOT_EOK;
+       uint16_t orig_rrtype = rr->type;
+       rr->type = KNOT_RRTYPE_CNAME;
+       while((merge_in_section(rr, section, 0, pool)) == KNOT_EOK) {
+               /* Cache the merged RRSet */
+               ret = kr_cache_insert(txn, rr, timestamp);
                if (ret != KNOT_EOK) {
                        return ret;
                }
+               /* Follow the chain */
+               rr->owner = (knot_dname_t *)knot_ns_name(&rr->rrs, 0);
+               knot_rdataset_clear(&rr->rrs, pool);
+
        }
 
        /* Now there may be a terminal record. */
-       cache_rr.type = knot_pkt_qtype(pkt);
-       knot_rdataset_clear(&cache_rr.rrs, pool);
-       ret = merge_in_section(&cache_rr, an, 0, pool);
+       rr->type = orig_rrtype;
+       ret = merge_in_section(rr, section, 0, pool);
        if (ret == KNOT_EOK) {
-               kr_cache_insert(txn, &cache_rr, timestamp);
+               kr_cache_insert(txn, rr, timestamp);
+               knot_rdataset_clear(&rr->rrs, pool);
        }
 
        return ret;
 }
 
-/*! \brief Cache stub nameservers. */
-static int update_cache_authority(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+/*! \brief Cache direct answer. */
+static int write_cache_answer(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
 {
-       bool found_ns_rr = false;
        knot_rrset_t cache_rr;
+       knot_rrset_init(&cache_rr, (knot_dname_t *)knot_pkt_qname(pkt), knot_pkt_qtype(pkt), knot_pkt_qclass(pkt));
 
-       /* Take first NS and merge with rest. */
+       const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
+       return write_cache_rr(an, &cache_rr, txn, pool, timestamp);
+}
+
+/*! \brief Cache stub nameservers. */
+static int write_cache_authority(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+{
+       knot_rrset_t glue_rr = { NULL, 0, 0 };
+       knot_rrset_t cache_rr = { NULL, 0, 0 };
        const knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
+       const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
+       static const uint16_t type_list[] = { KNOT_RRTYPE_A, KNOT_RRTYPE_AAAA };
+
+       /* Scan for NS records, cache glue. */
        for (unsigned i = 0; i < ns->count; ++i) {
                const knot_rrset_t *rr = knot_pkt_rr(ns, i);
                if (rr->type == KNOT_RRTYPE_NS) {
-                       knot_rrset_init(&cache_rr, (knot_dname_t *)rr->owner, rr->type, rr->rclass);
-                       found_ns_rr = true;
-                       break;
+                       /* Cache glue (if contains) */
+                       for (unsigned i = 0; i < sizeof(type_list)/sizeof(uint16_t); ++i) {
+                               knot_dname_t *owner = (knot_dname_t *)knot_ns_name(&rr->rrs, 0);
+                               knot_rrset_init(&glue_rr, owner, type_list[i], rr->rclass);
+                               (void) write_cache_rr(ar, &glue_rr, txn, pool, timestamp);
+                       }
+                       /* Keep first NS */
+                       if (cache_rr.owner == NULL) {
+                               knot_rrset_init(&cache_rr, (knot_dname_t *)rr->owner, rr->type, rr->rclass);
+                       }
                }
        }
 
-       /* Not found any viable NS */
-       if (!found_ns_rr) {
-               return KNOT_EOK;
-       }
-
-       int ret = merge_in_section(&cache_rr, ns, 0, pool);
-       if (ret != KNOT_EOK) {
-               return ret;
-       }
-
-       /* Cache the merged RRSet (may fail) */
-       return kr_cache_insert(txn, &cache_rr, timestamp);
-}
-
-static void update_cache_pkt(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
-{
-       /* Cache only positive answers. */
-       if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) {
-               return;
-       }
-
-       /* If authoritative, cache answer for current query. */
-       int ret = KNOT_EOK;
-       if (knot_wire_get_aa(pkt->wire)) {
-               ret = update_cache_answer(pkt, txn, pool, timestamp);
-       } else {
-               /* Cache authority records, but not glue. */
-               ret = update_cache_authority(pkt, txn, pool, timestamp);
+       /* Merge and cache NS record. */
+       if (cache_rr.owner == NULL) {
+               return KNOT_ENOENT;
        }
 
-       /* Cache full, do what we must. */
-       if (ret == KNOT_ESPACE) {
-               kr_cache_clear(txn);
-       }
+       return write_cache_rr(ns, &cache_rr, txn, pool, timestamp);
 }
 
-static int update_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
+static int write_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
 {
        struct kr_layer_param *param = ctx->data;
        struct kr_query *last_query = kr_rplan_last(param->rplan);
@@ -263,14 +247,31 @@ static int update_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
        }
 
        /* Open write transaction */
+       mm_ctx_t *pool = param->rplan->pool;
        uint32_t timestamp = last_query->timestamp.tv_sec;
        namedb_txn_t *txn = kr_rplan_txn_acquire(param->rplan, 0);
        if (txn == NULL) {
                return ctx->state; /* Couldn't acquire cache, ignore. */
        }
 
-       /* Selectively cache records from the packet. */
-       update_cache_pkt(pkt, txn, param->rplan->pool, timestamp);
+       /* Cache only positive answers. */
+       /*! \todo Negative answers cache support */
+       if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) {
+               return ctx->state;
+       }
+
+       /* If authoritative, cache answer for current query. */
+       int ret = KNOT_EOK;
+       if (knot_wire_get_aa(pkt->wire)) {
+               ret = write_cache_answer(pkt, txn, pool, timestamp);
+       } else {
+               ret = write_cache_authority(pkt, txn, pool, timestamp);
+       }
+
+       /* Cache full, do what we must. */
+       if (ret == KNOT_ESPACE) {
+               kr_cache_clear(txn);
+       }
 
        return ctx->state;
 }
@@ -280,8 +281,8 @@ static const knot_layer_api_t LAYER_ITERCACHE_MODULE = {
         &begin,
         NULL,
         NULL,
-        &update_cache,
-        &query_cache,
+        &write_cache,
+        &read_cache,
         NULL
 };