Set a client in blocking mode for the specified key (list, zset or stream), * with the specified timeout. The 'type' argument is BLOCKED_LIST, * BLOCKED_ZSET 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 p
| 652 | * be unblocked only when items with an ID greater or equal to the specified |
| 653 | * one is appended to the stream. */ |
| 654 | void blockForKeys(client *c, int btype, robj **keys, int numkeys, mstime_t timeout, robj *target, struct listPos *listpos, streamID *ids) { |
| 655 | dictEntry *de; |
| 656 | list *l; |
| 657 | int j; |
| 658 | |
| 659 | c->bpop.timeout = timeout; |
| 660 | c->bpop.target = target; |
| 661 | |
| 662 | if (listpos != NULL) c->bpop.listpos = *listpos; |
| 663 | |
| 664 | if (target != NULL) incrRefCount(target); |
| 665 | |
| 666 | for (j = 0; j < numkeys; j++) { |
| 667 | /* Allocate our bkinfo structure, associated to each key the client |
| 668 | * is blocked for. */ |
| 669 | bkinfo *bki = (bkinfo*)zmalloc(sizeof(*bki)); |
| 670 | if (btype == BLOCKED_STREAM) |
| 671 | bki->stream_id = ids[j]; |
| 672 | |
| 673 | /* If the key already exists in the dictionary ignore it. */ |
| 674 | if (dictAdd(c->bpop.keys,keys[j],bki) != DICT_OK) { |
| 675 | zfree(bki); |
| 676 | continue; |
| 677 | } |
| 678 | incrRefCount(keys[j]); |
| 679 | |
| 680 | /* And in the other "side", to map keys -> clients */ |
| 681 | de = dictFind(c->db->blocking_keys,keys[j]); |
| 682 | if (de == NULL) { |
| 683 | int retval; |
| 684 | |
| 685 | /* For every key we take a list of clients blocked for it */ |
| 686 | l = listCreate(); |
| 687 | retval = dictAdd(c->db->blocking_keys,keys[j],l); |
| 688 | incrRefCount(keys[j]); |
| 689 | serverAssertWithInfo(c,keys[j],retval == DICT_OK); |
| 690 | } else { |
| 691 | l = (list*)dictGetVal(de); |
| 692 | } |
| 693 | listAddNodeTail(l,c); |
| 694 | bki->listnode = listLast(l); |
| 695 | } |
| 696 | blockClient(c,btype); |
| 697 | } |
| 698 | |
| 699 | /* Unblock a client that's waiting in a blocking operation such as BLPOP. |
| 700 | * You should never call this function directly, but unblockClient() instead. */ |
no test coverage detected