Repository: valkey-io/valkey
File: src/cluster_legacy.c (C)

Code before:
     * TOTAL_PACKETS = 2 * 4 * NUM_OF_PRIMARIES.
     *
     * If we assume we have just primaries (so num of nodes and num of primaries
     * is the same), with 1/10 we always get over the majority, and specifically
     * 80% of the number of nodes, to account for many primaries failing at the
     * same time.
     *
     * Since we have non-voting replicas that lower the probability of an entry
     * to feature our node, we set the number of entries per packet as
     * 10% of the total nodes we have. */
    wanted = floor(dictSize(server.cluster->nodes) / 10);
    if (wanted < 3) wanted = 3;
    if (wanted > freshnodes) wanted = freshnodes;

    /* Include all the nodes in PFAIL state, so that failure reports are
     * faster to propagate to go from PFAIL to FAIL state. */
    int pfail_wanted = server.cluster->stats_pfail_nodes;

    /* Compute the maximum estlen to allocate our buffer. We'll fix the estlen
     * later according to the number of gossip sections we really were able
     * to put inside the packet. */
    estlen = sizeof(clusterMsg) - sizeof(union clusterMsgData);
    estlen += (sizeof(clusterMsgDataGossip) * (wanted + pfail_wanted));
    /* If the link or the node indicates that it supports extensions, then we
     * pass the extensions. */
    if (link->support_extension || (link->node && nodeSupportsExtensions(link->node))) {
        estlen += writePingExtensions(NULL, 0);
    }
    /* Note: clusterBuildMessageHdr() expects the buffer to be always at least
     * sizeof(clusterMsg) or more. */
    if (estlen < (int)sizeof(clusterMsg)) estlen = sizeof(clusterMsg);
    clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(type, estlen);
    clusterMsg *hdr = getMessageFromSendBlock(msgblock);

    if (!link->inbound) {
        if (type == CLUSTERMSG_TYPE_PING)
            link->node->ping_sent = mstime();
        else if (type == CLUSTERMSG_TYPE_MEET)
            link->node->meet_sent = mstime();
    }

    /* Populate the gossip fields */
    int maxiterations = wanted * 3;
    while (freshnodes > 0 && gossipcount < wanted && maxiterations--) {
        dictEntry *de = dictGetRandomKey(server.cluster->nodes);
        clusterNode *this = dictGetVal(de);

        /* Don't include this node: the whole packet header is about us
         * already, so we just gossip about other nodes.
         * Also, don't include the receiver. Receiver will not update its state
         * based on gossips about itself. */

Review comment (suggestion):
```suggestion
    if (link->support_extension) {
```

Code after:
     * in the node_timeout*2 failure reports validity time. So we have
     * that, for a single PFAIL node, we can expect to receive the following
     * number of failure reports (in the specified window of time):
     *
     * PROB * GOSSIP_ENTRIES_PER_PACKET * TOTAL_PACKETS:
     *
     * PROB = probability of being featured in a single gossip entry,
     *        which is 1 / NUM_OF_NODES.
     * ENTRIES = 10.
     * TOTAL_PACKETS = 2 * 4 * NUM_OF_PRIMARIES.
     *
     * If we assume we have just primaries (so num of nodes and num of primaries
     * is the same), with 1/10 we always get over the majority, and specifically
     * 80% of the number of nodes, to account for many primaries failing at the
     * same time.
     *
     * Since we have non-voting replicas that lower the probability of an entry
     * to feature our node, we set the number of entries per packet as
     * 10% of the total nodes we have. */
    wanted = floor(dictSize(server.cluster->nodes) / 10);
    if (wanted < 3) wanted = 3;
    if (wanted > freshnodes) wanted = freshnodes;

    /* Include all the nodes in PFAIL state, so that failure reports are
     * faster to propagate to go from PFAIL to FAIL state. */
    int pfail_wanted = server.cluster->stats_pfail_nodes;

    /* Compute the maximum estlen to allocate our buffer. We'll fix the estlen
     * later according to the number of gossip sections we really were able
     * to put inside the packet. */
    estlen = sizeof(clusterMsg) - sizeof(union clusterMsgData);
    estlen += (sizeof(clusterMsgDataGossip) * (wanted + pfail_wanted));
    /* If the link or the node indicates that it supports extensions, then we
     * pass the extensions. */
    if (linkSupportsExtension(link) || (link->node && nodeSupportsExtensions(link->node))) {
        estlen += writePingExtensions(NULL, 0);
    }
    /* Note: clusterBuildMessageHdr() expects the buffer to be always at least
     * sizeof(clusterMsg) or more. */
    if (estlen < (int)sizeof(clusterMsg)) estlen = sizeof(clusterMsg);
    clusterMsgSendBlock *msgblock = createClusterMsgSendBlock(type, estlen);
    clusterMsg *hdr = getMessageFromSendBlock(msgblock);

    if (!link->inbound) {
        if (type == CLUSTERMSG_TYPE_PING)
            link->node->ping_sent = mstime();
        else if (type == CLUSTERMSG_TYPE_MEET)
            link->node->meet_sent = mstime();
    }

    /* Populate the gossip fields */