void init_kvstore_htable(){ kvpair_size = destor.index_key_size + destor.index_value_length * 8; if(destor.index_key_size >=4) htable = g_hash_table_new_full(g_int_hash, g_feature_equal, free_kvpair, NULL); else htable = g_hash_table_new_full(g_feature_hash, g_feature_equal, free_kvpair, NULL); sds indexpath = sdsdup(destor.working_directory); indexpath = sdscat(indexpath, "index/htable"); /* Initialize the feature index from the dump file. */ FILE *fp; if ((fp = fopen(indexpath, "r"))) { /* The number of features */ int key_num; fread(&key_num, sizeof(int), 1, fp); for (; key_num > 0; key_num--) { /* Read a feature */ kvpair kv = new_kvpair(); fread(get_key(kv), destor.index_key_size, 1, fp); /* The number of segments/containers the feature refers to. */ int id_num, i; fread(&id_num, sizeof(int), 1, fp); assert(id_num <= destor.index_value_length); for (i = 0; i < id_num; i++) /* Read an ID */ fread(&get_value(kv)[i], sizeof(int64_t), 1, fp); g_hash_table_insert(htable, get_key(kv), kv); } fclose(fp); } sdsfree(indexpath); }
S triefort_open(TF ** const fort, const HCFG * const hashcfg, const char * const path) { NULLCHK(fort); NULLCHK(hashcfg); NULLCHK(path); S s; sds fortpath = sdsnew(path); sds cfgpath = sdsdup(fortpath); cfgpath = sdscat(cfgpath, "/" CONFIG_FILE_NAME); if (!file_exists(cfgpath)) { s = triefort_err_not_a_triefort; } else { *fort = calloc(1, sizeof(**fort)); TF * f = *fort; f->path = fortpath; // *fort takes ownership of `fortpath` f->hcfg = hashcfg; if (triefort_ok == (s = load_cfg(&f->cfg, cfgpath))) { if (!validate_cfg(&(*fort)->cfg)) { s = triefort_err_invalid_config; } if (0 != strncmp(hashcfg->fn_name, (*fort)->cfg.hash_name, MAX_LEN_HASH_NAME)) { s = triefort_err_hash_name_mismatch; } if (triefort_ok != s) { triefort_close(*fort); *fort = NULL; } } } sdsfree(cfgpath); return s; }
static int process_command(sub_client *c) { srv_log(LOG_DEBUG, "c->argv[0]: %s", c->argv[0]); sds name = sdsnew(c->argv[0]); sdstolower(name); sub_command *cmd = ght_get(server.sub_commands, sdslen(name), name); if (!cmd) { add_reply_error_fmt(c, "unknown command '%s'", name); } else if ((cmd->arity > 0 && cmd->arity != c->argc) || (c->argc < -cmd->arity)) { add_reply_error_fmt(c, "wrong number of arguments for '%s' command", name); } else { srv_log(LOG_DEBUG, "cmd name: %s arity: %d", cmd->name, cmd->arity); cmd->proc(c); } sdsfree(name); return SUBCLI_OK; }
/* Try to encode a string object in order to save space */ robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; if (o->encoding != REDIS_ENCODING_RAW) return o; /* Already encoded */ /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ if (o->refcount > 1) return o; /* Currently we try to encode only strings */ redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); /* Check if we can represent this string as a long integer */ if (!string2l(s,sdslen(s),&value)) return o; /* Ok, this object can be encoded... * * Can I use a shared object? Only if the object is inside a given * range and if the back end in use is in-memory. For disk store every * object in memory used as value should be independent. * * Note that we also avoid using shared integers when maxmemory is used * because every object needs to have a private LRU field for the LRU * algorithm to work well. */ if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { o->encoding = REDIS_ENCODING_INT; sdsfree(o->ptr); o->ptr = (void*) value; return o; } }
int processLineBuffer(ugClient *c) { char *newline = strstr(c->querybuf, "\r\n"); int argc, j; sds *argv; size_t querylen; /* Nothing to do without a \r\n */ if (newline == NULL) { if (sdslen(c->querybuf) > UG_INLINE_MAX_SIZE) { addReplyErrorFormat(c, "Protocol error: too big inline request"); setProtocolError(c,0); } return UGERR; } /* Split the input buffer up to the \r\n */ querylen = newline-(c->querybuf); argv = sdssplitlen(c->querybuf,(int)querylen," ",1,&argc); /* Leave data after the first line of the query in the buffer */ c->querybuf = sdsrange(c->querybuf,(int)(querylen+2),-1); /* Setup argv array on client structure */ if (c->argv) zfree(c->argv); c->argv = zmalloc(sizeof(robj *)*argc); /* Create redis objects for all arguments. */ for (c->argc = 0, j = 0; j < argc; j++) { if (sdslen(argv[j])) { c->argv[c->argc] = createObject(UG_STRING,argv[j]); c->argc++; } else { sdsfree(argv[j]); } } zfree(argv); return UGOK; }
void parg_asset_preload(parg_token id) { if (!_pngsuffix) { _pngsuffix = sdsnew(".png"); } sds filename = parg_token_to_sds(id); parg_buffer* buf = parg_buffer_from_path(filename); parg_assert(buf, "Unable to load asset"); if (sdslen(filename) > 4) { sds suffix = sdsdup(filename); sdsrange(suffix, -4, -1); if (!sdscmp(suffix, _pngsuffix)) { unsigned char* decoded; unsigned dims[3] = {0, 0, 4}; unsigned char* filedata = parg_buffer_lock(buf, PARG_READ); unsigned err = lodepng_decode_memory(&decoded, &dims[0], &dims[1], filedata, parg_buffer_length(buf), LCT_RGBA, 8); parg_assert(err == 0, "PNG decoding error"); parg_buffer_free(buf); int nbytes = dims[0] * dims[1] * dims[2]; buf = parg_buffer_alloc(nbytes + 12, PARG_CPU); int* ptr = parg_buffer_lock(buf, PARG_WRITE); *ptr++ = dims[0]; *ptr++ = dims[1]; *ptr++ = dims[2]; memcpy(ptr, decoded, nbytes); free(decoded); parg_buffer_unlock(buf); } sdsfree(suffix); } if (!_asset_registry) { _asset_registry = kh_init(assmap); } int ret; int iter = kh_put(assmap, _asset_registry, id, &ret); kh_value(_asset_registry, iter) = buf; }
static int cliReadMultiBulkReply(int fd) { sds replylen = cliReadLine(fd); int elements, c = 1; int retval = 0; if (replylen == NULL) return 1; elements = atoi(replylen); if (elements == -1) { sdsfree(replylen); printf("(nil)\n"); return 0; } if (elements == 0) { printf("(empty list or set)\n"); } while(elements--) { if (config.tty) printf("%d. ", c); if (cliReadReply(fd)) retval = 1; if (elements) printf("%c",config.mb_sep); c++; } return retval; }
/* Write the output buffer to the socket. * * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was * succesfully written to the socket. When the buffer is empty after the * write operation, "wdone" is set to 1 (if given). * * Returns REDIS_ERR if an error occured trying to write and sets * c->error to hold the appropriate error string. */ int redisBufferWrite(redisContext *c, int *done) { int nwritten; if (sdslen(c->obuf) > 0) { nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); if (nwritten == -1) { if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) { /* Try again later */ } else { __redisSetError(c,REDIS_ERR_IO,NULL); return REDIS_ERR; } } else if (nwritten > 0) { if (nwritten == (signed)sdslen(c->obuf)) { sdsfree(c->obuf); c->obuf = sdsempty(); } else { c->obuf = sdsrange(c->obuf,nwritten,-1); } } } if (done != NULL) *done = (sdslen(c->obuf) == 0); return REDIS_OK; }
void server_accept_log_client(struct evconnlistener *listener, evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr) { int nlen = len - offsetof(struct sockaddr_un, sun_path); struct sockaddr_un caddr; caddr.sun_path[nlen] = '\0'; server.log_client_connected++; log_info("Accepted log client, current[%d] max[%d] total[%"PRIu64"]", server.rlc_list->count + 1, ZR_MAX_LOG_CONN, server.log_client_connected); if(server.rlc_list->count >= ZR_MAX_LOG_CONN) { ssize_t wl; log_warn("Reached max log client connection: %d, current client will be closed.", server.rlc_list->count + 1); sds msg = sdscatprintf(sdsempty(), "%s 1%sMax log client connection error. [%d]", ZR_CMD_REP_ERR, ZR_MSG_NL, server.rlc_list->count); wl = write(sock, msg, sdslen(msg)); sdsfree(msg); close(sock); return; } rlclient_alloc(sock, &caddr); }
void server_accept_client(struct evconnlistener *listener, evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr) { int port = ntohs(((struct sockaddr_in*)addr)->sin_port); sds ip = sdsnew(inet_ntoa(((struct sockaddr_in*)addr)->sin_addr)); server.client_connected++; log_info("Accepted client socket from %s:%d, current[%d], max[%d], total[%"PRIu64"]", ip, port, server.client_current + 1, server.client_max, server.client_connected); if(server.client_current >= server.client_max) { ssize_t wl; log_warn("Reached max connection: %d, client will be closed.", server.client_current + 1); sds msg = sdscatprintf(sdsempty(), "%s 1%sMax connection error.", ZR_CMD_REP_ERR, ZR_MSG_NL); wl = write(sock, msg, sdslen(msg)); sdsfree(msg); close(sock); return; } //struct client *c = client_alloc(sock, (struct sockaddr_in*)addr); client_alloc(sock, (struct sockaddr_in*)addr); }
void prezLogObjectDebugInfo(robj *o) { prezLog(PREZ_WARNING,"Object type: %d", o->type); prezLog(PREZ_WARNING,"Object encoding: %d", o->encoding); prezLog(PREZ_WARNING,"Object refcount: %d", o->refcount); if (o->type == PREZ_STRING && sdsEncodedObject(o)) { prezLog(PREZ_WARNING,"Object raw string len: %zu", sdslen(o->ptr)); if (sdslen(o->ptr) < 4096) { sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr)); prezLog(PREZ_WARNING,"Object raw string content: %s", repr); sdsfree(repr); } } /*else if (o->type == PREZ_LIST) { prezLog(PREZ_WARNING,"List length: %d", (int) listTypeLength(o)); } else if (o->type == PREZ_SET) { prezLog(PREZ_WARNING,"Set size: %d", (int) setTypeSize(o)); } else if (o->type == PREZ_HASH) { prezLog(PREZ_WARNING,"Hash size: %d", (int) hashTypeLength(o)); } else if (o->type == PREZ_ZSET) { prezLog(PREZ_WARNING,"Sorted set size: %d", (int) zsetLength(o)); if (o->encoding == PREZ_ENCODING_SKIPLIST) prezLog(PREZ_WARNING,"Skiplist level: %d", (int) ((zset*)o->ptr)->zsl->level); } */ }
void init_container_store() { sds containerfile = sdsdup(destor.working_directory); containerfile = sdscat(containerfile, "/container.pool"); if ((fp = fopen(containerfile, "r+"))) { fread(&container_count, 8, 1, fp); } else if (!(fp = fopen(containerfile, "w+"))) { perror( "Can not create container.pool for read and write because"); exit(1); } sdsfree(containerfile); container_buffer = sync_queue_new(25); pthread_mutex_init(&mutex, NULL); pthread_create(&append_t, NULL, append_thread, NULL); NOTICE("Init container store successfully"); }
static void parseMarks(json_value *_marks, subtable_gpos_mark_to_ligature *subtable, classname_hash **h) { NEW(subtable->marks); subtable->marks->numGlyphs = _marks->u.object.length; NEW_N(subtable->marks->glyphs, subtable->marks->numGlyphs); NEW(subtable->markArray); subtable->markArray->markCount = _marks->u.object.length; NEW_N(subtable->markArray->records, subtable->markArray->markCount); for (uint16_t j = 0; j < _marks->u.object.length; j++) { char *gname = _marks->u.object.values[j].name; json_value *anchorRecord = _marks->u.object.values[j].value; subtable->marks->glyphs[j].name = sdsnewlen(gname, _marks->u.object.values[j].name_length); subtable->markArray->records[j].markClass = 0; subtable->markArray->records[j].anchor = otl_anchor_absent(); if (!anchorRecord || anchorRecord->type != json_object) continue; json_value *_className = json_obj_get_type(anchorRecord, "class", json_string); if (!_className) continue; sds className = sdsnewlen(_className->u.string.ptr, _className->u.string.length); classname_hash *s; HASH_FIND_STR(*h, className, s); if (!s) { NEW(s); s->className = className; s->classID = HASH_COUNT(*h); HASH_ADD_STR(*h, className, s); } else { sdsfree(className); } subtable->markArray->records[j].markClass = s->classID; subtable->markArray->records[j].anchor.present = true; subtable->markArray->records[j].anchor.x = json_obj_getnum(anchorRecord, "x"); subtable->markArray->records[j].anchor.y = json_obj_getnum(anchorRecord, "y"); } }
bool consolidate_gsub_multi(otfcc_Font *font, table_OTL *table, otl_Subtable *_subtable, const otfcc_Options *options) { subtable_gsub_multi *subtable = &(_subtable->gsub_multi); gsub_multi_hash *h = NULL; for (glyphid_t k = 0; k < subtable->length; k++) { if (!GlyphOrder.consolidateHandle(font->glyph_order, &subtable->items[k].from)) { logWarning("[Consolidate] Ignored missing glyph /%s.\n", subtable->items[k].from.name); continue; } fontop_consolidateCoverage(font, subtable->items[k].to, options); Coverage.shrink(subtable->items[k].to, false); gsub_multi_hash *s; int fromid = subtable->items[k].from.index; HASH_FIND_INT(h, &fromid, s); if (!s) { NEW(s); s->fromid = subtable->items[k].from.index; s->fromname = sdsdup(subtable->items[k].from.name); s->to = subtable->items[k].to; subtable->items[k].to = NULL; // Transfer ownership HASH_ADD_INT(h, fromid, s); } } HASH_SORT(h, by_from_id_multi); iSubtable_gsub_multi.clear(subtable); { gsub_multi_hash *s, *tmp; HASH_ITER(hh, h, s, tmp) { iSubtable_gsub_multi.push(subtable, ((otl_GsubMultiEntry){ .from = Handle.fromConsolidated(s->fromid, s->fromname), .to = s->to, })); sdsfree(s->fromname); HASH_DEL(h, s); FREE(s); }
/* Try to encode a string object in order to save space */ robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; if (o->encoding != REDIS_ENCODING_RAW) return o; /* Already encoded */ /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ if (o->refcount > 1) return o; /* Currently we try to encode only strings */ redisAssert(o->type == REDIS_STRING); /* Check if we can represent this string as a long integer */ if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return o; /* Ok, this object can be encoded... * * Can I use a shared object? Only if the object is inside a given * range and if this is the main thread, since when VM is enabled we * have the constraint that I/O thread should only handle non-shared * objects, in order to avoid race conditions (we don't have per-object * locking). */ if (value >= 0 && value < REDIS_SHARED_INTEGERS && pthread_equal(pthread_self(),server.mainthread)) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { o->encoding = REDIS_ENCODING_INT; sdsfree(o->ptr); o->ptr = (void*) value; return o; } }
static int cliReadReply(int output_raw_strings) { void *_reply; redisReply *reply; sds out; if (redisGetReply(context,&_reply) != REDIS_OK) { if (config.shutdown) return REDIS_OK; if (config.interactive) { /* Filter cases where we should reconnect */ if (context->err == REDIS_ERR_IO && errno == ECONNRESET) return REDIS_ERR; if (context->err == REDIS_ERR_EOF) return REDIS_ERR; } cliPrintContextError(); exit(1); return REDIS_ERR; /* avoid compiler warning */ } reply = (redisReply*)_reply; if (output_raw_strings) { out = cliFormatReplyRaw(reply); } else { if (config.raw_output) { out = cliFormatReplyRaw(reply); out = sdscat(out,"\n"); } else { out = cliFormatReplyTTY(reply,""); } } fwrite(out,sdslen(out),1,stdout); sdsfree(out); freeReplyObject(reply); return REDIS_OK; }
static int cliReadBulkReply(int fd) { sds replylen = cliReadLine(fd); char *reply, crlf[2]; int bulklen; if (replylen == NULL) return 1; bulklen = atoi(replylen); if (bulklen == -1) { sdsfree(replylen); printf("(nil)\n"); return 0; } reply = zmalloc(bulklen); anetRead(fd,reply,bulklen); anetRead(fd,crlf,2); if (bulklen && fwrite(reply,bulklen,1,stdout) == 0) { zfree(reply); return 1; } if (isatty(fileno(stdout)) && reply[bulklen-1] != '\n') printf("\n"); zfree(reply); return 0; }
void lsCommand(redisClient* c) { DIR* pstDir = opendir((const char*)c->argv[1]->ptr); if (pstDir == NULL) { addReplyErrorFormat(c, "opendir fail, %s", strerror(errno)); return; } list* dir = listCreate(); struct dirent* pstDirent = NULL; while ((pstDirent = readdir(pstDir)) != NULL) { if(strcmp(pstDirent->d_name, ".") == 0 || strcmp(pstDirent->d_name, "..") == 0) continue; sds path = sdsdup(c->argv[1]->ptr); size_t len = sdslen(path); if (path[len - 1] != '/') path = sdscat(path, "/"); path = sdscat(path, pstDirent->d_name); listAddNodeTail(dir, path); } closedir(pstDir); addReplyMultiBulkLen(c, listLength(dir)); listIter* iter = listGetIterator(dir, AL_START_HEAD); listNode* node = NULL; while ((node = listNext(iter))) { addReplyBulkCString(c, node->value); sdsfree(node->value); listDelNode(dir, node); } listRelease(dir); }
/* Try to encode a string object in order to save space */ static int tryObjectEncoding(robj *o) { long value; sds s = o->ptr; if (o->encoding != REDIS_ENCODING_RAW) return REDIS_ERR; /* Already encoded */ /* It's not save to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ if (o->refcount > 1) return REDIS_ERR; /* Currently we try to encode only strings */ redisAssert(o->type == REDIS_STRING); /* Check if we can represent this string as a long integer */ if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return REDIS_ERR; /* Ok, this object can be encoded */ o->encoding = REDIS_ENCODING_INT; sdsfree(o->ptr); o->ptr = (void*) value; return REDIS_OK; }
static void listDeleteClientObjects(void *cl) { ugClient *c = (ugClient *) cl; resetClient(c); if (c->querybuf) sdsfree(c->querybuf); if (c->reply) { LOG_TRACE("reply size :%d", listLength(c->reply)); listRelease(c->reply); } pubsubUnsubscribeAllChannels(c, 0); if (c->pubsub_channels) dictRelease(c->pubsub_channels); if (c->pubsub_patterns) listRelease(c->pubsub_patterns); aeDeleteFileEvent(server.el, c->fd, AE_READABLE); aeDeleteFileEvent(server.el, c->fd, AE_WRITABLE); #ifdef _WIN32 aeWinCloseSocket(c->fd); #else close(c->fd); #endif zfree(c); c = NULL; }
void luaReplyToRedisReply(redisClient *c, lua_State *lua) { int t = lua_type(lua,-1); switch(t) { case LUA_TSTRING: addReplyBulkCBuffer(c,(char*)lua_tostring(lua,-1),lua_strlen(lua,-1)); break; case LUA_TBOOLEAN: addReply(c,lua_toboolean(lua,-1) ? shared.cone : shared.nullbulk); break; case LUA_TNUMBER: addReplyLongLong(c,(long long)lua_tonumber(lua,-1)); break; case LUA_TTABLE: /* We need to check if it is an array, an error, or a status reply. * Error are returned as a single element table with 'err' field. * Status replies are returned as single element table with 'ok' field */ lua_pushstring(lua,"err"); lua_gettable(lua,-2); t = lua_type(lua,-1); if (t == LUA_TSTRING) { sds err = sdsnew(lua_tostring(lua,-1)); sdsmapchars(err,"\r\n"," ",2); addReplySds(c,sdscatprintf(sdsempty(),"-%s\r\n",err)); sdsfree(err); lua_pop(lua,2); return; } lua_pop(lua,1); lua_pushstring(lua,"ok"); lua_gettable(lua,-2); t = lua_type(lua,-1); if (t == LUA_TSTRING) { sds ok = sdsnew(lua_tostring(lua,-1)); sdsmapchars(ok,"\r\n"," ",2); addReplySds(c,sdscatprintf(sdsempty(),"+%s\r\n",ok)); sdsfree(ok); lua_pop(lua,1); } else { void *replylen = addDeferredMultiBulkLength(c); int j = 1, mbulklen = 0; lua_pop(lua,1); /* Discard the 'ok' field value we popped */ while(1) { lua_pushnumber(lua,j++); lua_gettable(lua,-2); t = lua_type(lua,-1); if (t == LUA_TNIL) { lua_pop(lua,1); break; } luaReplyToRedisReply(c, lua); mbulklen++; } setDeferredMultiBulkLength(c,replylen,mbulklen); } break; default: addReply(c,shared.nullbulk); } lua_pop(lua,1); }
static void callbackKeyDestructor(void *privdata, void *key) { ((void) privdata); sdsfree((sds)key); }
int luaRedisGenericCommand(lua_State *lua, int raise_error) { int j, argc = lua_gettop(lua); struct redisCommand *cmd; robj **argv; redisClient *c = server.lua_client; sds reply; /* Require at least one argument */ if (argc == 0) { luaPushError(lua, "Please specify at least one argument for redis.call()"); return 1; } /* Build the arguments vector */ argv = zmalloc(sizeof(robj*)*argc); for (j = 0; j < argc; j++) { if (!lua_isstring(lua,j+1)) break; argv[j] = createStringObject((char*)lua_tostring(lua,j+1), lua_strlen(lua,j+1)); } /* Check if one of the arguments passed by the Lua script * is not a string or an integer (lua_isstring() return true for * integers as well). */ if (j != argc) { j--; while (j >= 0) { decrRefCount(argv[j]); j--; } zfree(argv); luaPushError(lua, "Lua redis() command arguments must be strings or integers"); return 1; } /* Setup our fake client for command execution */ c->argv = argv; c->argc = argc; /* Command lookup */ cmd = lookupCommand(argv[0]->ptr); if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) || (argc < -cmd->arity))) { if (cmd) luaPushError(lua, "Wrong number of args calling Redis command From Lua script"); else luaPushError(lua,"Unknown Redis command called from Lua script"); goto cleanup; } /* There are commands that are not allowed inside scripts. */ if (cmd->flags & REDIS_CMD_NOSCRIPT) { luaPushError(lua, "This Redis command is not allowed from scripts"); goto cleanup; } /* 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; } } /* If we reached the memory limit configured via maxmemory, commands that * could enlarge the memory usage are not allowed, but only if this is the * first write in the context of this script, otherwise we can't stop * in the middle. */ if (server.maxmemory && server.lua_write_dirty == 0 && (cmd->flags & REDIS_CMD_DENYOOM)) { if (freeMemoryIfNeeded() == REDIS_ERR) { luaPushError(lua, shared.oomerr->ptr); goto cleanup; } } if (cmd->flags & REDIS_CMD_RANDOM) server.lua_random_dirty = 1; if (cmd->flags & REDIS_CMD_WRITE) server.lua_write_dirty = 1; /* Run the command */ c->cmd = cmd; call(c,REDIS_CALL_SLOWLOG | REDIS_CALL_STATS); /* Convert the result of the Redis command into a suitable Lua type. * The first thing we need is to create a single string from the client * output buffers. */ reply = sdsempty(); if (c->bufpos) { reply = sdscatlen(reply,c->buf,c->bufpos); c->bufpos = 0; } while(listLength(c->reply)) { robj *o = listNodeValue(listFirst(c->reply)); reply = sdscatlen(reply,o->ptr,sdslen(o->ptr)); listDelNode(c->reply,listFirst(c->reply)); } if (raise_error && reply[0] != '-') raise_error = 0; redisProtocolToLuaType(lua,reply); /* Sort the output array if needed, assuming it is a non-null multi bulk * reply as expected. */ if ((cmd->flags & REDIS_CMD_SORT_FOR_SCRIPT) && (reply[0] == '*' && reply[1] != '-')) { luaSortArray(lua); } sdsfree(reply); c->reply_bytes = 0; 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++) decrRefCount(c->argv[j]); zfree(c->argv); 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; }
TEST(sds, sds) { // struct sdshdr *sh; sds x = sdsnew("foo"), y; TEST_ASSERT_TRUE( sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) sdsfree(x); x = sdsnewlen("foo",2); TEST_ASSERT_TRUE( sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) x = sdscat(x,"bar"); TEST_ASSERT_TRUE( sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); x = sdscpy(x,"a"); TEST_ASSERT_TRUE( sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); TEST_ASSERT_TRUE( sdslen(x) == 33 && memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) sdsfree(x); x = sdscatprintf(sdsempty(),"%d",123); TEST_ASSERT_TRUE( sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) sdsfree(x); x = sdsnew("xxciaoyyy"); sdstrim(x,"xy"); TEST_ASSERT_TRUE( sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) y = sdsdup(x); sdsrange(y,1,1); TEST_ASSERT_TRUE( sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,-1); TEST_ASSERT_TRUE( sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,-2,-1); TEST_ASSERT_TRUE( sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,2,1); TEST_ASSERT_TRUE( sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,100); TEST_ASSERT_TRUE( sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,100,100); TEST_ASSERT_TRUE( sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); sdsfree(x); x = sdsnew("foo"); y = sdsnew("foa"); TEST_ASSERT_TRUE( sdscmp(x,y) > 0) sdsfree(y); sdsfree(x); x = sdsnew("bar"); y = sdsnew("bar"); TEST_ASSERT_TRUE( sdscmp(x,y) == 0) sdsfree(y); sdsfree(x); x = sdsnew("aar"); y = sdsnew("bar"); TEST_ASSERT_TRUE( sdscmp(x,y) < 0) sdsfree(y); sdsfree(x); // x = sdsnewlen("\a\n\0foo\r",7); // y = sdscatrepr(sdsempty(),x,sdslen(x)); // TEST_ASSERT_TRUE( // memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) #if 0 { int oldfree; sdsfree(x); x = sdsnew("0"); sh = (void*) (x-(sizeof(struct sdshdr))); TEST_ASSERT_TRUE( sh->len == 1 && sh->free == 0); x = sdsMakeRoomFor(x,1); sh = (void*) (x-(sizeof(struct sdshdr))); TEST_ASSERT_TRUE( sh->len == 1 && sh->free > 0); oldfree = sh->free; x[1] = '1'; sdsIncrLen(x,1); TEST_ASSERT_TRUE( x[0] == '0' && x[1] == '1'); TEST_ASSERT_TRUE( sh->len == 2); TEST_ASSERT_TRUE( sh->free == oldfree-1); } #endif }
void freeClient(redisClient *c) { listNode *ln; /* Note that if the client we are freeing is blocked into a blocking * call, we have to set querybuf to NULL *before* to call * unblockClientWaitingData() to avoid processInputBuffer() will get * called. Also it is important to remove the file events after * this, because this call adds the READABLE event. */ sdsfree(c->querybuf); c->querybuf = NULL; if (c->flags & REDIS_BLOCKED) unblockClientWaitingData(c); /* UNWATCH all the keys */ unwatchAllKeys(c); listRelease(c->watched_keys); /* Unsubscribe from all the pubsub channels */ pubsubUnsubscribeAllChannels(c,0); pubsubUnsubscribeAllPatterns(c,0); dictRelease(c->pubsub_channels); listRelease(c->pubsub_patterns); /* Obvious cleanup */ aeDeleteFileEvent(server.el,c->fd,AE_READABLE); aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); listRelease(c->reply); freeClientArgv(c); close(c->fd); /* Remove from the list of clients */ ln = listSearchKey(server.clients,c); redisAssert(ln != NULL); listDelNode(server.clients,ln); /* Remove from the list of clients waiting for swapped keys, or ready * to be restarted, but not yet woken up again. */ if (c->flags & REDIS_IO_WAIT) { redisAssert(server.vm_enabled); if (listLength(c->io_keys) == 0) { ln = listSearchKey(server.io_ready_clients,c); /* When this client is waiting to be woken up (REDIS_IO_WAIT), * it should be present in the list io_ready_clients */ redisAssert(ln != NULL); listDelNode(server.io_ready_clients,ln); } else { while (listLength(c->io_keys)) { ln = listFirst(c->io_keys); dontWaitForSwappedKey(c,ln->value); } } server.vm_blocked_clients--; } listRelease(c->io_keys); /* Master/slave cleanup. * Case 1: we lost the connection with a slave. */ if (c->flags & REDIS_SLAVE) { if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1) close(c->repldbfd); list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves; ln = listSearchKey(l,c); redisAssert(ln != NULL); listDelNode(l,ln); } /* Case 2: we lost the connection with the master. */ if (c->flags & REDIS_MASTER) { server.master = NULL; server.replstate = REDIS_REPL_CONNECT; /* Since we lost the connection with the master, we should also * close the connection with all our slaves if we have any, so * when we'll resync with the master the other slaves will sync again * with us as well. Note that also when the slave is not connected * to the master it will keep refusing connections by other slaves. */ while (listLength(server.slaves)) { ln = listFirst(server.slaves); freeClient((redisClient*)ln->value); } } /* Release memory */ zfree(c->argv); zfree(c->mbargv); freeClientMultiState(c); zfree(c); }
int redisvFormatCommand(char **target, const char *format, va_list ap) { const char *c = format; char *cmd = NULL; /* final command */ int pos; /* position in final command */ sds curarg, newarg; /* current argument */ int touched = 0; /* was the current argument touched? */ char **curargv = NULL, **newargv = NULL; int argc = 0; int totlen = 0; int j; /* Abort if there is not target to set */ if (target == NULL) return -1; /* Build the command string accordingly to protocol */ curarg = sdsempty(); if (curarg == NULL) return -1; while(*c != '\0') { if (*c != '%' || c[1] == '\0') { if (*c == ' ') { if (touched) { newargv = realloc(curargv,sizeof(char*)*(argc+1)); if (newargv == NULL) goto err; curargv = newargv; curargv[argc++] = curarg; totlen += bulklen(sdslen(curarg)); /* curarg is put in argv so it can be overwritten. */ curarg = sdsempty(); if (curarg == NULL) goto err; touched = 0; } } else { newarg = sdscatlen(curarg,c,1); if (newarg == NULL) goto err; curarg = newarg; touched = 1; } } else { char *arg; size_t size; /* Set newarg so it can be checked even if it is not touched. */ newarg = curarg; switch(c[1]) { case 's': arg = va_arg(ap,char*); size = strlen(arg); if (size > 0) newarg = sdscatlen(curarg,arg,size); break; case 'b': arg = va_arg(ap,char*); size = va_arg(ap,size_t); if (size > 0) newarg = sdscatlen(curarg,arg,size); break; case '%': newarg = sdscat(curarg,"%"); break; default: /* Try to detect printf format */ { char _format[16]; const char *_p = c+1; size_t _l = 0; va_list _cpy; /* Flags */ if (*_p != '\0' && *_p == '#') _p++; if (*_p != '\0' && *_p == '0') _p++; if (*_p != '\0' && *_p == '-') _p++; if (*_p != '\0' && *_p == ' ') _p++; if (*_p != '\0' && *_p == '+') _p++; /* Field width */ while (*_p != '\0' && isdigit(*_p)) _p++; /* Precision */ if (*_p == '.') { _p++; while (*_p != '\0' && isdigit(*_p)) _p++; } /* Copy va_list before consuming with va_arg */ va_copy(_cpy,ap); /* Integer conversion (without modifiers) */ if (strchr("diouxX",*_p) != NULL) { va_arg(ap,int); goto fmt_valid; } /* Double conversion (without modifiers) */ if (strchr("eEfFgGaA",*_p) != NULL) { va_arg(ap,double); goto fmt_valid; } /* Size: char */ if (_p[0] == 'h' && _p[1] == 'h') { _p += 2; if (*_p != '\0' && strchr("diouxX",*_p) != NULL) { va_arg(ap,int); /* char gets promoted to int */ goto fmt_valid; } goto fmt_invalid; } /* Size: short */ if (_p[0] == 'h') { _p += 1; if (*_p != '\0' && strchr("diouxX",*_p) != NULL) { va_arg(ap,int); /* short gets promoted to int */ goto fmt_valid; } goto fmt_invalid; } /* Size: long long */ if (_p[0] == 'l' && _p[1] == 'l') { _p += 2; if (*_p != '\0' && strchr("diouxX",*_p) != NULL) { va_arg(ap,long long); goto fmt_valid; } goto fmt_invalid; } /* Size: long */ if (_p[0] == 'l') { _p += 1; if (*_p != '\0' && strchr("diouxX",*_p) != NULL) { va_arg(ap,long); goto fmt_valid; } goto fmt_invalid; } fmt_invalid: va_end(_cpy); goto err; fmt_valid: _l = (_p+1)-c; if (_l < sizeof(_format)-2) { memcpy(_format,c,_l); _format[_l] = '\0'; newarg = sdscatvprintf(curarg,_format,_cpy); /* Update current position (note: outer blocks * increment c twice so compensate here) */ c = _p-1; } va_end(_cpy); break; } } if (newarg == NULL) goto err; curarg = newarg; touched = 1; c++; } c++; } /* Add the last argument if needed */ if (touched) { newargv = realloc(curargv,sizeof(char*)*(argc+1)); if (newargv == NULL) goto err; curargv = newargv; curargv[argc++] = curarg; totlen += bulklen(sdslen(curarg)); } else { sdsfree(curarg); } /* Clear curarg because it was put in curargv or was free'd. */ curarg = NULL; /* Add bytes needed to hold multi bulk count */ totlen += 1+intlen(argc)+2; /* Build the command at protocol level */ cmd = malloc(totlen+1); if (cmd == NULL) goto err; pos = sprintf(cmd,"*%d\r\n",argc); for (j = 0; j < argc; j++) { pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); pos += sdslen(curargv[j]); sdsfree(curargv[j]); cmd[pos++] = '\r'; cmd[pos++] = '\n'; } assert(pos == totlen); cmd[pos] = '\0'; free(curargv); *target = cmd; return totlen; err: while(argc--) sdsfree(curargv[argc]); free(curargv); if (curarg != NULL) sdsfree(curarg); /* No need to check cmd since it is the last statement that can fail, * but do it anyway to be as defensive as possible. */ if (cmd != NULL) free(cmd); return -1; }
/* dictionary types */ static void dictSdsDestructor(void *privdata, void *val) { DICT_NOTUSED(privdata); sdsfree((sds)val); }
void processInputBuffer(redisClient *c) { again: /* Before to process the input buffer, make sure the client is not * waitig for a blocking operation such as BLPOP. Note that the first * iteration the client is never blocked, otherwise the processInputBuffer * would not be called at all, but after the execution of the first commands * in the input buffer the client may be blocked, and the "goto again" * will try to reiterate. The following line will make it return asap. */ if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return; if (c->bulklen == -1) { /* Read the first line of the query */ char *p = strchr(c->querybuf,'\n'); size_t querylen; if (p) { sds query, *argv; int argc, j; query = c->querybuf; c->querybuf = sdsempty(); querylen = 1+(p-(query)); if (sdslen(query) > querylen) { /* leave data after the first line of the query in the buffer */ c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen); } *p = '\0'; /* remove "\n" */ if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */ sdsupdatelen(query); /* Now we can split the query in arguments */ argv = sdssplitlen(query,sdslen(query)," ",1,&argc); sdsfree(query); if (c->argv) zfree(c->argv); c->argv = zmalloc(sizeof(robj*)*argc); for (j = 0; j < argc; j++) { if (sdslen(argv[j])) { c->argv[c->argc] = createObject(REDIS_STRING,argv[j]); c->argc++; } else { sdsfree(argv[j]); } } zfree(argv); if (c->argc) { /* Execute the command. If the client is still valid * after processCommand() return and there is something * on the query buffer try to process the next command. */ if (processCommand(c) && sdslen(c->querybuf)) goto again; } else { /* Nothing to process, argc == 0. Just process the query * buffer if it's not empty or return to the caller */ if (sdslen(c->querybuf)) goto again; } return; } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) { redisLog(REDIS_VERBOSE, "Client protocol error"); freeClient(c); return; } } else { /* Bulk read handling. Note that if we are at this point the client already sent a command terminated with a newline, we are reading the bulk data that is actually the last argument of the command. */ int qbl = sdslen(c->querybuf); if (c->bulklen <= qbl) { /* Copy everything but the final CRLF as final argument */ c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2); c->argc++; c->querybuf = sdsrange(c->querybuf,c->bulklen,-1); /* Process the command. If the client is still valid after * the processing and there is more data in the buffer * try to parse it. */ if (processCommand(c) && sdslen(c->querybuf)) goto again; return; } } }
int redisvFormatCommand(char **target, const char *format, va_list ap) { size_t size; const char *arg, *c = format; char *cmd = NULL; /* final command */ int pos; /* position in final command */ sds current; /* current argument */ int touched = 0; /* was the current argument touched? */ char **argv = NULL; int argc = 0, j; int totlen = 0; /* Abort if there is not target to set */ if (target == NULL) return -1; /* Build the command string accordingly to protocol */ current = sdsempty(); while(*c != '\0') { if (*c != '%' || c[1] == '\0') { if (*c == ' ') { if (touched) { addArgument(current, &argv, &argc, &totlen); current = sdsempty(); touched = 0; } } else { current = sdscatlen(current,c,1); touched = 1; } } else { switch(c[1]) { case 's': arg = va_arg(ap,char*); size = strlen(arg); if (size > 0) current = sdscatlen(current,arg,size); break; case 'b': arg = va_arg(ap,char*); size = va_arg(ap,size_t); if (size > 0) current = sdscatlen(current,arg,size); break; case '%': current = sdscat(current,"%"); break; default: /* Try to detect printf format */ { char _format[16]; const char *_p = c+1; size_t _l = 0; va_list _cpy; /* Flags */ if (*_p != '\0' && *_p == '#') _p++; if (*_p != '\0' && *_p == '0') _p++; if (*_p != '\0' && *_p == '-') _p++; if (*_p != '\0' && *_p == ' ') _p++; if (*_p != '\0' && *_p == '+') _p++; /* Field width */ while (*_p != '\0' && isdigit(*_p)) _p++; /* Precision */ if (*_p == '.') { _p++; while (*_p != '\0' && isdigit(*_p)) _p++; } /* Modifiers */ if (*_p != '\0') { if (*_p == 'h' || *_p == 'l') { /* Allow a single repetition for these modifiers */ if (_p[0] == _p[1]) _p++; _p++; } } /* Conversion specifier */ if (*_p != '\0' && strchr("diouxXeEfFgGaA",*_p) != NULL) { _l = (_p+1)-c; if (_l < sizeof(_format)-2) { memcpy(_format,c,_l); _format[_l] = '\0'; va_copy(_cpy,ap); current = sdscatvprintf(current,_format,_cpy); va_end(_cpy); /* Update current position (note: outer blocks * increment c twice so compensate here) */ c = _p-1; } } /* Consume and discard vararg */ va_arg(ap,void); } } touched = 1; c++; } c++; } /* Add the last argument if needed */ if (touched) { addArgument(current, &argv, &argc, &totlen); } else { sdsfree(current); } /* Add bytes needed to hold multi bulk count */ totlen += 1+intlen(argc)+2; /* Build the command at protocol level */ cmd = malloc(totlen+1); if (!cmd) redisOOM(); pos = sprintf(cmd,"*%d\r\n",argc); for (j = 0; j < argc; j++) { pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(argv[j])); memcpy(cmd+pos,argv[j],sdslen(argv[j])); pos += sdslen(argv[j]); sdsfree(argv[j]); cmd[pos++] = '\r'; cmd[pos++] = '\n'; } assert(pos == totlen); free(argv); cmd[totlen] = '\0'; *target = cmd; return totlen; }
void freeValue(value_t *val) { if (val->encoding == ENCODING_RAW) { sdsfree(val->ptr); } zfree(val); }