From 1d439ec2b61ba92b67558a28b48891f848814eb0 Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Tue, 21 Oct 2014 15:22:33 +0200 Subject: [PATCH] memcache: try to handle hashtable resize failure Big hashtables may fail to resize. Let's not crash when this happens but evict some items and continue. --- apps/memcached/memcached.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/memcached/memcached.cc b/apps/memcached/memcached.cc index 65baf20af4..d8b7c52d37 100644 --- a/apps/memcached/memcached.cc +++ b/apps/memcached/memcached.cc @@ -145,6 +145,7 @@ struct cache_stats { size_t _expired {}; size_t _evicted {}; size_t _bytes {}; + size_t _resize_failure {}; }; enum class cas_result { @@ -238,13 +239,27 @@ private: if (_cache.size() >= _resize_up_threshold) { auto new_size = _cache.bucket_count() * 2; auto old_buckets = _buckets; - _buckets = new cache_type::bucket_type[new_size]; + try { + _buckets = new cache_type::bucket_type[new_size]; + } catch (const std::bad_alloc& e) { + _stats._resize_failure++; + evict(100); // In order to amortize the cost of resize failure + return; + } _cache.rehash(cache_type::bucket_traits(_buckets, new_size)); delete[] old_buckets; _resize_up_threshold = _cache.bucket_count() * load_factor; } } + // Evicts at most @count items. + void evict(size_t count) { + while (!_lru.empty() && count--) { + erase(_lru.back()); + _stats._evicted++; + } + } + void reclaim(size_t target) { size_t reclaimed_so_far = 0; @@ -570,6 +585,8 @@ private: return print_stat(out, "seastar.load", to_sstring_sprintf(v, "%.2lf")); }).then([this, &out, v = _cache.stats()._expired] { return print_stat(out, "seastar.expired", v); + }).then([this, &out, v = _cache.stats()._resize_failure] { + return print_stat(out, "seastar.resize_failure", v); }).then([this, &out, v = _cache.stats()._evicted] { return print_stat(out, "evicted", v); }).then([this, &out, v = _cache.stats()._bytes] {