Helper function for handleClientsBlockedOnKeys(). This function is called * in order to check if we can serve clients blocked by modules using * RM_BlockClientOnKeys(), when the corresponding key was signaled as ready: * our goal here is to call the RedisModuleBlockedClient reply() callback to * see if the key is really able to serve the client, and in that case, * unblock it. */
| 506 | * see if the key is really able to serve the client, and in that case, |
| 507 | * unblock it. */ |
| 508 | void serveClientsBlockedOnKeyByModule(readyList *rl) { |
| 509 | dictEntry *de; |
| 510 | |
| 511 | /* Optimization: If no clients are in type BLOCKED_MODULE, |
| 512 | * we can skip this loop. */ |
| 513 | if (!g_pserver->blocked_clients_by_type[BLOCKED_MODULE]) return; |
| 514 | |
| 515 | /* We serve clients in the same order they blocked for |
| 516 | * this key, from the first blocked to the last. */ |
| 517 | de = dictFind(rl->db->blocking_keys,rl->key); |
| 518 | if (de) { |
| 519 | list *clients = (list*)dictGetVal(de); |
| 520 | int numclients = listLength(clients); |
| 521 | |
| 522 | while(numclients--) { |
| 523 | listNode *clientnode = listFirst(clients); |
| 524 | client *receiver = (client*)clientnode->value; |
| 525 | |
| 526 | /* Put at the tail, so that at the next call |
| 527 | * we'll not run into it again: clients here may not be |
| 528 | * ready to be served, so they'll remain in the list |
| 529 | * sometimes. We want also be able to skip clients that are |
| 530 | * not blocked for the MODULE type safely. */ |
| 531 | listRotateHeadToTail(clients); |
| 532 | |
| 533 | if (receiver->btype != BLOCKED_MODULE) continue; |
| 534 | |
| 535 | /* Note that if *this* client cannot be served by this key, |
| 536 | * it does not mean that another client that is next into the |
| 537 | * list cannot be served as well: they may be blocked by |
| 538 | * different modules with different triggers to consider if a key |
| 539 | * is ready or not. This means we can't exit the loop but need |
| 540 | * to continue after the first failure. */ |
| 541 | monotime replyTimer; |
| 542 | elapsedStart(&replyTimer); |
| 543 | if (!moduleTryServeClientBlockedOnKey(receiver, rl->key)) continue; |
| 544 | updateStatsOnUnblock(receiver, 0, elapsedUs(replyTimer)); |
| 545 | |
| 546 | moduleUnblockClient(receiver); |
| 547 | } |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | /* This function should be called by Redis every time a single command, |
| 552 | * a MULTI/EXEC block, or a Lua script, terminated its execution after |
no test coverage detected