Commit a56eed2b authored by Marek Vavruša's avatar Marek Vavruša

lib/cache: check entry rank and TTD before overwriting it

parent 50acb952
......@@ -156,7 +156,7 @@ static size_t cache_key(uint8_t *buf, uint8_t tag, const knot_dname_t *name, uin
return name_len + KEY_HSIZE;
}
static struct kr_cache_entry *cache_entry(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type)
static struct kr_cache_entry *lookup(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type)
{
uint8_t keybuf[KEY_SIZE];
size_t key_len = cache_key(keybuf, tag, name, type);
......@@ -175,43 +175,50 @@ static struct kr_cache_entry *cache_entry(struct kr_cache_txn *txn, uint8_t tag,
return (struct kr_cache_entry *)val.data;
}
int kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
struct kr_cache_entry **entry, uint32_t *timestamp)
static int check_lifetime(struct kr_cache_entry *found, uint32_t *timestamp)
{
if (!txn || !txn->owner || !name || !entry) {
return kr_error(EINVAL);
}
struct kr_cache_entry *found = cache_entry(txn, tag, name, type);
if (!found) {
txn->owner->stats.miss += 1;
return kr_error(ENOENT);
}
/* No time constraint */
*entry = found;
if (!timestamp) {
txn->owner->stats.hit += 1;
return kr_ok();
} else if (*timestamp <= found->timestamp) {
/* John Connor record cached in the future. */
*timestamp = 0;
txn->owner->stats.hit += 1;
return kr_ok();
} else {
/* Check if the record is still valid. */
uint32_t drift = *timestamp - found->timestamp;
if (drift <= found->ttl) {
*timestamp = drift;
txn->owner->stats.hit += 1;
return kr_ok();
}
}
txn->owner->stats.miss += 1;
return kr_error(ESTALE);
}
int kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
struct kr_cache_entry **entry, uint32_t *timestamp)
{
if (!txn || !txn->owner || !name || !entry) {
return kr_error(EINVAL);
}
struct kr_cache_entry *found = lookup(txn, tag, name, type);
if (!found) {
txn->owner->stats.miss += 1;
return kr_error(ENOENT);
}
/* Check entry lifetime */
*entry = found;
int ret = check_lifetime(found, timestamp);
if (ret == 0) {
txn->owner->stats.hit += 1;
} else {
txn->owner->stats.miss += 1;
}
return ret;
}
static void entry_write(struct kr_cache_entry *dst, struct kr_cache_entry *header, namedb_val_t data)
{
assert(dst);
......@@ -236,6 +243,17 @@ int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n
namedb_val_t entry = { NULL, sizeof(*header) + data.len };
const namedb_api_t *db_api = txn_api(txn);
/* Do not overwrite entries that are higher ranked and not expired. */
namedb_val_t old_entry = { NULL, 0 };
int ret = txn_api(txn)->find(&txn->t, &key, &old_entry, 0);
if (ret == 0) {
struct kr_cache_entry *old = old_entry.data;
uint32_t timestamp = header->timestamp;
if (kr_cache_rank_cmp(old->rank, header->rank) > 0 && check_lifetime(old, &timestamp) == 0) {
return kr_error(EPERM);
}
}
/* LMDB can do late write and avoid copy */
txn->owner->stats.insert += 1;
if (db_api == namedb_lmdb_api()) {
......@@ -298,6 +316,9 @@ int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *rank,
if (ret != 0) {
return ret;
}
if (rank) {
*rank = entry->rank;
}
rr->rrs.rr_count = entry->count;
rr->rrs.data = entry->data;
return kr_ok();
......@@ -379,6 +400,9 @@ int kr_cache_peek_rrsig(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *ra
if (ret != 0) {
return ret;
}
if (rank) {
*rank = entry->rank;
}
rr->type = KNOT_RRTYPE_RRSIG;
rr->rrs.rr_count = entry->count;
rr->rrs.data = entry->data;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment