#include "util/log.h"
#include "util/config_file.h"
#include "util/data/msgreply.h"
+#include "util/storage/slabhash.h"
#include "services/listen_dnsport.h"
#include <signal.h>
signal_handling_record();
checklock_start();
daemon->need_to_exit = 0;
- daemon->msg_cache = lruhash_create(HASH_DEFAULT_STARTARRAY,
+ daemon->msg_cache = slabhash_create(4, HASH_DEFAULT_STARTARRAY,
HASH_DEFAULT_MAXMEM, msgreply_sizefunc, query_info_compare,
query_entry_delete, reply_info_delete, NULL);
if(!daemon->msg_cache) {
if(!daemon)
return;
listening_ports_free(daemon->ports);
- lruhash_delete(daemon->msg_cache);
+ slabhash_delete(daemon->msg_cache);
alloc_clear(&daemon->superalloc);
free(daemon->cwd);
free(daemon->pidfile);
struct config_file;
struct worker;
struct listen_port;
-struct lruhash;
+struct slabhash;
/**
* Structure holding worker list.
/** master allocation cache */
struct alloc_cache superalloc;
/** the message cache, content is struct msgreply_entry* */
- struct lruhash* msg_cache;
+ struct slabhash* msg_cache;
};
/**
#include "util/log.h"
#include "daemon/daemon.h"
#include "util/config_file.h"
+#include "util/storage/slabhash.h"
+#include "util/data/msgreply.h"
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
fatal_exit("malloc failed");
}
}
+ if(cfg->msg_cache_size != slabhash_get_size(daemon->msg_cache) ||
+ cfg->msg_cache_slabs != daemon->msg_cache->size) {
+ slabhash_delete(daemon->msg_cache);
+ daemon->msg_cache = slabhash_create(cfg->msg_cache_slabs,
+ HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
+ msgreply_sizefunc, query_info_compare,
+ query_entry_delete, reply_info_delete, NULL);
+ if(!daemon->msg_cache) {
+ fatal_exit("malloc failure updating config settings");
+ }
+ }
}
/** Read existing pid from pidfile. */
#include "daemon/daemon.h"
#include "util/netevent.h"
#include "util/config_file.h"
+#include "util/storage/slabhash.h"
#include "services/listen_dnsport.h"
#include "services/outside_network.h"
log_err("out of memory");
return 0;
}
- lruhash_insert(worker->daemon->msg_cache, worker->query_hash,
+ slabhash_insert(worker->daemon->msg_cache, worker->query_hash,
&e->entry, rep);
return 0;
}
return 1;
}
h = query_info_hash(&worker->qinfo);
- if((e=lruhash_lookup(worker->daemon->msg_cache, h, &worker->qinfo,
+ if((e=slabhash_lookup(worker->daemon->msg_cache, h, &worker->qinfo,
0))) {
/* answer from cache */
log_info("answer from the cache");
+26 March 2007: Wouter
+ - config settings for slab hash message cache.
+
23 March 2007: Wouter
- review of yesterday's commits.
- covered up memory leak of the entry locks.
# But also takes more system resources (for open sockets).
# outgoing-range: 16
+ # the amount of memory to use for the message cache.
+ # in bytes. default is 4 Mb
+ # msg-cache-size: 4194304
+
+ # the number of slabs to use for the message cache.
+ # more slabs reduce lock contention, but fracture memory usage.
+ # msg-cache-slabs: 4
+
# Enable IPv4, "yes" or "no".
# do-ip4: yes
query interface. Must be at least 1. Default is 16.
Larger numbers give more protection against spoofing attempts, but need
extra resources from the operating system.
+.It \fBmsg-cache-size:\fR <number>
+Number of bytes size of the message cache. Default is 4 megabytes.
+.It \fBmsg-cache-slabs:\fR <number>
+Number of slabs in the message cache. Slabs reduce lock contention by threads.
+Must be set to a power of 2. Setting (close) to the number of cpus is a
+reasonable guess.
.It \fBdo-ip4:\fR <yes or no>
Enable or disable whether ip4 queries are answered. Default is yes.
.It \fBdo-ip6:\fR <yes or no>
unit_assert( !str_is_ip6("213.154.224.12") );
unit_assert( !str_is_ip6("213.154.224.255") );
unit_assert( !str_is_ip6("255.255.255.0") );
+ unit_assert( is_pow2(0) );
+ unit_assert( is_pow2(1) );
+ unit_assert( is_pow2(2) );
+ unit_assert( is_pow2(4) );
+ unit_assert( is_pow2(8) );
+ unit_assert( is_pow2(16) );
+ unit_assert( is_pow2(1024) );
+ unit_assert( is_pow2(1024*1024) );
+ unit_assert( is_pow2(1024*1024*1024) );
+ unit_assert( !is_pow2(3) );
+ unit_assert( !is_pow2(5) );
+ unit_assert( !is_pow2(6) );
+ unit_assert( !is_pow2(7) );
+ unit_assert( !is_pow2(9) );
+ unit_assert( !is_pow2(10) );
+ unit_assert( !is_pow2(11) );
+ unit_assert( !is_pow2(17) );
+ unit_assert( !is_pow2(23) );
+ unit_assert( !is_pow2(257) );
+ unit_assert( !is_pow2(259) );
}
/** put dname into buffer */
cfg->do_tcp = 1;
cfg->outgoing_base_port = cfg->port + 1000;
cfg->outgoing_num_ports = 16;
+ cfg->msg_cache_size = 4 * 1024 * 1024;
+ cfg->msg_cache_slabs = 4;
if(!(cfg->fwd_address = strdup(""))) {config_delete(cfg); return NULL;}
if(!(cfg->username = strdup(""))) {config_delete(cfg); return NULL;}
if(!(cfg->chrootdir = strdup(""))) {config_delete(cfg); return NULL;}
/** outgoing port range number of ports (per thread, per if) */
int outgoing_num_ports;
+ /** size of the message cache */
+ size_t msg_cache_size;
+ /** slabs in the message cache. */
+ size_t msg_cache_slabs;
+
/** forwarder address. string. If not NULL fwder mode is enabled. */
char* fwd_address;
/** forwarder port */
directory{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DIRECTORY;}
logfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;}
pidfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;}
+msg-cache-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MSG_CACHE_SIZE;}
+msg-cache-slabs{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MSG_CACHE_SLABS;}
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
/* Quoted strings. Strip leading and ending quotes */
#include "util/configyyrename.h"
#include "util/config_file.h"
+#include "util/net_help.h"
int ub_c_lex(void);
void ub_c_error(const char *message);
%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_UDP VAR_DO_TCP
%token VAR_FORWARD_TO VAR_FORWARD_TO_PORT VAR_CHROOT
%token VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE
+%token VAR_MSG_CACHE_SIZE VAR_MSG_CACHE_SLABS
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
server_outgoing_port | server_outgoing_range | server_do_ip4 |
server_do_ip6 | server_do_udp | server_do_tcp | server_forward_to |
server_forward_to_port | server_interface | server_chroot |
- server_username | server_directory | server_logfile | server_pidfile;
+ server_username | server_directory | server_logfile | server_pidfile |
+ server_msg_cache_size | server_msg_cache_slabs;
server_num_threads: VAR_NUM_THREADS STRING
{
OUTYY(("P(server_num_threads:%s)\n", $2));
cfg_parser->cfg->pidfile = $2;
}
;
+server_msg_cache_size: VAR_MSG_CACHE_SIZE STRING
+ {
+ OUTYY(("P(server_msg_cache_size:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->msg_cache_size = atoi($2);
+ free($2);
+ }
+ ;
+server_msg_cache_slabs: VAR_MSG_CACHE_SLABS STRING
+ {
+ OUTYY(("P(server_msg_cache_slabs:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->msg_cache_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->msg_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
+ }
+ ;
%%
/* parse helper routines could be here */
}
return 1;
}
+
+int
+is_pow2(size_t num)
+{
+ if(num == 0) return 1;
+ return (num & (num-1)) == 0;
+}
*/
int fd_set_nonblock(int s);
+/**
+ * See if number is a power of 2.
+ * @param num: the value.
+ * @return: true if the number is a power of 2.
+ */
+int is_pow2(size_t num);
+
#endif /* NET_HELP_H */
lruhash_status(sl->array[i], num, extended);
}
}
+
+size_t slabhash_get_size(struct slabhash* sl)
+{
+ size_t i, total = 0;
+ for(i=0; i<sl->size; i++) {
+ lock_quick_lock(&sl->array[i]->lock);
+ total += sl->array[i]->space_max;
+ lock_quick_unlock(&sl->array[i]->lock);
+ }
+ return total;
+}
*/
void slabhash_status(struct slabhash* table, const char* id, int extended);
+/**
+ * Retrieve slab hash total size.
+ * @param table: hash table.
+ */
+size_t slabhash_get_size(struct slabhash* table);
+
#endif /* UTIL_STORAGE_SLABHASH_H */