summaryrefslogtreecommitdiff
path: root/slabs.c
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2016-06-23 15:22:15 -0700
committerdormando <dormando@rydia.net>2016-06-24 00:56:55 -0700
commit31541b371a79ead88d0f57cfa6c54958d819371c (patch)
treea49676b9eef84c55218a34e2d7297db7c537be98 /slabs.c
parent8d82383f0fc82b79975cd6e16d462b8ff0d2dd39 (diff)
downloadmemcached-31541b371a79ead88d0f57cfa6c54958d819371c.tar.gz
cache_memlimit command for tuning runtime maxbytes
Allows dynamically increasing the memory limit of a running system, if memory isn't being preallocated. If `-o modern` is in use, can also dynamically lower memory usage. pages are free()'ed back to the OS via the slab rebalancer as memory is freed up. Does not guarantee the OS will actually give the memory back for other applications to use, that depends on how the OS handles memory.
Diffstat (limited to 'slabs.c')
-rw-r--r--slabs.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/slabs.c b/slabs.c
index 879b69c..9bc42c6 100644
--- a/slabs.c
+++ b/slabs.c
@@ -446,6 +446,22 @@ static void *memory_allocate(size_t size) {
return ret;
}
+/* Must only be used if all pages are item_size_max */
+static void memory_release() {
+ void *p = NULL;
+ if (mem_base != NULL)
+ return;
+
+ if (!settings.slab_reassign)
+ return;
+
+ while (mem_malloced > mem_limit &&
+ (p = get_page_from_global_pool()) != NULL) {
+ free(p);
+ mem_malloced -= settings.item_size_max;
+ }
+}
+
void *slabs_alloc(size_t size, unsigned int id, unsigned int *total_chunks,
unsigned int flags) {
void *ret;
@@ -468,6 +484,25 @@ void slabs_stats(ADD_STAT add_stats, void *c) {
pthread_mutex_unlock(&slabs_lock);
}
+static bool do_slabs_adjust_mem_limit(size_t new_mem_limit) {
+ /* Cannot adjust memory limit at runtime if prealloc'ed */
+ if (mem_base != NULL)
+ return false;
+ settings.maxbytes = new_mem_limit;
+ mem_limit = new_mem_limit;
+ mem_limit_reached = false; /* Will reset on next alloc */
+ memory_release(); /* free what might already be in the global pool */
+ return true;
+}
+
+bool slabs_adjust_mem_limit(size_t new_mem_limit) {
+ bool ret;
+ pthread_mutex_lock(&slabs_lock);
+ ret = do_slabs_adjust_mem_limit(new_mem_limit);
+ pthread_mutex_unlock(&slabs_lock);
+ return ret;
+}
+
void slabs_adjust_mem_requested(unsigned int id, size_t old, size_t ntotal)
{
pthread_mutex_lock(&slabs_lock);
@@ -812,6 +847,9 @@ static void slab_rebalance_finish(void) {
memset(slab_rebal.slab_start, 0, (size_t)settings.item_size_max);
split_slab_page_into_freelist(slab_rebal.slab_start,
slab_rebal.d_clsid);
+ } else if (slab_rebal.d_clsid == SLAB_GLOBAL_PAGE_POOL) {
+ /* mem_malloc'ed might be higher than mem_limit. */
+ memory_release();
}
slab_rebal.done = 0;