/* Emit the commands needed to rebuild a list object. * The function returns 0 on error, 1 on success. */ int rewriteListObject(rio *r, robj *key, robj *o) { long long count = 0, items = listTypeLength(o); if (o->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *zl = o->ptr; unsigned char *p = ziplistIndex(zl,0); unsigned char *vstr; unsigned int vlen; long long vlong; while(ziplistGet(p,&vstr,&vlen,&vlong)) { if (count == 0) { int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; if (rioWriteBulkCount(r,'*',2+cmd_items) == 0) return 0; if (rioWriteBulkString(r,"RPUSH",5) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0; } if (vstr) { if (rioWriteBulkString(r,(char*)vstr,vlen) == 0) return 0; } else { if (rioWriteBulkLongLong(r,vlong) == 0) return 0; } p = ziplistNext(zl,p); if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) { list *list = o->ptr; listNode *ln; listIter li; listRewind(list,&li); while((ln = listNext(&li))) { robj *eleobj = listNodeValue(ln); if (count == 0) { int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; if (rioWriteBulkCount(r,'*',2+cmd_items) == 0) return 0; if (rioWriteBulkString(r,"RPUSH",5) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0; } if (rioWriteBulkObject(r,eleobj) == 0) return 0; if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } } else { redisPanic("Unknown list encoding"); } return 1; }
/* Emit the commands needed to rebuild a hash object. * The function returns 0 on error, 1 on success. */ int rewriteHashObject(rio *r, robj *key, robj *o) { hashTypeIterator *hi; long long count = 0, items = hashTypeLength(o); hi = hashTypeInitIterator(o); while (hashTypeNext(hi) != REDIS_ERR) { if (count == 0) { int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; if (rioWriteBulkCount(r,'*',2+cmd_items*2) == 0) return 0; if (rioWriteBulkString(r,"HMSET",5) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0; } if (rioWriteHashIteratorCursor(r, hi, REDIS_HASH_KEY) == 0) return 0; if (rioWriteHashIteratorCursor(r, hi, REDIS_HASH_VALUE) == 0) return 0; if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } hashTypeReleaseIterator(hi); return 1; }
/* Emit the commands needed to rebuild a S3 object. * The function returns 0 on error, 1 on success */ int rewriteSssObject(rio *r, robj *key, robj *o) { sssTypeIterator *si; sssEntry *se; si = sssTypeInitIterator(o); while ((se = sssIterNext(si)) != NULL) { robj *ks, *svc, *skey, *val; long long idx, vll; int kv_mode; char *cmd; int cmdlen; if (sssIterPeek(se, &ks, &svc, &skey, &idx, &val, &vll, &kv_mode) == REDIS_ERR) return 0; if(kv_mode == SSS_KV_LIST) { cmd = "S3LADDAT"; cmdlen = 8; } else { redisAssert(kv_mode == SSS_KV_SET); cmd = "S3SADDAT"; cmdlen = 8; } if (rioWriteBulkCount(r, '*', 7) == 0) return 0; if (rioWriteBulkString(r, cmd, cmdlen) == 0) return 0; if (rioWriteBulkObject(r, ks) == 0) return 0; if (rioWriteBulkObject(r, key) == 0) return 0; if (rioWriteBulkObject(r, svc) == 0) return 0; if (rioWriteBulkObject(r, skey) == 0) return 0; /* idx is not used */ if (rioWriteBulkObject(r, val) == 0) return 0; if (rioWriteBulkLongLong(r, vll) == 0) return 0; } sssTypeReleaseIterator(si); return 1; }
/* 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; }
/* Emit the commands needed to rebuild a set object. * The function returns 0 on error, 1 on success. */ int rewriteSetObject(rio *r, robj *key, robj *o) { long long count = 0, items = setTypeSize(o); if (o->encoding == REDIS_ENCODING_INTSET) { int ii = 0; int64_t llval; while(intsetGet(o->ptr,ii++,&llval)) { if (count == 0) { int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; if (rioWriteBulkCount(r,'*',2+cmd_items) == 0) return 0; if (rioWriteBulkString(r,"SADD",4) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0; } if (rioWriteBulkLongLong(r,llval) == 0) return 0; if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } } else if (o->encoding == REDIS_ENCODING_HT) { dictIterator *di = dictGetIterator(o->ptr); dictEntry *de; while((de = dictNext(di)) != NULL) { robj *eleobj = dictGetKey(de); if (count == 0) { int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; if (rioWriteBulkCount(r,'*',2+cmd_items) == 0) return 0; if (rioWriteBulkString(r,"SADD",4) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0; } if (rioWriteBulkObject(r,eleobj) == 0) return 0; if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } dictReleaseIterator(di); } else { redisPanic("Unknown set encoding"); } return 1; }
/* 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; }
/* Emit the commands needed to rebuild a sorted set object. * The function returns 0 on error, 1 on success. */ int rewriteSortedSetObject(rio *r, robj *key, robj *o) { long long count = 0, items = zsetLength(o); if (o->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *zl = o->ptr; unsigned char *eptr, *sptr; unsigned char *vstr; unsigned int vlen; long long vll; double score; eptr = ziplistIndex(zl,0); redisAssert(eptr != NULL); sptr = ziplistNext(zl,eptr); redisAssert(sptr != NULL); while (eptr != NULL) { redisAssert(ziplistGet(eptr,&vstr,&vlen,&vll)); score = zzlGetScore(sptr); if (count == 0) { int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; if (rioWriteBulkCount(r,'*',2+cmd_items*2) == 0) return 0; if (rioWriteBulkString(r,"ZADD",4) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0; } if (rioWriteBulkDouble(r,score) == 0) return 0; if (vstr != NULL) { if (rioWriteBulkString(r,(char*)vstr,vlen) == 0) return 0; } else { if (rioWriteBulkLongLong(r,vll) == 0) return 0; } zzlNext(zl,&eptr,&sptr); if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } } else if (o->encoding == REDIS_ENCODING_SKIPLIST) { zset *zs = o->ptr; dictIterator *di = dictGetIterator(zs->dict); dictEntry *de; while((de = dictNext(di)) != NULL) { robj *eleobj = dictGetKey(de); double *score = dictGetVal(de); if (count == 0) { int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; if (rioWriteBulkCount(r,'*',2+cmd_items*2) == 0) return 0; if (rioWriteBulkString(r,"ZADD",4) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0; } if (rioWriteBulkDouble(r,*score) == 0) return 0; if (rioWriteBulkObject(r,eleobj) == 0) return 0; if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; items--; } dictReleaseIterator(di); } else { redisPanic("Unknown sorted zset encoding"); } return 1; }
static int slotsmgrt(redisClient *c, sds host, sds port, int fd, int dbid, int timeout, robj *keys[], robj *vals[], int n) { rio cmd; rioInitWithBuffer(&cmd, sdsempty()); redisAssertWithInfo(c, NULL, rioWriteBulkCount(&cmd, '*', 2)); redisAssertWithInfo(c, NULL, rioWriteBulkString(&cmd, "SELECT", 6)); redisAssertWithInfo(c, NULL, rioWriteBulkLongLong(&cmd, dbid)); redisAssertWithInfo(c, NULL, rioWriteBulkCount(&cmd, '*', 1 + 3 * n)); redisAssertWithInfo(c, NULL, rioWriteBulkString(&cmd, "SLOTSRESTORE", 12)); sds onekey = NULL; for (int i = 0; i < n; i ++) { robj *key = keys[i], *val = vals[i]; long long ttl = 0, expireat = getExpire(c->db, key); if (expireat != -1) { ttl = expireat - mstime(); if (ttl < 1) { ttl = 1; } } sds skey = key->ptr; redisAssertWithInfo(c, NULL, rioWriteBulkString(&cmd, skey, sdslen(skey))); redisAssertWithInfo(c, NULL, rioWriteBulkLongLong(&cmd, ttl)); do { rio pld; createDumpPayload(&pld, val); sds buf = pld.io.buffer.ptr; redisAssertWithInfo(c, NULL, rioWriteBulkString(&cmd, buf, sdslen(buf))); sdsfree(buf); } while (0); if (onekey == NULL) { onekey = skey; } } do { sds buf = cmd.io.buffer.ptr; size_t pos = 0, towrite; int nwritten = 0; while ((towrite = sdslen(buf) - pos) > 0) { towrite = (towrite > (64 * 1024) ? (64 * 1024) : towrite); nwritten = syncWrite(fd, buf + pos, towrite, timeout); if (nwritten != (signed)towrite) { redisLog(REDIS_WARNING, "slotsmgrt: writing to target %s:%s, error '%s', " "nkeys = %d, onekey = '%s', cmd.len = %ld, pos = %ld, towrite = %ld", host, port, server.neterr, n, onekey, sdslen(buf), pos, towrite); addReplySds(c, sdsnew("-IOERR error or timeout writing to target\r\n")); sdsfree(buf); return -1; } pos += nwritten; } sdsfree(buf); } while (0); do { char buf1[1024]; char buf2[1024]; if (syncReadLine(fd, buf1, sizeof(buf1), timeout) <= 0 || syncReadLine(fd, buf2, sizeof(buf2), timeout) <= 0) { redisLog(REDIS_WARNING, "slotsmgrt: reading from target %s:%s, error '%s', nkeys = %d, onekey = '%s'", host, port, server.neterr, n, onekey); addReplySds(c, sdsnew("-IOERR error or timeout reading from target\r\n")); return -1; } if (buf1[0] == '-' || buf2[0] == '-') { redisLog(REDIS_WARNING, "slotsmgrt: response from target %s:%s: rsp1 = '%s', rsp2 = '%s', nkeys = %d, onekey = '%s'", host, port, buf1, buf2, n, onekey); addReplyError(c, "error on slotsrestore"); return -1; } } while (0); redisLog(REDIS_VERBOSE, "slotsmgrt: migrate to %s:%s, nkeys = %d, onekey = '%s'", host, port, n, onekey); return 0; }