summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2015-09-23 16:46:36 +0200
committerantirez <antirez@gmail.com>2015-10-01 13:02:25 +0200
commit9253d8507320dd1d7665a55e11e2cba3ae91c78d (patch)
tree305ccd34924ae2860cd5aec9788c3007621661fa
parent4d50d691e3fa80c9b9aef5aa0498a0a92654b324 (diff)
downloadredis-9253d8507320dd1d7665a55e11e2cba3ae91c78d.tar.gz
Threaded lazyfree WIP #1.
-rw-r--r--src/bio.c2
-rw-r--r--src/bio.h3
-rw-r--r--src/lazyfree.c26
-rw-r--r--src/server.c2
-rw-r--r--src/server.h11
5 files changed, 36 insertions, 8 deletions
diff --git a/src/bio.c b/src/bio.c
index 135b8f3b6..d0f74a296 100644
--- a/src/bio.c
+++ b/src/bio.c
@@ -185,6 +185,8 @@ void *bioProcessBackgroundJobs(void *arg) {
close((long)job->arg1);
} else if (type == BIO_AOF_FSYNC) {
aof_fsync((long)job->arg1);
+ } else if (type == BIO_LAZY_FREE) {
+ decrRefCount((robj*)job->arg1);
} else {
serverPanic("Wrong job type in bioProcessBackgroundJobs().");
}
diff --git a/src/bio.h b/src/bio.h
index eb3a2f5d8..4b15d1c4d 100644
--- a/src/bio.h
+++ b/src/bio.h
@@ -38,4 +38,5 @@ void bioKillThreads(void);
/* Background job opcodes */
#define BIO_CLOSE_FILE 0 /* Deferred close(2) syscall. */
#define BIO_AOF_FSYNC 1 /* Deferred AOF fsync. */
-#define BIO_NUM_OPS 2
+#define BIO_LAZY_FREE 2 /* Deferred objects freeing. */
+#define BIO_NUM_OPS 3
diff --git a/src/lazyfree.c b/src/lazyfree.c
index 84d4b3752..27f9a56e9 100644
--- a/src/lazyfree.c
+++ b/src/lazyfree.c
@@ -1,4 +1,7 @@
#include "server.h"
+#include "bio.h"
+
+static int lazyfree_threaded = 1; /* Use a thread to reclaim objects. */
/* Initialization of the lazy free engine. Must be called only once at server
* startup. */
@@ -97,7 +100,17 @@ size_t lazyfreeFastStep(void) {
/* Handles slow or fast collection steps. */
size_t lazyfreeStep(int type) {
- if (type == LAZYFREE_STEP_FAST) return lazyfreeFastStep();
+ /* Threaded implementaiton: only block for STEP_OOM. */
+ if (lazyfree_threaded) {
+ if (type == LAZYFREE_STEP_OOM)
+ return bioWaitStepOfType(BIO_LAZY_FREE);
+ return 0;
+ }
+
+ /* Non threaded implementation: free things incrementally avoiding
+ * to block. */
+ if (type == LAZYFREE_STEP_FAST ||
+ type == LAZYFREE_STEP_OOM) return lazyfreeFastStep();
size_t totalwork = 0;
mstime_t end = mstime()+2;
@@ -130,8 +143,12 @@ int dbAsyncDelete(redisDb *db, robj *key) {
/* If releasing the object is too much work, let's put it into the
* lazy free list. */
if (free_effort > LAZYFREE_THRESHOLD) {
- listAddNodeTail(server.lazyfree_obj,val);
- server.lazyfree_elements += free_effort;
+ if (lazyfree_threaded) {
+ bioCreateBackgroundJob(BIO_LAZY_FREE,val,NULL,NULL);
+ } else {
+ listAddNodeTail(server.lazyfree_obj,val);
+ server.lazyfree_elements += free_effort;
+ }
dictSetVal(db->dict,de,NULL);
}
}
@@ -165,6 +182,9 @@ int lazyfreeCron(struct aeEventLoop *eventLoop, long long id, void *clientData)
UNUSED(id);
UNUSED(clientData);
+ /* Threaded lazy free does not need a timer, unregister the timer event. */
+ if (lazyfree_threaded) return AE_NOMORE;
+
static size_t prev_mem;
static int timer_period = 1000; /* Defauls to 1HZ */
static double mem_trend = 0;
diff --git a/src/server.c b/src/server.c
index 98c915a3d..c5ab43b73 100644
--- a/src/server.c
+++ b/src/server.c
@@ -3330,7 +3330,7 @@ int freeMemoryIfNeeded(void) {
latencyStartMonitor(eviction_latency);
while (mem_freed < mem_tofree) {
delta = (long long) zmalloc_used_memory();
- size_t workdone = lazyfreeStep(LAZYFREE_STEP_FAST);
+ size_t workdone = lazyfreeStep(LAZYFREE_STEP_OOM);
delta -= (long long) zmalloc_used_memory();
mem_freed += delta;
if (!workdone) break; /* Lazy free list is empty. */
diff --git a/src/server.h b/src/server.h
index 3bc3a22e0..1d97d9360 100644
--- a/src/server.h
+++ b/src/server.h
@@ -1402,9 +1402,14 @@ void slotToKeyAdd(robj *key);
void slotToKeyDel(robj *key);
void slotToKeyFlush(void);
-/* Lazy free */
-#define LAZYFREE_STEP_SLOW 0
-#define LAZYFREE_STEP_FAST 1
+/* Lazy free. Note that SLOW and FAST are only useful when incremental
+ * lazy free is active. For threaded lazy free the actual freeing of objects
+ * happens in the background. Only STEP_OOM is used since it blocks waiting
+ * for the freeing thread to do some work before returning. */
+#define LAZYFREE_STEP_SLOW 0 /* Take 1-2 milliseconds to reclaim memory. */
+#define LAZYFREE_STEP_FAST 1 /* Free a few elements ASAP and return. */
+#define LAZYFREE_STEP_OOM 2 /* Free a few elements at any cost if there
+ is something to free: we are out of memory */
int dbAsyncDelete(redisDb *db, robj *key);
void initLazyfreeEngine(void);
size_t lazyfreeStep(int type);