============================
* BRPOPLPUSH
-* RPOPLPUSH should notify blocking POP operations
* List ops like L/RPUSH L/RPOP should return the new list length.
* Save dataset / fsync() on SIGTERM
-* MULTI/EXEC should support the "EXEC FSYNC" form
-* Synchronous Virtual Memory
+* MULTI/EXEC should support the "EXEC FSYNC" form?
* BLPOP & C. tests (write a non blocking Tcl client as first step)
Virtual Memory sub-TODO:
-* Check if the page selection algorithm is working well.
+* Check if the page selection algorithm is working well
* Divide swappability of objects by refcount
-* vm-swap-file <filename>. The swap file should go where the user wants, and if it's already there and of the right size we can avoid to create it again.
* it should be possible to give the vm-max-memory option in megabyte, gigabyte, ..., just using 2GB, 100MB, and so forth.
-* redis-cli vmstat, calling INFO every second and printing VM stats ala vmstat.
-* protect zmalloc memory usage increments with a mutex
+* Try to understand what can be moved into I/O threads that currently is instead handled by the main thread. For instance swapping file table scannig to find contiguous page could be a potential candidate (but I'm not convinced it's a good idea, better to improve the algorithm, for instance double the fast forward at every step?).
-VERSION 1.6 TODO (Virtual memory)
-=================================
+* Hashes (HSET, HGET, HDEL, HEXISTS, HLEN, ...).
-* Asynchronous Virtual Memory
-* Hashes (HSET, HGET, HEXISTS, HLEN, ...).
-
-VERSION 1.8 TODO (Fault tollerant sharding)
+VERSION 2.2 TODO (Fault tolerant sharding)
===========================================
* Redis-cluster, a fast intermediate layer (proxy) that implements consistent hashing and fault tollerant nodes handling.
- http://ayende.com/Blog/archive/2009/04/06/designing-rhino-dht-a-fault-tolerant-dynamically-distributed-hash.aspx
-VERSION 2.0 TODO (Optimizations and latency)
+VERSION 2.4 TODO (Optimizations and latency)
============================================
* Lower the CPU usage.
* Use epool and alike to rewrite ae.c for Linux and other platforms suppporting fater-than-select() mutiplexing APIs.
* Implement an UDP interface for low-latency GET/SET operations.
-VERSION 2.2 TODO (Optimizations and latency)
+VERSION 2.6 TODO (Optimizations and latency)
============================================
* JSON command able to access data serialized in JSON format. For instance if I've a key foobar with a json object I can alter the "name" file using somthing like: "JSON SET foobar name Kevin". We should have GET and INCRBY as well.
* POSSIBILITY OF SUCH DAMAGE.
*/
-#define REDIS_VERSION "1.3.2"
+#define REDIS_VERSION "1.3.3"
#include "fmacros.h"
#include "config.h"
static void initClientMultiState(redisClient *c);
static void freeClientMultiState(redisClient *c);
static void queueMultiCommand(redisClient *c, struct redisCommand *cmd);
-static void unblockClient(redisClient *c);
+static void unblockClientWaitingData(redisClient *c);
static int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele);
static void vmInit(void);
static void vmMarkPagesFree(off_t page, off_t count);
{"lrange",lrangeCommand,4,REDIS_CMD_INLINE},
{"ltrim",ltrimCommand,4,REDIS_CMD_INLINE},
{"lrem",lremCommand,4,REDIS_CMD_BULK},
- {"rpoplpush",rpoplpushcommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
+ {"rpoplpush",rpoplpushcommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
{"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
{"srem",sremCommand,3,REDIS_CMD_BULK},
{"smove",smoveCommand,4,REDIS_CMD_BULK},
} else if (c->flags & REDIS_BLOCKED) {
if (c->blockingto != 0 && c->blockingto < now) {
addReply(c,shared.nullmultibulk);
- unblockClient(c);
+ unblockClientWaitingData(c);
}
}
}
listNode *ln;
/* Note that if the client we are freeing is blocked into a blocking
- * call, we have to set querybuf to NULL *before* to call unblockClient()
- * to avoid processInputBuffer() will get called. Also it is important
- * to remove the file events after this, because this call adds
- * the READABLE event. */
+ * call, we have to set querybuf to NULL *before* to call
+ * unblockClientWaitingData() to avoid processInputBuffer() will get
+ * called. Also it is important to remove the file events after
+ * this, because this call adds the READABLE event. */
sdsfree(c->querybuf);
c->querybuf = NULL;
if (c->flags & REDIS_BLOCKED)
- unblockClient(c);
+ unblockClientWaitingData(c);
aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
}
/* Unblock a client that's waiting in a blocking operation such as BLPOP */
-static void unblockClient(redisClient *c) {
+static void unblockClientWaitingData(redisClient *c) {
dictEntry *de;
list *l;
int j;
c->flags &= (~REDIS_BLOCKED);
server.blockedclients--;
/* Ok now we are ready to get read events from socket, note that we
- * can't trap errors here as it's possible that unblockClients() is
+ * can't trap errors here as it's possible that unblockClientWaitingDatas() is
* called from freeClient() itself, and the only thing we can do
* if we failed to register the READABLE event is to kill the client.
* Still the following function should never fail in the real world as
* we are sure the file descriptor is sane, and we exit on out of mem. */
aeCreateFileEvent(server.el, c->fd, AE_READABLE, readQueryFromClient, c);
/* As a final step we want to process data if there is some command waiting
- * in the input buffer. Note that this is safe even if unblockClient()
- * gets called from freeClient() because freeClient() will be smart
- * enough to call this function *after* c->querybuf was set to NULL. */
+ * in the input buffer. Note that this is safe even if
+ * unblockClientWaitingData() gets called from freeClient() because
+ * freeClient() will be smart enough to call this function
+ * *after* c->querybuf was set to NULL. */
if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
}
addReplyBulkLen(receiver,ele);
addReply(receiver,ele);
addReply(receiver,shared.crlf);
- unblockClient(receiver);
+ unblockClientWaitingData(receiver);
return 1;
}
for (j = 0; j < server.dbnum; j++) {
redisDb *db = server.db+j;
- int maxtries = 1000;
+ int maxtries = 100;
if (dictSize(db->dict) == 0) continue;
for (i = 0; i < 5; i++) {
int mask)
{
char buf[1];
- int retval;
- int processed = 0;
- int toprocess = -1;
+ int retval, processed = 0, toprocess = -1, trytoswap = 1;
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
REDIS_NOTUSED(privdata);
freeIOJob(j);
/* Put a few more swap requests in queue if we are still
* out of memory */
- if (vmCanSwapOut() && zmalloc_used_memory() > server.vm_max_memory){
+ if (trytoswap && vmCanSwapOut() &&
+ zmalloc_used_memory() > server.vm_max_memory)
+ {
int more = 1;
while(more) {
lockThreadedIO();
(unsigned) server.vm_max_threads;
unlockThreadedIO();
/* Don't waste CPU time if swappable objects are rare. */
- if (vmSwapOneObjectThreaded() == REDIS_ERR) break;
+ if (vmSwapOneObjectThreaded() == REDIS_ERR) {
+ trytoswap = 0;
+ break;
+ }
}
}
}
return REDIS_OK;
}
+/* ============ Virtual Memory - Blocking clients on missing keys =========== */
+
+/* Is this client attempting to run a command against swapped keys?
+ * If so, block it ASAP, load the keys in background, then resume it.4
+ *
+ * The improtat thing about this function is that it can fail! If keys will
+ * still be swapped when the client is resumed, a few of key lookups will
+ * just block loading keys from disk. */
+#if 0
+static void blockClientOnSwappedKeys(redisClient *c) {
+}
+#endif
+
/* ================================= Debugging ============================== */
static void debugCommand(redisClient *c) {