/* Write binary-safe string in the format: "$<count>\r\n<payload>\r\n". */ size_t rioWriteBulkString(rio *r, const char *buf, size_t len) { size_t nwritten; if ((nwritten = rioWriteBulkCount(r,'$',len)) == 0) return 0; if (len > 0 && rioWrite(r,buf,len) == 0) return 0; if (rioWrite(r,"\r\n",2) == 0) return 0; return nwritten+len+2; }
static int rdbWriteRaw(rio* rdb, void* p, size_t len) { if (rdb && rioWrite(rdb, p, len) == 0) { return -1; } return len; }
/* Write binary-safe string in the format: "$<count>\r\n<payload>\r\n". * * 以 "$<count>\r\n<payload>\r\n" 的形式写入二进制安全字符 * * 例如 $3\r\nSET\r\n */ size_t rioWriteBulkString(rio *r, const char *buf, size_t len) { size_t nwritten; // 写入 $<count>\r\n if ((nwritten = rioWriteBulkCount(r,'$',len)) == 0) return 0; // 写入 <payload> if (len > 0 && rioWrite(r,buf,len) == 0) return 0; // 写入 \r\n if (rioWrite(r,"\r\n",2) == 0) return 0; // 返回写入总量 return nwritten+len+2; }
void rdb_save_triggles(rio *rdb) { //save event //db_num int int int int //db //scripts_num //key event lua_scripts //key event lua_scripts //....... dictIterator *di = NULL; dictEntry *de; int i=0; for(i=0;i<server.dbnum;i++){ int eventid=server.bridge_db.bridge_event[i]; rioWrite(rdb,&eventid,4); } for(i=0;i<server.dbnum;i++) { dict *d = server.bridge_db.triggle_scipts[i]; int mysize=dictSize(d); rioWrite(rdb,&mysize,4); if (dictSize(d) == 0) continue; di = dictGetSafeIterator(d); if (!di) { return ; } /* Iterate this DB writing every entry */ while((de = dictNext(di)) != NULL) { sds keystr = dictGetKey(de); robj key; initStaticStringObject(key,keystr); if (rdbSaveStringObject(rdb,&key) == -1) return; struct bridge_db_triggle_t * tmptrg=dictGetVal(de); int event_id=tmptrg->event; rioWrite(rdb,&event_id,4); int db_id=tmptrg->dbid; rioWrite(rdb,&db_id,4); if (rdbSaveObjectType(rdb,tmptrg->lua_scripts) == -1) return ; if (rdbSaveObject(rdb,tmptrg->lua_scripts) == -1) return ; } } if (di) dictReleaseIterator(di); }
/* Write multi bulk count in the format: "*<count>\r\n". */ size_t rioWriteBulkCount(rio *r, char prefix, int count) { char cbuf[128]; int clen; cbuf[0] = prefix; clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,count); cbuf[clen++] = '\r'; cbuf[clen++] = '\n'; if (rioWrite(r,cbuf,clen) == 0) return 0; return clen; }
/* * 以带 '\r\n' 后缀的形式写入字符串表示的 count 到 RIO * * 成功返回写入的数量,失败返回 0 。 */ size_t rioWriteBulkCount(rio *r, char prefix, int count) { char cbuf[128]; int clen; // cbuf = prefix ++ count ++ '\r\n' // 例如: *123\r\n cbuf[0] = prefix; clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,count); cbuf[clen++] = '\r'; cbuf[clen++] = '\n'; // 写入 if (rioWrite(r,cbuf,clen) == 0) return 0; // 返回写入字节数 return clen; }
/* Write a sequence of commands able to fully rebuild the dataset into * "filename". Used both by REWRITEAOF and BGREWRITEAOF. * * In order to minimize the number of commands needed in the rewritten * log Redis uses variadic commands when possible, such as RPUSH, SADD * and ZADD. However at max REDIS_AOF_REWRITE_ITEMS_PER_CMD items per time * are inserted using a single command. */ int rewriteAppendOnlyFile(char *filename) { dictIterator *di = NULL; dictEntry *de; rio aof; FILE *fp; char tmpfile[256]; int j; long long now = mstime(); /* Note that we have to use a different temp name here compared to the * one used by rewriteAppendOnlyFileBackground() function. */ snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid()); fp = fopen(tmpfile,"w"); if (!fp) { redisLog(REDIS_WARNING, "Opening the temp file for AOF rewrite in rewriteAppendOnlyFile(): %s", strerror(errno)); return REDIS_ERR; } rioInitWithFile(&aof,fp); for (j = 0; j < server.dbnum; j++) { char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n"; redisDb *db = server.db+j; dict *d = db->dict; if (dictSize(d) == 0) continue; di = dictGetSafeIterator(d); if (!di) { fclose(fp); return REDIS_ERR; } /* SELECT the new DB */ if (rioWrite(&aof,selectcmd,sizeof(selectcmd)-1) == 0) goto werr; if (rioWriteBulkLongLong(&aof,j) == 0) goto werr; /* Iterate this DB writing every entry */ while((de = dictNext(di)) != NULL) { sds keystr; robj key, *o; long long expiretime; keystr = dictGetKey(de); o = dictGetVal(de); initStaticStringObject(key,keystr); expiretime = getExpire(db,&key); /* Save the key and associated value */ if (o->type == REDIS_STRING) { /* Emit a SET command */ char cmd[]="*3\r\n$3\r\nSET\r\n"; if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr; /* Key and value */ if (rioWriteBulkObject(&aof,&key) == 0) goto werr; if (rioWriteBulkObject(&aof,o) == 0) goto werr; } else if (o->type == REDIS_LIST) { if (rewriteListObject(&aof,&key,o) == 0) goto werr; } else if (o->type == REDIS_SET) { if (rewriteSetObject(&aof,&key,o) == 0) goto werr; } else if (o->type == REDIS_ZSET) { if (rewriteSortedSetObject(&aof,&key,o) == 0) goto werr; } else if (o->type == REDIS_HASH) { if (rewriteHashObject(&aof,&key,o) == 0) goto werr; } else { redisPanic("Unknown object type"); } /* Save the expire time */ if (expiretime != -1) { char cmd[]="*3\r\n$9\r\nPEXPIREAT\r\n"; /* If this key is already expired skip it */ if (expiretime < now) continue; if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr; if (rioWriteBulkObject(&aof,&key) == 0) goto werr; if (rioWriteBulkLongLong(&aof,expiretime) == 0) goto werr; } } dictReleaseIterator(di); } /* Make sure data will not remain on the OS's output buffers */ fflush(fp); aof_fsync(fileno(fp)); fclose(fp); /* 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 append only file on the final destination: %s", strerror(errno)); unlink(tmpfile); return REDIS_ERR; } redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed"); return REDIS_OK; werr: fclose(fp); unlink(tmpfile); redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno)); if (di) dictReleaseIterator(di); return REDIS_ERR; }