void ltrimCommand(redisClient *c) { robj *o; long start, end, llen, j, ltrim, rtrim; list *list; listNode *ln; 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)) == 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]); notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } signalModifiedKey(c->db,c->argv[1]); server.dirty++; addReply(c,shared.ok); }
void freeClientsInAsyncFreeQueue(void) { while (listLength(server.clients_to_close)) { listNode *ln = listFirst(server.clients_to_close); client *c = listNodeValue(ln); c->flags &= ~CLIENT_CLOSE_ASAP; freeClient(c); listDelNode(server.clients_to_close,ln); } }
void *bioProcessBackgroundJobs(void *arg) { struct bio_job *job; unsigned long type = (unsigned long) arg; sigset_t sigset; /* Make the thread killable at any time, so that bioKillThreads() * can work reliably. */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_mutex_lock(&bio_mutex[type]); /* Block SIGALRM so we are sure that only the main thread will * receive the watchdog signal. */ sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) serverLog(LL_WARNING, "Warning: can't mask SIGALRM in bio.c thread: %s", strerror(errno)); while(1) { listNode *ln; /* The loop always starts with the lock hold. */ if (listLength(bio_jobs[type]) == 0) { pthread_cond_wait(&bio_newjob_cond[type],&bio_mutex[type]); continue; } /* Pop the job from the queue. */ ln = listFirst(bio_jobs[type]); job = ln->value; /* It is now possible to unlock the background system as we know have * a stand alone job structure to process.*/ pthread_mutex_unlock(&bio_mutex[type]); /* Process the job accordingly to its type. */ if (type == BIO_CLOSE_FILE) { close((long)job->arg1); } else if (type == BIO_AOF_FSYNC) { aof_fsync((long)job->arg1); } else { serverPanic("Wrong job type in bioProcessBackgroundJobs()."); } zfree(job); /* Unblock threads blocked on bioWaitStepOfType() if any. */ pthread_cond_broadcast(&bio_step_cond[type]); /* Lock again before reiterating the loop, if there are no longer * jobs to process we'll block again in pthread_cond_wait(). */ pthread_mutex_lock(&bio_mutex[type]); listDelNode(bio_jobs[type],ln); bio_pending[type]--; } }
bool replyIfNestedErr(redisClient *c, redisClient *rfc, char *msg) { if (!respNotErr(rfc)) { listNode *ln = listFirst(rfc->reply); robj *emsg = ln->value; robj *repl = _createStringObject(msg); repl->ptr = sdscatlen(repl->ptr, emsg->ptr, sdslen(emsg->ptr)); addReply(c, repl); decrRefCount(repl); return 0; } return 1; }
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 */ }
void printIList(tIlist * L){ listFirst(L); while (L->active != NULL){ printf("%p: ", (void *) L->active); printInstr(&L->active->instr); listNext(L); } }
/* This should be called from any function PUSHing into lists. * 'c' is the "pushing client", 'key' is the key it is pushing data against, * 'ele' is the element pushed. * * If the function returns 0 there was no client waiting for a list push * against this key. * * If the function returns 1 there was a client waiting for a list push * against this key, the element was passed to this client thus it's not * needed to actually add it to the list and the caller should return asap. */ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) { struct dictEntry *de; redisClient *receiver; int numclients; list *clients; listNode *ln; robj *dstkey, *dstobj; de = dictFind(c->db->blocking_keys,key); if (de == NULL) return 0; clients = dictGetVal(de); numclients = listLength(clients); /* Try to handle the push as long as there are clients waiting for a push. * Note that "numclients" is used because the list of clients waiting for a * push on "key" is deleted by unblockClient() when empty. * * This loop will have more than 1 iteration when there is a BRPOPLPUSH * that cannot push the target list because it does not contain a list. If * this happens, it simply tries the next client waiting for a push. */ while (numclients--) { ln = listFirst(clients); redisAssertWithInfo(c,key,ln != NULL); receiver = ln->value; dstkey = receiver->bpop.target; /* Protect receiver->bpop.target, that will be freed by * the next unblockClientWaitingData() call. */ if (dstkey) incrRefCount(dstkey); /* This should remove the first element of the "clients" list. */ unblockClientWaitingData(receiver); if (dstkey == NULL) { /* BRPOP/BLPOP */ addReplyMultiBulkLen(receiver,2); addReplyBulk(receiver,key); addReplyBulk(receiver,ele); return 1; /* Serve just the first client as in B[RL]POP semantics */ } else { /* BRPOPLPUSH, note that receiver->db is always equal to c->db. */ dstobj = lookupKeyWrite(receiver->db,dstkey); if (!(dstobj && checkType(receiver,dstobj,REDIS_LIST))) { rpoplpushHandlePush(c,receiver,dstkey,dstobj,ele); decrRefCount(dstkey); return 1; } decrRefCount(dstkey); } } return 0; }
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]); touchWatchedKey(c->db,c->argv[1]); server.dirty++; addReply(c,shared.ok); }
int isClientNeedSend(struct client *c) { struct listNode *node; struct conn *send_conn; if (listLength(c->conns) && isClientValid(c)) { node = listFirst(c->conns); send_conn = listNodeValue(node); if (listLength(send_conn->send_queue) || send_conn->ready_send) { return 1; } } return 0; }
// find matching value in list and remove. If found return 1 int removeMatchFromList(list *socklist, void *value) { listNode *node; if (socklist == NULL) return 0; node = listFirst(socklist); while (node != NULL) { if (listNodeValue(node) == value) { listDelNode(socklist, node); return 1; } node = listNextNode(node); } return 0; }
void *bioProcessBackgroundJobs(void *arg) { struct bio_job *job; #ifdef _WIN32 size_t type = (size_t) arg; #else unsigned long type = (unsigned long) arg; #endif sigset_t sigset; pthread_detach(pthread_self()); pthread_mutex_lock(&bio_mutex[type]); /* Block SIGALRM so we are sure that only the main thread will * receive the watchdog signal. */ sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) redisLog(REDIS_WARNING, "Warning: can't mask SIGALRM in bio.c thread: %s", strerror(errno)); while(1) { listNode *ln; /* The loop always starts with the lock hold. */ if (listLength(bio_jobs[type]) == 0) { pthread_cond_wait(&bio_condvar[type],&bio_mutex[type]); continue; } /* Pop the job from the queue. */ ln = listFirst(bio_jobs[type]); job = ln->value; /* It is now possible to unlock the background system as we know have * a stand alone job structure to process.*/ pthread_mutex_unlock(&bio_mutex[type]); /* Process the job accordingly to its type. */ if (type == REDIS_BIO_CLOSE_FILE) { close((long)job->arg1); } else if (type == REDIS_BIO_AOF_FSYNC) { aof_fsync((long)job->arg1); } else { redisPanic("Wrong job type in bioProcessBackgroundJobs()."); } zfree(job); /* Lock again before reiterating the loop, if there are no longer * jobs to process we'll block again in pthread_cond_wait(). */ pthread_mutex_lock(&bio_mutex[type]); listDelNode(bio_jobs[type],ln); bio_pending[type]--; } }
/* result buffer aggregation is taken from scripting.c */ sds fakeClientResultBuffer(redisClient *c) { sds reply; if (listLength(c->reply) == 0 && c->bufpos < REDIS_REPLY_CHUNK_BYTES) { /* This is a fast path for the common case of a reply inside the * client static buffer. Don't create an SDS string but just use * the client buffer directly. */ c->buf[c->bufpos] = '\0'; reply = c->buf; c->bufpos = 0; } else { reply = sdsnewlen(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)); } } return reply; }
/* * * 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); } }
void *bioProcessBackgroundJobs(void *arg) { //bioInit创建一个进程,用来刷文件。arg参数就是这个线程对应应该处理的任务号,用来索引bio_jobs[type] struct bio_job *job; unsigned long type = (unsigned long) arg;//实际上就是jobid。序号 sigset_t sigset; pthread_detach(pthread_self()); pthread_mutex_lock(&bio_mutex[type]);//先锁一下,待会pthread_cond_wait /* Block SIGALRM so we are sure that only the main thread will * receive the watchdog signal. */ sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) redisLog(REDIS_WARNING, "Warning: can't mask SIGALRM in bio.c thread: %s", strerror(errno)); while(1) { listNode *ln; /* The loop always starts with the lock hold. */ if (listLength(bio_jobs[type]) == 0) { //已经加锁了,进入等待bio_condvar[type]不为0,并立即解锁,等待。 //等其他线程pthread_cond_signal的时候,会通知这个线程,别等待了,从而再次加锁,返回。 pthread_cond_wait(&bio_condvar[type],&bio_mutex[type]); continue; } /* Pop the job from the queue. */ ln = listFirst(bio_jobs[type]);//获取到了一个任务,处理值。 job = ln->value; /* It is now possible to unlock the background system as we know have * a stand alone job structure to process.*/ pthread_mutex_unlock(&bio_mutex[type]); //根据不同的任务类型,做响应的清理。 /* Process the job accordingly to its type. */ if (type == REDIS_BIO_CLOSE_FILE) { close((long)job->arg1);//关闭文件。 } else if (type == REDIS_BIO_AOF_FSYNC) { aof_fsync((long)job->arg1);//同步刷新数据。 } else { redisPanic("Wrong job type in bioProcessBackgroundJobs()."); } zfree(job); /* Lock again before reiterating the loop, if there are no longer * jobs to process we'll block again in pthread_cond_wait(). */ pthread_mutex_lock(&bio_mutex[type]); listDelNode(bio_jobs[type],ln); bio_pending[type]--;//递减这种类型的挂起计数。 } }
static fdi_t getNextFDIAvailable(aeEventLoop *eventLoop) { listNode *fdi_node; fdi_t fdi; if (listLength(eventLoop->fdiMap->recycle_pool) > 0) { fdi_node = listFirst(eventLoop->fdiMap->recycle_pool); fdi = (fdi_t)fdi_node->value; listDelNode(eventLoop->fdiMap->recycle_pool, fdi_node); return fdi; } return eventLoop->fdiMap->next_available++; }
int repl_slaveof(char *host, int port){ // 如果 host 为空则表示清除 master 关系 if(host == NULL){ if(server.masterhost) sys_free(server.masterhost); server.masterhost = NULL; server.masterport = -1; if (server.master)cc_freeClient(server.master); if (server.repl_state == REPL_TRANSFER){ multi_deleteFileEvent(server.el, server.repl_transfer_s, MULTI_READABLE); close(server.repl_transfer_s); close(server.repl_transfer_fd); unlink(server.repl_transfer_tmpfile); server.repl_state = REPL_NONE; } else if (server.repl_state == REPL_CONNECTING){ multi_deleteFileEvent(server.el, server.repl_transfer_s, MULTI_WRITABLE|MULTI_READABLE); close(server.repl_transfer_s); server.repl_state = REPL_NONE; } // host 不为空, 则根据 host 连接 master } else if (host!=NULL && port!=0){ server.masterhost = sys_malloc(ADDR_MAX_LEN); memcpy(server.masterhost, host, ADDR_MAX_LEN); server.masterport = port; if(server.master) cc_freeClient(server.master); listNode *ln; // 若存在 slave 则和slave断开连接 while(listLength(server.slaves)) { ln = listFirst(server.slaves); cc_freeClient((clientContext*)ln->value); } // 若正在和某个 master 传输 db 数据, 则终止传输 // 删除 db 文件 if (server.repl_state == REPL_TRANSFER){ multi_deleteFileEvent(server.el, server.repl_transfer_s, MULTI_READABLE); close(server.repl_transfer_s); close(server.repl_transfer_fd); unlink(server.repl_transfer_tmpfile); server.repl_state = REPL_NONE; } // 置 server 状态为需要与 master 建立连接状态 server.repl_state = REPL_CONNECT; xlog(LOG_INFO, "slave connect: slave 创建 master ip=%s, port=%d\n", server.masterhost, server.masterport); } else { // 参数错误 return -1; } return 0; }
/* Find matching value in list and remove. If found return TRUE */ BOOL removeMatchFromList(list *requestlist, void *value) { listNode *node; if (requestlist == NULL) { return FALSE; } node = listFirst(requestlist); while (node != NULL) { if (listNodeValue(node) == value) { listDelNode(requestlist, node); return TRUE; } node = listNextNode(node); } return FALSE; }
/* Return the older job of the specified type. */ time_t bioOlderJobOfType(int type) { time_t time; listNode *ln; struct bio_job *job; pthread_mutex_lock(&bio_mutex[type]); ln = listFirst(bio_jobs[type]); if (ln == NULL) { pthread_mutex_unlock(&bio_mutex[type]); return 0; } job = ln->value; time = job->time; pthread_mutex_unlock(&bio_mutex[type]); return time; }
void *listFirstValue(list *l) { listNode *node; if(l == NULL) { return NULL; } node = listFirst(l); if(node == NULL) { return NULL; } return listNodeValue(node); }
/* This routine search the list for a specific element given by needle and * returns that element or NULL if it's not found. */ void *listSearch(list_t *list,int (*compare)(void *,void *),void *needle) { void *data; int found; /* At first we of course didn't find anything and especially when we do not receive a list we make sure we did not found anything as of yet. */ found=0; /* Does any element exist in the list? */ if((data=listFirst(list))!=NULL) { do { /* Yes, so search for our element... */ if((found=compare(data,needle))) break; /* ...untill none left. */ } while((data=listNext(list))!=NULL); } /* If we found our data return it, otherwise return NULL. */ return(found?data:NULL); }
/* This should be called from any function PUSHing into lists. * 'c' is the "pushing client", 'key' is the key it is pushing data against, * 'ele' is the element pushed. * * If the function returns 0 there was no client waiting for a list push * against this key. * * If the function returns 1 there was a client waiting for a list push * against this key, the element was passed to this client thus it's not * needed to actually add it to the list and the caller should return asap. */ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) { struct dictEntry *de; redisClient *receiver; list *l; listNode *ln; de = dictFind(c->db->blocking_keys,key); if (de == NULL) return 0; l = dictGetEntryVal(de); ln = listFirst(l); redisAssert(ln != NULL); receiver = ln->value; addReplySds(receiver,sdsnew("*2\r\n")); addReplyBulk(receiver,key); addReplyBulk(receiver,ele); unblockClientWaitingData(receiver); return 1; }
int inter(MainData * data, tListOfInstr * instrList) { listFirst(instrList); tInstr *instr; while (1) { instr = listGetData(ilist); //vytáhnu instrukci if(instr == NULL) return internalError(); TVarData *param1, *param2, *param3; int result; switch(instr->type) { /*******Aritmetické operace*******/ case I_ADD: if((param2->type==tDouble) && (param3->type==tDouble)) { param1->type = tDouble; param1->tDouble = param2->tDouble + param3->tDouble; } else if ((param2->type==tInteger) && (param3->type==tInteger)) { param1->type = tInteger; param1->tInteger = param2->tInteger + param3->tInteger; } else if ((param2->type==tDouble) && (param3->type==tInteger)) { param1->type = tInteger; param1->tInteger = param2->tDouble + param3->tInteger; } else if ((param2->type==tInteger) && (param3->type==tDouble)) { param1->type = tInteger; param1->tInteger = param2->tInteger + param3->tDouble; } else return INTERPRET_ERR; break; } } }
/* get data for socket / fd being monitored. Create if not found*/ aeSockState *aeGetSockState(void *apistate, SOCKET fd) { int sindex; listNode *node; list *socklist; aeSockState *sockState; if (apistate == NULL) return NULL; sindex = aeSocketIndex(fd); socklist = &(((aeApiState *)apistate)->lookup[sindex]); node = listFirst(socklist); while (node != NULL) { sockState = (aeSockState *)listNodeValue(node); if (sockState->fd == fd) { return sockState; } node = listNextNode(node); } // not found. Do lazy create of sockState. sockState = (aeSockState *)zmalloc(sizeof(aeSockState)); if (sockState != NULL) { sockState->fd = (int)fd; sockState->masks = 0; sockState->wreqs = 0; sockState->reqs = NULL; memset(&sockState->wreqlist, 0, sizeof(sockState->wreqlist)); if (listAddNodeHead(socklist, sockState) != NULL) { return sockState; } else { zfree(sockState); } } return NULL; }
void *bioProcessBackgroundJobs(void *arg) { struct bio_job *job; #ifdef _WIN32 size_t type = (size_t) arg; #else unsigned long type = (unsigned long) arg; #endif pthread_detach(pthread_self()); pthread_mutex_lock(&bio_mutex[type]); while(1) { listNode *ln; /* The loop always starts with the lock hold. */ if (listLength(bio_jobs[type]) == 0) { pthread_cond_wait(&bio_condvar[type],&bio_mutex[type]); continue; } /* Pop the job from the queue. */ ln = listFirst(bio_jobs[type]); job = ln->value; /* It is now possible to unlock the background system as we know have * a stand alone job structure to process.*/ pthread_mutex_unlock(&bio_mutex[type]); /* Process the job accordingly to its type. */ if (type == REDIS_BIO_CLOSE_FILE) { close((long)(size_t)job->arg1); } else if (type == REDIS_BIO_AOF_FSYNC) { aof_fsync((long)(size_t)job->arg1); } else { redisPanic("Wrong job type in bioProcessBackgroundJobs()."); } zfree(job); /* Lock again before reiterating the loop, if there are no longer * jobs to process we'll block again in pthread_cond_wait(). */ pthread_mutex_lock(&bio_mutex[type]); listDelNode(bio_jobs[type],ln); bio_pending[type]--; } }
/* get data for socket / fd being monitored */ aeSockState *aeGetExistingSockState(void *apistate, int fd) { int sindex; listNode *node; list *socklist; aeSockState *sockState; if (apistate == NULL) return NULL; sindex = aeSocketIndex(fd); socklist = &(((aeApiState *)apistate)->lookup[sindex]); node = listFirst(socklist); while (node != NULL) { sockState = (aeSockState *)listNodeValue(node); if (sockState->fd == fd) { return sockState; } node = listNextNode(node); } return NULL; }
/* This function is called in the beforeSleep() function of the event loop * in order to process the pending input buffer of clients that were * unblocked after a blocking operation. * 取消所有在 unblocked_clients 链表中的客户端的阻塞状态 * */ void processUnblockedClients(void) { listNode *ln; redisClient *c; while (listLength(server.unblocked_clients)) { ln = listFirst(server.unblocked_clients); redisAssert(ln != NULL); c = ln->value; listDelNode(server.unblocked_clients,ln); c->flags &= ~REDIS_UNBLOCKED; c->btype = REDIS_BLOCKED_NONE; /* Process remaining data in the input buffer. */ if (c->querybuf && sdslen(c->querybuf) > 0) { server.current_client = c; processInputBuffer(c); server.current_client = NULL; } } }
/* get the first node value, * and delete this node in this list */ void *listPop(list *l) { listNode *node; void *value; if (l == NULL) { return NULL; } node = listFirst(l); if (node == NULL) { return NULL; } value = listNodeValue(node); ASSERT(value != NULL); listDelNode(l, node); return value; }
static bool addDouble(redisClient *c, redisClient *fc, robj *key, robj *val, long *instd, bool val_is_dbl) { robj *vals = createObject(REDIS_STRING, NULL); if (val_is_dbl) { double d = *((double *)val); vals->ptr = (key->encoding == REDIS_ENCODING_RAW) ? sdscatprintf(sdsempty(), "%ld,%s,%f", *instd, (char *)key->ptr, d) : sdscatprintf(sdsempty(), "%ld,%ld,%f", *instd, (long) key->ptr, d); } else if (val->encoding == REDIS_ENCODING_RAW) { vals->ptr = (key->encoding == REDIS_ENCODING_RAW) ? sdscatprintf(sdsempty(), "%ld,%s,%s", *instd, (char *)key->ptr, (char *)val->ptr) : sdscatprintf(sdsempty(), "%ld,%ld,%s", *instd, (long) key->ptr, (char *)val->ptr); } else { vals->ptr = (key->encoding == REDIS_ENCODING_RAW) ? sdscatprintf(sdsempty(), "%ld,%s,%ld", *instd, (char *)key->ptr, (long)val->ptr) : sdscatprintf(sdsempty(), "%ld,%ld,%ld", *instd, (long) key->ptr, (long)val->ptr); } fc->argv[2] = vals; //RL4 "DBL: INSERTING [1]: %s [2]: %s", fc->argv[1]->ptr, fc->argv[2]->ptr); legacyInsertCommand(fc); decrRefCount(vals); if (!respOk(fc)) { /* insert error */ listNode *ln = listFirst(fc->reply); addReply(c, ln->value); return 0; } *instd = *instd + 1; return 1; }
/* This function is called in the beforeSleep() function of the event loop * in order to process the pending input buffer of clients that were * unblocked after a blocking operation. */ void processUnblockedClients(void) { listNode *ln; client *c; while (listLength(server.unblocked_clients)) { ln = listFirst(server.unblocked_clients); serverAssert(ln != NULL); c = ln->value; listDelNode(server.unblocked_clients,ln); c->flags &= ~CLIENT_UNBLOCKED; /* Process remaining data in the input buffer, unless the client * is blocked again. Actually processInputBuffer() checks that the * client is not blocked before to proceed, but things may change and * the code is conceptually more correct this way. */ if (!(c->flags & CLIENT_BLOCKED)) { if (c->querybuf && sdslen(c->querybuf) > 0) { processInputBuffer(c); } } } }
/* This function is called in the beforeSleep() function of the event loop * in order to process the pending input buffer of clients that were * unblocked after a blocking operation. */ void processUnblockedClients(void) { listNode *ln; client *c; while (listLength(server.unblocked_clients)) { ln = listFirst(server.unblocked_clients); serverAssert(ln != NULL); c = ln->value; listDelNode(server.unblocked_clients,ln); c->flags &= ~CLIENT_UNBLOCKED; /* Note that the client may be blocked again at this point, since * a new blocking command was processed. In that case we just remove * it from the unblocked clients list without actually processing * its pending query buffer. */ if (!(c->flags & CLIENT_BLOCKED)) { c->btype = BLOCKED_NONE; /* Process remaining data in the input buffer. */ if (c->querybuf && sdslen(c->querybuf) > 0) { processInputBuffer(c); } } } }