Processing Mechanism of redis after the hard disk is full

Source: Internet
Author: User
The hard disk Of A redis machine was full the other day, mainly because of program bugs that led to a surge in backup volume, and the monitoring program's notification mechanism also went on strike, so for the first time, I experienced the redis strike (read-only and not write ). Now let's take a look at the redis processing mechanism after the disk is full: save process: After serverCron-rdbSaveBackground-rdbSavesave

The hard disk Of A redis machine was full the other day, mainly because of program bugs that led to a surge in backup volume, and the monitoring program's notification mechanism also went on strike, so for the first time, I experienced the redis strike (read-only and not write ). Now let's take a look at the redis processing mechanism after the disk is full: save process: After serverCron-rdbSaveBackground-rdbSave save

The hard disk Of A redis machine was full the other day, mainly because of program bugs that led to a surge in backup volume, and the monitoring program's notification mechanism also went on strike, so for the first time, I experienced the redis strike (read-only and not write ).

Now let's take a look at the redis processing mechanism after the disk is full:

Save process: serverCron-> rdbSaveBackground-> rdbSave
Process after saving: serverCron-> backgroundSaveDoneHandler
The result of the above process is server. lastbgsave_status = REDIS_ERR,

Affected by this, in processCommand and luaRedisGenericCommand, if a write operation is performed, REDIS_ OK is returned directly without actual write operations.

1. REDIS_ERR will be returned for all write errors in rdbSave

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;    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;    }    rioInitWithFile(&rdb,fp);    if (server.rdb_checksum)        rdb.update_cksum = rioGenericUpdateChecksum;    snprintf(magic,sizeof(magic),"REDIS%04d",REDIS_RDB_VERSION);    if (rdbWriteRaw(&rdb,magic,9) == -1) goto werr;    for (j = 0; j < server.dbnum; j++) {        redisDb *db = server.db+j;        dict *d = db->dict;        if (dictSize(d) == 0) continue;        di = dictGetSafeIterator(d);        if (!di) {            fclose(fp);            return REDIS_ERR;        }        /* Write the SELECT DB opcode */        if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_SELECTDB) == -1) goto werr;        if (rdbSaveLen(&rdb,j) == -1) goto werr;        /* Iterate this DB writing every entry */        while((de = dictNext(di)) != NULL) {            sds keystr = dictGetKey(de);            robj key, *o = dictGetVal(de);            long long expire;            initStaticStringObject(key,keystr);            expire = getExpire(db,&key);            if (rdbSaveKeyValuePair(&rdb,&key,o,expire,now) == -1) goto werr;        }        dictReleaseIterator(di);    }    di = NULL; /* So that we don't release it again on error. */    /* EOF opcode */    if (rdbSaveType(&rdb,REDIS_RDB_OPCODE_EOF) == -1) goto werr;    /* CRC64 checksum. It will be zero if checksum computation is disabled, the     * loading code skips the check in this case. */    cksum = rdb.cksum;    memrev64ifbe(&cksum);    if (rioWrite(&rdb,&cksum,8) == 0) goto werr;    /* Make sure data will not remain on the OS's output buffers */    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. */    if (rename(tmpfile,filename) == -1) {        redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));        unlink(tmpfile);        return REDIS_ERR;    }    redisLog(REDIS_NOTICE,"DB saved on disk");    server.dirty = 0;    server.lastsave = time(NULL);    server.lastbgsave_status = REDIS_OK;    return REDIS_OK;werr:    fclose(fp);    unlink(tmpfile);    redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));    if (di) dictReleaseIterator(di);    return REDIS_ERR;}

2. In rdbSaveBackground, if the sub-process calls rdbsave to return REDIS_ERR, the sub-process exit (1)

Int rdbSaveBackground (char * filename) {pid_t childpid; long start; if (server. rdb_child_pid! =-1) return REDIS_ERR; server. dirty_before_bgsave = server. dirty; server. lastbgsave_try = time (NULL); start = ustime (); if (childpid = fork () = 0) {int retval;/* Child */closeListeningSockets (0 ); redisSetProcTitle ("redis-rdb-bgsave"); retval = rdbSave (filename); if (retval = REDIS_ OK) {size_t private_dirty = encrypt (); if (private_dirty) {redisLog (REDIS_NOTICE, "RDB: % zu MB of memory used by copy-on-write ", private_dirty/(1024*1024) ;}} exitFromChild (retval = REDIS_ OK )? 0: 1); // when the process exits, the system returns 0/1} else {/* Parent */server. stat_fork_time = ustime ()-start; if (childpid =-1) {server. lastbgsave_status = REDIS_ERR; redisLog (REDIS_WARNING, "Can't save in background: fork: % s", strerror (errno); return REDIS_ERR;} redisLog (REDIS_NOTICE, "Background saving started by pid % d", childpid); server. rdb_save_time_start = time (NULL); server. rdb_child_pid = childpid; updateDictResizePolicy (); return REDIS_ OK;} return REDIS_ OK;/* unreached */}
3. After bgsave is complete, the return code of the bgsave sub-process is obtained in serverCron for subsequent processing.
/* Check if a background saving or AOF rewrite in progress terminated. */if (server. rdb_child_pid! =-1 | server. aof_child_pid! =-1) {int statloc; pid_t pid; if (pid = wait3 (& statloc, WNOHANG, NULL ))! = 0) {int exitcode = WEXITSTATUS (statloc); int bysignal = 0; if (WIFSIGNALED (statloc) bysignal = WTERMSIG (statloc); if (pid = server. rdb_child_pid) {backgroundSaveDoneHandler (exitcode, bysignal); // perform subsequent processing based on the exitcode of the bgsave sub-process and the tag indicating whether the signal ends} else if (pid = server. aof_child_pid) {backgroundRewriteDoneHandler (exitcode, bysignal);} else {redisLog (REDIS_WARNING, "Warning, detected child with unmatched pid: % ld", (long) pid );} updateDictResizePolicy ();}}
4. If the child process does not end with a signal and the exitcode is not 0, set the bgsave status to REDIS_ERR.
Void backgroundSaveDoneHandler (int exitcode, int bysignal) {if (! Bysignal & exitcode = 0) {redisLog (REDIS_NOTICE, "Background saving terminated with success"); server. dirty = server. dirty-server. dirty_before_bgsave; server. lastsave = time (NULL); server. lastbgsave_status = REDIS_ OK;} else if (! Bysignal & exitcode! = 0) {redisLog (REDIS_WARNING, "Background saving error"); server. latency = REDIS_ERR; // state conversion} else {mstime_t latency; redisLog (REDIS_WARNING, "Background saving terminated by signal % d", bysignal); latencyStartMonitor (latency); latency (server. rdb_child_pid); latencyEndMonitor (latency); latencyAddSampleIfNeeded ("rdb-unlink-temp-file", latency);/* SIGUSR1 is whitelisted, so we Have a way to kill a child without * tirggering an error conditon. */if (bysignal! = SIGUSR1) server. lastbgsave_status = REDIS_ERR;} server. rdb_child_pid =-1; 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 )? REDIS_ OK: REDIS_ERR );}
5. If processCommand determines that cmd is a write operation, REDIS_ OK is returned directly.
    /* Don't accept write commands if there are problems persisting on disk     * and if this is a master instance. */    if (((server.stop_writes_on_bgsave_err &&          server.saveparamslen > 0 &&          server.lastbgsave_status == REDIS_ERR) ||          server.aof_last_write_status == REDIS_ERR) &&        server.masterhost == NULL &&        (c->cmd->flags & REDIS_CMD_WRITE ||         c->cmd->proc == pingCommand))    {        flagTransaction(c);        if (server.aof_last_write_status == REDIS_OK)            addReply(c, shared.bgsaveerr);        else            addReplySds(c,                sdscatprintf(sdsempty(),                "-MISCONF Errors writing to the AOF file: %s\r\n",                strerror(server.aof_last_write_errno)));        return REDIS_OK;    }
6. If the command in luaRedisGenericCommand determines that cmd is a write operation, block it.
    /* Write commands are forbidden against read-only slaves, or if a     * command marked as non-deterministic was already called in the context     * of this script. */    if (cmd->flags & REDIS_CMD_WRITE) {        if (server.lua_random_dirty) {            luaPushError(lua,                "Write commands not allowed after non deterministic commands");            goto cleanup;        } else if (server.masterhost && server.repl_slave_ro &&                   !server.loading &&                   !(server.lua_caller->flags & REDIS_MASTER))        {            luaPushError(lua, shared.roslaveerr->ptr);            goto cleanup;        } else if (server.stop_writes_on_bgsave_err &&                   server.saveparamslen > 0 &&                   server.lastbgsave_status == REDIS_ERR)        {            luaPushError(lua, shared.bgsaveerr->ptr);            goto cleanup;        }    }cleanup:    /* Clean up. Command code may have changed argv/argc so we use the     * argv/argc of the client instead of the local variables. */    for (j = 0; j < c->argc; j++) {        robj *o = c->argv[j];        /* Try to cache the object in the cached_objects array.         * The object must be small, SDS-encoded, and with refcount = 1         * (we must be the only owner) for us to cache it. */        if (j < LUA_CMD_OBJCACHE_SIZE &&            o->refcount == 1 &&            o->encoding == REDIS_ENCODING_RAW &&            sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)        {            struct sdshdr *sh = (void*)(((char*)(o->ptr))-(sizeof(struct sdshdr)));            if (cached_objects[j]) decrRefCount(cached_objects[j]);            cached_objects[j] = o;            cached_objects_len[j] = sh->free + sh->len;        } else {            decrRefCount(o);        }    }    if (c->argv != argv) {        zfree(c->argv);        argv = NULL;    }    if (raise_error) {        /* If we are here we should have an error in the stack, in the         * form of a table with an "err" field. Extract the string to         * return the plain error. */        lua_pushstring(lua,"err");        lua_gettable(lua,-2);        return lua_error(lua);    }    return 1;  

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.