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);
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);
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, ×tamp) == 0) {
+ return kr_error(EPERM);
+ }
+ }
+
/* LMDB can do late write and avoid copy */
txn->owner->stats.insert += 1;
if (db_api == namedb_lmdb_api()) {
if (ret != 0) {
return ret;
}
+ if (rank) {
+ *rank = entry->rank;
+ }
rr->rrs.rr_count = entry->count;
rr->rrs.data = entry->data;
return kr_ok();
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;