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