dns_cache: optimize dns cache.

This commit is contained in:
Nick Peng
2023-08-31 22:32:35 +08:00
parent 901baf80c0
commit c39a7b9b41
5 changed files with 197 additions and 81 deletions

View File

@@ -19,9 +19,11 @@
#include "dns_cache.h" #include "dns_cache.h"
#include "stringutil.h" #include "stringutil.h"
#include "tlog.h" #include "tlog.h"
#include "util.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h> #include <pthread.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
@@ -40,6 +42,8 @@ struct dns_cache_head {
pthread_mutex_t lock; pthread_mutex_t lock;
}; };
typedef int (*dns_cache_read_callback)(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data);
static struct dns_cache_head dns_cache_head; static struct dns_cache_head dns_cache_head;
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired) int dns_cache_init(int size, int enable_inactive, int inactive_list_expired)
@@ -127,7 +131,7 @@ static void _dns_cache_remove(struct dns_cache *dns_cache)
static void _dns_cache_move_inactive(struct dns_cache *dns_cache) static void _dns_cache_move_inactive(struct dns_cache *dns_cache)
{ {
list_del_init(&dns_cache->list); list_del(&dns_cache->list);
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list); list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
time(&dns_cache->info.replace_time); time(&dns_cache->info.replace_time);
} }
@@ -256,6 +260,24 @@ struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len
return (struct dns_cache_data *)cache_packet; return (struct dns_cache_data *)cache_packet;
} }
static void _dns_cache_insert_sorted(struct dns_cache *dns_cache, struct list_head *head)
{
time_t ttl;
struct dns_cache *tmp = NULL;
/* ascending order */
ttl = dns_cache->info.insert_time + dns_cache->info.ttl;
list_for_each_entry_reverse(tmp, head, list)
{
if ((tmp->info.insert_time + tmp->info.ttl) <= ttl) {
list_add(&dns_cache->list, &tmp->list);
return;
}
}
list_add(&dns_cache->list, head);
}
static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive, int inactive, static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive, int inactive,
struct dns_cache_data *cache_data) struct dns_cache_data *cache_data)
{ {
@@ -288,12 +310,12 @@ static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int spee
dns_cache->info.is_visited = 1; dns_cache->info.is_visited = 1;
old_cache_data = dns_cache->cache_data; old_cache_data = dns_cache->cache_data;
dns_cache->cache_data = cache_data; dns_cache->cache_data = cache_data;
list_del_init(&dns_cache->list); list_del(&dns_cache->list);
if (inactive == 0) { if (inactive == 0) {
time(&dns_cache->info.insert_time); time(&dns_cache->info.insert_time);
time(&dns_cache->info.replace_time); time(&dns_cache->info.replace_time);
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list); _dns_cache_insert_sorted(dns_cache, &dns_cache_head.cache_list);
} else { } else {
time(&dns_cache->info.replace_time); time(&dns_cache->info.replace_time);
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list); list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
@@ -354,24 +376,6 @@ static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
pthread_mutex_unlock(&dns_cache_head.lock); pthread_mutex_unlock(&dns_cache_head.lock);
} }
static void _dns_cache_insert_sorted(struct dns_cache *dns_cache, struct list_head *head)
{
time_t ttl;
struct dns_cache *tmp = NULL;
/* ascending order */
ttl = dns_cache->info.insert_time + dns_cache->info.ttl;
list_for_each_entry_reverse(tmp, head, list)
{
if ((tmp->info.insert_time + tmp->info.ttl) <= ttl) {
list_add(&dns_cache->list, &tmp->list);
return;
}
}
list_add_tail(&dns_cache->list, head);
}
static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head) static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head)
{ {
uint32_t key = 0; uint32_t key = 0;
@@ -607,8 +611,6 @@ void dns_cache_update(struct dns_cache *dns_cache)
{ {
pthread_mutex_lock(&dns_cache_head.lock); pthread_mutex_lock(&dns_cache_head.lock);
if (!list_empty(&dns_cache->list)) { if (!list_empty(&dns_cache->list)) {
list_del_init(&dns_cache->list);
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
dns_cache->info.hitnum += dns_cache->info.hitnum_update_add; dns_cache->info.hitnum += dns_cache->info.hitnum_update_add;
if (dns_cache->info.hitnum > DNS_CACHE_MAX_HITNUM) { if (dns_cache->info.hitnum > DNS_CACHE_MAX_HITNUM) {
dns_cache->info.hitnum = DNS_CACHE_MAX_HITNUM; dns_cache->info.hitnum = DNS_CACHE_MAX_HITNUM;
@@ -720,7 +722,7 @@ void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, unsigned
} }
} }
if (ttl < 0) { if (ttl <= 0) {
if (dns_cache_head.enable_inactive && dns_cache->info.no_inactive == 0) { if (dns_cache_head.enable_inactive && dns_cache->info.no_inactive == 0) {
_dns_cache_move_inactive(dns_cache); _dns_cache_move_inactive(dns_cache);
} else { } else {
@@ -745,15 +747,40 @@ void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, unsigned
} }
} }
static int _dns_cache_read_record(int fd, uint32_t cache_number) static int _dns_cache_read_to_cache(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data)
{ {
struct list_head *head = NULL;
if (cache_record->type == CACHE_RECORD_TYPE_ACTIVE) {
head = &dns_cache_head.cache_list;
} else if (cache_record->type == CACHE_RECORD_TYPE_INACTIVE) {
head = &dns_cache_head.inactive_list;
} else {
tlog(TLOG_ERROR, "read cache record type is invalid.");
goto errout;
}
if (_dns_cache_insert(&cache_record->info, cache_data, head) != 0) {
tlog(TLOG_ERROR, "insert cache data failed.");
cache_data = NULL;
goto errout;
}
daemon_keepalive();
/* keep cache_data */
return -2;
errout:
return -1;
}
static int _dns_cache_read_record(int fd, uint32_t cache_number, dns_cache_read_callback callback)
{
unsigned int i = 0; unsigned int i = 0;
ssize_t ret = 0; ssize_t ret = 0;
struct dns_cache_record cache_record; struct dns_cache_record cache_record;
struct dns_cache_data_head data_head; struct dns_cache_data_head data_head;
struct dns_cache_data *cache_data = NULL; struct dns_cache_data *cache_data = NULL;
struct list_head *head = NULL;
for (i = 0; i < cache_number; i++) { for (i = 0; i < cache_number; i++) {
ret = read(fd, &cache_record, sizeof(cache_record)); ret = read(fd, &cache_record, sizeof(cache_record));
@@ -767,15 +794,6 @@ static int _dns_cache_read_record(int fd, uint32_t cache_number)
goto errout; goto errout;
} }
if (cache_record.type == CACHE_RECORD_TYPE_ACTIVE) {
head = &dns_cache_head.cache_list;
} else if (cache_record.type == CACHE_RECORD_TYPE_INACTIVE) {
head = &dns_cache_head.inactive_list;
} else {
tlog(TLOG_ERROR, "read cache record type is invalid.");
goto errout;
}
ret = read(fd, &data_head, sizeof(data_head)); ret = read(fd, &data_head, sizeof(data_head));
if (ret != sizeof(data_head)) { if (ret != sizeof(data_head)) {
tlog(TLOG_ERROR, "read data head failed, %s", strerror(errno)); tlog(TLOG_ERROR, "read data head failed, %s", strerror(errno));
@@ -814,13 +832,15 @@ static int _dns_cache_read_record(int fd, uint32_t cache_number)
goto errout; goto errout;
} }
if (_dns_cache_insert(&cache_record.info, cache_data, head) != 0) { ret = callback(&cache_record, cache_data);
tlog(TLOG_ERROR, "insert cache data failed."); if (ret == -2) {
cache_data = NULL; cache_data = NULL;
} else if (ret != 0) {
goto errout; goto errout;
} else {
free(cache_data);
cache_data = NULL;
} }
cache_data = NULL;
} }
return 0; return 0;
@@ -831,7 +851,7 @@ errout:
return -1; return -1;
} }
int dns_cache_load(const char *file) static int _dns_cache_file_read(const char *file, dns_cache_read_callback callback)
{ {
int fd = -1; int fd = -1;
ssize_t ret = 0; ssize_t ret = 0;
@@ -864,7 +884,7 @@ int dns_cache_load(const char *file)
} }
tlog(TLOG_INFO, "load cache file %s, total %d records", file, cache_file.cache_number); tlog(TLOG_INFO, "load cache file %s, total %d records", file, cache_file.cache_number);
if (_dns_cache_read_record(fd, cache_file.cache_number) != 0) { if (_dns_cache_read_record(fd, cache_file.cache_number, callback) != 0) {
goto errout; goto errout;
} }
@@ -878,6 +898,11 @@ errout:
return -1; return -1;
} }
int dns_cache_load(const char *file)
{
return _dns_cache_file_read(file, _dns_cache_read_to_cache);
}
static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RECORD_TYPE type, struct list_head *head) static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RECORD_TYPE type, struct list_head *head)
{ {
struct dns_cache *dns_cache = NULL; struct dns_cache *dns_cache = NULL;
@@ -987,6 +1012,23 @@ errout:
return -1; return -1;
} }
static int _dns_cache_print(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data)
{
printf("domain: %s, qtype: %d, ttl: %d, speed: %.1fms\n", cache_record->info.domain, cache_record->info.qtype,
cache_record->info.ttl, (float)cache_record->info.speed / 10);
return 0;
}
int dns_cache_print(const char *file)
{
if (access(file, F_OK) != 0) {
tlog(TLOG_ERROR, "cache file %s not exist.", file);
return -1;
}
return _dns_cache_file_read(file, _dns_cache_print);
}
void dns_cache_destroy(void) void dns_cache_destroy(void)
{ {
struct dns_cache *dns_cache = NULL; struct dns_cache *dns_cache = NULL;

View File

@@ -188,6 +188,8 @@ int dns_cache_load(const char *file);
int dns_cache_save(const char *file, int check_lock); int dns_cache_save(const char *file, int check_lock);
int dns_cache_print(const char *file);
const char *dns_cache_file_version(void); const char *dns_cache_file_version(void);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -20,6 +20,7 @@
#include "smartdns.h" #include "smartdns.h"
#include "art.h" #include "art.h"
#include "atomic.h" #include "atomic.h"
#include "dns_cache.h"
#include "dns_client.h" #include "dns_client.h"
#include "dns_conf.h" #include "dns_conf.h"
#include "dns_server.h" #include "dns_server.h"
@@ -31,6 +32,7 @@
#include "util.h" #include "util.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h>
#include <libgen.h> #include <libgen.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <openssl/err.h> #include <openssl/err.h>
@@ -756,14 +758,15 @@ int main(int argc, char *argv[])
#endif #endif
{ {
int ret = 0; int ret = 0;
int is_foreground = 0; int is_run_as_daemon = 1;
int opt = 0; int opt = 0;
char config_file[MAX_LINE_LEN]; char config_file[MAX_LINE_LEN];
char pid_file[MAX_LINE_LEN]; char pid_file[MAX_LINE_LEN];
int signal_ignore = 0; int signal_ignore = 0;
sigset_t empty_sigblock; sigset_t empty_sigblock;
struct stat sb; struct stat sb;
int daemon_ret = 0;
static struct option long_options[] = {{"cache-print", required_argument, 0, 256}};
safe_strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN); safe_strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
@@ -778,10 +781,10 @@ int main(int argc, char *argv[])
sigprocmask(SIG_SETMASK, &empty_sigblock, NULL); sigprocmask(SIG_SETMASK, &empty_sigblock, NULL);
smartdns_close_allfds(); smartdns_close_allfds();
while ((opt = getopt(argc, argv, "fhc:p:SvxN:")) != -1) { while ((opt = getopt_long(argc, argv, "fhc:p:SvxN:", long_options, 0)) != -1) {
switch (opt) { switch (opt) {
case 'f': case 'f':
is_foreground = 1; is_run_as_daemon = 0;
break; break;
case 'c': case 'c':
if (full_path(config_file, sizeof(config_file), optarg) != 0) { if (full_path(config_file, sizeof(config_file), optarg) != 0) {
@@ -810,6 +813,8 @@ int main(int argc, char *argv[])
case 'h': case 'h':
_help(); _help();
return 1; return 1;
case 256:
return dns_cache_print(optarg);
} }
} }
@@ -819,20 +824,21 @@ int main(int argc, char *argv[])
goto errout; goto errout;
} }
if (is_foreground == 0 && dns_no_daemon == 0) { if (dns_no_daemon) {
daemon_ret = run_daemon(); is_run_as_daemon = 0;
if (daemon_ret < 0) { }
if (is_run_as_daemon) {
int daemon_ret = daemon_run();
if (daemon_ret != -2) {
char buff[4096]; char buff[4096];
char *log_path = realpath(_smartdns_log_path(), buff); char *log_path = realpath(_smartdns_log_path(), buff);
if (log_path != NULL && access(log_path, F_OK) == 0 && daemon_ret != -2) { if (log_path != NULL && access(log_path, F_OK) == 0 && daemon_ret != -3 && daemon_ret != 0) {
fprintf(stderr, "run daemon failed, please check log at %s\n", log_path); fprintf(stderr, "run daemon failed, please check log at %s\n", log_path);
} }
return 1;
}
if (daemon_ret == 0) { return daemon_ret;
return 0;
} }
} }
@@ -841,7 +847,7 @@ int main(int argc, char *argv[])
} }
if (strncmp(pid_file, "-", 2) != 0 && dns_no_pidfile == 0 && create_pid_file(pid_file) != 0) { if (strncmp(pid_file, "-", 2) != 0 && dns_no_pidfile == 0 && create_pid_file(pid_file) != 0) {
ret = -2; ret = -3;
goto errout; goto errout;
} }
@@ -863,8 +869,8 @@ int main(int argc, char *argv[])
goto errout; goto errout;
} }
if (daemon_ret > 0) { if (is_run_as_daemon) {
ret = daemon_kickoff(daemon_ret, 0, dns_conf_log_console | verbose_screen); ret = daemon_kickoff(0, dns_conf_log_console | verbose_screen);
if (ret != 0) { if (ret != 0) {
goto errout; goto errout;
} }
@@ -875,8 +881,8 @@ int main(int argc, char *argv[])
_smartdns_exit(); _smartdns_exit();
return ret; return ret;
errout: errout:
if (daemon_ret > 0) { if (is_run_as_daemon) {
daemon_kickoff(daemon_ret, ret, dns_conf_log_console | verbose_screen); daemon_kickoff(ret, dns_conf_log_console | verbose_screen);
} }
smartdns_test_notify(2); smartdns_test_notify(2);
return 1; return 1;

View File

@@ -103,8 +103,20 @@ struct ipset_netlink_msg {
__be16 res_id; __be16 res_id;
}; };
enum daemon_msg_type {
DAEMON_MSG_KICKOFF,
DAEMON_MSG_KEEPALIVE,
DAEMON_MSG_DAEMON_PID,
};
struct daemon_msg {
enum daemon_msg_type type;
int value;
};
static int ipset_fd; static int ipset_fd;
static int pidfile_fd; static int pidfile_fd;
static int daemon_fd;
unsigned long get_tick_count(void) unsigned long get_tick_count(void)
{ {
@@ -1609,14 +1621,20 @@ errout:
return; return;
} }
int daemon_kickoff(int fd, int status, int no_close) int daemon_kickoff(int status, int no_close)
{ {
if (fd <= 0) { struct daemon_msg msg;
if (daemon_fd <= 0) {
return -1; return -1;
} }
int ret = write(fd, &status, sizeof(status)); msg.type = DAEMON_MSG_KICKOFF;
if (ret != sizeof(status)) { msg.value = status;
int ret = write(daemon_fd, &msg, sizeof(msg));
if (ret != sizeof(msg)) {
fprintf(stderr, "notify parent process failed, %s\n", strerror(errno));
return -1; return -1;
} }
@@ -1636,12 +1654,40 @@ int daemon_kickoff(int fd, int status, int no_close)
} }
} }
close(fd); close(daemon_fd);
daemon_fd = -1;
return 0; return 0;
} }
int run_daemon() int daemon_keepalive(void)
{
struct daemon_msg msg;
static time_t last = 0;
time_t now = time(NULL);
if (daemon_fd <= 0) {
return -1;
}
if (now == last) {
return 0;
}
last = now;
msg.type = DAEMON_MSG_KEEPALIVE;
msg.value = 0;
int ret = write(daemon_fd, &msg, sizeof(msg));
if (ret != sizeof(msg)) {
return -1;
}
return 0;
}
int daemon_run(void)
{ {
pid_t pid = 0; pid_t pid = 0;
int fds[2] = {0}; int fds[2] = {0};
@@ -1660,7 +1706,6 @@ int run_daemon()
} else if (pid > 0) { } else if (pid > 0) {
struct pollfd pfd; struct pollfd pfd;
int ret = 0; int ret = 0;
int status = 0;
close(fds[1]); close(fds[1]);
@@ -1668,22 +1713,35 @@ int run_daemon()
pfd.events = POLLIN; pfd.events = POLLIN;
pfd.revents = 0; pfd.revents = 0;
ret = poll(&pfd, 1, 1000); do {
if (ret <= 0) { ret = poll(&pfd, 1, 3000);
fprintf(stderr, "run daemon process failed, wait child timeout\n"); if (ret <= 0) {
goto errout; fprintf(stderr, "run daemon process failed, wait child timeout, kill child.\n");
} goto errout;
}
if (!(pfd.revents & POLLIN)) { if (!(pfd.revents & POLLIN)) {
goto errout; goto errout;
} }
ret = read(fds[0], &status, sizeof(status)); struct daemon_msg msg;
if (ret != sizeof(status)) {
goto errout;
}
return status; ret = read(fds[0], &msg, sizeof(msg));
if (ret != sizeof(msg)) {
goto errout;
}
if (msg.type == DAEMON_MSG_KEEPALIVE) {
continue;
} else if (msg.type == DAEMON_MSG_DAEMON_PID) {
pid = msg.value;
continue;
} else if (msg.type == DAEMON_MSG_KICKOFF) {
return msg.value;
} else {
goto errout;
}
} while (true);
} }
setsid(); setsid();
@@ -1693,6 +1751,11 @@ int run_daemon()
fprintf(stderr, "double fork failed, %s\n", strerror(errno)); fprintf(stderr, "double fork failed, %s\n", strerror(errno));
_exit(1); _exit(1);
} else if (pid > 0) { } else if (pid > 0) {
struct daemon_msg msg;
int unused __attribute__((unused));
msg.type = DAEMON_MSG_DAEMON_PID;
msg.value = pid;
unused = write(fds[1], &msg, sizeof(msg));
_exit(0); _exit(0);
} }
@@ -1701,8 +1764,9 @@ int run_daemon()
goto errout; goto errout;
} }
close(fds[0]); close(fds[0]);
return fds[1];
daemon_fd = fds[1];
return -2;
errout: errout:
kill(pid, SIGKILL); kill(pid, SIGKILL);
return -1; return -1;

View File

@@ -147,9 +147,11 @@ void print_stack(void);
void close_all_fd(int keepfd); void close_all_fd(int keepfd);
int run_daemon(void); int daemon_run(void);
int daemon_kickoff(int fd, int status, int no_close); int daemon_kickoff(int status, int no_close);
int daemon_keepalive(void);
int write_file(const char *filename, void *data, int data_len); int write_file(const char *filename, void *data, int data_len);