/* Duplicate the whole list. On out of memory NULL is returned. * On success a copy of the original list is returned. * * The 'Dup' method set with listSetDupMethod() function is used * to copy the node value. Otherwise the same pointer value of * the original node is used as value of the copied node. * * The original list both on success or error is never modified. */ hilist *listDup(hilist *orig) { hilist *copy; listIter *iter; listNode *node; if ((copy = listCreate()) == NULL) return NULL; copy->dup = orig->dup; copy->free = orig->free; copy->match = orig->match; iter = listGetIterator(orig, AL_START_HEAD); while((node = listNext(iter)) != NULL) { void *value; if (copy->dup) { value = copy->dup(node->value); if (value == NULL) { listRelease(copy); listReleaseIterator(iter); return NULL; } } else value = node->value; if (listAddNodeTail(copy, value) == NULL) { listRelease(copy); listReleaseIterator(iter); return NULL; } } listReleaseIterator(iter); return copy; }
/* Duplicate the whole list. On out of memory NULL is returned. * On success a copy of the original list is returned. * * The 'Dup' method set with listSetDupMethod() function is used * to copy the node value. Otherwise the same pointer value of * the original node is used as value of the copied node. * * The original list both on success or error is never modified. */ list *listDup(list *orig) { list *copy; listIter iter; listNode *node; if ((copy = listCreate()) == NULL) return NULL; copy->dup = orig->dup; copy->free = orig->free; copy->match = orig->match; listRewind(orig, &iter); while((node = listNext(&iter)) != NULL) { void *value; if (copy->dup) { value = copy->dup(node->value); if (value == NULL) { listRelease(copy); return NULL; } } else value = node->value; if (listAddNodeTail(copy, value) == NULL) { listRelease(copy); return NULL; } } return copy; }
void freeFakeClient(struct redisClient *c) { sdsfree(c->querybuf); listRelease(c->reply); listRelease(c->watched_keys); freeClientMultiState(c); zfree(c); }
void cleanup_http_session(cli *c) { if (c->http.resp_hdr) { listRelease(c->http.resp_hdr); c->http.resp_hdr = NULL; } if (c->http.req_hdr) { listRelease(c->http.req_hdr); c->http.req_hdr = NULL; } }
void vnode_free(vnode_t *vnode){ work_queue_t *wq = vnode->write_queue; if ( wq != NULL ) { exit_work_queue(wq); zfree(wq); vnode->write_queue = NULL; } if ( vnode->logFile != 0 ){ close(vnode->logFile); vnode->logFile = 0; } if ( vnode->active_slicedb != NULL ){ uint32_t active_slicedb_id = vnode->active_slicedb->id; for ( int db_id = 0 ; db_id < active_slicedb_id ; db_id++ ){ if ( vnode->slicedbs[db_id] != NULL ){ slicedb_free(vnode->slicedbs[db_id]); vnode->slicedbs[db_id] = NULL; } } } if ( vnode->kvdb_metadata != NULL ){ kvdb_close(vnode->kvdb_metadata); vnode->kvdb_metadata = NULL; } if ( vnode->caching_objects != NULL ){ object_queue_free(vnode->caching_objects); vnode->caching_objects = NULL; } listRelease(vnode->received_objects); vnode->received_object_size = 0; listRelease(vnode->standby_objects); vnode->standby_object_size = 0; /* Index DB */ /*if ( vnode->kvdb != NULL ){*/ /*kvdb_close(vnode->kvdb);*/ /*vnode->kvdb = NULL;*/ /*}*/ /* datazones */ int i; for ( i = 0 ; i < MAX_DATAZONES ; i++ ){ if ( vnode->datazones[i] != NULL ){ datazone_destroy(vnode->datazones[i]); zfree(vnode->datazones[i]); } } zfree(vnode); }
void freeClient(vuiClient *c) { listNode *ln; listIter *it; cJSON *json; /* Free the query buffer */ sdsfree(c->querybuf); sdsfree(c->querymsg); sdsfree(c->res.body); sdsfree(c->res.reason); sdsfree(c->res.buf); /* Close socket, unregister events, and remove list of replies and * accumulated arguments. */ if (c->fd != -1) { aeDeleteFileEvent(server.el,c->fd,AE_READABLE); aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); close(c->fd); } it = listGetIterator(c->jsons, AL_START_HEAD); while((ln = listNext(it))) { json = (cJSON *)ln->value; cJSON_Delete(json); listDelNode(c->jsons, ln); } listRelease(c->jsons); listReleaseIterator(it); zfree(c); server.client = NULL; }
void dictCounterDestructor(void *privdata, void *val) { DICT_NOTUSED(privdata); listNode *ln; listIter li; counter *cntr = val; pubsub *p; /* Unsubscribe everyone */ if (cntr->subscribers != NULL) { while (listLength(cntr->subscribers)) { ln = listFirst(cntr->subscribers); p = listNodeValue(ln); pubsubUnsubscribeCounter(p->c,cntr->name,1); } } /* Free all shards */ listRewind(cntr->shards,&li); while ((ln = listNext(&li)) != NULL) { shard *shrd = listNodeValue(ln); zfree(shrd); } listRelease(cntr->shards); if (cntr->want_acks) dictRelease(cntr->want_acks); /* cntr->name will be freed by the dict code. */ zfree(cntr); }
int luaworkDoDir(lua_State *L,const char *path, char *err) { int ret = UGOK; sds relpath = sdsempty(); list *queue = listCreate(); listNode *node=NULL; listIter *iter = NULL; if (xfilelistdir(path, "*.lua", queue) == UGERR) { luaworkSetError(err, "list files for %s failed", path); ret = UGERR; goto END; } iter = listGetIterator(queue, AL_START_HEAD); while ((node=listNext(iter))!=NULL) { const char *filename = (char *) (node->value); sdsclear(relpath); relpath = sdscatprintf(relpath, "%s/%s", path, filename); ret = luaworkDoFile(L, relpath, err); if (ret != UGOK) break; } listReleaseIterator(iter); END: listRelease(queue); sdsfree(relpath); return ret; }
void msg_put(struct msg *msg) { listNode *node; struct mbuf *mbuf; log_debug(LOG_VVERB, "put msg %p id %"PRIu64"", msg, msg->id); while (listLength(msg->data) > 0) { node = listFirst(msg->data); mbuf = listNodeValue(node); listDelNode(msg->data, node); mbuf_put(mbuf); } listRelease(msg->data); msg->data = NULL; if (msg->frag_seq) { rmt_free(msg->frag_seq); msg->frag_seq = NULL; } if (msg->keys) { msg->keys->nelem = 0; /* a hack here */ array_destroy(msg->keys); msg->keys = NULL; } msg->mb = NULL; }
/* This function free the old AOF rewrite buffer if needed, and initialize * a fresh new one. It tests for server.aof_rewrite_buf_blocks equal to NULL * so can be used for the first initialization as well. */ void aofRewriteBufferReset(void) { if (server.aof_rewrite_buf_blocks) listRelease(server.aof_rewrite_buf_blocks); server.aof_rewrite_buf_blocks = listCreate(); listSetFreeMethod(server.aof_rewrite_buf_blocks,zfree); }
int mgr_on_process_init(event_manager* ev_mgr) { if (ev_mgr->excluded_threads != NULL) listRelease(ev_mgr->excluded_threads); ev_mgr->excluded_threads = NULL; ev_mgr->excluded_threads = listCreate(); ev_mgr->excluded_threads->match = &pidcomp; int rc = launch_rdma(ev_mgr->con_node); if (rc != 0 ) fprintf(stderr, "EVENT MANAGER : Cannot start rdma\n"); rc = launch_replica_thread(ev_mgr->con_node, ev_mgr->excluded_threads); if (rc != 0 ) fprintf(stderr, "EVENT MANAGER : Cannot launch replica thread\n"); pthread_t check_point_thread; if (pthread_create(&check_point_thread, NULL, &check_point_thread_start, NULL) != 0) fprintf(stderr, "EVENT MANAGER : Cannot create check point thread\n"); pthread_t *ck_thread = (pthread_t*)malloc(sizeof(pthread_t)); *ck_thread = check_point_thread; listAddNodeTail(ev_mgr->excluded_threads, (void*)ck_thread); return rc; }
void aofRewriteBufferReset(void){ /*release old buffer list if it exists, create new buffer list*/ if(server.aof_rewrite_buf_blocks){ listRelease(server.aof_rewrite_buf_blocks); } server.aof_rewrite_buf_blocks = listCreate(); listSetFreeMethod(server.aof_rewrite_buf_blocks, zfree); }
list *listDup(list *orign) /*{{{*/ { list *cpy; listIter *iter; listNode *node; if((cpy = listCreate()) == NULL) { return NULL; } cpy->free = orign->free; cpy->dup = orign->dup; cpy->match = orign->match; iter = listGetIterator(orign, AL_START_HEAD); while((node = listNext(iter)) != NULL) { void *value; if(cpy->dup) { value = cpy->dup(node->value); if(value == NULL) { listRelease(cpy); listReleaseIterator(iter); return NULL; } } else { value = node->value; } //出错只有一种情况,就是malloc失败了,return NULL; if(listAddNodeTail(cpy, value) == NULL) { listRelease(cpy); listReleaseIterator(iter); return NULL; } } listReleaseIterator(iter); return cpy; }
static void freeListOfIndRow(list *ll, int num_cols, bool is_ob) { listNode *ln; listIter *li = listGetIterator(ll, AL_START_HEAD); while((ln = listNext(li)) != NULL) { freeIndRow(ln->value, num_cols, is_ob, 1); } listReleaseIterator(li); listRelease(ll); }
/* 列表赋值方法,传入的参数为原始列表 */ list *listDup(list *orig) { list *copy; listIter *iter; listNode *node; //如果创建列表失败则直接返回 if ((copy = listCreate()) == NULL) return NULL; //为新列表赋值好3个函数指针 copy->dup = orig->dup; copy->free = orig->free; copy->match = orig->match; //获得从头方向开始的迭代器 iter = listGetIterator(orig, AL_START_HEAD); while((node = listNext(iter)) != NULL) { //从前往后遍历结点 void *value; if (copy->dup) { //如果定义了列表复制方法,则调用dup方法 value = copy->dup(node->value); if (value == NULL) { //如果发生OOM内存溢出问题,直接释放所有空间 listRelease(copy); listReleaseIterator(iter); return NULL; } } else //没定义直接复制函数指针 value = node->value; if (listAddNodeTail(copy, value) == NULL) { //后面的结点都是从尾部逐一添加结点,如果内存溢出,同上操作 listRelease(copy); listReleaseIterator(iter); return NULL; } } //最后释放迭代器 listReleaseIterator(iter); return copy; }
void aeDeleteEventLoop(aeEventLoop *eventLoop) { aeApiFree(eventLoop); #ifdef _WIN32 dictRelease(eventLoop->fdiMap->map); listRelease(eventLoop->fdiMap->recycle_pool); zfree(eventLoop->fdiMap); #endif zfree(eventLoop->events); zfree(eventLoop->fired); zfree(eventLoop); }
void delete_list() { listNode *node; list *ll=found_list(&node); if(ll){ listDelNode(listall,node); listRelease(ll); printf("释放完毕\n"); }else{ printf("没有这个链表\n"); } }
void freeListObject(robj *o) { switch (o->encoding) { case REDIS_ENCODING_LINKEDLIST: listRelease((list*) o->ptr); break; case REDIS_ENCODING_ZIPLIST: zfree(o->ptr); break; default: redisPanic("Unknown list encoding type"); } }
static void init_DXDB_PersistentStorageItems(uint32 ntbl, uint32 nindx) { if (Tbl) free(Tbl); Num_tbls = 0; Tbl = malloc(sizeof(r_tbl_t) * ntbl); bzero(Tbl, sizeof(r_tbl_t) * ntbl); Tbl_HW = ntbl; if (TblD) dictRelease(TblD); TblD = dictCreate(&sdsDictType, NULL); if (DropT) { listRelease(DropT); DropT = NULL; } if (Index) free(Index); Num_indx = 0; Index = malloc(sizeof(r_ind_t) * nindx); bzero(Index, sizeof(r_ind_t) * nindx); Ind_HW = nindx; if (IndD) dictRelease(IndD); IndD = dictCreate(&sdsDictType, NULL); if (DropI) { listRelease(DropI); DropI = NULL; } if (StmtD) dictRelease(StmtD); StmtD = dictCreate(&dbDictType, NULL); }
/* Duplicate the whole list. On out of memory NULL is returned. * On success a copy of the original list is returned. * * The 'Dup' method set with listSetDupMethod() function is used * to copy the node value. Otherwise the same pointer value of * the original node is used as value of the copied node. * * The original list both on success or error is never modified. */ list *listDup(list *orig) { list *copy; listIter *iter; listNode *node; if ((copy = listCreate()) == NULL) return NULL; /* set the auxiliary function */ copy->dup = orig->dup; copy->free = orig->free; copy->match = orig->match; /* get iter of list from head */ iter = listGetIterator(orig, AL_START_HEAD); /* loop all the node of list */ while((node = listNext(iter)) != NULL) { void *value; /* if there is a user defined copy function */ if (copy->dup) { /* set value by calling user defined function */ value = copy->dup(node->value); if (value == NULL) { /* opppps, we get some error */ listRelease(copy);/* release the new list */ listReleaseIterator(iter); /* release the iterator */ return NULL; } } else value = node->value; /* shadow copy if there isn't a user defined function */ if (listAddNodeTail(copy, value) == NULL) { /* if we get some error when add the new node to the end of the new list */ listRelease(copy);/* release the new list */ listReleaseIterator(iter); /* release the iterator */ return NULL; } } listReleaseIterator(iter);/* release the iterator */ return copy; }
/* * * slotsdel slot1 [slot2 ...] * */ void slotsdelCommand(redisClient *c) { int slots_slot[HASH_SLOTS_SIZE]; int n = 0; if (c->argc <= 1) { addReplyErrorFormat(c, "wrong number of arguments for 'slotsdel' command"); return; } int i; for (i = 1; i < c->argc; i ++) { int slot; if (parse_slot(c, c->argv[i], &slot) != 0) { return; } slots_slot[n] = slot; n ++; } for (i = 0; i < n; i ++) { dict *d = c->db->hash_slots[slots_slot[i]]; int s = dictSize(d); if (s == 0) { continue; } list *l = listCreate(); listSetFreeMethod(l, decrRefCountVoid); unsigned long cursor = 0; do { cursor = dictScan(d, cursor, slotsScanSdsKeyCallback, l); } while (cursor != 0); while (1) { listNode *head = listFirst(l); if (head == NULL) { break; } robj *key = listNodeValue(head); robj *keys[] = {key}; slotsremove(c, keys, 1, 0); listDelNode(l, head); } listRelease(l); } addReplyMultiBulkLen(c, n); for (i = 0; i < n; i ++) { int n = slots_slot[i]; int s = dictSize(c->db->hash_slots[n]); addReplyMultiBulkLen(c, 2); addReplyLongLong(c, n); addReplyLongLong(c, s); } }
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; }
static void free_redis_test_client(redis_test_client *c) { printf("%s %d: fd = %d\n", __FUNCTION__, __LINE__, c->fd); /* Free the query buffer */ sdsfree(c->querybuf); c->querybuf = NULL; /* Free data structures. */ listRelease(c->reply); /* Unlink the client: this will close the socket, remove the I/O * handlers, and remove references of the client from different * places where active clients may be referenced. */ unlink_redis_test_client(c); zfree(c); }
aeEventLoop *aeCreateEventLoop(int setsize) { aeEventLoop *eventLoop; int i; if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) goto err; eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize); eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize); if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err; eventLoop->setsize = setsize; eventLoop->lastTime = time(NULL); eventLoop->timeEventHead = NULL; eventLoop->timeEventNextId = 0; eventLoop->stop = 0; eventLoop->maxfd = EVENTLOOP_MAXFD_INITIAL_VALUE; eventLoop->beforesleep = NULL; if (aeApiCreate(eventLoop) == -1) goto err; /* Events with mask == AE_NONE are not set. So let's initialize the * vector with it. */ for (i = 0; i < setsize; i++) eventLoop->events[i].mask = AE_NONE; #ifdef _WIN32 if ((eventLoop->fdiMap = zmalloc(sizeof(fd_index_map_t))) == NULL) goto err; eventLoop->fdiMap->map = dictCreate(&fdiDictType, NULL); eventLoop->fdiMap->recycle_pool = listCreate(); if (eventLoop->fdiMap->map == NULL || eventLoop->fdiMap->recycle_pool == NULL) goto err; eventLoop->fdiMap->next_available = 3; // stdin(0), stdout(1) and stderr(2) #endif return eventLoop; err: #ifdef _WIN32 if (eventLoop->fdiMap) { if (eventLoop->fdiMap->map != NULL) dictRelease(eventLoop->fdiMap->map); if (eventLoop->fdiMap->recycle_pool != NULL) listRelease(eventLoop->fdiMap->recycle_pool); zfree(eventLoop->fdiMap); } #endif if (eventLoop) { zfree(eventLoop->events); zfree(eventLoop->fired); zfree(eventLoop); } return NULL; }
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); }
void aio_destroy(void) { if (aio_ctx) { if (-1 == io_destroy(aio_ctx)) { logerror("io_destroy fail. %s", strerror(errno)); } } if (aio_fd) { if (-1 == close(aio_fd)) { logerror("close eventfd fail. %s", strerror(errno)); } } #if AIO_QUEUE if (aio_queue) { listRelease(aio_queue); } #endif }
int main(int argc, char *argv[]) { unsigned char *zl, *p; unsigned char *entry; unsigned int elen; long long value; /* If an argument is given, use it as the random seed. */ if (argc == 2) srand(atoi(argv[1])); zl = createIntList(); ziplistRepr(zl); zl = createList(); ziplistRepr(zl); pop(zl,ZIPLIST_TAIL); ziplistRepr(zl); pop(zl,ZIPLIST_HEAD); ziplistRepr(zl); pop(zl,ZIPLIST_TAIL); ziplistRepr(zl); pop(zl,ZIPLIST_TAIL); ziplistRepr(zl); printf("Get element at index 3:\n"); { zl = createList(); p = ziplistIndex(zl, 3); if (!ziplistGet(p, &entry, &elen, &value)) { printf("ERROR: Could not access index 3\n"); return 1; } if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); printf("\n"); } else { printf("%lld\n", value); } printf("\n"); } printf("Get element at index 4 (out of range):\n"); { zl = createList(); p = ziplistIndex(zl, 4); if (p == NULL) { printf("No entry\n"); } else { printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl); return 1; } printf("\n"); } printf("Get element at index -1 (last element):\n"); { zl = createList(); p = ziplistIndex(zl, -1); if (!ziplistGet(p, &entry, &elen, &value)) { printf("ERROR: Could not access index -1\n"); return 1; } if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); printf("\n"); } else { printf("%lld\n", value); } printf("\n"); } printf("Get element at index -4 (first element):\n"); { zl = createList(); p = ziplistIndex(zl, -4); if (!ziplistGet(p, &entry, &elen, &value)) { printf("ERROR: Could not access index -4\n"); return 1; } if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); printf("\n"); } else { printf("%lld\n", value); } printf("\n"); } printf("Get element at index -5 (reverse out of range):\n"); { zl = createList(); p = ziplistIndex(zl, -5); if (p == NULL) { printf("No entry\n"); } else { printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl); return 1; } printf("\n"); } printf("Iterate list from 0 to end:\n"); { zl = createList(); p = ziplistIndex(zl, 0); while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } p = ziplistNext(zl,p); printf("\n"); } printf("\n"); } printf("Iterate list from 1 to end:\n"); { zl = createList(); p = ziplistIndex(zl, 1); while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } p = ziplistNext(zl,p); printf("\n"); } printf("\n"); } printf("Iterate list from 2 to end:\n"); { zl = createList(); p = ziplistIndex(zl, 2); while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } p = ziplistNext(zl,p); printf("\n"); } printf("\n"); } printf("Iterate starting out of range:\n"); { zl = createList(); p = ziplistIndex(zl, 4); if (!ziplistGet(p, &entry, &elen, &value)) { printf("No entry\n"); } else { printf("ERROR\n"); } printf("\n"); } printf("Iterate from back to front:\n"); { zl = createList(); p = ziplistIndex(zl, -1); while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } p = ziplistPrev(zl,p); printf("\n"); } printf("\n"); } printf("Iterate from back to front, deleting all items:\n"); { zl = createList(); p = ziplistIndex(zl, -1); while (ziplistGet(p, &entry, &elen, &value)) { printf("Entry: "); if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld", value); } zl = ziplistDelete(zl,&p); p = ziplistPrev(zl,p); printf("\n"); } printf("\n"); } printf("Delete inclusive range 0,0:\n"); { zl = createList(); zl = ziplistDeleteRange(zl, 0, 1); ziplistRepr(zl); } printf("Delete inclusive range 0,1:\n"); { zl = createList(); zl = ziplistDeleteRange(zl, 0, 2); ziplistRepr(zl); } printf("Delete inclusive range 1,2:\n"); { zl = createList(); zl = ziplistDeleteRange(zl, 1, 2); ziplistRepr(zl); } printf("Delete with start index out of range:\n"); { zl = createList(); zl = ziplistDeleteRange(zl, 5, 1); ziplistRepr(zl); } printf("Delete with num overflow:\n"); { zl = createList(); zl = ziplistDeleteRange(zl, 1, 5); ziplistRepr(zl); } printf("Delete foo while iterating:\n"); { zl = createList(); p = ziplistIndex(zl,0); while (ziplistGet(p,&entry,&elen,&value)) { if (entry && strncmp("foo",(char*)entry,elen) == 0) { printf("Delete foo\n"); zl = ziplistDelete(zl,&p); } else { printf("Entry: "); if (entry) { if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite"); } else { printf("%lld",value); } p = ziplistNext(zl,p); printf("\n"); } } printf("\n"); ziplistRepr(zl); } printf("Regression test for >255 byte strings:\n"); { char v1[257],v2[257]; memset(v1,'x',256); memset(v2,'y',256); zl = ziplistNew(); zl = ziplistPush(zl,(unsigned char*)v1,strlen(v1),ZIPLIST_TAIL); zl = ziplistPush(zl,(unsigned char*)v2,strlen(v2),ZIPLIST_TAIL); /* Pop values again and compare their value. */ p = ziplistIndex(zl,0); assert(ziplistGet(p,&entry,&elen,&value)); assert(strncmp(v1,(char*)entry,elen) == 0); p = ziplistIndex(zl,1); assert(ziplistGet(p,&entry,&elen,&value)); assert(strncmp(v2,(char*)entry,elen) == 0); printf("SUCCESS\n\n"); } printf("Regression test deleting next to last entries:\n"); { char v[3][257]; zlentry e[3]; int i; for (i = 0; i < (sizeof(v)/sizeof(v[0])); i++) { memset(v[i], 'a' + i, sizeof(v[0])); } v[0][256] = '\0'; v[1][ 1] = '\0'; v[2][256] = '\0'; zl = ziplistNew(); for (i = 0; i < (sizeof(v)/sizeof(v[0])); i++) { zl = ziplistPush(zl, (unsigned char *) v[i], strlen(v[i]), ZIPLIST_TAIL); } verify(zl, e); assert(e[0].prevrawlensize == 1); assert(e[1].prevrawlensize == 5); assert(e[2].prevrawlensize == 1); /* Deleting entry 1 will increase `prevrawlensize` for entry 2 */ unsigned char *p = e[1].p; zl = ziplistDelete(zl, &p); verify(zl, e); assert(e[0].prevrawlensize == 1); assert(e[1].prevrawlensize == 5); printf("SUCCESS\n\n"); } printf("Create long list and check indices:\n"); { zl = ziplistNew(); char buf[32]; int i,len; for (i = 0; i < 1000; i++) { len = sprintf(buf,"%d",i); zl = ziplistPush(zl,(unsigned char*)buf,len,ZIPLIST_TAIL); } for (i = 0; i < 1000; i++) { p = ziplistIndex(zl,i); assert(ziplistGet(p,NULL,NULL,&value)); assert(i == value); p = ziplistIndex(zl,-i-1); assert(ziplistGet(p,NULL,NULL,&value)); assert(999-i == value); } printf("SUCCESS\n\n"); } printf("Compare strings with ziplist entries:\n"); { zl = createList(); p = ziplistIndex(zl,0); if (!ziplistCompare(p,(unsigned char*)"hello",5)) { printf("ERROR: not \"hello\"\n"); return 1; } if (ziplistCompare(p,(unsigned char*)"hella",5)) { printf("ERROR: \"hella\"\n"); return 1; } p = ziplistIndex(zl,3); if (!ziplistCompare(p,(unsigned char*)"1024",4)) { printf("ERROR: not \"1024\"\n"); return 1; } if (ziplistCompare(p,(unsigned char*)"1025",4)) { printf("ERROR: \"1025\"\n"); return 1; } printf("SUCCESS\n\n"); } printf("Stress with random payloads of different encoding:\n"); { int i,j,len,where; unsigned char *p; char buf[1024]; int buflen; list *ref; listNode *refnode; /* Hold temp vars from ziplist */ unsigned char *sstr; unsigned int slen; long long sval; for (i = 0; i < 20000; i++) { zl = ziplistNew(); ref = listCreate(); listSetFreeMethod(ref, sdsfree); len = rand() % 256; /* Create lists */ for (j = 0; j < len; j++) { where = (rand() & 1) ? ZIPLIST_HEAD : ZIPLIST_TAIL; if (rand() % 2) { buflen = randstring(buf,1,sizeof(buf)-1); } else { switch(rand() % 3) { case 0: buflen = sprintf(buf,"%lld",(0LL + rand()) >> 20); break; case 1: buflen = sprintf(buf,"%lld",(0LL + rand())); break; case 2: buflen = sprintf(buf,"%lld",(0LL + rand()) << 20); break; default: assert(NULL); } } /* Add to ziplist */ zl = ziplistPush(zl, (unsigned char*)buf, buflen, where); /* Add to reference list */ if (where == ZIPLIST_HEAD) { listAddNodeHead(ref,sdsnewlen(buf, buflen)); } else if (where == ZIPLIST_TAIL) { listAddNodeTail(ref,sdsnewlen(buf, buflen)); } else { assert(NULL); } } assert(listLength(ref) == ziplistLen(zl)); for (j = 0; j < len; j++) { /* Naive way to get elements, but similar to the stresser * executed from the Tcl test suite. */ p = ziplistIndex(zl,j); refnode = listIndex(ref,j); assert(ziplistGet(p,&sstr,&slen,&sval)); if (sstr == NULL) { buflen = sprintf(buf,"%lld",sval); } else { buflen = slen; memcpy(buf,sstr,buflen); buf[buflen] = '\0'; } assert(memcmp(buf,listNodeValue(refnode),buflen) == 0); } zfree(zl); listRelease(ref); } printf("SUCCESS\n\n"); } printf("Stress with variable ziplist size:\n"); { stress(ZIPLIST_HEAD,100000,16384,256); stress(ZIPLIST_TAIL,100000,16384,256); } return 0; }
/* The SORT command is the most complex command in Redis. Warning: this code * is optimized for speed and a bit less for readability */ void sortCommand(redisClient *c) { list *operations; unsigned int outputlen = 0; int desc = 0, alpha = 0; long limit_start = 0, limit_count = -1, start, end; int j, dontsort = 0, vectorlen; int getop = 0; /* GET operation counter */ int int_convertion_error = 0; robj *sortval, *sortby = NULL, *storekey = NULL; redisSortObject *vector; /* Resulting vector to sort */ /* Lookup the key to sort. It must be of the right types */ sortval = lookupKeyRead(c->db,c->argv[1]); if (sortval && sortval->type != REDIS_SET && sortval->type != REDIS_LIST && sortval->type != REDIS_ZSET) { addReply(c,shared.wrongtypeerr); return; } /* Create a list of operations to perform for every sorted element. * Operations can be GET/DEL/INCR/DECR */ operations = listCreate(); listSetFreeMethod(operations,zfree); j = 2; /* Now we need to protect sortval incrementing its count, in the future * SORT may have options able to overwrite/delete keys during the sorting * and the sorted key itself may get destroied */ if (sortval) incrRefCount(sortval); else sortval = createListObject(); /* The SORT command has an SQL-alike syntax, parse it */ while(j < c->argc) { int leftargs = c->argc-j-1; if (!strcasecmp(c->argv[j]->ptr,"asc")) { desc = 0; } else if (!strcasecmp(c->argv[j]->ptr,"desc")) { desc = 1; } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) { alpha = 1; } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) { if ((getLongFromObjectOrReply(c, c->argv[j+1], &limit_start, NULL) != REDIS_OK) || (getLongFromObjectOrReply(c, c->argv[j+2], &limit_count, NULL) != REDIS_OK)) return; j+=2; } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) { storekey = c->argv[j+1]; j++; } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) { sortby = c->argv[j+1]; /* If the BY pattern does not contain '*', i.e. it is constant, * we don't need to sort nor to lookup the weight keys. */ if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1; j++; } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) { listAddNodeTail(operations,createSortOperation( REDIS_SORT_GET,c->argv[j+1])); getop++; j++; } else { decrRefCount(sortval); listRelease(operations); addReply(c,shared.syntaxerr); return; } j++; } /* If we have STORE we need to force sorting for deterministic output * and replication. We use alpha sorting since this is guaranteed to * work with any input. */ if (storekey && dontsort) { dontsort = 0; alpha = 1; sortby = NULL; } /* Destructively convert encoded sorted sets for SORT. */ if (sortval->type == REDIS_ZSET) zsetConvert(sortval, REDIS_ENCODING_SKIPLIST); /* Load the sorting vector with all the objects to sort */ switch(sortval->type) { case REDIS_LIST: vectorlen = listTypeLength(sortval); break; case REDIS_SET: vectorlen = setTypeSize(sortval); break; case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break; default: vectorlen = 0; redisPanic("Bad SORT type"); /* Avoid GCC warning */ } vector = zmalloc(sizeof(redisSortObject)*vectorlen); j = 0; if (sortval->type == REDIS_LIST) { listTypeIterator *li = listTypeInitIterator(sortval,0,REDIS_TAIL); listTypeEntry entry; while(listTypeNext(li,&entry)) { vector[j].obj = listTypeGet(&entry); vector[j].u.score = 0; vector[j].u.cmpobj = NULL; j++; } listTypeReleaseIterator(li); } else if (sortval->type == REDIS_SET) { setTypeIterator *si = setTypeInitIterator(sortval); robj *ele; while((ele = setTypeNextObject(si)) != NULL) { vector[j].obj = ele; vector[j].u.score = 0; vector[j].u.cmpobj = NULL; j++; } setTypeReleaseIterator(si); } else if (sortval->type == REDIS_ZSET) { dict *set = ((zset*)sortval->ptr)->dict; dictIterator *di; dictEntry *setele; di = dictGetIterator(set); while((setele = dictNext(di)) != NULL) { vector[j].obj = dictGetKey(setele); vector[j].u.score = 0; vector[j].u.cmpobj = NULL; j++; } dictReleaseIterator(di); } else { redisPanic("Unknown type"); } redisAssertWithInfo(c,sortval,j == vectorlen); /* Now it's time to load the right scores in the sorting vector */ if (dontsort == 0) { for (j = 0; j < vectorlen; j++) { robj *byval; if (sortby) { /* lookup value to sort by */ byval = lookupKeyByPattern(c->db,sortby,vector[j].obj); if (!byval) continue; } else { /* use object itself to sort by */ byval = vector[j].obj; } if (alpha) { if (sortby) vector[j].u.cmpobj = getDecodedObject(byval); } else { if (byval->encoding == REDIS_ENCODING_RAW) { char *eptr; vector[j].u.score = strtod(byval->ptr,&eptr); if (eptr[0] != '\0' || errno == ERANGE || isnan(vector[j].u.score)) { int_convertion_error = 1; } } else if (byval->encoding == REDIS_ENCODING_INT) { /* Don't need to decode the object if it's * integer-encoded (the only encoding supported) so * far. We can just cast it */ vector[j].u.score = (long)byval->ptr; } else { redisAssertWithInfo(c,sortval,1 != 1); } } /* when the object was retrieved using lookupKeyByPattern, * its refcount needs to be decreased. */ if (sortby) { decrRefCount(byval); } } } /* We are ready to sort the vector... perform a bit of sanity check * on the LIMIT option too. We'll use a partial version of quicksort. */ start = (limit_start < 0) ? 0 : limit_start; end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1; if (start >= vectorlen) { start = vectorlen-1; end = vectorlen-2; } if (end >= vectorlen) end = vectorlen-1; server.sort_dontsort = dontsort; if (dontsort == 0) { server.sort_desc = desc; server.sort_alpha = alpha; server.sort_bypattern = sortby ? 1 : 0; if (sortby && (start != 0 || end != vectorlen-1)) pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end); else qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare); } /* Send command output to the output buffer, performing the specified * GET/DEL/INCR/DECR operations if any. */ outputlen = getop ? getop*(end-start+1) : end-start+1; if (int_convertion_error) { addReplyError(c,"One or more scores can't be converted into double"); } else if (storekey == NULL) { /* STORE option not specified, sent the sorting result to client */ addReplyMultiBulkLen(c,outputlen); for (j = start; j <= end; j++) { listNode *ln; listIter li; if (!getop) addReplyBulk(c,vector[j].obj); listRewind(operations,&li); while((ln = listNext(&li))) { redisSortOperation *sop = ln->value; robj *val = lookupKeyByPattern(c->db,sop->pattern, vector[j].obj); if (sop->type == REDIS_SORT_GET) { if (!val) { addReply(c,shared.nullbulk); } else { addReplyBulk(c,val); decrRefCount(val); } } else { /* Always fails */ redisAssertWithInfo(c,sortval,sop->type == REDIS_SORT_GET); } } } } else { robj *sobj = createZiplistObject(); /* STORE option specified, set the sorting result as a List object */ for (j = start; j <= end; j++) { listNode *ln; listIter li; if (!getop) { listTypePush(sobj,vector[j].obj,REDIS_TAIL); } else { listRewind(operations,&li); while((ln = listNext(&li))) { redisSortOperation *sop = ln->value; robj *val = lookupKeyByPattern(c->db,sop->pattern, vector[j].obj); if (sop->type == REDIS_SORT_GET) { if (!val) val = createStringObject("",0); /* listTypePush does an incrRefCount, so we should take care * care of the incremented refcount caused by either * lookupKeyByPattern or createStringObject("",0) */ listTypePush(sobj,val,REDIS_TAIL); decrRefCount(val); } else { /* Always fails */ redisAssertWithInfo(c,sortval,sop->type == REDIS_SORT_GET); } } } } if (outputlen) { setKey(c->db,storekey,sobj); server.dirty += outputlen; } else if (dbDelete(c->db,storekey)) { signalModifiedKey(c->db,storekey); server.dirty++; } decrRefCount(sobj); addReplyLongLong(c,outputlen); } /* Cleanup */ if (sortval->type == REDIS_LIST || sortval->type == REDIS_SET) for (j = 0; j < vectorlen; j++) decrRefCount(vector[j].obj); decrRefCount(sortval); listRelease(operations); for (j = 0; j < vectorlen; j++) { if (alpha && vector[j].u.cmpobj) decrRefCount(vector[j].u.cmpobj); } zfree(vector); }
void syncCommand(redisClient *c) { /* ignore SYNC if aleady slave or in monitor mode */ if (c->flags & REDIS_SLAVE) return; /* Refuse SYNC requests if we are a slave but the link with our master * is not ok... */ if (server.masterhost && server.replstate != REDIS_REPL_CONNECTED) { addReplyError(c,"Can't SYNC while not connected with my master"); return; } /* SYNC can't be issued when the server has pending data to send to * the client about already issued commands. We need a fresh reply * buffer registering the differences between the BGSAVE and the current * dataset, so that we can copy to other slaves if needed. */ if (listLength(c->reply) != 0) { addReplyError(c,"SYNC is invalid with pending input"); return; } redisLog(REDIS_NOTICE,"Slave ask for synchronization"); /* Here we need to check if there is a background saving operation * in progress, or if it is required to start one */ if (server.bgsavechildpid != -1) { /* Ok a background save is in progress. Let's check if it is a good * one for replication, i.e. if there is another slave that is * registering differences since the server forked to save */ redisClient *slave; listNode *ln; listIter li; listRewind(server.slaves,&li); while((ln = listNext(&li))) { slave = ln->value; if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break; } if (ln) { /* Perfect, the server is already registering differences for * another slave. Set the right state, and copy the buffer. */ listRelease(c->reply); c->reply = listDup(slave->reply); c->replstate = REDIS_REPL_WAIT_BGSAVE_END; redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC"); } else { /* No way, we need to wait for the next BGSAVE in order to * register differences */ c->replstate = REDIS_REPL_WAIT_BGSAVE_START; redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC"); } } else { /* Ok we don't have a BGSAVE in progress, let's start one */ redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC"); if (rdbSaveBackground(server.dbfilename) != REDIS_OK) { redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE"); addReplyError(c,"Unable to perform background save"); return; } c->replstate = REDIS_REPL_WAIT_BGSAVE_END; } c->repldbfd = -1; c->flags |= REDIS_SLAVE; c->slaveseldb = 0; listAddNodeTail(server.slaves,c); return; }
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); }