/* Set a client in blocking mode for the specified key, with the specified * timeout */ void blockForKeys(redisClient *c, robj **keys, int numkeys, mstime_t timeout, robj *target) { dictEntry *de; list *l; int j; c->bpop.timeout = timeout; c->bpop.target = target; if (target != NULL) incrRefCount(target); for (j = 0; j < numkeys; j++) { /* If the key already exists in the dict ignore it. */ if (dictAdd(c->bpop.keys,keys[j],NULL) != DICT_OK) continue; incrRefCount(keys[j]); redisDb *db = &(c->db)[keyHashSlot(keys[j]->ptr, sdslen(keys[j]->ptr))]; /* And in the other "side", to map keys -> clients */ de = dictFind(db->blocking_keys,keys[j]); if (de == NULL) { int retval; /* For every key we take a list of clients blocked for it */ l = listCreate(); retval = dictAdd(db->blocking_keys,keys[j],l); incrRefCount(keys[j]); redisAssertWithInfo(c,keys[j],retval == DICT_OK); } else { l = dictGetVal(de); } listAddNodeTail(l,c); } blockClient(c,REDIS_BLOCKED_LIST); }
void readQueryFromClient(aeEventLoop *el, int fd, httpClient *c) { char buf[CCACHE_IOBUF_LEN]; int nread; nread = read(fd, buf, CCACHE_IOBUF_LEN); if (nread == -1) { if (errno == EAGAIN) { /* try again */ nread = 0; } else { ulog(CCACHE_VERBOSE, "Reading from client: %s",strerror(errno)); freeClient(c); return; } } else if (nread == 0) { ulog(CCACHE_VERBOSE, "End of client request"); freeClient(c); return; } if (nread>0) { printf("Read Request: %.2lf \n", (double)(clock())); c->lastinteraction = time(NULL); listMoveNodeToTail(el->clients,c->elNode); /* NOTICE: nread or nread-1 */ switch(requestParse(c->req,buf,buf+nread)){ case parse_not_completed: break; case parse_completed: { int handle_result = requestHandle(c->req,c->rep,el->cache,c); if(handle_result == HANDLER_BLOCK){ blockClient(el,c); } else { if (_installWriteEvent(el, c) != CCACHE_OK) return; printf("Install Write: %.2lf\n", (double)(clock())); /* For HANDLE_OK there is nothing to do */ if(handle_result == HANDLER_ERR) requestHandleError(c->req,c->rep); } break; } case parse_error: if (_installWriteEvent(el, c) != CCACHE_OK) { return; } requestHandleError(c->req,c->rep); break; default: break; }; } }
/* Set a client in blocking mode for the specified key (list or stream), with * the specified timeout. The 'type' argument is BLOCKED_LIST or BLOCKED_STREAM * depending on the kind of operation we are waiting for an empty key in * order to awake the client. The client is blocked for all the 'numkeys' * keys as in the 'keys' argument. When we block for stream keys, we also * provide an array of streamID structures: clients will be unblocked only * when items with an ID greater or equal to the specified one is appended * to the stream. */ void blockForKeys(client *c, int btype, robj **keys, int numkeys, mstime_t timeout, robj *target, streamID *ids) { dictEntry *de; list *l; int j; c->bpop.timeout = timeout; c->bpop.target = target; if (target != NULL) incrRefCount(target); for (j = 0; j < numkeys; j++) { /* The value associated with the key name in the bpop.keys dictionary * is NULL for lists, or the stream ID for streams. */ void *key_data = NULL; if (btype == BLOCKED_STREAM) { key_data = zmalloc(sizeof(streamID)); memcpy(key_data,ids+j,sizeof(streamID)); } /* If the key already exists in the dictionary ignore it. */ if (dictAdd(c->bpop.keys,keys[j],key_data) != DICT_OK) { zfree(key_data); continue; } incrRefCount(keys[j]); /* And in the other "side", to map keys -> clients */ de = dictFind(c->db->blocking_keys,keys[j]); if (de == NULL) { int retval; /* For every key we take a list of clients blocked for it */ l = listCreate(); retval = dictAdd(c->db->blocking_keys,keys[j],l); incrRefCount(keys[j]); serverAssertWithInfo(c,keys[j],retval == DICT_OK); } else { l = dictGetVal(de); } listAddNodeTail(l,c); } blockClient(c,btype); }
// keys是一个key的数组,个数为numkeys个 // timeout保存超时时间 // target保存解除阻塞时的key对象,用于BRPOPLPUSH函数 // 根据给定的key将client阻塞 void blockForKeys(client *c, robj **keys, int numkeys, mstime_t timeout, robj *target) { dictEntry *de; list *l; int j; //设置超时时间和target c->bpop.timeout = timeout; c->bpop.target = target; //增加target的引用计数 if (target != NULL) incrRefCount(target); //将当前client的numkeys个key设置为阻塞 for (j = 0; j < numkeys; j++) { /* If the key already exists in the dict ignore it. */ //bpop.keys记录所有造成client阻塞的键 //将要阻塞的键放入bpop.keys字典中 if (dictAdd(c->bpop.keys,keys[j],NULL) != DICT_OK) continue; //当前的key引用计数加1 incrRefCount(keys[j]); /* And in the other "side", to map keys -> clients */ //db->blocking_keys是一个字典,字典的键为bpop.keys中的一个键,值是一个列表,保存着所有被该键阻塞的client //当前造成client被阻塞的键有没有当前的key de = dictFind(c->db->blocking_keys,keys[j]); if (de == NULL) { //没有当前的key,添加进去 int retval; /* For every key we take a list of clients blocked for it */ //创建一个列表 l = listCreate(); //将造成阻塞的键和列表添加到db->blocking_keys字典中 retval = dictAdd(c->db->blocking_keys,keys[j],l); incrRefCount(keys[j]); serverAssertWithInfo(c,keys[j],retval == DICT_OK); } else { //如果已经有了,则当前key的值保存起来,值是一个列表 l = dictGetVal(de); } listAddNodeTail(l,c); //将当前client加入到阻塞的client的列表 } blockClient(c,BLOCKED_LIST); //阻塞client }