Skip to content

SMFac::Execute和SMFac::ExecuteForCheckpoint应该消除不必要的string拷贝 #231

@dyx2025

Description

@dyx2025

SMFac::Execute和SMFac::ExecuteForCheckpoint分别是状态机执行和checkpoint执行的热路径,应该消除不必要的string拷贝。

原代码路径:
src/sm-base/sm_base.cpp

// ...

bool SMFac :: Execute(const int iGroupIdx, const uint64_t llInstanceID, const std::string & sPaxosValue, SMCtx * poSMCtx)
{
    if (sPaxosValue.size() < sizeof(int))
    {   
        PLG1Err("Value wrong, instanceid %lu size %zu", llInstanceID, sPaxosValue.size());
        //need do nothing, just skip
        return true;
    }   

    int iSMID = 0;
    memcpy(&iSMID, sPaxosValue.data(), sizeof(int));

    if (iSMID == 0)
    {   
        PLG1Imp("Value no need to do sm, just skip, instanceid %lu", llInstanceID);
        return true;
    }   

    // 先把body拷贝到string临时对象,再从string临时对象拷贝到sBodyValue。
    // 对于BatchExecute只用到从sPaxosValue.data() + sizeof(int)开始长度为sPaxosValue.size() - sizeof(int)的内容反序列化,没必要创建sBodyValue。
    // 对于DoExecute需要用到sBodyValue,但创建sBodyValue过程中没必要引入string临时对象。
    std::string sBodyValue = string(sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int));
    if (iSMID == BATCH_PROPOSE_SMID)
    {   
        BatchSMCtx * poBatchSMCtx = nullptr;
        if (poSMCtx != nullptr && poSMCtx->m_pCtx != nullptr)
        {   
            poBatchSMCtx = (BatchSMCtx *)poSMCtx->m_pCtx;
        }   
        return BatchExecute(iGroupIdx, llInstanceID, sBodyValue, poBatchSMCtx);
    }   
    else
    {   
        return DoExecute(iGroupIdx, llInstanceID, sBodyValue, iSMID, poSMCtx);
    }   
}

bool SMFac :: BatchExecute(const int iGroupIdx, const uint64_t llInstanceID, const std::string & sBodyValue, BatchSMCtx * poBatchSMCtx)
{
    BatchPaxosValues oBatchValues;
    bool bSucc = oBatchValues.ParseFromArray(sBodyValue.data(), sBodyValue.size());
    if (!bSucc)
    {   
        PLG1Err("ParseFromArray fail, valuesize %zu", sBodyValue.size());
        return false;
    }   

    if (poBatchSMCtx != nullptr) 
    {   
        if ((int)poBatchSMCtx->m_vecSMCtxList.size() != oBatchValues.values_size())
        {
            PLG1Err("values size %d not equal to smctx size %zu",
                    oBatchValues.values_size(), poBatchSMCtx->m_vecSMCtxList.size());
            return false;
        }
    }

    for (int i = 0; i < oBatchValues.values_size(); i++)
    {
        const PaxosValue & oValue = oBatchValues.values(i);
        SMCtx * poSMCtx = poBatchSMCtx != nullptr ? poBatchSMCtx->m_vecSMCtxList[i] : nullptr;
        bool bExecuteSucc = DoExecute(iGroupIdx, llInstanceID, oValue.value(), oValue.smid(), poSMCtx);
        if (!bExecuteSucc)
        {
            return false;
        }
    }

    return true;
}

// ...

bool SMFac :: ExecuteForCheckpoint(const int iGroupIdx, const uint64_t llInstanceID, const std::string & sPaxosValue)
{
    if (sPaxosValue.size() < sizeof(int))
    {
        PLG1Err("Value wrong, instanceid %lu size %zu", llInstanceID, sPaxosValue.size());
        //need do nothing, just skip
        return true;
    }

    int iSMID = 0;
    memcpy(&iSMID, sPaxosValue.data(), sizeof(int));

    if (iSMID == 0)
    {
        PLG1Imp("Value no need to do sm, just skip, instanceid %lu", llInstanceID);
        return true;
    }

    // 先把body拷贝到string临时对象,再从string临时对象拷贝到sBodyValue。
    // 对于BatchExecuteForCheckpoint只用到从sPaxosValue.data() + sizeof(int)开始长度为sPaxosValue.size() - sizeof(int)的内容反序列化,没必要创建sBodyValue。
    // **对于DoExecuteForCheckpoint需要用到sBodyValue,但创建sBodyValue过程中没必要引入string临时对象。**
    std::string sBodyValue = string(sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int));
    if (iSMID == BATCH_PROPOSE_SMID)
    {
        return BatchExecuteForCheckpoint(iGroupIdx, llInstanceID, sBodyValue);
    }
    else
    {
        return DoExecuteForCheckpoint(iGroupIdx, llInstanceID, sBodyValue, iSMID);
    }
}

bool SMFac :: BatchExecuteForCheckpoint(const int iGroupIdx, const uint64_t llInstanceID, 
        const std::string & sBodyValue)
{
    BatchPaxosValues oBatchValues;
    bool bSucc = oBatchValues.ParseFromArray(sBodyValue.data(), sBodyValue.size());
    if (!bSucc)
    {
        PLG1Err("ParseFromArray fail, valuesize %zu", sBodyValue.size());
        return false;
    }

    for (int i = 0; i < oBatchValues.values_size(); i++)
    {
        const PaxosValue & oValue = oBatchValues.values(i);
        bool bExecuteSucc = DoExecuteForCheckpoint(iGroupIdx, llInstanceID, oValue.value(), oValue.smid());
        if (!bExecuteSucc)
        {
            return false;
        }
    }

    return true;
}   

修改后代码路径:
src/sm-base/sm_base.h

// ...

/*
    bool BatchExecute(const int iGroupIdx, const uint64_t llInstanceID,                                                                                                             
            const std::string & sBodyValue, BatchSMCtx * poBatchSMCtx);
*/

    bool BatchExecute(const int iGroupIdx, const uint64_t llInstanceID,                                                                                                             
            const char* body, size_t body_len, BatchSMCtx * poBatchSMCtx);

/*
    bool BatchExecuteForCheckpoint(const int iGroupIdx, const uint64_t llInstanceID, 
            const std::string & sBodyValue);
*/

    bool BatchExecuteForCheckpoint(const int iGroupIdx, const uint64_t llInstanceID, 
            const char* body, size_t body_len);

// ...

src/sm-base/sm_base.cpp

// ...

bool SMFac :: Execute(const int iGroupIdx, const uint64_t llInstanceID, const std::string & sPaxosValue, SMCtx * poSMCtx)
{
    if (sPaxosValue.size() < sizeof(int))
    {   
        PLG1Err("Value wrong, instanceid %lu size %zu", llInstanceID, sPaxosValue.size());
        //need do nothing, just skip
        return true;
    }   

    int iSMID = 0;
    memcpy(&iSMID, sPaxosValue.data(), sizeof(int));

    if (iSMID == 0)
    {   
        PLG1Imp("Value no need to do sm, just skip, instanceid %lu", llInstanceID);
        return true;
    }   

    // std::string sBodyValue = string(sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int));
    if (iSMID == BATCH_PROPOSE_SMID)
    {   
        BatchSMCtx * poBatchSMCtx = nullptr;
        if (poSMCtx != nullptr && poSMCtx->m_pCtx != nullptr)
        {   
            poBatchSMCtx = (BatchSMCtx *)poSMCtx->m_pCtx;
        }
        // return BatchExecute(iGroupIdx, llInstanceID, sBodyValue, poBatchSMCtx);
        // 没有创建sBodyValue   
        return BatchExecute(iGroupIdx, llInstanceID, sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int), poBatchSMCtx);
    }   
    else
    {
        // 创建sBodyValue,没有临时string对象 
        std::string sBodyValue(sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int);   
        return DoExecute(iGroupIdx, llInstanceID, sBodyValue, iSMID, poSMCtx);
    }   
}

// bool SMFac :: BatchExecute(const int iGroupIdx, const uint64_t llInstanceID, const std::string & sBodyValue, BatchSMCtx * poBatchSMCtx)
bool SMFac :: BatchExecute(const int iGroupIdx, const uint64_t llInstanceID,  const char* body, size_t body_len, BatchSMCtx * poBatchSMCtx)
{
    BatchPaxosValues oBatchValues;
    // bool bSucc = oBatchValues.ParseFromArray(sBodyValue.data(), sBodyValue.size());
    bool bSucc = oBatchValues.ParseFromArray(body, body_len);
    if (!bSucc)
    {   
        // PLG1Err("ParseFromArray fail, valuesize %zu", sBodyValue.size());
        PLG1Err("ParseFromArray fail, valuesize %zu", body_len);
        return false;
    }   

    if (poBatchSMCtx != nullptr) 
    {   
        if ((int)poBatchSMCtx->m_vecSMCtxList.size() != oBatchValues.values_size())
        {
            PLG1Err("values size %d not equal to smctx size %zu",
                    oBatchValues.values_size(), poBatchSMCtx->m_vecSMCtxList.size());
            return false;
        }
    }

    for (int i = 0; i < oBatchValues.values_size(); i++)
    {
        const PaxosValue & oValue = oBatchValues.values(i);
        SMCtx * poSMCtx = poBatchSMCtx != nullptr ? poBatchSMCtx->m_vecSMCtxList[i] : nullptr;
        bool bExecuteSucc = DoExecute(iGroupIdx, llInstanceID, oValue.value(), oValue.smid(), poSMCtx);
        if (!bExecuteSucc)
        {
            return false;
        }
    }

    return true;
}

// ...

bool SMFac :: ExecuteForCheckpoint(const int iGroupIdx, const uint64_t llInstanceID, const std::string & sPaxosValue)
{
    if (sPaxosValue.size() < sizeof(int))
    {
        PLG1Err("Value wrong, instanceid %lu size %zu", llInstanceID, sPaxosValue.size());
        //need do nothing, just skip
        return true;
    }

    int iSMID = 0;
    memcpy(&iSMID, sPaxosValue.data(), sizeof(int));

    if (iSMID == 0)
    {
        PLG1Imp("Value no need to do sm, just skip, instanceid %lu", llInstanceID);
        return true;
    }

    // std::string sBodyValue = string(sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int));
    if (iSMID == BATCH_PROPOSE_SMID)
    {
        // return BatchExecuteForCheckpoint(iGroupIdx, llInstanceID, sBodyValue);
        // 没有创建sBodyValue
        return BatchExecuteForCheckpoint(iGroupIdx, llInstanceID, sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int));
    }
    else
    {
        // 创建sBodyValue,没有临时string对象 
        std::string sBodyValue(sPaxosValue.data() + sizeof(int), sPaxosValue.size() - sizeof(int); 
        return DoExecuteForCheckpoint(iGroupIdx, llInstanceID, sBodyValue, iSMID);
    }
}

/*
bool SMFac :: BatchExecuteForCheckpoint(const int iGroupIdx, const uint64_t llInstanceID, 
        const std::string & sBodyValue)
*/
bool SMFac :: BatchExecuteForCheckpoint(const int iGroupIdx, const uint64_t llInstanceID, 
        const char* body, size_t body_len)
{
    BatchPaxosValues oBatchValues;
    // bool bSucc = oBatchValues.ParseFromArray(sBodyValue.data(), sBodyValue.size());
    bool bSucc = oBatchValues.ParseFromArray(body, body_len);
    if (!bSucc)
    {
        // PLG1Err("ParseFromArray fail, valuesize %zu", sBodyValue.size());
        PLG1Err("ParseFromArray fail, valuesize %zu", body_len);
        return false;
    }

    for (int i = 0; i < oBatchValues.values_size(); i++)
    {
        const PaxosValue & oValue = oBatchValues.values(i);
        bool bExecuteSucc = DoExecuteForCheckpoint(iGroupIdx, llInstanceID, oValue.value(), oValue.smid());
        if (!bExecuteSucc)
        {
            return false;
        }
    }

    return true;
}   

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