flush data from cache.

git-svn-id: file:///svn/unbound/trunk@1268 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-09-23 14:07:02 +00:00
parent 91138fc32a
commit 16734a0e04
8 changed files with 238 additions and 4 deletions

View file

@ -59,6 +59,9 @@
#include "util/storage/slabhash.h"
#include "util/fptr_wlist.h"
#include "util/data/dname.h"
#include "validator/validator.h"
#include "validator/val_kcache.h"
#include "validator/val_kentry.h"
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
@ -982,6 +985,182 @@ do_lookup(SSL* ssl, struct worker* worker, char* arg)
free(nm);
}
/** flush a type */
static void
do_flush_type(SSL* ssl, struct worker* worker, char* arg)
{
uint8_t* nm;
int nmlabs;
size_t nmlen;
char* arg2;
uint16_t t;
if(!find_arg2(ssl, arg, &arg2))
return;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
return;
t = ldns_get_rr_type_by_name(arg2);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
t, LDNS_RR_CLASS_IN, 0);
free(nm);
send_ok(ssl);
}
/**
* Local info for deletion functions
*/
struct del_info {
/** worker */
struct worker* worker;
/** name to delete */
uint8_t* name;
/** length */
size_t len;
/** labels */
int labs;
/** time to invalidate to */
uint32_t expired;
/** number of rrsets removed */
size_t num_rrsets;
/** number of key entries removed */
size_t num_keys;
};
/** callback to delete rrsets in a zone */
static void
zone_del_rrset(struct lruhash_entry* e, void* arg)
{
/* entry is locked */
struct del_info* inf = (struct del_info*)arg;
struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key;
if(dname_subdomain_c(k->rk.dname, inf->name)) {
struct packed_rrset_data* d =
(struct packed_rrset_data*)e->data;
d->ttl = inf->expired;
inf->num_rrsets++;
}
}
/** callback to delete keys in zone */
static void
zone_del_kcache(struct lruhash_entry* e, void* arg)
{
/* entry is locked */
struct del_info* inf = (struct del_info*)arg;
struct key_entry_key* k = (struct key_entry_key*)e->key;
if(dname_subdomain_c(k->name, inf->name)) {
struct key_entry_data* d = (struct key_entry_data*)e->data;
d->ttl = inf->expired;
inf->num_keys++;
}
}
/** traverse a lruhash */
static void
lruhash_traverse(struct lruhash* h, int wr,
void (*func)(struct lruhash_entry*, void*), void* arg)
{
size_t i;
struct lruhash_entry* e;
lock_quick_lock(&h->lock);
for(i=0; i<h->size; i++) {
lock_quick_lock(&h->array[i].lock);
for(e = h->array[i].overflow_list; e; e = e->overflow_next) {
if(wr) {
lock_rw_wrlock(&e->lock);
} else {
lock_rw_rdlock(&e->lock);
}
(*func)(e, arg);
lock_rw_unlock(&e->lock);
}
lock_quick_unlock(&h->array[i].lock);
}
lock_quick_unlock(&h->lock);
}
/** traverse a slabhash */
static void
slabhash_traverse(struct slabhash* sh, int wr,
void (*func)(struct lruhash_entry*, void*), void* arg)
{
size_t i;
for(i=0; i<sh->size; i++)
lruhash_traverse(sh->array[i], wr, func, arg);
}
/** remove all rrsets and keys from zone from cache */
static void
do_flush_zone(SSL* ssl, struct worker* worker, char* arg)
{
uint8_t* nm;
int nmlabs;
size_t nmlen;
struct del_info inf;
int idx;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
return;
/* delete all RRs and key entries from zone */
/* what we do is to set them all expired */
inf.worker = worker;
inf.name = nm;
inf.len = nmlen;
inf.labs = nmlabs;
inf.expired = *worker->env.now;
inf.expired -= 3; /* handle 3 seconds skew between threads */
inf.num_rrsets = 0;
inf.num_keys = 0;
slabhash_traverse(&worker->env.rrset_cache->table, 1,
&zone_del_rrset, &inf);
/* and validator cache */
idx = modstack_find(&worker->daemon->mods, "validator");
if(idx != -1) {
struct val_env* ve = (struct val_env*)worker->env.modinfo[idx];
slabhash_traverse(ve->kcache->slab, 1, &zone_del_kcache, &inf);
}
free(nm);
(void)ssl_printf(ssl, "ok removed %u rrsets and %u key entries\n",
(unsigned)inf.num_rrsets, (unsigned)inf.num_keys);
}
/** remove name rrset from cache */
static void
do_flush_name(SSL* ssl, struct worker* worker, char* arg)
{
uint8_t* nm;
int nmlabs;
size_t nmlen;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
return;
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN, 0);
rrset_cache_remove(worker->env.rrset_cache, nm, nmlen,
LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN, 0);
free(nm);
send_ok(ssl);
}
/** execute a remote control command */
static void
execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
@ -1010,6 +1189,12 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
if(load_cache(ssl, rc->worker)) send_ok(ssl);
} else if(strncmp(p, "lookup", 6) == 0) {
do_lookup(ssl, rc->worker, skipwhite(p+6));
} else if(strncmp(p, "flush_zone", 10) == 0) {
do_flush_zone(ssl, rc->worker, skipwhite(p+10));
} else if(strncmp(p, "flush_type", 10) == 0) {
do_flush_type(ssl, rc->worker, skipwhite(p+10));
} else if(strncmp(p, "flush", 5) == 0) {
do_flush_name(ssl, rc->worker, skipwhite(p+5));
} else {
(void)ssl_printf(ssl, "error unknown command '%s'\n", p);
}

View file

@ -1,5 +1,6 @@
23 September 2008: Wouter
- Msg cache is loaded. A cache load enables cache responses.
- unbound-control flush [name], flush_type and flush_zone.
22 September 2008: Wouter
- dump_cache and load_cache statements in unbound-control.

View file

@ -37,10 +37,10 @@ load_cache
client sends cache contents (like from dump_cache), which is stored
in the cache. end of data indicated with a line with 'EOF' on it.
The data is sent after the query line.
flush_name <name>
flush <name>
flushes some information regarding the name from the cache.
removes the A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR types.
Does not remote other types.
removes the A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV, NAPTR types.
Does not remove other types.
flush_type <name> <RR type>
removes rrtype entry from the cache.
flush_zone <name>

View file

@ -56,7 +56,7 @@ not stats on SIGUSR1. perhaps also see which slow auth servers cause >1sec value
+ remote control to add/remove localinfo, redirects.
+ remote control to load/store cache contents
+ remote control to start, stop, reload.
* remote control to flush names or domains (all under a name) from the
+ remote control to flush names or domains (all under a name) from the
cache. Include NSes. And the A, AAAA for its NSes.
+ remote control to see delegation; what servers would be used to get
data for a name.

View file

@ -95,6 +95,22 @@ in old or wrong data returned to clients.
.B lookup \fIname
Print to stdout the name servers that would be used to look up the
name specified.
.TP
.B flush \fIname
Remove the name from the cache. Removes the types
A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV and NAPTR.
Because that is fast to do. Other record types can be removed using
.B flush_type
or
.B flush_zone\fR.
.TP
.B flush_type \fIname\fR \fItype
Remove the name, type information from the cache.
.TP
.B flush_zone \fIname
Remove all information at or below the name from the cache.
The rrsets and key entries are removed so that new lookups will be performed.
This needs to walk and inspect the entire cache, and is a slow operation.
.SH "EXIT CODE"
The unbound-control program exits with status code 1 on error, 0 on success.
.SH "SET UP"

View file

@ -371,3 +371,17 @@ rrset_check_sec_status(struct rrset_cache* r,
}
lock_rw_unlock(&e->lock);
}
void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
uint16_t type, uint16_t dclass, uint32_t flags)
{
struct ub_packed_rrset_key key;
key.entry.key = &key;
key.rk.dname = nm;
key.rk.dname_len = nmlen;
key.rk.rrset_class = htons(dclass);
key.rk.type = htons(type);
key.rk.flags = flags;
key.entry.hash = rrset_key_hash(&key.rk);
slabhash_remove(&r->table, key.entry.hash, &key);
}

View file

@ -209,6 +209,18 @@ void rrset_update_sec_status(struct rrset_cache* r,
void rrset_check_sec_status(struct rrset_cache* r,
struct ub_packed_rrset_key* rrset, uint32_t now);
/**
* Remove an rrset from the cache, by name and type and flags
* @param r: rrset cache
* @param nm: name of rrset
* @param nmlen: length of name
* @param type: type of rrset
* @param dclass: class of rrset, host order
* @param flags: flags of rrset, host order
*/
void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
uint16_t type, uint16_t dclass, uint32_t flags);
/** mark rrset to be deleted, set id=0 */
void rrset_markdel(void* key);

View file

@ -71,6 +71,12 @@ usage()
printf(" dump_cache print cache to stdout\n");
printf(" load_cache load cache from stdin\n");
printf(" lookup [name] print nameservers for name\n");
printf(" flush [name] flushes common types for name from cache\n");
printf(" types: A, AAAA, MX, PTR, NS,\n");
printf(" SOA, CNAME, DNAME, SRV, NAPTR\n");
printf(" flush_type [name] [type] flush name, type from cache\n");
printf(" flush_zone [name] flush everything at or under name\n");
printf(" from rr and dnssec caches\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n");
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);