From: Marek VavruĊĦa Date: Mon, 5 Jan 2015 00:14:14 +0000 (+0100) Subject: cache: cache glue records instead of refetching X-Git-Tag: v1.0.0-beta1~372 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1b67a2408441fd4e3ee2f94b6ef94409bcd25320;p=thirdparty%2Fknot-resolver.git cache: cache glue records instead of refetching --- diff --git a/lib/cache.c b/lib/cache.c index d9fc2ec59..7b7db6891 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -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); diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 51c1b5656..eac492102 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -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; } diff --git a/lib/layer/itercache.c b/lib/layer/itercache.c index 3bd97c428..07b31d7e8 100644 --- a/lib/layer/itercache.c +++ b/lib/layer/itercache.c @@ -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, ×tamp) != 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(¶m->rplan->zone_cut, txn, &cache_rr, timestamp); + ret = read_cache_zonecut(¶m->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 };