Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or * 0 if the client was not subscribed to the specified channel. */
| 163 | /* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or |
| 164 | * 0 if the client was not subscribed to the specified channel. */ |
| 165 | int pubsubUnsubscribeChannel(client *c, robj *channel, int notify) { |
| 166 | dictEntry *de; |
| 167 | list *clients; |
| 168 | listNode *ln; |
| 169 | int retval = 0; |
| 170 | |
| 171 | /* Remove the channel from the client -> channels hash table */ |
| 172 | incrRefCount(channel); /* channel may be just a pointer to the same object |
| 173 | we have in the hash tables. Protect it... */ |
| 174 | if (dictDelete(c->pubsub_channels,channel) == DICT_OK) { |
| 175 | retval = 1; |
| 176 | /* Remove the client from the channel -> clients list hash table */ |
| 177 | de = dictFind(g_pserver->pubsub_channels,channel); |
| 178 | serverAssertWithInfo(c,NULL,de != NULL); |
| 179 | clients = (list*)dictGetVal(de); |
| 180 | ln = listSearchKey(clients,c); |
| 181 | serverAssertWithInfo(c,NULL,ln != NULL); |
| 182 | listDelNode(clients,ln); |
| 183 | if (listLength(clients) == 0) { |
| 184 | /* Free the list and associated hash entry at all if this was |
| 185 | * the latest client, so that it will be possible to abuse |
| 186 | * Redis PUBSUB creating millions of channels. */ |
| 187 | dictDelete(g_pserver->pubsub_channels,channel); |
| 188 | } |
| 189 | } |
| 190 | /* Notify the client */ |
| 191 | if (notify) addReplyPubsubUnsubscribed(c,channel); |
| 192 | decrRefCount(channel); /* it is finally safe to release it */ |
| 193 | return retval; |
| 194 | } |
| 195 | |
| 196 | /* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the client was already subscribed to that pattern. */ |
| 197 | int pubsubSubscribePattern(client *c, robj *pattern) { |
no test coverage detected