cache: support expired domain prefetch
This commit is contained in:
@@ -243,7 +243,7 @@ struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *pack
|
||||
return (struct dns_cache_data *)cache_packet;
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
int _dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, int inactive, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache_data *old_cache_data = NULL;
|
||||
@@ -269,11 +269,19 @@ int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
dns_cache->info.qtype = qtype;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.speed = speed;
|
||||
time(&dns_cache->info.insert_time);
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
dns_cache->cache_data = cache_data;
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
|
||||
if (inactive == 0) {
|
||||
time(&dns_cache->info.insert_time);
|
||||
time(&dns_cache->info.replace_time);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
} else {
|
||||
time(&dns_cache->info.replace_time);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
dns_cache_data_free(old_cache_data);
|
||||
@@ -281,6 +289,16 @@ int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(domain, ttl, qtype, speed, 0, cache_data);
|
||||
}
|
||||
|
||||
int dns_cache_replace_inactive(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(domain, ttl, qtype, speed, 1, cache_data);
|
||||
}
|
||||
|
||||
int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
@@ -354,6 +372,7 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
info.speed = speed;
|
||||
time(&info.insert_time);
|
||||
time(&info.replace_time);
|
||||
|
||||
return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list);
|
||||
}
|
||||
@@ -418,7 +437,7 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
return ttl;
|
||||
}
|
||||
|
||||
int dns_cache_get_cname_ttl(struct dns_cache *dns_cache)
|
||||
int dns_cache_get_cname_ttl(struct dns_cache *dns_cache)
|
||||
{
|
||||
time_t now;
|
||||
int ttl = 0;
|
||||
@@ -444,10 +463,10 @@ int dns_cache_get_cname_ttl(struct dns_cache *dns_cache)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ttl;
|
||||
return ttl;
|
||||
}
|
||||
|
||||
int dns_cache_is_soa(struct dns_cache *dns_cache)
|
||||
int dns_cache_is_soa(struct dns_cache *dns_cache)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
return 0;
|
||||
@@ -502,12 +521,14 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
}
|
||||
|
||||
void _dns_cache_remove_expired_ttl(time_t *now)
|
||||
void _dns_cache_remove_expired_ttl(dns_cache_callback inactive_precallback, int ttl_inactive_pre, time_t *now)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp;
|
||||
int ttl = 0;
|
||||
LIST_HEAD(checklist);
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.inactive_list, list)
|
||||
{
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - *now;
|
||||
@@ -515,15 +536,42 @@ void _dns_cache_remove_expired_ttl(time_t *now)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dns_cache_head.inactive_list_expired + ttl > 0) {
|
||||
if (dns_cache_head.inactive_list_expired + ttl < 0) {
|
||||
_dns_cache_remove(dns_cache);
|
||||
continue;
|
||||
}
|
||||
|
||||
_dns_cache_remove(dns_cache);
|
||||
ttl = dns_cache->info.replace_time + dns_cache->info.ttl - *now;
|
||||
if (ttl > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dns_cache->del_pending == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
||||
if (inactive_precallback && ttl_inactive_pre < -ttl) {
|
||||
list_add_tail(&dns_cache->check_list, &checklist);
|
||||
dns_cache_get(dns_cache);
|
||||
dns_cache->del_pending = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
||||
{
|
||||
/* run inactive_precallback */
|
||||
if (inactive_precallback) {
|
||||
inactive_precallback(dns_cache);
|
||||
}
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
}
|
||||
|
||||
void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, dns_cache_callback inactive_precallback,
|
||||
int ttl_inactive_pre)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp;
|
||||
@@ -542,7 +590,7 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - now;
|
||||
if (ttl > 0 && ttl < ttl_pre) {
|
||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
||||
if (callback && dns_cache->del_pending == 0) {
|
||||
if (precallback && dns_cache->del_pending == 0) {
|
||||
list_add_tail(&dns_cache->check_list, &checklist);
|
||||
dns_cache_get(dns_cache);
|
||||
dns_cache->del_pending = 1;
|
||||
@@ -558,18 +606,17 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
if (dns_cache_head.enable_inactive && dns_cache_head.inactive_list_expired != 0) {
|
||||
_dns_cache_remove_expired_ttl(&now);
|
||||
_dns_cache_remove_expired_ttl(inactive_precallback, ttl_inactive_pre, &now);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
||||
{
|
||||
/* run callback */
|
||||
if (callback) {
|
||||
callback(dns_cache);
|
||||
if (precallback) {
|
||||
precallback(dns_cache);
|
||||
}
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ struct dns_cache_info {
|
||||
int speed;
|
||||
int hitnum_update_add;
|
||||
time_t insert_time;
|
||||
time_t replace_time;
|
||||
dns_type_t qtype;
|
||||
};
|
||||
|
||||
@@ -124,6 +125,8 @@ int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_replace_inactive(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype);
|
||||
@@ -138,9 +141,10 @@ int dns_cache_hitnum_dec_get(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_update(struct dns_cache *dns_cache);
|
||||
|
||||
typedef void dns_cache_preinvalid_callback(struct dns_cache *dns_cache);
|
||||
typedef void dns_cache_callback(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre);
|
||||
void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, dns_cache_callback inactive_precallback,
|
||||
int ttl_inactive_pre);
|
||||
|
||||
int dns_cache_get_ttl(struct dns_cache *dns_cache);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ int dns_conf_max_reply_ip_num = DNS_MAX_REPLY_IP_NUM;
|
||||
int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
|
||||
int dns_conf_prefetch = 0;
|
||||
int dns_conf_serve_expired = 1;
|
||||
int dns_conf_serve_expired_ttl = 0;
|
||||
int dns_conf_serve_expired_ttl = 24 * 3600; /* 1 day */
|
||||
int dns_conf_serve_expired_reply_ttl = 3;
|
||||
|
||||
/* upstream servers */
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#define SOCKET_IP_TOS (IPTOS_LOWDELAY | IPTOS_RELIABILITY)
|
||||
#define SOCKET_PRIORITY (6)
|
||||
#define CACHE_AUTO_ENABLE_SIZE (1024 * 1024 * 128)
|
||||
#define EXPIRED_DOMAIN_PREFTCH_TIME (3600 * 8)
|
||||
|
||||
#define RECV_ERROR_AGAIN 1
|
||||
#define RECV_ERROR_OK 0
|
||||
@@ -216,6 +217,7 @@ struct dns_request {
|
||||
int passthrough;
|
||||
int request_wait;
|
||||
int prefetch;
|
||||
int prefetch_expired_domain;
|
||||
|
||||
int dualstack_selection;
|
||||
int dualstack_selection_force_soa;
|
||||
@@ -256,7 +258,7 @@ static tlog_log *dns_audit;
|
||||
|
||||
static int is_ipv6_ready;
|
||||
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags,
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain, uint32_t server_flags,
|
||||
struct dns_query_options *options);
|
||||
static int _dns_server_get_answer(struct dns_server_post_context *context);
|
||||
static void _dns_server_request_get(struct dns_request *request);
|
||||
@@ -314,7 +316,7 @@ static void _dns_server_set_dualstack_selection(struct dns_request *request)
|
||||
{
|
||||
struct dns_rule_flags *rule_flag = NULL;
|
||||
|
||||
if (request->dualstack_selection_query) {
|
||||
if (request->dualstack_selection_query || request->prefetch_expired_domain == 1) {
|
||||
request->dualstack_selection = 0;
|
||||
return;
|
||||
}
|
||||
@@ -931,8 +933,14 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
if (request->prefetch_expired_domain == 0) {
|
||||
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
if (dns_cache_replace_inactive(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
@@ -1058,8 +1066,14 @@ int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
if (dns_cache_replace(request->cname, ttl, context->qtype, speed, cache_packet) != 0) {
|
||||
goto errout;
|
||||
if (request->prefetch_expired_domain == 0) {
|
||||
if (dns_cache_replace(request->cname, ttl, context->qtype, speed, cache_packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
if (dns_cache_replace_inactive(request->cname, ttl, context->qtype, speed, cache_packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
@@ -3480,7 +3494,7 @@ out_update_cache:
|
||||
options.enable_flag |= DNS_QUEY_OPTION_ECS_DNS;
|
||||
memcpy(&options.ecs_dns, &request->ecs, sizeof(options.ecs_dns));
|
||||
}
|
||||
_dns_server_prefetch_request(request->domain, request->qtype, server_flags, &options);
|
||||
_dns_server_prefetch_request(request->domain, request->qtype, 0, server_flags, &options);
|
||||
} else {
|
||||
dns_cache_update(dns_cache);
|
||||
}
|
||||
@@ -3564,9 +3578,10 @@ static void _dns_server_request_set_id(struct dns_request *request, unsigned sho
|
||||
request->id = id;
|
||||
}
|
||||
|
||||
static void _dns_server_request_set_enable_prefetch(struct dns_request *request)
|
||||
static void _dns_server_request_set_enable_prefetch(struct dns_request *request, int expired_domain)
|
||||
{
|
||||
request->prefetch = 1;
|
||||
request->prefetch_expired_domain = expired_domain;
|
||||
}
|
||||
|
||||
static int _dns_server_request_set_client_addr(struct dns_request *request, struct sockaddr_storage *from,
|
||||
@@ -3794,6 +3809,7 @@ int _dns_server_query_dualstack(struct dns_request *request)
|
||||
request_dualstack->qtype = qtype;
|
||||
request_dualstack->dualstack_selection_query = 1;
|
||||
request_dualstack->prefetch = request->prefetch;
|
||||
request_dualstack->prefetch_expired_domain = request->prefetch_expired_domain;
|
||||
_dns_server_request_get(request);
|
||||
request_dualstack->dualstack_request = request;
|
||||
_dns_server_request_set_callback(request_dualstack, dns_server_dualstack_callback, request);
|
||||
@@ -4034,7 +4050,7 @@ static int _dns_server_prefetch_setup_options(struct dns_request *request, struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags,
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain, uint32_t server_flags,
|
||||
struct dns_query_options *options)
|
||||
{
|
||||
int ret = -1;
|
||||
@@ -4050,7 +4066,7 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t
|
||||
request->qtype = qtype;
|
||||
request->server_flags = server_flags;
|
||||
_dns_server_prefetch_setup_options(request, options);
|
||||
_dns_server_request_set_enable_prefetch(request);
|
||||
_dns_server_request_set_enable_prefetch(request, expired_domain);
|
||||
ret = _dns_server_do_query(request);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "do query %s failed.\n", request->domain);
|
||||
@@ -4480,7 +4496,19 @@ static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
||||
/* start prefetch domain */
|
||||
tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d, hitnum %d", dns_cache->info.domain, dns_cache->info.qtype,
|
||||
dns_cache->info.ttl, hitnum);
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype,
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0,
|
||||
dns_cache_get_cache_flag(dns_cache->cache_data), NULL) != 0) {
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||
}
|
||||
}
|
||||
|
||||
static void _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
|
||||
{
|
||||
/* start prefetch domain */
|
||||
tlog(TLOG_DEBUG, "expired domain, prefetch by cache %s, qtype %d, ttl %d", dns_cache->info.domain,
|
||||
dns_cache->info.qtype, dns_cache->info.ttl);
|
||||
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1,
|
||||
dns_cache_get_cache_flag(dns_cache->cache_data), NULL) != 0) {
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||
}
|
||||
@@ -4523,7 +4551,7 @@ static void _dns_server_period_run_second(void)
|
||||
}
|
||||
|
||||
if (now - 180 > last) {
|
||||
dns_cache_invalidate(NULL, 0);
|
||||
dns_cache_invalidate(NULL, 0, NULL, 0);
|
||||
tlog(TLOG_WARN, "Service paused for 180s, force invalidate cache.");
|
||||
}
|
||||
|
||||
@@ -4532,9 +4560,17 @@ static void _dns_server_period_run_second(void)
|
||||
if (sec % 2 == 0) {
|
||||
if (dns_conf_prefetch) {
|
||||
/* do pre-fetching */
|
||||
dns_cache_invalidate(_dns_server_prefetch_domain, 3);
|
||||
if (dns_conf_serve_expired) {
|
||||
int prefetch_time = dns_conf_serve_expired_ttl / 2;
|
||||
if (prefetch_time == 0 || prefetch_time > EXPIRED_DOMAIN_PREFTCH_TIME) {
|
||||
prefetch_time = EXPIRED_DOMAIN_PREFTCH_TIME;
|
||||
}
|
||||
dns_cache_invalidate(NULL, 0, _dns_server_prefetch_expired_domain, prefetch_time);
|
||||
} else {
|
||||
dns_cache_invalidate(_dns_server_prefetch_domain, 3, NULL, 0);
|
||||
}
|
||||
} else {
|
||||
dns_cache_invalidate(NULL, 0);
|
||||
dns_cache_invalidate(NULL, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user