diff options
-rw-r--r-- | logger.c | 2 | ||||
-rw-r--r-- | memcached.c | 5 | ||||
-rw-r--r-- | memcached.h | 5 | ||||
-rw-r--r-- | storage.c | 31 | ||||
-rw-r--r-- | t/extstore.t | 30 |
5 files changed, 59 insertions, 14 deletions
@@ -66,7 +66,7 @@ static const entry_details default_entries[] = { "type=compact_read_start id=%lu offset=%llu" }, [LOGGER_COMPACT_READ_END] = {LOGGER_TEXT_ENTRY, 512, LOG_SYSEVENTS, - "type=compact_read_end id=%lu offset=%llu rescues=%lu lost=%lu" + "type=compact_read_end id=%lu offset=%llu rescues=%lu lost=%lu skipped=%lu" }, [LOGGER_COMPACT_END] = {LOGGER_TEXT_ENTRY, 512, LOG_SYSEVENTS, "type=compact_end id=%lu" diff --git a/memcached.c b/memcached.c index 9302580..c848360 100644 --- a/memcached.c +++ b/memcached.c @@ -3102,6 +3102,11 @@ static void server_stats(ADD_STAT add_stats, conn *c) { APPEND_STAT("log_watcher_sent", "%llu", (unsigned long long)stats.log_watcher_sent); STATS_UNLOCK(); #ifdef EXTSTORE + STATS_LOCK(); + APPEND_STAT("extstore_compact_lost", "%llu", (unsigned long long)stats.extstore_compact_lost); + APPEND_STAT("extstore_compact_rescues", "%llu", (unsigned long long)stats.extstore_compact_rescues); + APPEND_STAT("extstore_compact_skipped", "%llu", (unsigned long long)stats.extstore_compact_skipped); + STATS_UNLOCK(); extstore_get_stats(c->thread->storage, &st); APPEND_STAT("extstore_page_allocs", "%llu", (unsigned long long)st.page_allocs); APPEND_STAT("extstore_page_evictions", "%llu", (unsigned long long)st.page_evictions); diff --git a/memcached.h b/memcached.h index 97c78f6..b1eab10 100644 --- a/memcached.h +++ b/memcached.h @@ -319,6 +319,11 @@ struct stats { uint64_t log_worker_written; /* logs written by worker threads */ uint64_t log_watcher_skipped; /* logs watchers missed */ uint64_t log_watcher_sent; /* logs sent to watcher buffers */ +#ifdef EXTSTORE + uint64_t extstore_compact_lost; /* items lost because they were locked */ + uint64_t extstore_compact_rescues; /* items re-written during compaction */ + uint64_t extstore_compact_skipped; /* unhit items skipped during compaction */ +#endif struct timeval maxconns_entered; /* last time maxconns entered */ }; @@ -95,8 +95,8 @@ int lru_maintainer_store(void *storage, const int clsid) { * compaction, up to a desired target when all pages are full. */ static int storage_compact_check(void *storage, logger *l, - uint32_t *page_id, - uint64_t *page_version, uint64_t *page_size) { + uint32_t *page_id, uint64_t *page_version, + uint64_t *page_size, bool *drop_unread) { struct extstore_stats st; int x; double rate; @@ -114,6 +114,10 @@ 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, @@ -158,11 +162,12 @@ struct storage_compact_wrap { }; static void storage_compact_readback(void *storage, logger *l, - char *readback_buf, + bool drop_unread, char *readback_buf, uint32_t page_id, uint64_t page_version, uint64_t read_size) { uint64_t offset = 0; unsigned int rescues = 0; unsigned int lost = 0; + unsigned int skipped = 0; while (offset < read_size) { item *hdr_it = NULL; @@ -190,7 +195,12 @@ static void storage_compact_readback(void *storage, logger *l, if (hdr->page_id == page_id && hdr->page_version == page_version) { // Item header is still completely valid. extstore_delete(storage, page_id, page_version, 1, ntotal); - do_write = true; + if (drop_unread && (hdr_it->it_flags & ITEM_FETCHED) == 0) { + do_write = false; + skipped++; + } else { + do_write = true; + } } } @@ -233,8 +243,13 @@ static void storage_compact_readback(void *storage, logger *l, break; } + STATS_LOCK(); + stats.extstore_compact_lost += lost; + stats.extstore_compact_rescues += rescues; + stats.extstore_compact_skipped += skipped; + STATS_UNLOCK(); LOGGER_LOG(l, LOG_SYSEVENTS, LOGGER_COMPACT_READ_END, - NULL, page_id, offset, rescues, lost); + NULL, page_id, offset, rescues, lost, skipped); } static void _storage_compact_cb(void *e, obj_io *io, int ret) { @@ -262,6 +277,7 @@ static void *storage_compact_thread(void *arg) { uint64_t page_size = 0; uint64_t page_offset = 0; uint32_t page_id = 0; + bool drop_unread = false; char *readback_buf = NULL; struct storage_compact_wrap wrap; @@ -291,7 +307,7 @@ static void *storage_compact_thread(void *arg) { } if (!compacting && storage_compact_check(storage, l, - &page_id, &page_version, &page_size)) { + &page_id, &page_version, &page_size, &drop_unread)) { page_offset = 0; compacting = true; LOGGER_LOG(l, LOG_SYSEVENTS, LOGGER_COMPACT_START, @@ -319,7 +335,7 @@ static void *storage_compact_thread(void *arg) { } else if (wrap.submitted && wrap.done) { LOGGER_LOG(l, LOG_SYSEVENTS, LOGGER_COMPACT_READ_START, NULL, page_id, page_offset); - storage_compact_readback(storage, l, + storage_compact_readback(storage, l, drop_unread, readback_buf, page_id, page_version, settings.ext_wbuf_size); page_offset += settings.ext_wbuf_size; wrap.done = false; @@ -328,6 +344,7 @@ 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 b20a6ff..4b610c0 100644 --- a/t/extstore.t +++ b/t/extstore.t @@ -63,15 +63,17 @@ mem_get_is($sock, "foo", "hi"); cmp_ok($stats->{extstore_objects_used}, '>', $stats2->{extstore_objects_used}, 'objects used dropped after deletions'); is($stats2->{badcrc_from_extstore}, 0, 'CRC checks successful'); + + # delete the rest + for (1 .. $keycount) { + next unless $_ % 2 == 1; + print $sock "delete nfoo$_ noreply\r\n"; + } } -# TODO: no compaction counters exist. -# could watch log entries? need to disable lru crawler to reduce noise. -# fill to compaction. or add the counters... -# check counters -# + # fill to eviction { - my $keycount = 2000; + my $keycount = 3000; for (1 .. $keycount) { print $sock "set mfoo$_ 0 0 20000 noreply\r\n$value\r\n"; } @@ -82,6 +84,18 @@ mem_get_is($sock, "foo", "hi"); cmp_ok($stats->{extstore_page_evictions}, '>', 0, 'at least one page evicted'); cmp_ok($stats->{extstore_objects_evicted}, '>', 0, 'at least one object evicted'); cmp_ok($stats->{extstore_bytes_evicted}, '>', 0, 'some bytes evicted'); + is($stats->{extstore_pages_free}, 0, '0 pages are free'); + + for (1 .. $keycount) { + next unless $_ % 2 == 0; + print $sock "delete mfoo$_ noreply\r\n"; + } + + sleep 4; + $stats = mem_stats($sock); + 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'); } # attempt to incr/decr/append/prepend or chunk objects that were sent to disk. @@ -104,3 +118,7 @@ mem_get_is($sock, "foo", "hi"); } done_testing(); + +END { + unlink $ext_path; +} |