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. */
| 483 | * see if the key is really able to serve the client, and in that case, |
| 484 | * unblock it. */ |
| 485 | void serveClientsBlockedOnKeyByModule(readyList *rl) { |
| 486 | dictEntry *de; |
| 487 | |
| 488 | /* Optimization: If no clients are in type BLOCKED_MODULE, |
| 489 | * we can skip this loop. */ |
| 490 | if (!server.blocked_clients_by_type[BLOCKED_MODULE]) return; |
| 491 | |
| 492 | /* We serve clients in the same order they blocked for |
| 493 | * this key, from the first blocked to the last. */ |
| 494 | de = dictFind(rl->db->blocking_keys,rl->key); |
| 495 | if (de) { |
| 496 | list *clients = dictGetVal(de); |
| 497 | int numclients = listLength(clients); |
| 498 | |
| 499 | while(numclients--) { |
| 500 | listNode *clientnode = listFirst(clients); |
| 501 | client *receiver = clientnode->value; |
| 502 | |
| 503 | /* Put at the tail, so that at the next call |
| 504 | * we'll not run into it again: clients here may not be |
| 505 | * ready to be served, so they'll remain in the list |
| 506 | * sometimes. We want also be able to skip clients that are |
| 507 | * not blocked for the MODULE type safely. */ |
| 508 | listRotateHeadToTail(clients); |
| 509 | |
| 510 | if (receiver->btype != BLOCKED_MODULE) continue; |
| 511 | |
| 512 | /* Note that if *this* client cannot be served by this key, |
| 513 | * it does not mean that another client that is next into the |
| 514 | * list cannot be served as well: they may be blocked by |
| 515 | * different modules with different triggers to consider if a key |
| 516 | * is ready or not. This means we can't exit the loop but need |
| 517 | * to continue after the first failure. */ |
| 518 | monotime replyTimer; |
| 519 | elapsedStart(&replyTimer); |
| 520 | if (!moduleTryServeClientBlockedOnKey(receiver, rl->key)) continue; |
| 521 | updateStatsOnUnblock(receiver, 0, elapsedUs(replyTimer)); |
| 522 | |
| 523 | moduleUnblockClient(receiver); |
| 524 | } |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | /* This function should be called by Redis every time a single command, |
| 529 | * a MULTI/EXEC block, or a Lua script, terminated its execution after |
no test coverage detected