X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/af4e866dbb1455a50d51b3d5f46832f1a36e2080..144a5e72f2adc9d151438569f680533e41778504:/src/vm.c?ds=inline diff --git a/src/vm.c b/src/vm.c index 1aaa57eb..ee831fb9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -86,10 +86,9 @@ void vmInit(void) { } else { redisLog(REDIS_NOTICE,"Swap file allocated with success"); } - server.vm_bitmap = zmalloc((server.vm_pages+7)/8); + server.vm_bitmap = zcalloc((server.vm_pages+7)/8); redisLog(REDIS_VERBOSE,"Allocated %lld bytes page table for %lld pages", (long long) (server.vm_pages+7)/8, server.vm_pages); - memset(server.vm_bitmap,0,(server.vm_pages+7)/8); /* Initialize threaded I/O (used by Virtual Memory) */ server.io_newjobs = listCreate(); @@ -111,6 +110,11 @@ void vmInit(void) { /* LZF requires a lot of stack */ pthread_attr_init(&server.io_threads_attr); pthread_attr_getstacksize(&server.io_threads_attr, &stacksize); + + /* Solaris may report a stacksize of 0, let's set it to 1 otherwise + * multiplying it by 2 in the while loop later will not really help ;) */ + if (!stacksize) stacksize = 1; + while (stacksize < REDIS_THREAD_STACK_SIZE) stacksize *= 2; pthread_attr_setstacksize(&server.io_threads_attr, stacksize); /* Listen for events in the threaded I/O pipe */ @@ -396,15 +400,20 @@ double computeObjectSwappability(robj *o) { z = (o->type == REDIS_ZSET); d = z ? ((zset*)o->ptr)->dict : o->ptr; - asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d)); - if (z) asize += sizeof(zset)-sizeof(dict); - if (dictSize(d)) { - de = dictGetRandomKey(d); - ele = dictGetEntryKey(de); - elesize = (ele->encoding == REDIS_ENCODING_RAW) ? - (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o); - asize += (sizeof(struct dictEntry)+elesize)*dictSize(d); - if (z) asize += sizeof(zskiplistNode)*dictSize(d); + if (!z && o->encoding == REDIS_ENCODING_INTSET) { + intset *is = o->ptr; + asize = sizeof(*is)+is->encoding*is->length; + } else { + asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d)); + if (z) asize += sizeof(zset)-sizeof(dict); + if (dictSize(d)) { + de = dictGetRandomKey(d); + ele = dictGetEntryKey(de); + elesize = (ele->encoding == REDIS_ENCODING_RAW) ? + (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o); + asize += (sizeof(struct dictEntry)+elesize)*dictSize(d); + if (z) asize += sizeof(zskiplistNode)*dictSize(d); + } } break; case REDIS_HASH: @@ -544,7 +553,15 @@ void freeIOJob(iojob *j) { /* Every time a thread finished a Job, it writes a byte into the write side * of an unix pipe in order to "awake" the main thread, and this function - * is called. */ + * is called. + * + * Note that this is called both by the event loop, when a I/O thread + * sends a byte in the notification pipe, and is also directly called from + * waitEmptyIOJobsQueue(). + * + * In the latter case we don't want to swap more, so we use the + * "privdata" argument setting it to a not NULL value to signal this + * condition. */ void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata, int mask) { @@ -554,6 +571,8 @@ void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata, REDIS_NOTUSED(mask); REDIS_NOTUSED(privdata); + if (privdata != NULL) trytoswap = 0; /* check the comments above... */ + /* For every byte we read in the read side of the pipe, there is one * I/O job completed to process. */ while((retval = read(fd,buf,1)) == 1) { @@ -865,7 +884,8 @@ void waitEmptyIOJobsQueue(void) { io_processed_len = listLength(server.io_processed); unlockThreadedIO(); if (io_processed_len) { - vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read,NULL,0); + vmThreadedIOCompletedJob(NULL,server.io_ready_pipe_read, + (void*)0xdeadbeef,0); usleep(1000); /* 1 millisecond */ } else { usleep(10000); /* 10 milliseconds */ @@ -1075,6 +1095,11 @@ int dontWaitForSwappedKey(redisClient *c, robj *key) { listIter li; struct dictEntry *de; + /* The key object might be destroyed when deleted from the c->io_keys + * list (and the "key" argument is physically the same object as the + * object inside the list), so we need to protect it. */ + incrRefCount(key); + /* Remove the key from the list of keys this client is waiting for. */ listRewind(c->io_keys,&li); while ((ln = listNext(&li)) != NULL) { @@ -1095,6 +1120,7 @@ int dontWaitForSwappedKey(redisClient *c, robj *key) { if (listLength(l) == 0) dictDelete(c->db->io_keys,key); + decrRefCount(key); return listLength(c->io_keys) == 0; }