“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

preface

Over the years, Redis has gone through six major releases, and the 6.0 series has added many new features, such as multithreading for IO and so on. At the same time, the source code still maintains a very high level, concise directory layout and clear documentation comments and code structure, so that people can be very happy to read the developer’s intention and solution, compared to THE SOURCE code of PHP is burdened with a heavy historical baggage, not to say much, tear the code.

  • Source version: 6.0.14

Test cases

The root directory./ SRC /server.c is the startup file of the service. After the startup, first judge whether it is a test startup

2. The environment and resources are initialized

OOM handler () ¶

The logic is print log & exit service.

3. Initialize the service configuration

callvoid initServerConfig(void)Method initializationserverThe default field value of an object.

4. Initialize the ACL

  • The ACL subsystem must be initialized as soon as possible because basic network code and client creation depend on ACLs. Note: www.oschina.net/p/acl for the ACL network library
  • ModuleInitModulesSystem: Initializes the module system, including setting the key notification subscriber list and static client, setting the command filter list, creating the timer radix tree, initializing the event listening list, etc

5. Run parameter memory transfer

Put the executable path and parameters in a safe place in order so that you can restart the server later. See the high availability idea in the details:

6. Initialize the Sentinel configuration

7. Command line and configuration parsing

8. Initialize the service

  • Register the semaphore correlation function
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
setupSignalHandlers();
makeThreadKillable();
Copy the code
  • Initialize the server configuration
server.aof_state = server.aof_enabled ? AOF_ON : AOF_OFF;
server.hz = server.config_hz;
server.pid = getpid();
server.in_fork_child = CHILD_TYPE_NONE;
server.main_thread_id = pthread_self();
server.current_client = NULL;
server.fixed_time_expire = 0; .Copy the code
  • Create a global shared memory object and maximize the number of file descriptors available to the main server process, as the service needs other file descriptors besides the maximum operable file descriptors determined by the maxClient parameter, such as persistence, listening sockets, log files, etc
// Create a global object
createSharedObjects();
    shared.crlf = createObject(OBJ_STRING,sdsnew("\r\n"));
    shared.ok = createObject(OBJ_STRING,sdsnew("+OK\r\n")); .// Adjust the file open limit
// First try to read the number of files set by the single couple
// If this fails, use: 1024 - The configured minimum number of fd's (default: 32)
// Otherwise, calculate and set as followsadjustOpenFilesLimit(); .while(bestlimit > oldlimit) {
        rlim_t decr_step = 16;

        limit.rlim_cur = bestlimit;
        limit.rlim_max = bestlimit;
        if(setrlimit(RLIMIT_NOFILE,&limit) ! =- 1) break;
        setrlimit_error = errno;

        /* We failed to set file limit to 'bestlimit'. Try with a * smaller limit decrementing by a few FDs per iteration. */
        if (bestlimit < decr_step) break; bestlimit -= decr_step; }...Copy the code
  • Create event listener rotation: aeCreateEventLoop. The operations related to the event are briefly discussed here. The next article will explain the event mechanism of Redis in detail
server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR); .Copy the code
  • Important: Create the socket and listen. The service listens on two configured ports, one for service and one for TLS. If there is a configured or initialized value, the service listens on two configured or initialized ports and calls the same function listenToPort. The listenToPort function does some IPv6 special operations. AnetTcpServer, the prototype of this method is:
int anetTcpServer(char *err, int port, char *bindaddr, int backlog)
{
    return _anetTcpServer(err, port, bindaddr, AF_INET, backlog);
}
Copy the code

We follow the call to anetListen and enter the familiar bind and LISTEN series of functions to create, listen, and bind the socket:

static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog) {
    // Familiar binding operations
    if (bind(s,sa,len) == - 1) {
        anetSetError(err, "bind: %s", strerror(errno));
        close(s);
        return ANET_ERR;
    }
    
    // Familiar listening operations
    if (listen(s, backlog) == - 1) {
        anetSetError(err, "listen: %s", strerror(errno));
        close(s);
        return ANET_ERR;
    }
    return ANET_OK;
}
Copy the code

The * DB field in struct redisServer is an array of Pointers to type redisDb, and then the server object’s arguments are assigned. The code is not displayed here, interested students can debug and view, after completion will create aE time time and aE file time, respectively call: AeCreateFileEvent, aeCreateFileEvent, is part of the same time-dependent Api. The next highlight is the familiar Accept

# Call first:void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask)# step:int anetTcpAccept(char *err, int s, char *ip, size_t ip_len, int *port) {...static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len)
    ...
}

# 步进:
int fd;
    while(1) {
        fd = accept(s,sa,len);
        if (fd == - 1) {
            if (errno == EINTR)
                continue;
            else {
                anetSetError(err, "accept: %s", strerror(errno));
                returnANET_ERR; }}break;
    }
    return fd;
Copy the code

This completes the socket creation, binding, listening, and accept operations for the service.

  • The last step is to initialize the other operations, explained as follows:
# initialization script cache replicationScriptCacheInit (); Lua scriptingInit();1); # initialize slowlog slowlogInit(); # Initialize latencyMonitorInit();Copy the code

At this point, the initServer processing is complete.

9. Perform other initialization or check operations

// Redis ACSII character drawing, character drawing variable definition: ascii_logo
void redisAsciiArt(void)
// Check the TCP-backlog parameter Settings. This is another important parameter setting that can be optimized for different scenarios
void checkTcpBacklogSettings(void)

// The following are different Settings or initialization operations for each platform. Here we will only read the operations in Linux:
moduleLoadFromQueue(a);
ACLLoadUsersAtStartup();
InitServerLast();
loadDataFromDisk();

// Set the CPU affinity
redisSetCpuAffinity();
// Set the OOM score
setOOMScoreAdj();
Copy the code

10. Enable event handlers to train and process events

Event mechanism is more important and has more content. Similarly, we will interpret the Event mechanism of Redis separately in the next article.


aeMain(server.el):
    // Function implementation
    eventLoop->stop = 0;
    while(! eventLoop->stop) { aeProcessEvents(eventLoop, AE_ALL_EVENTS| AE_CALL_BEFORE_SLEEP| AE_CALL_AFTER_SLEEP); } aeDeleteEventLoop(server.el);// Function implementation
    aeApiFree(eventLoop);
    zfree(eventLoop->events);
    zfree(eventLoop->fired);

    /* Free the time events list. */
    aeTimeEvent *next_te, *te = eventLoop->timeEventHead;
    while (te) {
        next_te = te->next;
        zfree(te);
        te = next_te;
    }
    zfree(eventLoop);
/ / end
return 0;
Copy the code

End

So far Redis startup process interpretation is complete, you can see that Redis to deal with a lot of operating system details do very well, it is worth us to learn, the next article we start to analyze Redis time and thread mechanism, I hope you read a little like, progress together 🙂