Reading Redis #2
Redis’s src/ directory contains multiple main() functions, because src/Makefile builds multiple executable files from the directory.
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_DUMP_NAME) $(REDIS_CHECK_AOF_NAME)
	@echo ""
	@echo "Hint: It's a good idea to run 'make test' ;)"
	@echo ""
In addition to that, a few files have main() as a test function.
% git grep 'TEST_*MAIN' src
src/crc64.c:184:#ifdef TEST_MAIN
src/endianconv.c:104:#ifdef TESTMAIN
src/intset.c:284:#ifdef INTSET_TEST_MAIN
src/sds.c:965:#ifdef SDS_TEST_MAIN
src/util.c:577:#ifdef UTIL_TEST_MAIN
src/ziplist.c:955:#ifdef ZIPLIST_TEST_MAIN
src/zipmap.c:373:#ifdef ZIPMAP_TEST_MAIN
%
src/redis.c
Let’s read redis-server first. Its main() is in src/redis.c and this file is pretty long. Actually that’s the third longest file under src/.
% wc -l src/*.c | sort -n | tail
    1556 src/hyperloglog.c
    1764 src/networking.c
    1929 src/config.c
    2104 src/replication.c
    2298 src/redis-cli.c
    2856 src/t_zset.c
    3690 src/redis.c
    3900 src/sentinel.c
    5007 src/cluster.c
   51031 total
%
The main() is calling aeSetBeforeSleepProc(), aeMain() and aeDeleteEventLoop() in the end. These functions are defined under ae.c, Redis’ event-driven programming library.
int main(int argc, char **argv) {
    struct timeval tv;
    /* We need to initialize our libraries, and the server configuration. */
#ifdef INIT_SETPROCTITLE_REPLACEMENT
    spt_init(argc, argv);
#endif
    setlocale(LC_COLLATE,"");
    zmalloc_enable_thread_safeness();
    zmalloc_set_oom_handler(redisOutOfMemoryHandler);
    srand(time(NULL)^getpid());
    gettimeofday(&tv,NULL);
    dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid());
    server.sentinel_mode = checkForSentinelMode(argc,arg ev);
    initServerConfig();
...
    aeSetBeforeSleepProc(server.el,beforeSleep);
    aeMain(server.el);
    aeDeleteEventLoop(server.el);
    return 0;
}
The purpose of the library is similar to libevent. It abstracts the difference between Solaris’ event ports, Linux’s epoll, *BSD’s (incl. OS X) kqueue, and good old-fashioned select().
/* A simple event-driven programming library. Originally I wrote this code
 * for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
 * it in form of a library for easy reuse.
 *
 * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
 * All rights reserved.
 *
 ...
 */
...
/* Include the best multiplexing layer supported by this system.
 * The following should be ordered by performances, descending. */
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif
redis.c is initializing this event library from initServer().
void initServer(void) {
    int j;
...
    createSharedObjects();
    adjustOpenFilesLimit();
    server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
    server.db = zmalloc(sizeof(redisDb)*server.dbnum);
...
    /* Create the serverCron() time event, that's our main way to process
     * background operations. */
    if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
        redisPanic("Can't create the serverCron time event.");
        exit(1);
    }
    /* Create an event handler for accepting new connections in TCP and Unix
     * domain sockets. */
    for (j = 0; j < server.ipfd_count; j++) {
        if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
            acceptTcpHandler,NULL) == AE_ERR)
            {
                redisPanic(
                    "Unrecoverable error creating server.ipfd file event.");
            }
    }
    if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
        acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event.");
...
    if (server.cluster_enabled) clusterInit();
    replicationScriptCacheInit();
    scriptingInit();
    slowlogInit();
    latencyMonitorInit();
    bioInit();
}
...
Both acceptTcpHandler() and acceptUnixHandler() are defined under networking.c, and it delegates the process to acceptCommonHandler().
What’s next?
I will read networking.c, where we can see redis-server’s protocol parser.