int compareStringObjectsWithFlags(robj *a, robj *b, int flags) { serverAssertWithInfo(NULL,a,a->type == OBJ_STRING && b->type == OBJ_STRING); char bufa[128], bufb[128], *astr, *bstr; size_t alen, blen, minlen; if (a == b) return 0; if (sdsEncodedObject(a)) { astr = a->ptr; alen = sdslen(astr); } else { alen = ll2string(bufa,sizeof(bufa),(long) a->ptr); astr = bufa; } if (sdsEncodedObject(b)) { bstr = b->ptr; blen = sdslen(bstr); } else { blen = ll2string(bufb,sizeof(bufb),(long) b->ptr); bstr = bufb; } if (flags & REDIS_COMPARE_COLL) { return strcoll(astr,bstr); } else { int cmp; minlen = (alen < blen) ? alen : blen; cmp = memcmp(astr,bstr,minlen); if (cmp == 0) return alen-blen; return cmp; } }
/* The API provided to the rest of the Redis core is a simple function: * * notifyKeyspaceEvent(char *event, robj *key, int dbid); * * 'event' is a C string representing the event name. * * event 参数是一个字符串表示的事件名 * * 'key' is a Redis object representing the key name. * * key 参数是一个 Redis 对象表示的键名 * * 'dbid' is the database ID where the key lives. * * dbid 参数为键所在的数据库 */ void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24]; /* If notifications for this class of events are off, return ASAP. */ // 如果服务器配置为不发送 type 类型的通知,那么直接返回 if (!(server.notify_keyspace_events & type)) return; // 事件的名字 eventobj = createStringObject(event,strlen(event)); /* __keyspace@<db>__:<key> <event> notifications. */ // 发送键空间通知 if (server.notify_keyspace_events & REDIS_NOTIFY_KEYSPACE) { // 构建频道对象 chan = sdsnewlen("__keyspace@",11); len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, key->ptr); chanobj = createObject(REDIS_STRING, chan); // 通过 publish 命令发送通知 pubsubPublishMessage(chanobj, eventobj); // 释放频道对象 decrRefCount(chanobj); } /* __keyevente@<db>__:<event> <key> notifications. */ // 发送键事件通知 if (server.notify_keyspace_events & REDIS_NOTIFY_KEYEVENT) { // 构建频道对象 chan = sdsnewlen("__keyevent@",11); // 如果在前面发送键空间通知的时候计算了 len ,那么它就不会是 -1 // 这可以避免计算两次 buf 的长度 if (len == -1) len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, eventobj->ptr); chanobj = createObject(REDIS_STRING, chan); // 通过 publish 命令发送通知 pubsubPublishMessage(chanobj, key); // 释放频道对象 decrRefCount(chanobj); } // 释放事件对象 decrRefCount(eventobj); }
int main() { int v1 = 0; int v2 = 10; int v3 = 100; int v4 = 100123; printf("%d to %s\n", v1, ll2string(v1)); printf("%d to %s\n", v2, ll2string(v2)); printf("%d to %s\n", v3, ll2string(v3)); printf("%d to %s\n", v4, ll2string(v4)); return 0; }
void luaTriggleSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec) { int j; lua_newtable(lua); for (j = 0; j < elec; j++) { if(elev[j]->encoding==REDIS_ENCODING_RAW){ lua_pushlstring(lua,(char*)elev[j]->ptr,sdslen(elev[j]->ptr)); lua_rawseti(lua,-2,j+1); } else{ if(elev[j]->encoding==REDIS_ENCODING_INT){ char buf[32]; ll2string(buf,32,(long)elev[j]->ptr); lua_pushlstring(lua,buf,strlen(buf)); lua_rawseti(lua,-2,j+1); } else{ redisLog(REDIS_WARNING,"Unknown type push to lua"); } } } lua_setglobal(lua,var); }
void addReplyBulkLen(redisClient *c, robj *obj) { size_t len, intlen; char buf[128]; if (obj->encoding == REDIS_ENCODING_RAW) { len = sdslen(obj->ptr); } else { long n = (long)obj->ptr; /* Compute how many bytes will take this integer as a radix 10 string */ len = 1; if (n < 0) { len++; n = -n; } while((n = n/10) != 0) { len++; } } buf[0] = '$'; intlen = ll2string(buf+1,sizeof(buf)-1,(long long)len); buf[intlen+1] = '\r'; buf[intlen+2] = '\n'; addReplySds(c,sdsnewlen(buf,intlen+3)); }
/* Write a long long value in format: "$<count>\r\n<payload>\r\n". */ size_t rioWriteBulkLongLong(rio *r, long long l) { char lbuf[32]; unsigned int llen; llen = ll2string(lbuf,sizeof(lbuf),l); return rioWriteBulkString(r,lbuf,llen); }
static char* rdb_read_string(int fd) { uint8_t is_encoded; uint32_t len; char *buf; int32_t val; len = rdb_read_store_len(fd, &is_encoded); if (is_encoded) { switch (len) { case REDIS_RDB_ENC_INT8: case REDIS_RDB_ENC_INT16: case REDIS_RDB_ENC_INT32: val = rdb_read_int(fd, len); return ll2string(val); case REDIS_RDB_ENC_LZF: return rdb_read_lzf_string(fd); default: logger(ERROR, "Exited, as error on load string.\n"); } } int i = 0, bytes; buf = malloc(len + 1); if (!buf) { logger(ERROR, "Exited, as malloc failed at load string.\n"); } while (i < len && (bytes = rdb_crc_read(fd, buf + i, len - i))) { i += bytes; } buf[len] = '\0'; return buf; }
/* Write a long value in bulk format $<count>\r\n<payload>\r\n */ int fwriteBulkLongLong(FILE *fp, long long l) { char bbuf[128], lbuf[128]; unsigned int blen, llen; llen = ll2string(lbuf,32,l); blen = snprintf(bbuf,sizeof(bbuf),"$%u\r\n%s\r\n",llen,lbuf); if (fwrite(bbuf,blen,1,fp) == 0) return 0; return 1; }
//获取字符串的长度 size_t stringObjectLen(robj *o) { redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); if (sdsEncodedObject(o)) { return sdslen(o->ptr); } else { char buf[32]; return ll2string(buf,32,(long)o->ptr); } }
/* Add a long long as integer reply or bulk len / multi bulk count. * Basically this is used to output <prefix><long long><crlf>. */ void addReplyLongLongWithPrefix(client *c, long long ll, char prefix) { char buf[128]; int len; buf[0] = prefix; len = ll2string(buf+1,sizeof(buf)-1,ll); buf[len+1] = '\r'; buf[len+2] = '\n'; addReplyString(c,buf,len+3); }
size_t stringObjectLen(robj *o) { redisAssert(o->type == REDIS_STRING); if (o->encoding == REDIS_ENCODING_RAW) { return sdslen(o->ptr); } else { char buf[32]; return ll2string(buf,32,(long)o->ptr); } }
/* The API provided to the rest of the Redis core is a simple function: * * notifyKeyspaceEvent(char *event, robj *key, int dbid); * * 'event' is a C string representing the event name. * 'key' is a Redis object representing the key name. * 'dbid' is the database ID where the key lives. */ void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24]; /* If any modules are interested in events, notify the module system now. * This bypasses the notifications configuration, but the module engine * will only call event subscribers if the event type matches the types * they are interested in. */ moduleNotifyKeyspaceEvent(type, event, key, dbid); /* If notifications for this class of events are off, return ASAP. */ if (!(server.notify_keyspace_events & type)) return; eventobj = createStringObject(event,strlen(event)); /* __keyspace@<db>__:<key> <event> notifications. */ if (server.notify_keyspace_events & NOTIFY_KEYSPACE) { chan = sdsnewlen("__keyspace@",11); len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, key->ptr); chanobj = createObject(OBJ_STRING, chan); pubsubPublishMessage(chanobj, eventobj); decrRefCount(chanobj); } /* __keyevent@<db>__:<event> <key> notifications. */ if (server.notify_keyspace_events & NOTIFY_KEYEVENT) { chan = sdsnewlen("__keyevent@",11); if (len == -1) len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, eventobj->ptr); chanobj = createObject(OBJ_STRING, chan); pubsubPublishMessage(chanobj, key); decrRefCount(chanobj); } decrRefCount(eventobj); }
/* 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; }
/* Write binary-safe string into a file in the bulkformat * $<count>\r\n<payload>\r\n */ int fwriteBulkString(FILE *fp, char *s, unsigned long len) { char cbuf[128]; int clen; cbuf[0] = '$'; clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,len); cbuf[clen++] = '\r'; cbuf[clen++] = '\n'; if (fwrite(cbuf,clen,1,fp) == 0) return 0; if (len > 0 && fwrite(s,len,1,fp) == 0) return 0; if (fwrite("\r\n",2,1,fp) == 0) return 0; return 1; }
/* Write a long long value in format: "$<count>\r\n<payload>\r\n". * * 以 "$<count>\r\n<payload>\r\n" 的格式写入 long long 值 */ size_t rioWriteBulkLongLong(rio *r, long long l) { char lbuf[32]; unsigned int llen; // 取出 long long 值的字符串形式 // 并计算该字符串的长度 llen = ll2string(lbuf,sizeof(lbuf),l); // 写入 $llen\r\nlbuf\r\n return rioWriteBulkString(r,lbuf,llen); }
/* Compare two string objects via strcmp() or alike. * Note that the objects may be integer-encoded. In such a case we * use ll2string() to get a string representation of the numbers on the stack * and compare the strings, it's much faster than calling getDecodedObject(). * * Important note: if objects are not integer encoded, but binary-safe strings, * sdscmp() from sds.c will apply memcmp() so this function ca be considered * binary safe. */ int compareStringObjects(robj *a, robj *b) { redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING); char bufa[128], bufb[128], *astr, *bstr; int bothsds = 1; if (a == b) return 0; if (a->encoding != REDIS_ENCODING_RAW) { ll2string(bufa,sizeof(bufa),(long) a->ptr); astr = bufa; bothsds = 0; } else { astr = a->ptr; } if (b->encoding != REDIS_ENCODING_RAW) { ll2string(bufb,sizeof(bufb),(long) b->ptr); bstr = bufb; bothsds = 0; } else { bstr = b->ptr; } return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr); }
/* * 返回字符串对象中字符串值的长度 */ size_t stringObjectLen(robj *o) { redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); if (sdsEncodedObject(o)) { return sdslen(o->ptr); // INT 编码,计算将这个值转换为字符串要多少字节 // 相当于返回它的长度 } else { char buf[32]; return ll2string(buf,32,(long)o->ptr); } }
//根据flags比较两个字符串对象a和b,返回0表示相等,非零表示不相等 int compareStringObjectsWithFlags(robj *a, robj *b, int flags) { serverAssertWithInfo(NULL,a,a->type == OBJ_STRING && b->type == OBJ_STRING); char bufa[128], bufb[128], *astr, *bstr; size_t alen, blen, minlen; if (a == b) return 0; //如果是同一对象直接返回 //如果是指向字符串值的两种OBJ_ENCODING_EMBSTR或OBJ_ENCODING_RAW的两类对象 if (sdsEncodedObject(a)) { astr = a->ptr; alen = sdslen(astr); //获取字符串的长度 } else { //如果是整数类型的OBJ_ENCODING_INT编码 alen = ll2string(bufa,sizeof(bufa),(long) a->ptr); //转换为字符串 astr = bufa; } //如果是指向字符串值的两种OBJ_ENCODING_EMBSTR或OBJ_ENCODING_RAW的两类对象 if (sdsEncodedObject(b)) { bstr = b->ptr; blen = sdslen(bstr); //获取字符串的长度 } else { //如果是整数类型的OBJ_ENCODING_INT编码 blen = ll2string(bufb,sizeof(bufb),(long) b->ptr); //转换为字符串 bstr = bufb; } //以本地指定的字符次序进行比较 if (flags & REDIS_COMPARE_COLL) { //strcoll()会依环境变量LC_COLLATE所指定的文字排列次序来比较两字符串 return strcoll(astr,bstr); //比较a和b的字符串对象,相等返回0 } else { //以二进制方式进行比较 int cmp; minlen = (alen < blen) ? alen : blen; cmp = memcmp(astr,bstr,minlen); //相等返回0,否则返回第一个字符串和第二个字符串的长度差 if (cmp == 0) return alen-blen; return cmp; } }
//通知键空间事件 void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24]; /* If notifications for this class of events are off, return ASAP. */ if (!(server.notify_keyspace_events & type)) return; eventobj = createStringObject(event,strlen(event)); /* __keyspace@<db>__:<key> <event> notifications. */ if (server.notify_keyspace_events & REDIS_NOTIFY_KEYSPACE) { chan = sdsnewlen("__keyspace@",11); len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, key->ptr); chanobj = createObject(REDIS_STRING, chan); pubsubPublishMessage(chanobj, eventobj); decrRefCount(chanobj); } /* __keyevente@<db>__:<event> <key> notifications. */ if (server.notify_keyspace_events & REDIS_NOTIFY_KEYEVENT) { chan = sdsnewlen("__keyevent@",11); if (len == -1) len = ll2string(buf,sizeof(buf),dbid); chan = sdscatlen(chan, buf, len); chan = sdscatlen(chan, "__:", 3); chan = sdscatsds(chan, eventobj->ptr); chanobj = createObject(REDIS_STRING, chan); pubsubPublishMessage(chanobj, key); decrRefCount(chanobj); } decrRefCount(eventobj); }
sds catAppendOnlyGenericCommand(sds dst, int argc, robj **argv) { char buf[32]; int len, j; robj *o; buf[0] = '*'; len = 1+ll2string(buf+1,sizeof(buf)-1,argc); buf[len++] = '\r'; buf[len++] = '\n'; dst = sdscatlen(dst,buf,len); for (j = 0; j < argc; j++) { o = getDecodedObject(argv[j]); buf[0] = '$'; len = 1+ll2string(buf+1,sizeof(buf)-1,sdslen(o->ptr)); buf[len++] = '\r'; buf[len++] = '\n'; dst = sdscatlen(dst,buf,len); dst = sdscatlen(dst,o->ptr,sdslen(o->ptr)); dst = sdscatlen(dst,"\r\n",2); decrRefCount(o); } return dst; }
/* Check if the sds string 's' can be represented by a long long * (that is, is a number that fits into long without any other space or * character before or after the digits, so that converting this number * back to a string will result in the same bytes as the original string). * * If so, the function returns REDIS_OK and *llongval is set to the value * of the number. Otherwise REDIS_ERR is returned */ int isStringRepresentableAsLongLong(sds s, long long *llongval) { char buf[32], *endptr; long long value; int slen; value = strtoll(s, &endptr, 10); if (endptr[0] != '\0') return REDIS_ERR; slen = ll2string(buf,32,value); /* If the number converted back into a string is not identical * then it's not possible to encode the string as integer */ if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR; if (llongval) *llongval = value; return REDIS_OK; }
/* Get a decoded version of an encoded object (returned as a new object). * If the object is already raw-encoded just increment the ref count. */ robj *getDecodedObject(robj *o) { robj *dec; if (sdsEncodedObject(o)) { return o; } if (o->type == OBJ_STRING && o->encoding == OBJ_ENCODING_INT) { char buf[32]; ll2string(buf,32,(long)o->ptr); dec = createStringObject(buf,strlen(buf)); return dec; } else { serverPanic("Unknown encoding type"); } }
void addReplyLongLong(redisClient *c, long long ll) { char buf[128]; size_t len; if (ll == 0) { addReply(c,shared.czero); return; } else if (ll == 1) { addReply(c,shared.cone); return; } buf[0] = ':'; len = ll2string(buf+1,sizeof(buf)-1,ll); buf[len+1] = '\r'; buf[len+2] = '\n'; addReplySds(c,sdsnewlen(buf,len+3)); }
//将对象是整型的解码为字符串并返回,如果是字符串编码则之间返回输入对象,只需增加引用计数 robj *getDecodedObject(robj *o) { robj *dec; if (sdsEncodedObject(o)) { //如果是OBJ_ENCODING_RAW或OBJ_ENCODING_EMBSTR类型的对象 incrRefCount(o); //增加应用计数 return o; } if (o->type == OBJ_STRING && o->encoding == OBJ_ENCODING_INT) { //如果是整数对象 char buf[32]; ll2string(buf,32,(long)o->ptr); //将整数转换为字符串 dec = createStringObject(buf,strlen(buf)); //创建一个字符串对象 return dec; } else { serverPanic("Unknown encoding type"); } }
/* Get a decoded version of an encoded object (returned as a new object). * If the object is already raw-encoded just increment the ref count. */ robj *getDecodedObject(robj *o) { robj *dec; if (o->encoding == REDIS_ENCODING_RAW) { incrRefCount(o); return o; } if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) { char buf[32]; ll2string(buf,32,(long)o->ptr); dec = createStringObject(buf,strlen(buf)); return dec; } else { redisPanic("Unknown encoding type"); } }
/* Get a decoded version of an encoded object (returned as a new object). * If the object is already raw-encoded just increment the ref count. */ robj *getDecodedObject(robj *o) { robj *dec; if (sdsEncodedObject(o)) { incrRefCount(o); return o; } if (o->type == OBJ_STRING && o->encoding == OBJ_ENCODING_INT) { char buf[32]; ll2string(buf,32,(long)o->ptr); dec = createStringObject(buf,strlen(buf)); return dec; } else { rr_log(RR_LOG_ERROR,"Unknown encoding type"); return NULL; } }
/* * 以带 '\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; }
/* Convert a double to a string representation. Returns the number of bytes * required. The representation should always be parsable by strtod(3). */ int d2string ( char *buf, size_t len, double value ) { if ( isnan (value) ) { len = snprintf (buf, len, "nan"); } else if ( isinf (value) ) { if ( value < 0 ) len = snprintf (buf, len, "-inf"); else len = snprintf (buf, len, "inf"); } else if ( value == 0 ) { /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */ if ( 1.0 / value < 0 ) len = snprintf (buf, len, "-0"); else len = snprintf (buf, len, "0"); } else { #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL) /* Check if the float is in a safe range to be casted into a * long long. We are assuming that long long is 64 bit here. * Also we are assuming that there are no implementations around where * double has precision < 52 bit. * * Under this assumptions we test if a double is inside an interval * where casting to long long is safe. Then using two castings we * make sure the decimal part is zero. If all this is true we use * integer printing function that is much faster. */ double min = - 4503599627370495; /* (2^52)-1 */ double max = 4503599627370496; /* -(2^52) */ if ( value > min && value < max && value == ( ( double ) ( ( long long ) value ) ) ) len = ll2string (buf, len, ( long long ) value); else #endif len = snprintf (buf, len, "%.17g", value); } return len; }
/// 将STRING类型的obj以string编码返回 robj *getDecodedObject(robj *o) { robj *dec; /// 已经是RAW编码,直接返回 if (sdsEncodedObject(o)) { incrRefCount(o); return o; } /// 将INT类型编码转为STRING编码并返回新的obj if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) { char buf[32]; ll2string(buf,32,(long)o->ptr); dec = createStringObject(buf,strlen(buf)); return dec; } else { redisPanic("Unknown encoding type"); } }
static void rdb_load_intset_value(lua_State *L, int fd) { int i; int64_t v64; char *str, *s64; str = rdb_read_string(fd); intset *is = (intset*) str; lua_pushstring(L, VAL_FIELD_STR); lua_newtable(L); for (i = 0; i < is->length; i++) { intset_get(is, i, &v64); s64 = ll2string(v64); script_push_list_elem(L, s64, i); free(s64); } lua_settable(L, -3); free(str); }