]> git.saurik.com Git - redis.git/commitdiff
Max limit to 10k clients removed, this implements feature request on issue #194
authorantirez <antirez@gmail.com>
Thu, 15 Dec 2011 10:42:40 +0000 (11:42 +0100)
committerantirez <antirez@gmail.com>
Thu, 15 Dec 2011 10:42:40 +0000 (11:42 +0100)
src/ae.c
src/ae.h
src/ae_epoll.c
src/ae_kqueue.c
src/redis-benchmark.c
src/redis.c

index 0580289002dfa72db5d1d267f13f27f0f02438d9..98ff7a8eee60242f64a0080555d74cdfb2a10295 100644 (file)
--- a/src/ae.c
+++ b/src/ae.c
     #endif
 #endif
 
-aeEventLoop *aeCreateEventLoop(void) {
+aeEventLoop *aeCreateEventLoop(int setsize) {
     aeEventLoop *eventLoop;
     int i;
 
-    eventLoop = zmalloc(sizeof(*eventLoop));
-    if (!eventLoop) return NULL;
+    if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) return NULL;
+    eventLoop->events = NULL;
+    eventLoop->fired = NULL;
+    eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);
+    eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
+    if (eventLoop->events == NULL || eventLoop->fired == NULL) {
+        zfree(eventLoop->events);
+        zfree(eventLoop->fired);
+        zfree(eventLoop);
+        return NULL;
+    }
+    eventLoop->setsize = setsize;
     eventLoop->timeEventHead = NULL;
     eventLoop->timeEventNextId = 0;
     eventLoop->stop = 0;
@@ -69,7 +79,7 @@ aeEventLoop *aeCreateEventLoop(void) {
     }
     /* Events with mask == AE_NONE are not set. So let's initialize the
      * vector with it. */
-    for (i = 0; i < AE_SETSIZE; i++)
+    for (i = 0; i < setsize; i++)
         eventLoop->events[i].mask = AE_NONE;
     return eventLoop;
 }
@@ -86,7 +96,7 @@ void aeStop(aeEventLoop *eventLoop) {
 int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
         aeFileProc *proc, void *clientData)
 {
-    if (fd >= AE_SETSIZE) return AE_ERR;
+    if (fd >= eventLoop->setsize) return AE_ERR;
     aeFileEvent *fe = &eventLoop->events[fd];
 
     if (aeApiAddEvent(eventLoop, fd, mask) == -1)
@@ -102,7 +112,7 @@ int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
 
 void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
 {
-    if (fd >= AE_SETSIZE) return;
+    if (fd >= eventLoop->setsize) return;
     aeFileEvent *fe = &eventLoop->events[fd];
 
     if (fe->mask == AE_NONE) return;
@@ -119,7 +129,7 @@ void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
 }
 
 int aeGetFileEvents(aeEventLoop *eventLoop, int fd) {
-    if (fd >= AE_SETSIZE) return 0;
+    if (fd >= eventLoop->setsize) return 0;
     aeFileEvent *fe = &eventLoop->events[fd];
 
     return fe->mask;
index 9e23a6fdeea0352d996dcd0a183520c272071641..e1dccfc76a684a50b7aafb06809348bb0a9b98e7 100644 (file)
--- a/src/ae.h
+++ b/src/ae.h
@@ -33,8 +33,6 @@
 #ifndef __AE_H__
 #define __AE_H__
 
-#define AE_SETSIZE (1024*10)    /* Max number of fd supported */
-
 #define AE_OK 0
 #define AE_ERR -1
 
@@ -87,10 +85,11 @@ typedef struct aeFiredEvent {
 
 /* State of an event based program */
 typedef struct aeEventLoop {
-    int maxfd;
+    int maxfd;   /* highest file descriptor currently registered */
+    int setsize; /* max number of file descriptors tracked */
     long long timeEventNextId;
-    aeFileEvent events[AE_SETSIZE]; /* Registered events */
-    aeFiredEvent fired[AE_SETSIZE]; /* Fired events */
+    aeFileEvent *events; /* Registered events */
+    aeFiredEvent *fired; /* Fired events */
     aeTimeEvent *timeEventHead;
     int stop;
     void *apidata; /* This is used for polling API specific data */
@@ -98,7 +97,7 @@ typedef struct aeEventLoop {
 } aeEventLoop;
 
 /* Prototypes */
-aeEventLoop *aeCreateEventLoop(void);
+aeEventLoop *aeCreateEventLoop(int setsize);
 void aeDeleteEventLoop(aeEventLoop *eventLoop);
 void aeStop(aeEventLoop *eventLoop);
 int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
index 5680b6a2767617319e1d07732530553d1eb2457b..fc6d9ccddc0120fd25f5b19649fbc6de9a911e6f 100644 (file)
@@ -6,15 +6,21 @@
 
 typedef struct aeApiState {
     int epfd;
-    struct epoll_event events[AE_SETSIZE];
+    struct epoll_event *events;
 } aeApiState;
 
 static int aeApiCreate(aeEventLoop *eventLoop) {
     aeApiState *state = zmalloc(sizeof(aeApiState));
 
     if (!state) return -1;
+    state->events = zmalloc(sizeof(epoll_event)*eventLoop->setsize);
+    if (!state->events) {
+        zfree(state);
+        return -1;
+    }
     state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */
     if (state->epfd == -1) {
+        zfree(state->events);
         zfree(state);
         return -1;
     }
@@ -26,6 +32,7 @@ static void aeApiFree(aeEventLoop *eventLoop) {
     aeApiState *state = eventLoop->apidata;
 
     close(state->epfd);
+    zfree(state->events);
     zfree(state);
 }
 
@@ -70,7 +77,7 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
     aeApiState *state = eventLoop->apidata;
     int retval, numevents = 0;
 
-    retval = epoll_wait(state->epfd,state->events,AE_SETSIZE,
+    retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
             tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
     if (retval > 0) {
         int j;
index 6bf64f4ef868be13203ebfb2aefd70a6f9dfe9f1..e91a254d524af1879d3f9919f8b358f16094d1e4 100644 (file)
@@ -8,15 +8,21 @@
 
 typedef struct aeApiState {
     int kqfd;
-    struct kevent events[AE_SETSIZE];
+    struct kevent *events;
 } aeApiState;
 
 static int aeApiCreate(aeEventLoop *eventLoop) {
     aeApiState *state = zmalloc(sizeof(aeApiState));
 
     if (!state) return -1;
+    state->events = zmalloc(sizeof(struct kevent)*eventLoop->setsize);
+    if (!state->events) {
+        zfree(state);
+        return -1;
+    }
     state->kqfd = kqueue();
     if (state->kqfd == -1) {
+        zfree(state->events);
         zfree(state);
         return -1;
     }
@@ -29,6 +35,7 @@ static void aeApiFree(aeEventLoop *eventLoop) {
     aeApiState *state = eventLoop->apidata;
 
     close(state->kqfd);
+    zfree(state->events);
     zfree(state);
 }
 
@@ -69,10 +76,12 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
         struct timespec timeout;
         timeout.tv_sec = tvp->tv_sec;
         timeout.tv_nsec = tvp->tv_usec * 1000;
-        retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, &timeout);
+        retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize,
+                        &timeout);
     } else {
-        retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, NULL);
-    }    
+        retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize,
+                        NULL);
+    }
 
     if (retval > 0) {
         int j;
index b22322f4a70d4da179d89eacfa1589d091ff6f98..f7ca312de2a3003352ba6c4048129ea17e6acdc7 100644 (file)
@@ -490,7 +490,7 @@ int main(int argc, const char **argv) {
     config.numclients = 50;
     config.requests = 10000;
     config.liveclients = 0;
-    config.el = aeCreateEventLoop();
+    config.el = aeCreateEventLoop(1024*10);
     aeCreateTimeEvent(config.el,1,showThroughput,NULL,NULL);
     config.keepalive = 1;
     config.datasize = 3;
index 6926458b24db9fdccc4e19b3624b34a4a5cf5d80..28240b03d7eee3a7b696bfe670d2ee4fc5d0d459 100644 (file)
@@ -954,6 +954,43 @@ void initServerConfig() {
     server.bug_report_start = 0;
 }
 
+/* This function will try to raise the max number of open files accordingly to
+ * the configured max number of clients. It will also account for 32 additional
+ * file descriptors as we need a few more for persistence, listening
+ * sockets, log files and so forth.
+ *
+ * If it will not be possible to set the limit accordingly to the configured
+ * max number of clients, the function will do the reverse setting
+ * server.maxclients to the value that we can actually handle. */
+void adjustOpenFilesLimit(void) {
+    rlim_t maxfiles = server.maxclients+32;
+    struct rlimit limit;
+
+    if (maxfiles < 1024) maxfiles = 1024;
+    if (getrlimit(RLIMIT_NOFILE,&limit) == -1) {
+        redisLog(REDIS_WARNING,"Unable to obtain the current NOFILE limit (%s), assuming 1024 and setting the max clients configuration accordingly.",
+            strerror(errno));
+        server.maxclients = 1024-32;
+    } else {
+        rlim_t oldlimit = limit.rlim_cur;
+
+        /* Set the max number of files if the current limit is not enough
+         * for our needs. */
+        if (oldlimit < maxfiles) {
+            limit.rlim_cur = maxfiles;
+            limit.rlim_max = maxfiles;
+            if (setrlimit(RLIMIT_NOFILE,&limit) == -1) {
+                server.maxclients = oldlimit-32;
+                redisLog(REDIS_WARNING,"Unable to set the max number of files limit to %d (%s), setting the max clients configuration to %d.",
+                    (int) maxfiles, strerror(errno), (int) server.maxclients);
+            } else {
+                redisLog(REDIS_NOTICE,"Max number of open files set to %d",
+                    (int) maxfiles);
+            }
+        }
+    }
+}
+
 void initServer() {
     int j;
 
@@ -972,7 +1009,8 @@ void initServer() {
     server.unblocked_clients = listCreate();
 
     createSharedObjects();
-    server.el = aeCreateEventLoop();
+    adjustOpenFilesLimit();
+    server.el = aeCreateEventLoop(server.maxclients+1024);
     server.db = zmalloc(sizeof(redisDb)*server.dbnum);
 
     if (server.port != 0) {
@@ -1045,38 +1083,6 @@ void initServer() {
     bioInit();
     srand(time(NULL)^getpid());
 
-    /* Try to raise the max number of open files accordingly to the
-     * configured max number of clients. Also account for 32 additional
-     * file descriptors as we need a few more for persistence, listening
-     * sockets, log files and so forth. */
-    {
-        rlim_t maxfiles = server.maxclients+32;
-        struct rlimit limit;
-
-        if (maxfiles < 1024) maxfiles = 1024;
-        if (getrlimit(RLIMIT_NOFILE,&limit) == -1) {
-            redisLog(REDIS_WARNING,"Unable to obtain the current NOFILE limit (%s), assuming 1024 and setting the max clients configuration accordingly.",
-                strerror(errno));
-            server.maxclients = 1024-32;
-        } else {
-            rlim_t oldlimit = limit.rlim_cur;
-
-            /* Set the max number of files if the current limit is not enough
-             * for our needs. */
-            if (oldlimit < maxfiles) {
-                limit.rlim_cur = maxfiles;
-                limit.rlim_max = maxfiles;
-                if (setrlimit(RLIMIT_NOFILE,&limit) == -1) {
-                    server.maxclients = oldlimit-32;
-                    redisLog(REDIS_WARNING,"Unable to set the max number of files limit to %d (%s), setting the max clients configuration to %d.",
-                        (int) maxfiles, strerror(errno), (int) server.maxclients);
-                } else {
-                    redisLog(REDIS_NOTICE,"Max number of open files set to %d",
-                        (int) maxfiles);
-                }
-            }
-        }
-    }
 }
 
 /* Populates the Redis Command Table starting from the hard coded list