Here only introduces when the RDB is triggered, the data format of the RDB itself will not be introduced. By observing the code, we can generally find that the redisObject is processed according to the agreed format, or the data stream is restored to the redisObject according to the parse. The loading logic for the RDB is described in the redis initialization process. Now let’s see when the RDB generation is triggered.

This can be seen first in the parsing of aOF. Corresponding thin AOF file generation, according to the configuration items of the server will select the RDB data.

The corresponding code is

int rewriteAppendOnlyFile(char *filename) { ... If (server.aof_use_rdb_preamble) {int error; if (server.aof_use_rdb_preamble) {int error; When generating RDB data as AOF, rDBFlags is RDBFLAGS_AOF_PREAMBLE, so that RDBFLAGS_AOF_PREAMBLE can be read from the parent process while generating RDB data (rdbSaveRio(&aof,&error,RDBFLAGS_AOF_PREAMBLE,NULL) == C_ERR) { errno = error; goto werr; }} else {// Generate the simplest command directly based on the current DB data equivalent to a slimmdown aof if (rewriteAppendOnlyFileRio(&aof) == C_ERR) goto werr; }Copy the code

If you look at what other actions trigger the RDB file, you can see that Redis exposes two commands

saveCommand:

@param c */ void saveCommand(client *c) {if (server.rdb_child_pid! = -1) { addReplyError(c,"Background save already in progress"); return; } rdbSaveInfo rsi, *rsiptr; RdbSaveInfo rSIPtr = rdbPopulateSaveInfo(&rsi); If (rdbSave(server.rdb_filename,rsiptr) == C_OK) {addReply(c,shared.ok); } else { addReply(c,shared.err); }}Copy the code

RdbSave () is a method that will not be expanded in detail. It is to process each DB redisObject one by one and write them into the file according to the format specified by the RDB protocol. In the conversion process, compression algorithms or some coding skills are often involved to save memory, which is consistent with Lucene. It also tries to generate RDB files when preparing to shut down the Redis server.

/** * prepare to shut down redis server * @param flags * @return */ int prepareForShutdown(int flags) {... /* Create a new RDB file no longer intended to be withdrawn. * A COPY of RDB data will be generated if save is coerced * If save is not coerced the saveParam condition will be checked if the saveParam condition is met at that time * if noSAVE is required If ((server.saveParamslen > 0 &&! nosave) || save) { serverLog(LL_NOTICE,"Saving the final RDB snapshot before exiting."); If (server.supervised_mode == SUPERVISED_SYSTEMD) redisCommunicateSystemd("STATUS=Saving the final RDB snapshot\n"); /* Snapshotting. Perform a SYNC SAVE and exit */ rdbSaveInfo rsi, *rsiptr; Rsiptr = rdbPopulateSaveInfo(&rsi); If (rdbSave(server.rdb_filename,rsiptr)! = C_OK) { /* Ooops.. error saving! The best we can do is to continue * operating. Note that if there was a background saving process, * in the next cron() Redis will be notified that the background * saving aborted, handling special stuff like slaves pending for * synchronization... * /Copy the code

Then there is the API -bgsaveCommand – that uses child processes to generate RDB data

/* BGSAVE [SCHEDULE] */ void bgsaveCommand(client *c) {int SCHEDULE = 0; /* The SCHEDULE option changes the behavior of BGSAVE when an AOF rewrite * is in progress. Instead of returning an Error BGSAVE gets scheduled * */ argc (c->argc > 1) {if (c->argc == 2 &&! strcasecmp(c->argv[1]->ptr,"schedule")) { schedule = 1; } else { addReply(c,shared.syntaxerr); return; } } rdbSaveInfo rsi, *rsiptr; rsiptr = rdbPopulateSaveInfo(&rsi); If (server.rdb_child_pid! = -1) { addReplyError(c,"Background save already in progress"); } else if (hasActiveChildProcess()) {if (schedule) {if (schedule) { server.rdb_bgsave_scheduled = 1; addReplyStatus(c,"Background saving scheduled"); } else { addReplyError(c, "Another child process is active (AOF?) : can't BGSAVE right now. " "Use BGSAVE SCHEDULE in order to schedule a BGSAVE whenever " "possible."); Else if (rdbSaveBackground(server.rdb_filename, rSIPtr) == C_OK) {addReplyStatus(c,"Background saving  started"); } else { addReply(c,shared.err); }}Copy the code

The server.rdb_BGSAVE_scheduled tag is the same as the tag that delayed executing aOF. It is also found in the main loop of serverCron and starts the child process to generate the RDB.

The RDB operation is then attempted in serverCron based on the SaveParam parameter

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { ... /* If there is not a background saving/rewrite in progress check If * we have to save/rewrite now. Check whether saveParam condition is met and trigger storage RDB logic * */ for (j = 0; j < server.saveparamslen; Struct saveParam *sp = server.saveparams+j; /* Save if we reached the given amount of changes, * the given amount of seconds, and if the latest bgsave was * successful or if, in case of an error, At least * CONFIG_BGSAVE_RETRY_DELAY seconds already Elapsed Sp ->changes && server.unixtime-server.lastsave > sp->seconds && // If the last RDB was generated successfully, you can also try to generate RDB this time So there will be a waiting time Must wait for such a long time before they can generate RDB (server. Unixtime - server. Lastbgsave_try > CONFIG_BGSAVE_RETRY_DELAY | | server.lastbgsave_status == C_OK)) { serverLog(LL_NOTICE,"%d changes in %d seconds. Saving..." , sp->changes, (int)sp->seconds); rdbSaveInfo rsi, *rsiptr; SaveInfo rsiptr = rdbPopulateSaveInfo(&rsi); rdbSaveBackground(server.rdb_filename,rsiptr); break; }}Copy the code

The core logic of rdbSaveBackground is to use the child process to execute rdbSave, which is relevant to the previous section. Finally, when the child process completes the task, different postfunctions are executed depending on the type of task that triggered the RDB

/* When a background RDB saving/transfer terminates, Call the right handler. * RDB execute this method when the child to be completely recycled * * / void backgroundSaveDoneHandler (int exitcode, int bysignal) { int type = server.rdb_child_type; switch(server.rdb_child_type) { case RDB_CHILD_TYPE_DISK: / / when is responsible for the RDB data written to the file after the child to complete the work Trigger the method to determine whether a child was accidentally shut down And clean up the temporary file backgroundSaveDoneHandlerDisk (exitcode bysignal); break; // The RDB subprocess type generated when the slave needs to synchronize data is the socket type case RDB_CHILD_TYPE_SOCKET: / / here is mainly print log backgroundSaveDoneHandlerSocket exitcode bysignal); break; default: serverPanic("Unknown RDB child type."); break; } // reset the state of the child process and update the storage time server.rdb_child_pid = -1; server.rdb_child_type = RDB_CHILD_TYPE_NONE; server.rdb_save_time_last = time(NULL)-server.rdb_save_time_start; server.rdb_save_time_start = -1; /* Possibly there are slaves waiting for a BGSAVE in order to be served * (the first stage of SYNC is a bulk transfer of  dump.rdb) */ updateSlavesWaitingBgsave((! bysignal && exitcode == 0) ? C_OK : C_ERR, type); } /* A background saving child (BGSAVE) terminated its work. Handle this. * This function covers the case of actual BGSAVEs. * a backend storage RDB file task has been completed At this time to clean up the logical * * / static void backgroundSaveDoneHandlerDisk (int exitcode, Int bysignal {// If (! bysignal && exitcode == 0) { serverLog(LL_NOTICE, "Background saving terminated with success"); Server.dirty = server.dirty - server.dirty_before_bgsave; server.lastsave = time(NULL); server.lastbgsave_status = C_OK; } else if (! bysignal && exitcode ! = 0) { serverLog(LL_WARNING, "Background saving error"); server.lastbgsave_status = C_ERR; } else {// Indicates that this process is terminated at least because of some signal. serverLog(LL_WARNING, "Background saving terminated by signal %d", bysignal); latencyStartMonitor(latency); // Clean up the temporary file rdbRemoveTempFile(server.rdb_child_pid, 0) created by the child process; latencyEndMonitor(latency); latencyAddSampleIfNeeded("rdb-unlink-temp-file",latency); /* SIGUSR1 is whitelisted, so we have a way to kill a child without * triggering an error condition. */ if (bysignal ! = SIGUSR1) server.lastbgsave_status = C_ERR; }}Copy the code

The above RDB parsing is also complete