예제 #1
0
    unsigned sendData(const UdpPermitToSendMsg &permit, bool isLocal, TokenBucket *bucket, bool &moreRequested, unsigned &maxPackets)
    {
        moreRequested = false;
        maxPackets = permit.max_data;
        PointerArray toSend;
        unsigned totalSent = cleanRetryData(permit, toSend);
        while (toSend.length() < maxPackets && dataQueued())
        {
            DataBuffer *buffer = popQueuedData();
            if (buffer) // Aborted slave queries leave NULL records on queue
            {
                UdpPacketHeader *header = (UdpPacketHeader*) buffer->data;
                toSend.append(buffer);
                totalSent += header->length;
#ifdef __linux__
                if (isLocal && (totalSent> 100000)) 
                    break;
#endif
            }
        }
        maxPackets = toSend.length();
        for (unsigned idx = 0; idx < maxPackets; idx++)
        {
            DataBuffer *buffer = (DataBuffer *) toSend.item(idx);
            UdpPacketHeader *header = (UdpPacketHeader*) buffer->data;
            bool isRetry = (header->udpSequence != 0);
            if (isRetry)
            {
                if (checkTraceLevel(TRACE_RETRY_DATA, 1))
                    DBGLOG("UdpSender: Resending packet to destination node %u sequence %u", permit.destNodeIndex, header->udpSequence);
                atomic_inc(&packetsRetried);
            }
            else
                header->udpSequence = nextUdpSequence();
            unsigned length = header->length;
            if (bucket)
            {
                MTIME_SECTION(timer, "bucket_wait");
                bucket->wait((length / 1024)+1);
            }
            try
            {
                if (udpSendCompletedInData)
                {
                    if (idx == maxPackets-1)
                    {
                         // MORE - is this safe ? Any other thread looking at the data right now? Don't _think_ so...
                        if (false && dataQueued()) // Causes some problems because no flow control info gets through at all
                        {
                            moreRequested = true;
                            header->udpSequence |= (UDP_SEQUENCE_COMPLETE|UDP_SEQUENCE_MORE);
                        }
                        else
                            header->udpSequence |= UDP_SEQUENCE_COMPLETE;
                    }
                }
#ifdef _SIMULATE_LOST_PACKETS
                if (isRetry || (header->udpSequence % 100) != 0)
#endif
                data_socket->write(buffer->data, length);
                header->udpSequence &= ~UDP_SEQUENCE_BITS;
            }
            catch(IException *e)
            {
                StringBuffer s;
                DBGLOG("UdpSender: write exception - write(%p, %u) - %s", buffer->data, length, e->errorMessage(s).str());
                e->Release();
            } 
            catch(...)
            {
                DBGLOG("UdpSender: write exception - unknown exception");
            }
            if (!isRetry && maxRetryData)
            {
                unsigned slot = (retryDataIdx + retryDataCount) % maxRetryData;
                if (retryDataCount < maxRetryData)
                    retryDataCount++;
                else
                {
                    if (udpTraceLevel > 0)
                        DBGLOG("Overflow in resend packet buffer for destination node %u - discarding packet sequence %u", permit.destNodeIndex, header->udpSequence);
                    ::Release(retryData[slot]);
                }
                retryData[slot] = buffer;
            }
            else
            {
                ::Release(buffer);
            }
        }
        return totalSent;
    }
예제 #2
0
    unsigned cleanRetryData(const UdpPermitToSendMsg &permit, PointerArray &retries)
    {
        // Any saved packets < lastReceived that are not listed as missing can be deleted
        SpinBlock b(lock);
        unsigned totalData = 0;
        if (checkTraceLevel(TRACE_RETRY_DATA, 3))
        {
            unsigned minUdpSequence;
            if (retryDataCount)
                minUdpSequence = ((UdpPacketHeader *) retryData[retryDataIdx]->data)->udpSequence;
            else
                minUdpSequence = maxUdpSequence;
            StringBuffer permitStr;
            permit.toString(permitStr);
            DBGLOG("UdpSender: cleanRetryData (%s), total %u available between %u and %u", permitStr.str(), retryDataCount, minUdpSequence, maxUdpSequence); 
        }
        unsigned lastReceived = permit.lastSequenceSeen;
        unsigned missingIndex = 0;
        unsigned missingCount = permit.missingCount;
        unsigned i = 0;
        if (maxRetryData)
        {
            while (i < retryDataCount && retries.length() < permit.max_data)
            {
                unsigned idx = (retryDataIdx + i) % maxRetryData;
                DataBuffer *buffer = retryData[idx];
                if (buffer)
                {
                    UdpPacketHeader *header = (UdpPacketHeader*) buffer->data;
                    unsigned thisSequence = header->udpSequence;
                    if (thisSequence > lastReceived)
                        break;

                    if (!missingCount || thisSequence < permit.missingSequences[missingIndex])
                    {
                        ::Release(buffer);
                        retryData[idx] = NULL;
                        if (i)
                            i++; // MORE - leaves holes - is this smart? Alternatively could close up... Should be rare anyway
                        else
                        {
                            retryDataIdx = (retryDataIdx + 1) % maxRetryData;
                            retryDataCount--; 
                        }               
                    }
                    else if (thisSequence == permit.missingSequences[missingIndex])
                    {
                        totalData += header->length;
                        retries.append(buffer);
                        i++;
                        missingIndex++;
                        missingCount--;
                    }
                    else
                    {
                        missingIndex++;
                        missingCount--;
                    }
                }
                else
                {
                    if (i)
                        i++;
                    else
                    {
                        // Removing leading nulls
                        retryDataCount--;
                        retryDataIdx = (retryDataIdx + 1) % maxRetryData;
                    }
                }
            }
        }
        if (checkTraceLevel(TRACE_RETRY_DATA, 3))
            DBGLOG("UdpSender: cleanRetryData found %u to resend total size %u, total %u still available", retries.length(), totalData, retryDataCount);
        return totalData;
    }