This command implements the generic zpop operation, used by: * ZPOPMIN, ZPOPMAX, BZPOPMIN and BZPOPMAX. This function is also used * inside blocked.c in the unblocking stage of BZPOPMIN and BZPOPMAX. * * If 'emitkey' is true also the key name is emitted, useful for the blocking * behavior of BZPOP[MIN|MAX], since we can block into multiple keys. * * The synchronous version instead does not
| 3805 | * The synchronous version instead does not need to emit the key, but may |
| 3806 | * use the 'count' argument to return multiple items if available. */ |
| 3807 | void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey, robj *countarg) { |
| 3808 | int idx; |
| 3809 | robj *key = NULL; |
| 3810 | robj *zobj = NULL; |
| 3811 | sds ele; |
| 3812 | double score; |
| 3813 | long count = 1; |
| 3814 | |
| 3815 | /* If a count argument as passed, parse it or return an error. */ |
| 3816 | if (countarg) { |
| 3817 | if (getLongFromObjectOrReply(c,countarg,&count,NULL) != C_OK) |
| 3818 | return; |
| 3819 | if (count <= 0) { |
| 3820 | addReply(c,shared.emptyarray); |
| 3821 | return; |
| 3822 | } |
| 3823 | } |
| 3824 | |
| 3825 | /* Check type and break on the first error, otherwise identify candidate. */ |
| 3826 | idx = 0; |
| 3827 | while (idx < keyc) { |
| 3828 | key = keyv[idx++]; |
| 3829 | zobj = lookupKeyWrite(c->db,key); |
| 3830 | if (!zobj) continue; |
| 3831 | if (checkType(c,zobj,OBJ_ZSET)) return; |
| 3832 | break; |
| 3833 | } |
| 3834 | |
| 3835 | /* No candidate for zpopping, return empty. */ |
| 3836 | if (!zobj) { |
| 3837 | addReply(c,shared.emptyarray); |
| 3838 | return; |
| 3839 | } |
| 3840 | |
| 3841 | void *arraylen_ptr = addReplyDeferredLen(c); |
| 3842 | long result_count = 0; |
| 3843 | |
| 3844 | /* We emit the key only for the blocking variant. */ |
| 3845 | if (emitkey) addReplyBulk(c,key); |
| 3846 | |
| 3847 | /* Respond with a single (flat) array in RESP2 or if countarg is not |
| 3848 | * provided (returning a single element). In RESP3, when countarg is |
| 3849 | * provided, use nested array. */ |
| 3850 | int use_nested_array = c->resp > 2 && countarg != NULL; |
| 3851 | |
| 3852 | /* Remove the element. */ |
| 3853 | do { |
| 3854 | if (zobj->encoding == OBJ_ENCODING_ZIPLIST) { |
| 3855 | unsigned char *zl = (unsigned char*)zobj->m_ptr; |
| 3856 | unsigned char *eptr, *sptr; |
| 3857 | unsigned char *vstr; |
| 3858 | unsigned int vlen; |
| 3859 | long long vlong; |
| 3860 | |
| 3861 | /* Get the first or last element in the sorted set. */ |
| 3862 | eptr = ziplistIndex(zl,where == ZSET_MAX ? -2 : 0); |
| 3863 | serverAssertWithInfo(c,zobj,eptr != NULL); |
| 3864 | serverAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong)); |
no test coverage detected