XACK ... * * Acknowledge a message as processed. In practical terms we just check the * pendine entries list (PEL) of the group, and delete the PEL entry both from * the group and the consumer (pending messages are referenced in both places). * * Return value of the command is the number of messages successfully * acknowledged, that is, the IDs we were actually
| 2543 | * acknowledged, that is, the IDs we were actually able to resolve in the PEL. |
| 2544 | */ |
| 2545 | void xackCommand(client *c) { |
| 2546 | streamCG *group = NULL; |
| 2547 | robj_roptr o = lookupKeyRead(c->db,c->argv[1]); |
| 2548 | streamID static_ids[STREAMID_STATIC_VECTOR_LEN]; |
| 2549 | streamID *ids = static_ids; |
| 2550 | int id_count = c->argc-3; |
| 2551 | int acknowledged = 0; |
| 2552 | |
| 2553 | if (o) { |
| 2554 | if (checkType(c,o,OBJ_STREAM)) return; /* Type error. */ |
| 2555 | group = streamLookupCG((stream*)ptrFromObj(o),szFromObj(c->argv[2])); |
| 2556 | } |
| 2557 | |
| 2558 | /* No key or group? Nothing to ack. */ |
| 2559 | if (o == nullptr || group == NULL) { |
| 2560 | addReply(c,shared.czero); |
| 2561 | return; |
| 2562 | } |
| 2563 | |
| 2564 | /* Start parsing the IDs, so that we abort ASAP if there is a syntax |
| 2565 | * error: the return value of this command cannot be an error in case |
| 2566 | * the client successfully acknowledged some messages, so it should be |
| 2567 | * executed in a "all or nothing" fashion. */ |
| 2568 | if (id_count > STREAMID_STATIC_VECTOR_LEN) |
| 2569 | ids = (streamID*)zmalloc(sizeof(streamID)*id_count); |
| 2570 | for (int j = 3; j < c->argc; j++) { |
| 2571 | if (streamParseStrictIDOrReply(c,c->argv[j],&ids[j-3],0) != C_OK) goto cleanup; |
| 2572 | } |
| 2573 | |
| 2574 | for (int j = 3; j < c->argc; j++) { |
| 2575 | unsigned char buf[sizeof(streamID)]; |
| 2576 | streamEncodeID(buf,&ids[j-3]); |
| 2577 | |
| 2578 | /* Lookup the ID in the group PEL: it will have a reference to the |
| 2579 | * NACK structure that will have a reference to the consumer, so that |
| 2580 | * we are able to remove the entry from both PELs. */ |
| 2581 | streamNACK *nack = (streamNACK*)raxFind(group->pel,buf,sizeof(buf)); |
| 2582 | if (nack != raxNotFound) { |
| 2583 | raxRemove(group->pel,buf,sizeof(buf),NULL); |
| 2584 | raxRemove(nack->consumer->pel,buf,sizeof(buf),NULL); |
| 2585 | streamFreeNACK(nack); |
| 2586 | acknowledged++; |
| 2587 | g_pserver->dirty++; |
| 2588 | } |
| 2589 | } |
| 2590 | addReplyLongLong(c,acknowledged); |
| 2591 | cleanup: |
| 2592 | if (ids != static_ids) zfree(ids); |
| 2593 | } |
| 2594 | |
| 2595 | /* XPENDING <key> <group> [[IDLE <idle>] <start> <stop> <count> [<consumer>]] |
| 2596 | * |
nothing calls this directly
no test coverage detected