Skip to content

MessageEvent::DoOnWrite应该消除不必要的buffer拷贝 #230

@dyx2025

Description

@dyx2025

MessageEvent::DoOnWrite是发消息的热路径,应该消除不必要的buffer拷贝。
通过本类新增iovec 结构体数组成员变量暂存niBuffLen和poMessage,新增成员变量暂存已发送的字节个数,使用 writev 系统调用,再对逻辑做适当的修改就能消除buffer拷贝 。

原代码路径:
src/communicate/tcp/message_event.cpp

int MessageEvent :: DoOnWrite()
{
    if (m_iLeftWriteLen > 0)
    {
        return WriteLeft();
    }

    m_oMutex.lock();
    if (m_oInQueue.empty())
    {
        m_oMutex.unlock();
        return 0;
    }
    QueueData tData = m_oInQueue.front();
    m_oInQueue.pop();
    m_iQueueMemSize -= tData.psValue->size();
    m_oMutex.unlock();

    std::string * poMessage = tData.psValue;
    uint64_t llNowTime = Time::GetSteadyClockMS();
    int iDelayMs = llNowTime > tData.llEnqueueAbsTime ? (int)(llNowTime - tData.llEnqueueAbsTime) : 0;
    BP->GetNetworkBP()->TcpOutQueue(iDelayMs);
    if (iDelayMs > TCP_OUTQUEUE_DROP_TIMEMS)
    {
        //PLErr("drop request because enqueue timeout, nowtime %lu unqueuetime %lu",
                //llNowTime, tData.llEnqueueAbsTime);
        delete poMessage;
        return 0;
    }

    int iBuffLen = poMessage->size();
    int niBuffLen = htonl(iBuffLen + 4);

    int iLen = iBuffLen + 4;
    // 没有必要拷贝niBuffLen和poMessage到buffer
    // 通过本类的成员变量暂存niBuffLen和poMessage,以及记录发送的字节个数,再对逻辑做适当的修改就能消除buffer拷贝  
    m_oWriteCacheBuffer.Ready(iLen);
    memcpy(m_oWriteCacheBuffer.GetPtr(), &niBuffLen, 4);
    memcpy(m_oWriteCacheBuffer.GetPtr() + 4, poMessage->c_str(), iBuffLen);

    m_iLeftWriteLen = iLen;
    m_iLastWritePos = 0;

    delete poMessage;

    //PLImp("write len %d ip %s port %d", iLen, m_oAddr.getHost().c_str(), m_oAddr.getPort());

    int iWriteLen = m_oSocket.send(m_oWriteCacheBuffer.GetPtr(), iLen);
    if (iWriteLen < 0)
    {
        PLErr("fail, write len %d ip %s port %d",
                iWriteLen, m_oAddr.getHost().c_str(), m_oAddr.getPort());
        return -1;
    }

    if (iWriteLen == 0)
    {
        //need wait next write
        AddEvent(EPOLLOUT);

        return 1;
    }

    //PLImp("real write len %d", iWriteLen);

    if (iWriteLen == iLen)
    {
        m_iLeftWriteLen = 0;
        m_iLastWritePos = 0;
        //write done
    }
    else if (iWriteLen < iLen)
    {
        m_iLastWritePos = iWriteLen;
        m_iLeftWriteLen = iLen - iWriteLen;

        PLImp("write buflen %d smaller than expectlen %d", iWriteLen, iLen);
    }
    else
    {
        PLErr("write buflen %d large than expectlen %d", iWriteLen, iLen);
    }

    return 0;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions