summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--logger.c2
-rw-r--r--memcached.c5
-rw-r--r--memcached.h5
-rw-r--r--storage.c31
-rw-r--r--t/extstore.t30
5 files changed, 59 insertions, 14 deletions
diff --git a/logger.c b/logger.c
index b9165eb..082dceb 100644
--- a/logger.c
+++ b/logger.c
@@ -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 */
};
diff --git a/storage.c b/storage.c
index 0a2d9c3..3e92f2a 100644
--- a/storage.c
+++ b/storage.c
@@ -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;
+}