void ltrimCommand(redisClient *c) { robj *o; long start, end, llen, j, ltrim, rtrim; list *list; listNode *ln; int slotnum = keyHashSlot(c->argv[1]->ptr, sdslen(c->argv[1]->ptr)); if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) || (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return; if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.ok,slotnum)) == NULL || checkType(c,o,REDIS_LIST)) return; llen = listTypeLength(o); /* convert negative indexes */ if (start < 0) start = llen+start; if (end < 0) end = llen+end; if (start < 0) start = 0; /* Invariant: start >= 0, so this test will be true when end < 0. * The range is empty when start > end or start >= length. */ if (start > end || start >= llen) { /* Out of range start or start > end result in empty list */ ltrim = llen; rtrim = 0; } else { if (end >= llen) end = llen-1; ltrim = start; rtrim = llen-end-1; } /* Remove list elements to perform the trim */ if (o->encoding == REDIS_ENCODING_ZIPLIST) { o->ptr = ziplistDeleteRange(o->ptr,0,ltrim); o->ptr = ziplistDeleteRange(o->ptr,-rtrim,rtrim); } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) { list = o->ptr; for (j = 0; j < ltrim; j++) { ln = listFirst(list); listDelNode(list,ln); } for (j = 0; j < rtrim; j++) { ln = listLast(list); listDelNode(list,ln); } } else { redisPanic("Unknown list encoding"); } notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"ltrim",c->argv[1],c->db->id); if (listTypeLength(o) == 0) { dbDelete(c->db,c->argv[1],slotnum); notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } signalModifiedKey(c->db,c->argv[1],slotnum); server.dirty++; addReply(c,shared.ok); }
/* Push a new entry into the slow log. * This function will make sure to trim the slow log accordingly to the * configured max length. */ void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) { if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */ if (duration >= server.slowlog_log_slower_than) listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration)); /* Remove old entries if needed. */ while (listLength(server.slowlog) > server.slowlog_max_len) listDelNode(server.slowlog,listLast(server.slowlog)); }
felist *listAddLast(felist *root, felist *l) { if (root != NULL) { felist *tmp = listLast(root); tmp->next = l; l->prev = tmp; return root; } return l; }
/* Return the current size of the AOF rerwite buffer. */ unsigned long aofRewriteBufferSize(void) { listNode *ln = listLast(server.aof_rewrite_buf_blocks); aofrwblock *block = ln ? ln->value : NULL; if (block == NULL) return 0; unsigned long size = (listLength(server.aof_rewrite_buf_blocks)-1) * AOF_RW_BUF_BLOCK_SIZE; size += block->used; return size; }
void *IOThreadEntryPoint(void *arg) { iojob *j; listNode *ln; REDIS_NOTUSED(arg); pthread_detach(pthread_self()); while(1) { /* Get a new job to process */ lockThreadedIO(); if (listLength(server.io_newjobs) == 0) { /* No new jobs in queue, exit. */ redisLog(REDIS_DEBUG,"Thread %ld exiting, nothing to do", (long) pthread_self()); server.io_active_threads--; unlockThreadedIO(); return NULL; } ln = listFirst(server.io_newjobs); j = ln->value; listDelNode(server.io_newjobs,ln); /* Add the job in the processing queue */ j->thread = pthread_self(); listAddNodeTail(server.io_processing,j); ln = listLast(server.io_processing); /* We use ln later to remove it */ unlockThreadedIO(); redisLog(REDIS_DEBUG,"Thread %ld got a new job (type %d): %p about key '%s'", (long) pthread_self(), j->type, (void*)j, (char*)j->key->ptr); /* Process the Job */ if (j->type == REDIS_IOJOB_LOAD) { vmpointer *vp = (vmpointer*)j->id; j->val = vmReadObjectFromSwap(j->page,vp->vtype); } else if (j->type == REDIS_IOJOB_PREPARE_SWAP) { j->pages = rdbSavedObjectPages(j->val); } else if (j->type == REDIS_IOJOB_DO_SWAP) { if (vmWriteObjectOnSwap(j->val,j->page) == REDIS_ERR) j->canceled = 1; } /* Done: insert the job into the processed queue */ redisLog(REDIS_DEBUG,"Thread %ld completed the job: %p (key %s)", (long) pthread_self(), (void*)j, (char*)j->key->ptr); lockThreadedIO(); listDelNode(server.io_processing,ln); listAddNodeTail(server.io_processed,j); unlockThreadedIO(); /* Signal the main thread there is new stuff to process */ redisAssert(write(server.io_ready_pipe_write,"x",1) == 1); } return NULL; /* never reached */ }
felist *listCat(felist *l1, felist *l2) { felist *t; if (l1 == NULL) return l2; else if (l2 == NULL) return l1; else { t = listLast(l1); t->next = l2; l2->prev = t; } return l1; }
void ltrimCommand(redisClient *c) { robj *o; int start = atoi(c->argv[2]->ptr); int end = atoi(c->argv[3]->ptr); int llen; int j, ltrim, rtrim; list *list; listNode *ln; if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.ok)) == NULL || checkType(c,o,REDIS_LIST)) return; llen = listTypeLength(o); /* convert negative indexes */ if (start < 0) start = llen+start; if (end < 0) end = llen+end; if (start < 0) start = 0; /* Invariant: start >= 0, so this test will be true when end < 0. * The range is empty when start > end or start >= length. */ if (start > end || start >= llen) { /* Out of range start or start > end result in empty list */ ltrim = llen; rtrim = 0; } else { if (end >= llen) end = llen-1; ltrim = start; rtrim = llen-end-1; } /* Remove list elements to perform the trim */ if (o->encoding == REDIS_ENCODING_ZIPLIST) { o->ptr = ziplistDeleteRange(o->ptr,0,ltrim); o->ptr = ziplistDeleteRange(o->ptr,-rtrim,rtrim); } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) { list = o->ptr; for (j = 0; j < ltrim; j++) { ln = listFirst(list); listDelNode(list,ln); } for (j = 0; j < rtrim; j++) { ln = listLast(list); listDelNode(list,ln); } } else { redisPanic("Unknown list encoding"); } if (listTypeLength(o) == 0) dbDelete(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]); server.dirty++; addReply(c,shared.ok); }
unsigned long aofRewriteBufferSize(void){ /*return the contents size of current AOF rewrite buffer*/ listNode *last; unsigned long lastused, size; if((last = listLast(server.aof_rewrite_buf_blocks)) == NULL){ return 0; } lastused = (last->value)->used; size = (listLength(server.aof_rewrite_buf_blocks)-1)*AOF_RW_BUF_BLOCK_SIZE + lastused; return size; }
void *listLastValue(list *l) { listNode *node; if (l == NULL) { return NULL; } node = listLast(l); if (node == NULL) { return NULL; } return listNodeValue(node); }
/* Push a new entry into the slow log. * * 如果参数 duration 超过服务器设置的上限时间, * 那么将一个新条目以 FIFO 顺序推入到慢查询日志中。 * * This function will make sure to trim the slow log accordingly to the * configured max length. * * 根据服务器设置的最大日志长度,可能会对日志进行截断(trim) */ void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) { // 慢查询功能未开启,直接返回 if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */ // 如果执行时间超过服务器设置的上限,那么将命令添加到慢查询日志 if (duration >= server.slowlog_log_slower_than) // 新日志添加到链表表头 listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration)); /* Remove old entries if needed. */ // 如果日志数量过多,那么进行删除 while (listLength(server.slowlog) > server.slowlog_max_len) listDelNode(server.slowlog,listLast(server.slowlog)); }
void aofRewriteBufferAppend(unsigned char *s, unsigned long len){ /*add string s at the end of AOF buffer, assign a new block if needed*/ listNode *last; aofrwblock *block; unsigned int clen; int counts; last = listLast(server.aof_rewrite_buf_blocks); if(last){ block = last->value; } else{ block = NULL; } while(len > 0){ if(block){ clen = (block->free < len)? block->free: len; memcpy(block->buf, s, clen); block->free -= clen; block->used += clen; s += clen; len -= clen; } if(len){ block = zmalloc(sizeof(aofrwblock)); block->free = AOF_RW_BUF_BLOCK_SIZE; block->used = 0; listAddNodeTail(server.aof_rewrite_buf_blocks, block); /*NOTICE when node number is coming to n*10, WARNING when n*100*/ counts = listLength(server.aof_rewrite_buf_blocks); if(((counts+1) % 100) == 0){ xredisLog(XREDIS_WARNING, "Background AOF buffer size: %lu MB", aofRewriteBufferSize()/(1024*1024)); } else if(((counts+1)%10) == 0){ xredisLog(XREDIS_NOTICE, "Background AOF buffer size: %lu MB", aofRewriteBufferSize()/(1024*1024)); } } } }
/* Append data to the AOF rewrite buffer, allocating new blocks if needed. */ void aofRewriteBufferAppend(unsigned char *s, unsigned long len) { listNode *ln = listLast(server.aof_rewrite_buf_blocks); aofrwblock *block = ln ? ln->value : NULL; while(len) { /* If we already got at least an allocated block, try appending * at least some piece into it. */ if (block) { unsigned long thislen = (block->free < len) ? block->free : len; if (thislen) { /* The current block is not already full. */ memcpy(block->buf+block->used, s, thislen); block->used += thislen; block->free -= thislen; s += thislen; len -= thislen; } } if (len) { /* First block to allocate, or need another block. */ int numblocks; block = zmalloc(sizeof(*block)); block->free = AOF_RW_BUF_BLOCK_SIZE; block->used = 0; listAddNodeTail(server.aof_rewrite_buf_blocks,block); /* Log every time we cross more 10 or 100 blocks, respectively * as a notice or warning. */ numblocks = listLength(server.aof_rewrite_buf_blocks); if (((numblocks+1) % 10) == 0) { int level = ((numblocks+1) % 100) == 0 ? REDIS_WARNING : REDIS_NOTICE; redisLog(level,"Background AOF buffer size: %lu MB", aofRewriteBufferSize()/(1024*1024)); } } } }
struct mbuf * msg_ensure_mbuf(struct msg *msg, size_t len) { listNode *node; mbuf_base *mb = msg->mb; struct mbuf *mbuf; node = listLast(msg->data); if (node == NULL || mbuf_size(listNodeValue(node)) < len) { mbuf = mbuf_get(mb); if (mbuf == NULL) { return NULL; } listAddNodeTail(msg->data, mbuf); } else { mbuf = listNodeValue(node); } return mbuf; }
robj *listTypePop(robj *subject, int where) { robj *value = NULL; if (subject->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *p; unsigned char *vstr; unsigned int vlen; long long vlong; int pos = (where == REDIS_HEAD) ? 0 : -1; p = ziplistIndex(subject->ptr,pos); if (ziplistGet(p,&vstr,&vlen,&vlong)) { if (vstr) { value = createStringObject((char*)vstr,vlen); } else { value = createStringObjectFromLongLong(vlong); } /* We only need to delete an element when it exists */ subject->ptr = ziplistDelete(subject->ptr,&p); } } else if (subject->encoding == REDIS_ENCODING_LINKEDLIST) { list *list = subject->ptr; listNode *ln; if (where == REDIS_HEAD) { ln = listFirst(list); } else { ln = listLast(list); } if (ln != NULL) { value = listNodeValue(ln); incrRefCount(value); listDelNode(list,ln); } } else { redisPanic("Unknown list encoding"); } return value; }
int main(int argc,char **argv) { list_t list; int index; char *arg; int elements; /* Initialize our list. */ listInitialize(&list); /* Fill our list with all command line arguments given, but skip the * first argument since that's our needle (see below -> listSearch()). */ for(index=2;index<argc;index++) { /* Append the argument to our list. */ if(listAppend(&list,(void *)argv[index])!=listRtrnOk) { fprintf(stderr,"Can't create item!\n"); break; } /* Advance to this next position. By default listAppend() does not * advance our current pointer to the appended element. */ listNext(&list); } /* Print all our arguments from the first to the last. */ printf("First to last:\n"); /* Does any argument exist? */ if((arg=(char *)listFirst(&list))!=NULL) { /* Yes, we print it and... */ do { printf("[%s]\n",arg); /* ...advance to the next argument, untill none left. */ } while((arg=(char *)listNext(&list))!=NULL); } else { printf("empty list\n"); } /* Print all our arguments from the last to the first. */ printf("Last to first:\n"); /* Does any argument exist? */ if((arg=(char *)listLast(&list))!=NULL) { /* Yes, we print it and... */ do { printf("[%s]\n",arg); /* ...advance to the next argument, untill none left. */ } while((arg=(char *)listPrevious(&list))!=NULL); } else { printf("empty list\n"); } /* If there do exist enough arguments... */ if(argc>=2) { /* ...search for the first one given... */ arg=listSearch(&list,cmpr,(void *)argv[1]); /* ...and tell if it's found. */ printf("searching for [%s]... %sfound\n",argv[1],arg!=NULL?"":"not "); } /* Randomly remove half of the arguments. */ srandom(getpid()); for(elements=listElements(&list)/2;elements>0;elements--) { int element=(random()%(argc-2))+2; arg=listSearch(&list,cmpr,(void *)argv[element]); printf("Removing [%s]... ",argv[element]); if(arg!=NULL) { listRemove(&list,NULL); printf("ok\n"); } else { printf("not in the list!\n"); } } /* Print all our arguments from the first to the last. */ printf("First to last:\n"); /* Does any argument exist? */ if((arg=(char *)listFirst(&list))!=NULL) { /* Yes, we print it and... */ do { printf("[%s]\n",arg); /* ...advance to the next argument, untill none left. */ } while((arg=(char *)listNext(&list))!=NULL); } else { printf("empty list\n"); } /* Print all our arguments from the last to the first. */ printf("Last to first:\n"); /* Does any argument exist? */ if((arg=(char *)listLast(&list))!=NULL) { /* Yes, we print it and... */ do { printf("[%s]\n",arg); /* ...advance to the next argument, untill none left. */ } while((arg=(char *)listPrevious(&list))!=NULL); } else { printf("empty list\n"); } /* Destroy the list and all its elements. */ listDestroy(&list,garbageCollect); return(0); }
/* Remove all the entries from the current slow log. */ void slowlogReset(void) { while (listLength(server.slowlog) > 0) listDelNode(server.slowlog,listLast(server.slowlog)); }
if (c->fd <= 0) return REDIS_ERR; if (c->bufpos == 0 && listLength(c->reply) == 0 && (c->replstate == REDIS_REPL_NONE || c->replstate == REDIS_REPL_ONLINE) && aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, sendReplyToClient, c) == AE_ERR) return REDIS_ERR; return REDIS_OK; } /* Create a duplicate of the last object in the reply list when * it is not exclusively owned by the reply list. */ robj *dupLastObjectIfNeeded(list *reply) { robj *new, *cur; listNode *ln; redisAssert(listLength(reply) > 0); ln = listLast(reply); cur = listNodeValue(ln); if (cur->refcount > 1) { new = dupStringObject(cur); decrRefCount(cur); listNodeValue(ln) = new; } return listNodeValue(ln); } /* ----------------------------------------------------------------------------- * Low level functions to add more data to output buffers. * -------------------------------------------------------------------------- */ int _addReplyToBuffer(redisClient *c, char *s, size_t len) { size_t available = sizeof(c->buf)-c->bufpos;
int main() { TTable table; tableInit(&table); printf("\nTabulka by mela byt prazdna: \n"); tablePrintOrder(table); printf("\n----------------------------\n"); tableInsertFunction(&table, strCreateString("func1")); functionInsertVar(table.lastAddedFunc, strCreateString("var1func1")); functionInsertVar(table.lastAddedFunc, strCreateString("var2func1")); functionInsertVar(table.lastAddedFunc, strCreateString("var3func1")); printf("\nJedna funkce: \n"); tablePrintOrder(table); printf("\n----------------------------\n"); tableInsertFunction(&table, strCreateString("func2")); functionInsertVar(table.lastAddedFunc, strCreateString("var1func2")); functionInsertVar(table.lastAddedFunc, strCreateString("var2func2")); functionInsertVar(table.lastAddedFunc, strCreateString("var3func2")); printf("\nDve funkce: \n"); tablePrintOrder(table); printf("\n----------------------------\n"); tableInsertFunction(&table, strCreateString("func3")); functionInsertVar(table.lastAddedFunc, strCreateString("var1func3")); functionInsertVar(table.lastAddedFunc, strCreateString("var2func3")); functionInsertVar(table.lastAddedFunc, strCreateString("var3func3")); printf("\nVsechny: \n"); tablePrintOrder(table); printf("\n----------------------------\n"); // test heldani { TFunction *fceSearch; printf("\nObsahuje tabulka funkci %s? \t", "func1"); fceSearch = tableSearchFunction(&table, strCreateString("func1")); if(fceSearch != NULL) { printf("ANO\n"); printf(" Obsahuje funkce promenou %s?\t", "var1func1"); if(functionSearchVar(fceSearch, strCreateString("var1func1")) != NULL) printf("ANO"); else printf("NE"); } else printf("NE\n"); printf("\nObsahuje tabulka funkci %s? \t", "funcX"); fceSearch = tableSearchFunction(&table, strCreateString("funcX")); if(fceSearch != NULL) { printf("ANO\n"); printf(" Obsahuje funkce promenou %s?\t", "var1func1"); if(functionSearchVar(fceSearch, strCreateString("var1func1")) != NULL) printf("ANO"); else printf("NE"); } else printf("NE\n"); printf("\n----------------------------\n"); } // test zásobníku: printf("TEST ZASOBNIKU:\n"); printf("----------------------------\n"); TStack s; stackInit(&s); prazdnyStack(s); TFunction *fce = tableSearchFunction(&table, strCreateString("func2")); TVar *id = functionSearchVar(fce, strCreateString("var1func2")); stackPush(&s, (void*)id); prazdnyStack(s); tiskniStack(&s); id = functionSearchVar(fce, strCreateString("var2func2")); stackPush(&s, (void*)id); tiskniStack(&s); id = functionSearchVar(fce, strCreateString("var3func2")); stackPush(&s, (void*)id); tiskniStack(&s); id = functionSearchVar(fce, strCreateString("var1func2")); stackPush(&s, (void*)id); tiskniStack(&s); TVar *data = (TVar*)stackTopPop(&s); if (data != NULL) printf("Vybráno ze zásobníku: %s\n",data->name); else printf("Ukazatel je nulový! \n"); prazdnyStack(s); data = (TVar*)stackTopPop(&s); if (data != NULL) printf("Vybráno ze zásobníku: %s\n",data->name); else printf("Ukazatel je nulový! \n"); prazdnyStack(s); data = (TVar*)stackTopPop(&s); if (data != NULL) printf("Vybráno ze zásobníku: %s\n",data->name); else printf("Ukazatel je nulový! \n"); prazdnyStack(s); tiskniStack(&s); stackDelete (&s); prazdnyStack(s); tiskniStack(&s); data = (TVar*)stackTopPop(&s); if (data != NULL) printf("Vybráno ze zásobníku: %s\n",data->name); else printf("Ukazatel je nulový! \n"); printf("----------------------------\n"); // test seznamu: printf("TEST SEZNAMU:\n"); printf("----------------------------\n"); TList L; listInit (&L); id = functionSearchVar(fce, strCreateString("var1func2")); TLItem *uk2 = listGetActive (&L); listSetActive(&L, uk2); aktivniList(L); listInsertLast(&L, id); tiskniList(&L); void *uk4 = listCopyLast(&L); printf("Zkopírováno: %s\n",((TVar*)uk4)->name); aktivniList(L); listFirst(&L); tiskniList(&L); listLast(&L); tiskniList(&L); id = functionSearchVar(fce, strCreateString("var2func2")); listPostInsert(&L, id); tiskniList(&L); id = functionSearchVar(fce, strCreateString("var3func2")); listInsertLast(&L, id); tiskniList(&L); id = functionSearchVar(fce, strCreateString("var1func2")); listInsertLast(&L, id); tiskniList(&L); listFirst(&L); listSucc(&L); TLItem *uk = listGetActive (&L); tiskniList(&L); listLast(&L); tiskniList(&L); listSetActive(&L, uk); tiskniList(&L); aktivniList(L); listDeleteFirst(&L); tiskniList(&L); void *uk3 = listCopyLast(&L); printf("Zkopírováno: %s\n",((TVar*)uk3)->name); listSucc(&L); tiskniList(&L); listActualize(&L, uk3); tiskniList(&L); listDispose (&L); printf("----------------------------\n"); // konec testu seznamu printf("\nSmazu: \n"); tableClear(&table); tablePrintOrder(table); printf("\n----------------------------\n"); }