The amount of code on the Redis server is really quite large, if an API learning how to achieve, is undoubtedly a very inefficient approach, so I today to the implementation of the service side of the code to learn, heavy on his implementation process, and for his module design in the last article I have analyzed, Students who do not understand can go on to see a chapter. So I'm learning to analyze the implementation of the Redis server is also mainly starting with the main function. Before parsing the main execution process, Redis's author declared several variables here, which we need to know.
/* Our shared "common" objects * * * Shared Object * * struct sharedobjectsstruct share; /* Global VARs that are actually used as constants. The following double * values are used for double on-disk serialization, and are initialized * in runtime to avoid Stran GE compiler optimizations.
*////* Global Double type constant */double R_zero, R_posinf, R_neginf, R_nan; /*================================= Globals ================================= *////////////* Global Redisserver/s truct Redisserver server;
/* Server Global state */* our command table.
* * Every entry is composed of the following fields: * * name:a string representing the command name.
* Function:pointer to the C function implementing the command. * Arity:number of arguments, it is possible to use-n to say >= N * Sflags:command flags As String.
Below for a table of flags. * Flags:flags as bitmask.
Computed by Redis using the ' sflags ' field. * Get_keys_proc:an optional function to get key arguments from a command. * This are only used when the following three fields are not * enough to specify what
NTS are keys. * First_key_index:first argument is a key * last_key_index:last argument this is a key * Key_step:step to get AL L The keys from the argument. For instance * in Mset the "step is two since arguments are key,val,key,val,... * Microseconds:microseconds of
Total execution to this command.
* Calls:total number of calls of this command.
* The flags, microseconds and calls fields are computed by Redis and should * always is set to zero. * Command flags are expressed using strings where every character represents * a flag.
Later the populatecommandtable () function would take care of * populating the real ' flags ' field using this characters.
* * This is the meaning of the flags: * w:write Command (may modify the key space).
* R:read command (would never modify the key space). * M:may Increase MEmory usage once called.
Don ' t allow if out of memory.
* a:admin command, like SAVE or SHUTDOWN.
* P:pub/sub related command.
* F:force replication of this command, regardless of server.dirty.
* S:command not allowed in scripts. * R:random command. The command is not deterministic, which is, the same command * and the same arguments, with the same key spaces, may have D Ifferent * results.
For instance Spop and Randomkey are two random.
* S:sort command output array if called from script and so this output * is deterministic.
* L:allow command while loading the database. * T:allow Command while a slave has stale data but are not allowed to * server this data.
Normally no command is accepted in this condition * but just a few.
* M:do not automatically propagate the command on MONITOR. * F:fast Command:o (1) or O (log (N)) command that should never delay * Its execution as long as the kernel I
s giving us time. * Note that commands that could trigger a DEL as a side effect (like SET) * are not fast commands. */////////////* Redis command form correspondence/struct Rediscommand rediscommandtable[] = {{"Get", getcommand,2, "RF", 0,null,1,1,1,0,0}, {"s Et ", setcommand,-3," WM ", 0,null,1,1,1,0,0}, {" Setnx ", setnxcommand,3," WmF ", 0,null,1,1,1,0,0}, {" Setex ", Setexcommand , 4, "WM", 0,null,1,1,1,0,0}, ...
This command table is quite a lot, omitted, and basically contains all the possible commands. After all, the server is the response of these commands to achieve. The following is the emphasis to learn, in the server's implementation of the main program, how to do it, to a flow diagram:
The specific code implementation is as follows:
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, "");
Enable thread safe Mode zmalloc_enable_thread_safeness ();
Enable the Handler method Zmalloc_set_oom_handler (Redisoutofmemoryhandler) When a memory overflow occurs;
Srand (Time (NULL) ^getpid ());
Gets the current time gettimeofday (&tv,null);
Dictsethashfunctionseed (Tv.tv_sec^tv.tv_usec^getpid ());
Server.sentinel_mode = Checkforsentinelmode (ARGC,ARGV);
Initialize the configuration of the server Initserverconfig (); /* We need to Init Sentinel right now as parsing the configuration file * In Sentinel mode would have the effect of PO Pulating the Sentinel * data structures with master nodes to monitor.
*///Initialize the service-side mode if (Server.sentinel_mode) {initsentinelconfig ();
Initsentinel ();
} if (argc >= 2) {int j = 1; SDS options = Sdsempty ();
char *configfile = NULL;
/* Handle Special Options--help and--version */if (strcmp (argv[1), "-V") = = 0 | |
strcmp (Argv[1], "--version") = = 0) version ();
if (strcmp (argv[1], "--help") = = 0 | |
strcmp (Argv[1], "-h") = = 0) usage ();
if (strcmp (argv[1], "--test-memory") = = 0) {if (argc = = 3) {memtest (atoi (argv[2)), 50);
Exit (0);
else {fprintf (stderr, "Please specify the amount of memory to test in megabytes.\n");
fprintf (stderr, "Example:./redis-server--test-memory 4096\n\n");
Exit (1); }}/* argument is the config file name?
*/if (argv[j][0]!= '-' | | | argv[j][1]!= '-') configfile = argv[j++]; /* All of the other options are parsed and conceptually appended to the * configuration file. For instance--port 6380 would genErate the * string "Port 6380\n" to being parsed after the actual file name * are parsed, if any. */while (J!= argc) {if (argv[j][0] = = '-' && argv[j][1] = = '-') {/* Option
Name/if (Sdslen (options)) options = Sdscat (options, "\ n");
Options = Sdscat (options,argv[j]+2);
Options = Sdscat (Options, "");
else {/* Option argument */options = SDSCATREPR (Options,argv[j],strlen (argv[j));
Options = Sdscat (Options, "");
} j + +; } if (Server.sentinel_mode && configfile && *configfile = '-') {Redislog (Redis_warni
NG, "Sentinel config from STDIN not allowed."); Redislog (redis_warning, "Sentinel needs config file on disk to save state.
Exiting ... ");
Exit (1); } if (ConfigFile) SERVER.CONFIGFile = GetAbsolutePath (configfile);
Resetserversaveparams ();
Load the server-side configuration and load Loadserverconfig (configfile,options) according to config profile;
Sdsfree (options); else {redislog (redis_warning, warning:no config file specified, using the default Config.) In order to specify a config file with%s/path/to/%s.conf ", argv[0], Server.sentinel_mode?
"Sentinel": "Redis");
//Whether to open daemon if (server.daemonize) daemonize ();
Initserver ();
if (server.daemonize) createpidfile ();
Redissetproctitle (Argv[0]);
Redisasciiart (); if (!server.sentinel_mode) {/* things not needed when running in Sentinel mode. */Redislog (redis_warning
, "Server started, Redis version" redis_version);
#ifdef __linux__ linuxovercommitmemorywarning ();
#endif Loaddatafromdisk (); if (Server.ipfd_count > 0) redislog (redis_notice, "The server is now ready to accept connections on port%d"
, Server.port); if (Server.sofd > 0) redislog (redis_notice, "The server is now ready to accept connections at%s", server.
Unixsocket);
else {sentinelisrunning (); }/* Warning the user about suspicious maxmemory setting. */if (server.maxmemory > 0 && server.maxmemory < 1024*1024) {Redislog (redis_warning, "WARNING: You specified a MaxMemory value this is less than 1MB (the current value is%llu bytes).
Are You are sure this is what you really want? ", server.maxmemory);
The Beforesleep method called before///event loading Aesetbeforesleepproc (server.el,beforesleep);
Open event-driven cycle Aemain (Server.el);
Aedeleteeventloop (Server.el);
return 0;
}
The method is very simple command, some people estimate more puzzled, why did not connect operation, client and server is not to have connection operation, why not here, because those are the active operation of the client, so the server side main operation is relatively simple many.