Redis Source Learning (RDB persistence)

Source: Internet
Author: User
Tags goto time in milliseconds redis server

Redis is a memory database, all operations are in memory, but the memory has a feature is that the program problem or system problems, restart, shutdown will cause memory data loss.

So you need to dump the in-memory data to the hard disk to back up.


RDB persistence is the process of dump the memory database to the hard disk, where the RDB is a file format and will be introduced later.

This paper is based on the analysis of two directions

1) load the Dump.rdb file into memory.

2) The memory database dumps the Dump.rdb file to the hard disk.


loading Dump.rdb files into memory

Main function Entry:

int main (int argc, char **argv) {    //...        Load Data Loaddatafromdisk () from a AOF file or an RDB file        ;    //...}
The Loaddatafromdisk function is to load the hard disk data into memory (AOF or RDB), the specific implementation to see the code:

/* Function Called at the startup to load RDB or AOF the file in memory.    */void Loaddatafromdisk (void) {//Record start time long long start = Ustime ();    AOF persistent is turned on? if (server.aof_state = = redis_aof_on) {//try to load aof file if (loadappendonlyfile (server.aof_filename) = = Redis_ OK)//Print load information and calculate load time-consuming length Redislog (redis_notice, "DB loaded from append-only file:%.3f seconds", (float    ) (Ustime ()-start)/1000000); AOF Persistence not open} else {//attempt to load an RDB file if (rdbload (server.rdb_filename) = = REDIS_OK) {//Print load Letter Load time-consuming length Redislog (redis_notice, "DB loaded from disk:%.3f seconds", (float) (Ustime ()-start)/1        000000); } else if (errno! = ENOENT) {redislog (redis_warning, "Fatal Error loading the DB:%s. Exiting.", Strerror (errno)            );        Exit (1); }    }}
AoF the next file to dissect his structure, now look at the loading of the Rdb file:

if (rdbload (server.rdb_filename) = = REDIS_OK) {//Rdb file loaded,server.rdb_filename default value bit Dump.rdb

/* * Load the data stored in the given RDB into the database.    */int rdbload (char *filename) {uint32_t dbid;    int type, rdbver;    Redisdb *db = server.db+0;    Char buf[1024];    Long Long expiretime, now = Mstime ();    FILE *FP;    Rio Rdb;    Open the Rdb file if (fp = fopen (filename, "r")) = = NULL) return redis_err;    Initializes the write stream rioinitwithfile (&AMP;RDB,FP);    Rdb.update_cksum = Rdbloadprogresscallback;    Rdb.max_processing_chunk = server.loading_process_events_interval_bytes;    if (Rioread (&rdb,buf,9) = = 0) goto Eoferr;    BUF[9] = ' + ';        Check the version number if (MEMCMP (buf, "REDIS", 5)! = 0) {fclose (FP);        Redislog (redis_warning, "wrong signature trying to load DB from file");        errno = EINVAL;    return redis_err;    } rdbver = Atoi (buf+5);        if (Rdbver < 1 | | rdbver > Redis_rdb_version) {fclose (FP);        Redislog (redis_warning, "Can ' t handle RDB format version%d", rdbver);        errno = EINVAL;    return redis_err; }//Adjust the server state to start loading status startloading (FP);   while (1) {robj *key, *val;        Expiretime =-1;          /* Read type.         * * Read-in type indication, determine how to read the data followed after.         * * This indication can be one of all constants defined in Rdb.h that are prefixed with * redis_rdb_type_*, or any of the constants prefixed with redis_rdb_opcode_*        */if (type = Rdbloadtype (&rdb)) = =-1) goto Eoferr; Read in Expiration time value if (type = = Redis_rdb_opcode_expiretime) {//The expiration time is calculated in seconds if (Expiretime = Rdbloadt            IME (&rdb)) = =-1) goto Eoferr;              /* We read the need to read the object type again. * * After the expiration time will follow a key value pair, we want to read into the type of the key value pair */if (type = Rdbloadtype (&rdb)) = =-1) goto EOF            Err              /* The Expiretime opcode specifies time in seconds and so convert * to milliseconds.        * * Convert format to milliseconds */expiretime *= 1000; } else if (type = = Redis_rdb_opcode_expiretime_ms) {//The expiration time in milliseconds/* Milliseconds PreciSion expire times introduced with RDB * Version 3.            */if ((Expiretime = Rdbloadmillisecondtime (&rdb)) = =-1) goto Eoferr;             /* We read the need to read the object type again. * * After the expiration time will follow a key value pair, we want to read into the type of the key value pair */if (type = Rdbloadtype (&rdb)) = =-1) goto EOF        Err        }//Read in the data EOF (not EOF of the Rdb file) if (type = = redis_rdb_opcode_eof) break; /* Handle SELECT DB opcode as a special case * * Read-in Toggle database indication */if (type = = Redis_rdb_opcode _SELECTDB) {//Read in database number if (dbid = Rdbloadlen (&rdb,null)) = = Redis_rdb_lenerr) g            Oto Eoferr;  Check the correctness of the database number if (dbid >= (unsigned) server.dbnum) {Redislog (redis_warning, "Fatal:data file was created with a Redis server configured to handle more than%d databases.                Exiting\n ", server.dbnum); Exit (1);            }//In the program content switch Database db = Server.db+dbid;        skipping over continue; }/* Read key * * reads in key */if ((Key = Rdbloadstringobject (&AMP;RDB)) = = NULL) Goto EO        Ferr;        /* Read Value * * Reads in values */if ((val = Rdbloadobject (type,&rdb)) = = NULL) goto Eoferr; /* Check If the key already expired. This function is used if loading * an RDB file from disk, either at startup, or if an RDB was * receiv Ed from the master. In the latter case, the master was * responsible for key expiry.          If we would expire keys here, the * snapshot taken by the master could not be reflected on the slave. * * If the server is the primary node, * Then when the keys have expired, they are no longer associated to the database */if (Server.masterhost = = NULL && ex            Piretime! =-1 && expiretime < now) {Decrrefcount (key);            Decrrefcount (Val);      Skip Over      Continue        }/* Add the new object in the hash table * * To associate key-value pairs in the database */Dbadd (db,key,val); /* Set the expire time if needed * * Setting Expiration */if (expiretime! = 1) setexpire (Db,key        , expiretime);    Decrrefcount (key);  }/* Verify the checksum if RDB version is >= 5 * * If the RDB version >= 5, then the parity checksum */if (Rdbver >= 5        && server.rdb_checksum) {uint64_t cksum, expected = rdb.cksum;        Read-in File checksum if (Rioread (&rdb,&cksum,8) = = 0) goto Eoferr;        Memrev64ifbe (&cksum); Comparison checksum if (cksum = = 0) {Redislog (redis_warning, "RDB file was saved with checksum disabled:no check p Erformed. "); else if (cksum! = expected) {Redislog (redis_warning, "wrong RDB checksum.            Aborting now. ");        Exit (1);    }}//Off RDB fclose (FP);    The server Exits stoploading () from the onboarding state; Return Redis_ok;eoferR:/* Unexpected end of file is handled here with a fatal exit */Redislog (redis_warning, "short read or OOM loading DB.    Unrecoverable error, aborting now. ");    Exit (1); return redis_err; /* Just to avoid warning */}

function int Rdbload (char *filename), it is clear that the file structure of the RDB is as follows:


Memory database dump to hard disk Dump.rdb file

Use the function Rdbsave:

/* Save the DB on disk. Return Redis_err On Error, REDIS_OK on Success * * Save the database to disk. * * Save successfully returned REDIS_OK, error/Failure return REDIS_ERR.    */int Rdbsave (char *filename) {dictiterator *di = NULL;    Dictentry *de;    Char tmpfile[256];    Char magic[10];    Int J;    Long Long now = Mstime ();    FILE *FP;    Rio Rdb;    uint64_t cksum;    Create temporary file snprintf (tmpfile,256, "Temp-%d.rdb", (int) getpid ());    fp = fopen (Tmpfile, "w");        if (!FP) {Redislog (redis_warning, "Failed opening. Rdb for saving:%s", Strerror (errno));    return redis_err;    }//Initialize I/O rioinitwithfile (&AMP;RDB,FP);    Sets the checksum function if (server.rdb_checksum) rdb.update_cksum = riogenericupdatechecksum;    Write the RDB version number snprintf (Magic,sizeof (Magic), "redis%04d", redis_rdb_version);    if (Rdbwriteraw (&rdb,magic,9) = =-1) goto Werr;        Traverse all databases for (j = 0; J < Server.dbnum; J + +) {//point to database Redisdb *db = server.db+j; Point to Database key space Dict *d = Db->dicT        Skip Empty Database if (dictsize (d) = = 0) continue;        Create a key space iterator di = Dictgetsafeiterator (d);            if (!di) {fclose (FP);        return redis_err; }/* Write the Select db opcode * * writes to the DB selector */if (Rdbsavetype (&rdb,redis_rdb        _OPCODE_SELECTDB) = =-1) goto Werr;        if (Rdbsavelen (&rdb,j) = =-1) goto Werr; /* Iterate this DB writing every entry * * traverse the database and write data for each key-value pair */while (de = Dictnext (DI))            ! = NULL) {SDS keystr = Dictgetkey (DE);            RobJ key, *o = Dictgetval (DE);                        Long long expire;            According to KEYSTR, create a key object in the stack initstaticstringobject (KEY,KEYSTR);            Gets the expiration time of the key expire = Getexpire (Db,&key);        Save key value pair data if (Rdbsavekeyvaluepair (&rdb,&key,o,expire,now) = =-1) goto Werr;    } dictreleaseiterator (DI); } di = NULL; /* So, we DOn ' t release it again on error.    */* EOF opcode * * Write EOF code */if (Rdbsavetype (&rdb,redis_rdb_opcode_eof) = =-1) goto Werr; /* CRC64 checksum.      It would be a zero if checksum computation is disabled and the * Loading code skips the check in this case.     * * CRC64 checksum.     * * If the checksum function is turned off, then Rdb.cksum will be 0, * in this case, the RDB will skip the checksum check when it is loaded.    */cksum = rdb.cksum;    Memrev64ifbe (&cksum);    Riowrite (&rdb,&cksum,8);    /* Make sure data won't remain on the OS ' s output buffers *///flush cache, making sure data is written to disk if (fflush (fp) = = EOF) goto Werr;    if (Fsync (Fileno (fp)) = =-1) goto Werr;    if (fclose (fp) = = EOF) goto Werr;      /* Use RENAME to make sure the db file is changed atomically only * If the Generate DB file is OK.     * * Use RENAME, atomically to rename the temporary file, overwriting the original RDB file. */if (rename (tmpfile,filename) = =-1) {Redislog (redis_warning, "Error Moving temp DB file on the final Destinat        Ion:%s ", Strerror (errno)); Unlink(tmpfile);    return redis_err;    }//write completed, print log redislog (Redis_notice, "DB saved on disk");    Clear 0 Database Dirty state server.dirty = 0;    Records the last time the SAVE was completed server.lastsave = times (NULL);    Records the last state of SAVE server.lastbgsave_status = REDIS_OK;    return Redis_ok;werr://Close file fclose (FP);    Delete File unlink (tmpfile);    Redislog (redis_warning, "Write Error saving DB on disk:%s", Strerror (errno));    if (di) dictreleaseiterator (DI); return redis_err;}

The above is the approximate process of the RDB optimization, and the details have to continue to buckle code.


Redis Source Learning (RDB persistence)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.