summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2017-11-28 17:56:20 -0800
committerdormando <dormando@rydia.net>2017-11-28 17:56:20 -0800
commit81c83e803d2be797f70147e7214b2382ecadb5fc (patch)
tree54a625358371781fbbc26ac8871d960b6f0b682a
parent9716994daec8b30844c5c9bb8ee69f2dba031929 (diff)
downloadmemcached-81c83e803d2be797f70147e7214b2382ecadb5fc.tar.gz
extstore: add ext_drop_unread option + live tune
was struggling to figure out how to automatically turn this on or off, but I think it should be part of an outside process. ie; a mechanism should be able to target a specific write rate, and one of its tools for reducing the write rate should be flipping this on. there's *still* a hole where you can't trigger a compaction attempt if there's no fragmentation. I kind of want, if this feature is on, to attempt a compaction on the oldest page while dropping unread items.
-rw-r--r--memcached.c14
-rw-r--r--memcached.h1
-rw-r--r--storage.c11
-rw-r--r--t/extstore.t9
4 files changed, 28 insertions, 7 deletions
diff --git a/memcached.c b/memcached.c
index 1c4e8bf..a93f87d 100644
--- a/memcached.c
+++ b/memcached.c
@@ -4487,6 +4487,13 @@ static void process_extstore_command(conn *c, token_t *tokens, const size_t ntok
} else if (strcmp(tokens[1].value, "max_frag") == 0) {
if (!safe_strtod(tokens[2].value, &settings.ext_max_frag))
ok = false;
+ } else if (strcmp(tokens[1].value, "drop_unread") == 0) {
+ unsigned int v;
+ if (!safe_strtoul(tokens[2].value, &v)) {
+ ok = false;
+ } else {
+ settings.ext_drop_unread = v == 0 ? false : true;
+ }
} else {
ok = false;
}
@@ -6161,6 +6168,7 @@ static void usage(void) {
" - ext_item_size: store items larger than this (bytes)\n"
" - ext_item_age: store items idle at least this long\n"
" - ext_low_ttl: consider TTLs lower than this specially\n"
+ " - ext_drop_unread: don't re-write unread values during compaction\n"
" - ext_recache_rate: recache an item every N accesses\n"
" - ext_max_frag: max page fragmentation to tolerage\n"
" (see doc/storage.txt for more info)"
@@ -6499,6 +6507,7 @@ int main (int argc, char **argv) {
EXT_LOW_TTL,
EXT_RECACHE_RATE,
EXT_MAX_FRAG,
+ EXT_DROP_UNREAD,
#endif
};
char *const subopts_tokens[] = {
@@ -6553,6 +6562,7 @@ int main (int argc, char **argv) {
[EXT_LOW_TTL] = "ext_low_ttl",
[EXT_RECACHE_RATE] = "ext_recache_rate",
[EXT_MAX_FRAG] = "ext_max_frag",
+ [EXT_DROP_UNREAD] = "ext_drop_unread",
#endif
NULL
};
@@ -6573,6 +6583,7 @@ int main (int argc, char **argv) {
settings.ext_low_ttl = 0;
settings.ext_recache_rate = 2000;
settings.ext_max_frag = 0.8;
+ settings.ext_drop_unread = false;
settings.ext_wbuf_size = 1024 * 1024 * 4;
ext_cf.page_size = 1024 * 1024 * 64;
ext_cf.page_count = 64;
@@ -7221,6 +7232,9 @@ int main (int argc, char **argv) {
return 1;
}
break;
+ case EXT_DROP_UNREAD:
+ settings.ext_drop_unread = true;
+ break;
case EXT_PATH:
storage_file = strdup(subopts_value);
break;
diff --git a/memcached.h b/memcached.h
index 5a6cec8..dff66a2 100644
--- a/memcached.h
+++ b/memcached.h
@@ -412,6 +412,7 @@ struct settings {
unsigned int ext_recache_rate; /* counter++ % recache_rate == 0 > recache */
unsigned int ext_wbuf_size; /* read only note for the engine */
double ext_max_frag; /* ideal maximum page fragmentation */
+ bool ext_drop_unread; /* skip unread items during compaction */
#endif
};
diff --git a/storage.c b/storage.c
index aee0dbe..f2d4263 100644
--- a/storage.c
+++ b/storage.c
@@ -130,7 +130,7 @@ int lru_maintainer_store(void *storage, const int clsid) {
*/
static int storage_compact_check(void *storage, logger *l,
uint32_t *page_id, uint64_t *page_version,
- uint64_t *page_size, bool *drop_unread) {
+ uint64_t *page_size) {
struct extstore_stats st;
int x;
double rate;
@@ -148,10 +148,6 @@ static int storage_compact_check(void *storage, logger *l,
// the number of free pages reduces the configured frag limit
// this allows us to defrag early if pages are very empty.
rate = 1.0 - ((double)st.pages_free / st.page_count);
- // if we're nearly out of pages, drop more data ahead of eviction.
- if (st.pages_free < 2) {
- *drop_unread = true;
- }
rate *= settings.ext_max_frag;
frag_limit = st.page_size * rate;
LOGGER_LOG(l, LOG_SYSEVENTS, LOGGER_COMPACT_FRAGINFO,
@@ -348,9 +344,11 @@ static void *storage_compact_thread(void *arg) {
pthread_mutex_lock(&storage_compact_plock);
if (!compacting && storage_compact_check(storage, l,
- &page_id, &page_version, &page_size, &drop_unread)) {
+ &page_id, &page_version, &page_size)) {
page_offset = 0;
compacting = true;
+ // only allow this to flip inbetween compactions.
+ drop_unread = settings.ext_drop_unread;
LOGGER_LOG(l, LOG_SYSEVENTS, LOGGER_COMPACT_START,
NULL, page_id, page_version);
}
@@ -385,7 +383,6 @@ static void *storage_compact_thread(void *arg) {
compacting = false;
wrap.done = false;
wrap.submitted = false;
- drop_unread = false;
extstore_close_page(storage, page_id, page_version);
LOGGER_LOG(l, LOG_SYSEVENTS, LOGGER_COMPACT_END,
NULL, page_id);
diff --git a/t/extstore.t b/t/extstore.t
index 8a8180e..4963ca6 100644
--- a/t/extstore.t
+++ b/t/extstore.t
@@ -100,6 +100,13 @@ mem_get_is($sock, "foo", "hi");
is($stats->{extstore_pages_free}, 0, '0 pages are free');
is($stats->{miss_from_extstore}, 1, 'exactly one miss');
+ # refresh some keys so rescues happen while drop_unread == 1.
+ for (1 .. $keycount / 2) {
+ next unless $_ % 2 == 1;
+ print $sock "touch mfoo$_ 0 noreply\r\n";
+ }
+ print $sock "extstore drop_unread 1\r\n";
+ my $res = <$sock>;
for (1 .. $keycount) {
next unless $_ % 2 == 0;
print $sock "delete mfoo$_ noreply\r\n";
@@ -110,6 +117,8 @@ mem_get_is($sock, "foo", "hi");
cmp_ok($stats->{extstore_pages_free}, '>', 0, 'some pages now free');
cmp_ok($stats->{extstore_compact_rescues}, '>', 0, 'some compaction rescues happened');
cmp_ok($stats->{extstore_compact_skipped}, '>', 0, 'some compaction skips happened');
+ print $sock "extstore drop_unread 0\r\n";
+ $res = <$sock>;
}
# attempt to incr/decr/append/prepend or chunk objects that were sent to disk.