summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2011-09-28 14:09:59 -0700
committerdormando <dormando@rydia.net>2011-09-28 14:09:59 -0700
commit1db1de38283fdd3f5cdc556ac9ca9cb05892a75d (patch)
tree7ed5d308e6e728b08dc6bb4f547e1c5e7687c028
parent108e2cd600ed2c698222b4ac7d90301c23d4810a (diff)
downloadmemcached-1db1de38283fdd3f5cdc556ac9ca9cb05892a75d.tar.gz
Allow setting initial size of the hash table
Instances which run many millions of items can now have its hash table presized. This can avoid some minor memory churn during the warmup period.
-rw-r--r--assoc.c7
-rw-r--r--assoc.h2
-rw-r--r--memcached.c32
-rw-r--r--memcached.h4
4 files changed, 39 insertions, 6 deletions
diff --git a/assoc.c b/assoc.c
index 7ab3aec..9500b00 100644
--- a/assoc.c
+++ b/assoc.c
@@ -32,7 +32,7 @@ typedef unsigned long int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1; /* unsigned 1-byte quantities */
/* how many powers of 2's worth of buckets we use */
-static unsigned int hashpower = 16;
+static unsigned int hashpower = HASHPOWER_DEFAULT;
#define hashsize(n) ((ub4)1<<(n))
#define hashmask(n) (hashsize(n)-1)
@@ -58,7 +58,10 @@ static bool expanding = false;
*/
static unsigned int expand_bucket = 0;
-void assoc_init(void) {
+void assoc_init(const int hashtable_init) {
+ if (hashtable_init) {
+ hashpower = hashtable_init;
+ }
primary_hashtable = calloc(hashsize(hashpower), sizeof(void *));
if (! primary_hashtable) {
fprintf(stderr, "Failed to init hashtable.\n");
diff --git a/assoc.h b/assoc.h
index dbb1caf..031958b 100644
--- a/assoc.h
+++ b/assoc.h
@@ -1,5 +1,5 @@
/* associative array */
-void assoc_init(void);
+void assoc_init(const int hashpower_init);
item *assoc_find(const char *key, const size_t nkey);
int assoc_insert(item *item);
void assoc_delete(const char *key, const size_t nkey);
diff --git a/memcached.c b/memcached.c
index 4603aca..a548eb2 100644
--- a/memcached.c
+++ b/memcached.c
@@ -216,6 +216,7 @@ static void settings_init(void) {
settings.binding_protocol = negotiating_prot;
settings.item_size_max = 1024 * 1024; /* The famous 1MB upper limit. */
settings.maxconns_fast = false;
+ settings.hashpower_init = 0;
}
/*
@@ -2591,6 +2592,7 @@ static void process_stat_settings(ADD_STAT add_stats, void *c) {
APPEND_STAT("auth_enabled_sasl", "%s", settings.sasl ? "yes" : "no");
APPEND_STAT("item_size_max", "%d", settings.item_size_max);
APPEND_STAT("maxconns_fast", "%s", settings.maxconns_fast ? "yes" : "no");
+ APPEND_STAT("hashpower_init", "%d", settings.hashpower_init);
}
static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
@@ -4397,7 +4399,12 @@ static void usage(void) {
#endif
printf("-o Comma separated list of extended or experimental options\n"
" - (EXPERIMENTAL) maxconns_fast: immediately close new\n"
- " connections if over maxconns limit\n");
+ " connections if over maxconns limit\n"
+ " - hashpower: An integer multiplier for how large the hash\n"
+ " table should be. Can be grown at runtime if not big enough.\n"
+ " Set this based on \"STAT hash_power_level\" before a \n"
+ " restart.\n"
+ );
return;
}
@@ -4614,10 +4621,12 @@ int main (int argc, char **argv) {
char *subopts;
char *subopts_value;
enum {
- MAXCONNS_FAST = 0
+ MAXCONNS_FAST = 0,
+ HASHPOWER_INIT
};
char *const subopts_tokens[] = {
[MAXCONNS_FAST] = "maxconns_fast",
+ [HASHPOWER_INIT] = "hashpower",
NULL
};
@@ -4846,6 +4855,23 @@ int main (int argc, char **argv) {
case MAXCONNS_FAST:
settings.maxconns_fast = true;
break;
+ case HASHPOWER_INIT:
+ if (subopts_value == NULL) {
+ fprintf(stderr, "Missing numeric argument for hashpower\n");
+ return 1;
+ }
+ settings.hashpower_init = atoi(subopts_value);
+ if (settings.hashpower_init < 12) {
+ fprintf(stderr, "Initial hashtable multiplier of %d is too low\n",
+ settings.hashpower_init);
+ return 1;
+ } else if (settings.hashpower_init > 64) {
+ fprintf(stderr, "Initial hashtable multiplier of %d is too high\n"
+ "Choose a value based on \"STAT hash_power_level\" from a running instance\n",
+ settings.hashpower_init);
+ return 1;
+ }
+ break;
default:
printf("Illegal suboption \"%s\"\n", subopts_value);
return 1;
@@ -4979,7 +5005,7 @@ int main (int argc, char **argv) {
/* initialize other stuff */
stats_init();
- assoc_init();
+ assoc_init(settings.hashpower_init);
conn_init();
slabs_init(settings.maxbytes, settings.factor, preallocate);
diff --git a/memcached.h b/memcached.h
index c151abe..8fe9113 100644
--- a/memcached.h
+++ b/memcached.h
@@ -60,6 +60,9 @@
#define MIN_BIN_PKT_LENGTH 16
#define BIN_PKT_HDR_WORDS (MIN_BIN_PKT_LENGTH/sizeof(uint32_t))
+/* Initial power multiplier for the hash table */
+#define HASHPOWER_DEFAULT 16
+
/* unistd.h is here */
#if HAVE_UNISTD_H
# include <unistd.h>
@@ -293,6 +296,7 @@ struct settings {
int item_size_max; /* Maximum item size, and upper end for slabs */
bool sasl; /* SASL on/off */
bool maxconns_fast; /* Whether or not to early close connections */
+ int hashpower_init; /* Starting hash power level */
};
extern struct stats stats;