/*

 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.



 * ubs-io is licensed under the Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.

 * You may obtain a copy of Mulan PSL v2 at:

 *      http://license.coscl.org.cn/MulanPSL2

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.

 * See the Mulan PSL v2 for more details.

 */



#include "cm_server_view.h"

#include "cm_comm.h"

#include "cm_config.h"

#include "cm_log.h"

#include "cm_pt_calc.h"

#include "cm_pt_store.h"

#include "cm_server_monitor.h"

#include "cm_server_schedule.h"

#include "cm_thread.h"

#include "cm_zkadapter.h"

#include "securec.h"



#define CM_SERVER_PT_INITIAL "cm_server_pt_initial"



#define CM_SERVER_PT_INITIAL_DELAY_TIME (60)

#define CM_SERVER_PT_TRY_INTERAL (5000)



typedef struct {

    CM_RWLOCK_T lock;

    int32_t used;

    int32_t nodeChange;

    int32_t stateChange;

    int32_t ptChange;

    int32_t isInitialOk;

    int32_t isInitialDoing;

    PoolInfo *pool;

    NodeInfoList *nodeList;

    NodeStateList *stateList;

    PtEntryList *ptEntryList;

    Calculator *calculator;

    CalcOps *calcOps;

    Storer *storer;

    StoreOps *storeOps;

} CmServerPool;



typedef struct {

    CM_RWLOCK_T lock;

    CmServerRole role;

    CmServerPool list[MAX_POOL_NUM];

} CmServerPoolMgr;



static CmServerPoolMgr g_sPoolMgr;



static void CmServerViewResetPool(uint16_t poolId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;



    spool->stateChange = FALSE;

    spool->ptChange = FALSE;

    spool->isInitialOk = FALSE;

    spool->isInitialDoing = FALSE;



    uint16_t nodeId;



    spool->nodeList->poolId = pool->poolId;

    spool->nodeList->nodeNum = pool->maxNodeNum;



    int32_t nlen = (int32_t)(sizeof(NodeInfo) * pool->maxNodeNum);

    memset_s(spool->nodeList->nodeList, nlen, 0, nlen);



    spool->stateList->poolId = pool->poolId;

    spool->stateList->nodeNum = pool->maxNodeNum;

    size_t dlen = sizeof(NodeDiskState) * DISK_LIST_NUM;

    for (nodeId = 0; nodeId < pool->maxNodeNum; nodeId++) {

        spool->stateList->nodeList[nodeId].state = NODE_STATE_INVALID;

        spool->stateList->nodeList[nodeId].clusterState = NODE_CLUSTER_STATE_INVALID;

        spool->stateList->nodeList[nodeId].diskNum = 0;

        memset_s(spool->stateList->nodeList[nodeId].diskList, dlen, 0, dlen);

    }

}



static const char *g_nstate[NODE_STATE_BUTT + 1] = {

    "invalid",

    "up",

    "down",

    "butt",

};



static const char *g_cstate[NODE_CLUSTER_STATE_BUTT + 1] = {

    "invalid",

    "out",

    "in",

    "butt",

};



static int32_t CmServerViewUpdatePtEntryList(uint16_t poolId, CmNodeEvent *nodeEvent)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    int32_t ret = CM_OK;



    if (pool->redundance != PT_NONE) {

        int32_t isNeed =

            spool->calcOps->needRebalance(spool->calculator, spool->nodeList, spool->stateList, spool->ptEntryList);

        if (isNeed == TRUE) {

            ret = spool->calcOps->viewRebalance(spool->calculator, spool->nodeList, spool->stateList,

                                                spool->ptEntryList, nodeEvent);

            if (ret != CM_OK) {

                CM_LOGERROR("Rebalance failed, poolId(%u) ret(%d).", pool->poolId, ret);

                return ret;

            }

            spool->ptChange = TRUE;

        }

    }



    if (spool->ptChange == TRUE) {

        ret = spool->storeOps->update(spool->storer, spool->ptEntryList);

        if (ret != CM_OK) {

            CM_LOGERROR("Record ptEntryList failed, poolId(%u) ret(%d).", poolId, ret);

            return ret;

        }

        spool->ptChange = FALSE;

    }



    return ret;

}



static void CmServerViewExpiredNodeSet(uint16_t poolId, uint16_t nodeId)

{

    NodeStateInfo *cmState = &g_sPoolMgr.list[poolId].stateList->nodeList[nodeId];



    if (cmState->clusterState == NODE_CLUSTER_STATE_OUT) {

        return;

    }



    cmState->clusterState = NODE_CLUSTER_STATE_OUT;

    g_sPoolMgr.list[poolId].stateChange = TRUE;



    CM_LOGINFO("Expired, poolId(%u) nodeId(%u) state(%s-%s).", poolId, nodeId, g_nstate[cmState->state],

               g_cstate[cmState->clusterState]);

    return;

}



static void CmServerViewExpiredDiskSet(uint16_t poolId, uint16_t nodeId, uint16_t diskId)

{

    NodeStateInfo *cmState = &g_sPoolMgr.list[poolId].stateList->nodeList[nodeId];

    uint16_t index;



    for (index = 0; index < cmState->diskNum; index++) {

        if (cmState->diskList[index].diskId == diskId) {

            if (cmState->diskList[index].clusterState == DISK_CLUSTER_STATE_OUT) {

                return;

            } else {

                cmState->diskList[index].clusterState = DISK_CLUSTER_STATE_OUT;

                g_sPoolMgr.list[poolId].stateChange = TRUE;



                CM_LOGINFO("Expired, poolId(%u) nodeId(%u) state(%s-%s) diskId(%u) disk state(%s).", poolId, nodeId,

                           g_nstate[cmState->state], g_cstate[cmState->clusterState], diskId,

                           CM_DISK_STATE(DISK_STATE_FAULT));

                return;

            }

        }

    }



    CM_LOGERROR("Impossible.");

    return;

}



static int32_t CmServerViewExpiredCommit(uint16_t poolId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    int32_t ret;



    if (spool->stateChange == FALSE) {

        return CM_OK;

    }



    ret = CmServerZkRecordStateList(spool->stateList);

    if (ret != CM_OK) {

        CM_LOGERROR("Record stateList failed, poolId(%u) ret(%d).", poolId, ret);

        return ret;

    }



    spool->stateChange = FALSE;



    ret = CmServerViewUpdatePtEntryList(poolId, NULL);

    if (ret != CM_OK) {

        CM_LOGERROR("Update ptEntryList failed, poolId(%u) ret(%d).", pool->poolId, ret);

        return ret;

    }



    return CM_OK;

}



static void CmServerViewRegisterExpiredHandle(void)

{

    CmServerMonitorExpiredHandle handle;



    handle.expiredNodeSet = CmServerViewExpiredNodeSet;

    handle.expiredDiskSet = CmServerViewExpiredDiskSet;

    handle.expiredCommit = CmServerViewExpiredCommit;



    CmServerMonitorRegisterHandle(handle);

    return;

}



static void CmServerViewCheckDiskFault(uint16_t poolId, NodeInfo *nodeInfo, NodeStateInfo *nodeState)

{

    DiskList *diskList = &nodeInfo->diskList;



    if (diskList->num == 0) {

        return; // 不需要监控磁盘故障

    }



    uint16_t index;



    for (index = 0; index < diskList->num; index++) {

        if (diskList->list[index].state == DISK_STATE_FAULT &&

            nodeState->diskList[index].clusterState == DISK_CLUSTER_STATE_IN) {

            CmServerListenDiskFault(poolId, nodeInfo->nodeId, diskList->list[index].diskId);

        } else {

            CmServerCancelDiskFault(poolId, nodeInfo->nodeId, diskList->list[index].diskId);

        }

    }



    return;

}



static void CmServerViewUpdateMasterNodeId(uint16_t poolId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    NodeInfoList *nodeList = spool->nodeList;

    NodeStateList *stateList = spool->stateList;



    uint16_t mstId = stateList->masterNodeId;

    if (mstId != NODE_ID_INVALID && stateList->nodeList[mstId].state == NODE_STATE_UP &&

        stateList->nodeList[mstId].clusterState == NODE_CLUSTER_STATE_IN &&

        nodeList->nodeList[mstId].status == NODE_STATUS_OK) {

        return;

    }



    uint16_t nodeId;

    for (nodeId = 0; nodeId < stateList->nodeNum; nodeId++) {

        if (stateList->nodeList[nodeId].state != NODE_STATE_UP ||

            stateList->nodeList[nodeId].clusterState != NODE_CLUSTER_STATE_IN ||

            nodeList->nodeList[nodeId].status != NODE_STATUS_OK) {

            continue;

        }

        stateList->masterNodeId = nodeId;

        spool->stateChange = TRUE;

        return;

    }

    return;

}



static void SyncDiskListToState(CmServerPool *spool, uint16_t nodeId, const NodeInfo *cache)

{

    NodeStateInfo *dst = &spool->stateList->nodeList[nodeId];

    const DiskList *srcDiskList = &cache->diskList;

    dst->diskNum = srcDiskList->num;



    for (uint16_t j = 0; j < srcDiskList->num; ++j) {

        dst->diskList[j].diskId = srcDiskList->list[j].diskId;

        dst->diskList[j].clusterState = DISK_CLUSTER_STATE_IN;

    }



    spool->stateChange = TRUE;

    spool->ptChange = TRUE;

}



static int32_t CompareAndUpdateNodeInfo(uint16_t poolId, uint16_t nodeId, CmServerPool *spool, bool isInit)

{

    NodeInfo *nodeInfo = &spool->nodeList->nodeList[nodeId];

    NodeStateInfo *nodeState = &spool->stateList->nodeList[nodeId];

    NodeInfo cache;

    cache.nodeId = nodeId;



    int32_t ret = CmServerZkGetNodeInfo(poolId, &cache);

    if (ret != CM_OK) {

        CM_LOGERROR("Get nodeInfo failed, poolId(%u) nodeId(%u) ret(%d).", poolId, nodeId, ret);

        return ret;

    }



    if (memcmp(nodeInfo, &cache, sizeof(NodeInfo)) != 0) {

        if (!isInit) {

            SyncDiskListToState(spool, nodeId, &cache);

        }

        memcpy_s(nodeInfo, sizeof(NodeInfo), &cache, sizeof(NodeInfo));

        spool->nodeChange = TRUE;

    }



    return CM_OK;

}



static int32_t CmServerViewBuildNode(uint16_t poolId, uint16_t nodeId, bool isInit)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    NodeInfo *nodeInfo = &spool->nodeList->nodeList[nodeId];

    NodeStateInfo *nodeState = &spool->stateList->nodeList[nodeId];



    if (nodeState->state == NODE_STATE_INVALID) {

        return CM_OK;

    }



    int32_t ret = CompareAndUpdateNodeInfo(poolId, nodeId, spool, isInit);

    if (ret != CM_OK) {

        return ret;

    }



    CmServerViewUpdateMasterNodeId(poolId);



    if (nodeState->state == NODE_STATE_DOWN && nodeState->clusterState == NODE_CLUSTER_STATE_IN) {

        CmServerListenNodeFault(poolId, nodeId);

        if (pool->redundance != PT_NONE) {

            spool->calcOps->updateState(nodeId, NODE_STATE_DOWN, nodeInfo, spool->ptEntryList, &spool->ptChange);

        }

        return CM_OK;

    }



    if (nodeState->state == NODE_STATE_UP && nodeState->clusterState == NODE_CLUSTER_STATE_IN) {

        CmServerViewCheckDiskFault(poolId, nodeInfo, nodeState);

        if (pool->redundance != PT_NONE) {

            spool->calcOps->updateState(nodeId, NODE_STATE_UP, nodeInfo, spool->ptEntryList, &spool->ptChange);

        }

        return CM_OK;

    }



    return CM_OK;

}



int32_t CmServerViewBuildNodeList(uint16_t poolId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    int32_t ret;



    CmServerViewResetPool(poolId);



    ret = CmServerZkGetNodeList(spool->nodeList);

    if (ret != CM_OK) {

        CM_LOGERROR("Get stateList failed, ret(%d) poolId(%u).", ret, pool->poolId);

        return ret;

    }



    ret = CmServerZkGetStateList(spool->stateList);

    if (ret != CM_OK) {

        CM_LOGERROR("Get stateList failed, ret(%d) poolId(%u).", ret, pool->poolId);

        return ret;

    }



    uint16_t nodeId;

    for (nodeId = 0; nodeId < spool->stateList->nodeNum; nodeId++) {

        ret = CmServerViewBuildNode(pool->poolId, nodeId, TRUE);

        if (ret != CM_OK) {

            CM_LOGERROR("Build node failed, poolId(%u) nodeId(%u) ret(%d).", pool->poolId, nodeId, ret);

            return ret;

        }

    }



    if (spool->nodeChange == TRUE) {

        ret = CmServerZkRecordNodeList(spool->nodeList);

        if (ret != CM_OK) {

            CM_LOGERROR("Update nodeList failed, poolId(%u) ret(%d).", poolId, ret);

            return ret;

        }

        spool->nodeChange = FALSE;

    }



    if (spool->stateChange == TRUE) {

        ret = CmServerZkRecordStateList(spool->stateList);

        if (ret != CM_OK) {

            CM_LOGERROR("Record stateList failed, poolId(%u) ret(%d).", poolId, ret);

            return ret;

        }

        spool->stateChange = FALSE;

    }



    ret = CmServerViewUpdatePtEntryList(poolId, NULL);

    if (ret != CM_OK) {

        CM_LOGERROR("Update ptEntryList failed, poolId(%u) ret(%d).", pool->poolId, ret);

        return ret;

    }



    return CM_OK;

}



uint16_t CmServerViewFindNodeIndex(uint16_t *nodeList, uint16_t nodeNum, uint16_t nodeId)

{

    uint16_t index;



    for (index = 0; index < nodeNum; index++) {

        if (nodeList[index] == nodeId) {

            return index;

        }

    }

    return nodeNum;

}



static int32_t CmServerViewNodeOffline(uint16_t poolId, uint16_t nodeId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    NodeInfo *nodeInfo = &spool->nodeList->nodeList[nodeId];

    NodeStateInfo *nodeState = &spool->stateList->nodeList[nodeId];



    if (nodeState->state == NODE_STATE_INVALID || nodeState->state == NODE_STATE_DOWN) {

        return CM_OK;

    }



    spool->stateChange = TRUE;



    nodeState->state = NODE_STATE_DOWN;

    CmServerViewUpdateMasterNodeId(poolId);



    CM_LOGINFO("Node offline, poolId(%u) nodeId(%u) state(%s-%s).", poolId, nodeId, g_nstate[nodeState->state],

               g_cstate[nodeState->clusterState]);



    if (nodeState->clusterState == NODE_CLUSTER_STATE_IN) {

        CmServerListenNodeFault(poolId, nodeId); // 加入节点故障监控

        if (pool->redundance != PT_NONE) {

            spool->calcOps->updateState(nodeId, NODE_STATE_DOWN, nodeInfo, spool->ptEntryList,

                                        &spool->ptChange); // 更新PT副本状态

        }

    }



    return CM_OK;

}



static void CmServerViewOnlineUpdateState(NodeInfo *nodeInfo, NodeStateInfo *nodeState)

{

    uint16_t index;



    nodeState->state = NODE_STATE_UP;

    if (nodeState->clusterState == NODE_CLUSTER_STATE_INVALID || nodeState->clusterState == NODE_CLUSTER_STATE_OUT) {

        for (index = 0; index < nodeInfo->diskList.num; index++) {

            nodeState->diskList[index].diskId = nodeInfo->diskList.list[index].diskId;

            nodeState->diskList[index].clusterState = DISK_CLUSTER_STATE_IN;

        }

        nodeState->diskNum = nodeInfo->diskList.num;

        nodeState->clusterState = NODE_CLUSTER_STATE_IN;

    }



    for (index = 0; index < nodeState->diskNum; index++) {

        if (nodeInfo->diskList.list[index].state == DISK_STATE_NORMAL) {

            nodeState->diskList[index].clusterState = DISK_CLUSTER_STATE_IN;

        } else {

            nodeState->diskList[index].clusterState = DISK_CLUSTER_STATE_OUT;

        }

    }



    return;

}



int32_t CmServerViewNodeOnline(uint16_t poolId, uint16_t nodeId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    NodeInfo *nodeInfo = &spool->nodeList->nodeList[nodeId];

    NodeStateInfo *nodeState = &spool->stateList->nodeList[nodeId];

    int32_t ret;



    if (nodeState->state == NODE_STATE_UP) {

        return CM_OK;

    }



    spool->stateChange = TRUE;



    CmServerCancelNodeFault(poolId, nodeId);



    NodeInfo cache;

    cache.nodeId = nodeId;

    ret = CmServerZkGetNodeInfo(poolId, &cache);

    if (ret != CM_OK) {

        CM_LOGERROR("Get nodeInfo failed, poolId(%u) nodeId(%u) ret(%d).", poolId, nodeId, ret);

        return ret;

    }



    if (memcmp(nodeInfo, &cache, sizeof(NodeInfo)) != 0) {

        memcpy_s(nodeInfo, sizeof(NodeInfo), &cache, sizeof(NodeInfo));

        spool->nodeChange = TRUE;

    }



    CmServerViewOnlineUpdateState(nodeInfo, nodeState);

    CmServerViewUpdateMasterNodeId(poolId);



    CM_LOGINFO("Node online, poolId(%u) nodeId(%u) state(%s-%s).", poolId, nodeId, g_nstate[nodeState->state],

               g_cstate[nodeState->clusterState]);



    if (nodeState->clusterState == NODE_CLUSTER_STATE_IN) {

        CmServerViewCheckDiskFault(poolId, nodeInfo, nodeState); // 扫描节点磁盘故障监控

        if (pool->redundance != PT_NONE) {

            spool->calcOps->updateState(nodeId, NODE_STATE_UP, nodeInfo, spool->ptEntryList,

                                        &spool->ptChange); // 更新PT副本状态

        }

        return CM_OK;

    }



    return CM_OK;

}



int32_t CmServerViewNodeListChange(CmNodeIdList *watchList)

{

    CmServerPool *spool = &g_sPoolMgr.list[watchList->poolId];

    PoolInfo *pool = spool->pool;

    NodeInfoList *nodeList = spool->nodeList;



    if (g_sPoolMgr.role != CM_SERVER_MASTER) {

        CM_LOGWARN("Local role to slave, req abort.");

        return CM_OK;

    }



    uint16_t nodeId;

    uint16_t nodeIndex;

    int32_t ret;



    CM_RWLOCK_WRLOCK(&spool->lock);

    for (nodeId = 0; nodeId < nodeList->nodeNum; nodeId++) {

        nodeIndex = CmServerViewFindNodeIndex(watchList->nodeList, watchList->nodeNum, nodeId);

        if (nodeIndex == watchList->nodeNum) {

            ret = CmServerViewNodeOffline(watchList->poolId, nodeId);

        } else {

            ret = CmServerViewNodeOnline(watchList->poolId, nodeId);

        }

        if (ret != CM_OK) {

            CM_RWLOCK_UNLOCK(&spool->lock);

            CM_LOGERROR("Node deal failed, poolId(%u) nodeId(%u) ret(%d).", watchList->poolId, nodeId, ret);

            return ret;

        }

    }

    CM_RWLOCK_UNLOCK(&spool->lock);



    if (spool->nodeChange == TRUE) {

        ret = CmServerZkRecordNodeList(spool->nodeList);

        if (ret != CM_OK) {

            CM_LOGERROR("Update nodeList failed, poolId(%u) ret(%d).", watchList->poolId, ret);

            return ret;

        }

        spool->nodeChange = FALSE;

    }



    if (spool->stateChange == TRUE) {

        ret = CmServerZkRecordStateList(spool->stateList);

        if (ret != CM_OK) {

            CM_LOGERROR("Record stateList failed, poolId(%u) ret(%d).", watchList->poolId, ret);

            return ret;

        }

        spool->stateChange = FALSE;

    }



    ret = CmServerViewUpdatePtEntryList(watchList->poolId, NULL);

    if (ret != CM_OK) {

        CM_LOGERROR("Update ptEntryList failed, poolId(%u) ret(%d).", pool->poolId, ret);

        return ret;

    }



    return CM_OK;

}



static uint16_t CmServerViewCopyNum(PtRedundanceMode redundance)

{

    static uint16_t s_copyNum[PT_REDUNDANCE_BUTT] = {

        3,

        1,

        2,

        3,

    };



    return s_copyNum[redundance];

}



static uint16_t CmServerViewMinCopyNum(PtRedundanceMode redundance)

{

    static uint16_t s_minCopyNum[PT_REDUNDANCE_BUTT] = {

        3,

        1,

        1,

        1,

    };



    return s_minCopyNum[redundance];

}



int32_t CmServerViewNodeEvent(CmNodeEvent *nodeEvent)

{

    if (g_sPoolMgr.role != CM_SERVER_MASTER) {

        CM_LOGWARN("Local role to slave, req abort.");

        return CM_OK;

    }



    int32_t ret = CmServerViewBuildNode(nodeEvent->poolId, nodeEvent->nodeId, FALSE);

    if (ret != CM_OK) {

        CM_LOGERROR("Build node failed, poolId(%u) nodeId(%u) ret(%d).", nodeEvent->poolId, nodeEvent->nodeId, ret);

        return ret;

    }



    CmServerPool *spool = &g_sPoolMgr.list[nodeEvent->poolId];

    if (spool->nodeChange == TRUE) {

        ret = CmServerZkRecordNodeList(spool->nodeList);

        if (ret != CM_OK) {

            CM_LOGERROR("Update nodeList failed, poolId(%u) ret(%d).", nodeEvent->poolId, ret);

            return ret;

        }

        spool->nodeChange = FALSE;

    }



    if (spool->stateChange == TRUE) {

        ret = CmServerZkRecordStateList(spool->stateList);

        if (ret != CM_OK) {

            CM_LOGERROR("Record stateList failed, poolId(%u) ret(%d).", nodeEvent->poolId, ret);

            return ret;

        }

        spool->stateChange = FALSE;

    }



    ret = CmServerViewUpdatePtEntryList(nodeEvent->poolId, nodeEvent);

    if (ret != CM_OK) {

        CM_LOGERROR("Update ptEntryList failed, poolId(%u) ret(%d).", nodeEvent->poolId, ret);

        return ret;

    }



    return CM_OK;

}



void CmServerViewPtEvent(CmPtEvent *ptEvent)

{

    CmServerPool *spool = &g_sPoolMgr.list[ptEvent->poolId];

    PoolInfo *pool = spool->pool;



    if (g_sPoolMgr.role != CM_SERVER_MASTER) {

        CM_LOGWARN("Local role to slave, req abort.");

        return;

    }



    if (pool->redundance == PT_NONE) {

        CM_LOGERROR("Impossible, poolId(%u).", ptEvent->poolId);

        return;

    }



    uint16_t validNum = 0;

    for (uint16_t index = 0; index < spool->stateList->nodeNum; index++) {

        if (spool->stateList->nodeList[index].clusterState == NODE_CLUSTER_STATE_IN) {

            validNum++;

        }

    }



    spool->calcOps->updateFinish(ptEvent->nodeId, ptEvent->ptList, ptEvent->ptNum, spool->ptEntryList, &spool->ptChange,

                                 pool->maxNodeNum, validNum);

    return;

}



int32_t CmServerViewPtEventCommit(uint16_t poolId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];



    if (spool->ptChange == TRUE) {

        int32_t ret = spool->storeOps->update(spool->storer, spool->ptEntryList);

        if (ret != CM_OK) {

            CM_LOGERROR("Record ptEntryList failed, ret(%d) poolId(%u).", ret, poolId);

            return ret;

        }

        spool->ptChange = FALSE;

    }

    return CM_OK;

}



static void *CmServerViewInitialThread(void *ctx)

{

    CmServerPool *spool = (CmServerPool *)ctx;

    PoolInfo *pool = spool->pool;



    int32_t ret;



    ret = spool->calcOps->viewInitial(spool->calculator, spool->nodeList, spool->stateList, spool->ptEntryList);

    if (ret != CM_OK) {

        CM_LOGWARN("Initial ptEntryList failed, poolId(%u) ret(%d).", pool->poolId, ret);

        spool->isInitialDoing = FALSE;

        return NULL;

    }



    ret = spool->storeOps->initial(spool->storer, spool->ptEntryList);

    if (ret != CM_OK) {

        CM_LOGWARN("Record ptEntryList failed, poolId(%u) ret(%d).", pool->poolId, ret);

        spool->isInitialDoing = FALSE;

        return NULL;

    }



    spool->isInitialOk = TRUE;

    spool->isInitialDoing = FALSE;



    return NULL;

}



static void *CmServerViewInitialDetectThread(void *ctx)

{

    CmServerPool *spool = (CmServerPool *)ctx;

    PoolInfo *pool = spool->pool;



    uint64_t times = CmGetSecondsTime();



    uint16_t copyNum = CmServerViewCopyNum(pool->redundance);



    do {

        uint16_t nodeId;

        uint16_t okNum = 0;



        if (g_sPoolMgr.role != CM_SERVER_MASTER) {

            CM_LOGINFO("Stop detect, poolId(%u).", pool->poolId);

            break;

        }



        if (spool->isInitialDoing == TRUE) {

            CmSleep(CM_SERVER_PT_TRY_INTERAL);

            continue;

        }



        if (spool->isInitialOk == TRUE) {

            break;

        }



        CM_RWLOCK_RDLOCK(&spool->lock);

        for (nodeId = 0; nodeId < spool->stateList->nodeNum; nodeId++) {

            NodeStateInfo *stateInfo = &spool->stateList->nodeList[nodeId];

            if (stateInfo->state == NODE_STATE_UP && stateInfo->clusterState == NODE_CLUSTER_STATE_IN) {

                okNum++;

            }

        }

        CM_RWLOCK_UNLOCK(&spool->lock);



        uint64_t curTimes = CmGetSecondsTime();



        CM_LOGINFO("Current poolId(%u) normNum(%u).", pool->poolId, okNum);



        if (okNum >= pool->initialNodeNum ||

            ((okNum >= copyNum) && (curTimes > (times + CM_SERVER_PT_INITIAL_DELAY_TIME)))) {

            spool->isInitialDoing = TRUE;

            CmServerSchedueAdd(pool->poolId, CmServerViewInitialThread, ctx);

        }



        CmSleep(CM_SERVER_PT_TRY_INTERAL);

    } while (1);



    return NULL;

}



int32_t CmServerViewBuildPtEntryList(uint16_t poolId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    int32_t ret;



    if (pool->redundance == PT_NONE) {

        return CM_OK;

    }



    spool->ptEntryList->poolId = pool->poolId;

    spool->ptEntryList->ptNum = pool->maxPtNum;



    ret = CmServerZkGetPtEntryList(spool->ptEntryList);

    if (ret != CM_OK) {

        CM_LOGERROR("Get ptEntryList failed, poolId(%u) ret(%d).", pool->poolId, ret);

        return ret;

    }



    if (spool->ptEntryList->ptNum == 0) {

        ret = CmSwitchThreadAsync(CM_SERVER_PT_INITIAL, (void *)spool, CmServerViewInitialDetectThread);

        if (ret != CM_OK) {

            CM_LOGERROR("Create detect thread failed, ret(%d).", ret);

            return ret;

        }

        return CM_OK;

    }



    ret = spool->storeOps->loadcheck(spool->storer, spool->ptEntryList);

    if (ret != CM_OK) {

        CM_LOGERROR("Check ptEntryList failed, poolId(%u) ret(%d).", pool->poolId, ret);

        return ret;

    }

    return CM_OK;

}



int32_t CmServerViewBuildPool(uint16_t poolId)

{

    int32_t ret;



    ret = CmServerViewBuildPtEntryList(poolId);

    if (ret != CM_OK) {

        CM_LOGERROR("Build ptEntryList failed, poolId(%u) ret(%d).", poolId, ret);

        return ret;

    }



    ret = CmServerViewBuildNodeList(poolId);

    if (ret != CM_OK) {

        CM_LOGERROR("Build nodeList failed, poolId(%u) ret(%d).", poolId, ret);

        return ret;

    }



    ret = CmServerZkSubNodeListChange(poolId, CmServerViewNodeListChange);

    if (ret != CM_OK) {

        CM_LOGERROR("Sub node change failed, poolId(%u) ret(%d).", poolId, ret);

        return ret;

    }



    ret = CmServerZkSubNodeEvent(poolId, CmServerViewNodeEvent);

    if (ret != CM_OK) {

        CM_LOGERROR("Sub node event failed, poolId(%u) ret(%d).", poolId, ret);

        return ret;

    }



    ret = CmServerZkSubPtEvent(poolId, CmServerViewPtEvent, CmServerViewPtEventCommit);

    if (ret != CM_OK) {

        CM_LOGERROR("Sub pt event failed, poolId(%u) ret(%d).", poolId, ret);

        return ret;

    }



    return CM_OK;

}



int32_t CmServerViewToMaster(void)

{

    uint16_t poolId;

    int32_t ret;



    for (poolId = 0; poolId < MAX_POOL_NUM; poolId++) {

        CmServerPool *spool = &g_sPoolMgr.list[poolId];

        if (spool->pool == NULL) {

            continue;

        }

        ret = CmServerViewBuildPool(poolId);

        if (ret != CM_OK) {

            CM_LOGERROR("Build pool failed, poolId(%u) ret(%d).", poolId, ret);

            return ret;

        }

    }

    return CM_OK;

}



int32_t CmServerViewToSlave(void)

{

    CmServerMonitorReset();



    return CM_OK;

}



int32_t CmServerViewRoleChange(CmServerRole role)

{

    g_sPoolMgr.role = role;



    if (role == CM_SERVER_MASTER) {

        return CmServerViewToMaster();

    } else {

        return CmServerViewToSlave();

    }

}



int32_t CmServerViewInitPool(uint16_t poolId)

{

    CmServerPool *spool = &g_sPoolMgr.list[poolId];

    PoolInfo *pool = spool->pool;

    size_t len;



    spool->used = TRUE;



    spool->nodeList = (NodeInfoList *)malloc(sizeof(NodeInfo) * pool->maxNodeNum + sizeof(NodeInfoList));

    spool->stateList = (NodeStateList *)malloc(sizeof(NodeStateInfo) * pool->maxNodeNum + sizeof(NodeStateList));

    if (spool->nodeList == NULL || spool->stateList == NULL) {

        CM_LOGERROR("Malloc nodeList or stateList buff failed.");

        return CM_ERR;

    }

    len = sizeof(NodeInfo) * pool->maxNodeNum + sizeof(NodeInfoList);

    memset_s(spool->nodeList, len, 0, len);

    len = sizeof(NodeStateInfo) * pool->maxNodeNum + sizeof(NodeStateList);

    memset_s(spool->stateList, len, 0, len);



    if (pool->redundance == PT_NONE) {

        return CM_OK;

    }



    spool->ptEntryList = (PtEntryList *)malloc(sizeof(PtEntry) * pool->maxPtNum + sizeof(PtEntryList));

    if (spool->ptEntryList == NULL) {

        CM_LOGERROR("Malloc ptEntryList buff failed.");

        return CM_ERR;

    }

    len = sizeof(PtEntry) * pool->maxPtNum + sizeof(PtEntryList);

    memset_s(spool->ptEntryList, len, 0, len);



    uint16_t copyNum = CmServerViewCopyNum(pool->redundance);

    uint16_t minCopyNum = CmServerViewMinCopyNum(pool->redundance);



    spool->calcOps = CmPtCalcOpsGet(PT_NUM_LIMIT_FIXED);

    spool->calculator = spool->calcOps->createCalculator(pool->maxNodeNum, pool->maxPtNum, copyNum, minCopyNum);

    if (spool->calculator == NULL) {

        CM_LOGERROR("Create calculator failed, poolId(%u).", pool->poolId);

        return CM_ERR;

    }



    spool->storeOps = CmPtStoreOpsGet();

    spool->storer = spool->storeOps->createStorer(pool->maxNodeNum, pool->maxPtNum, copyNum);

    if (spool->storer == NULL) {

        CM_LOGERROR("Create storer failed, poolId(%u).", pool->poolId);

        return CM_ERR;

    }



    return CM_OK;

}



void CmServerViewReset(void)

{

    uint16_t poolId;



    CM_RWLOCK_INIT(&g_sPoolMgr.lock, NULL);



    g_sPoolMgr.role = CM_SERVER_SLAVE;



    for (poolId = 0; poolId < MAX_POOL_NUM; poolId++) {

        CM_RWLOCK_INIT(&g_sPoolMgr.list[poolId].lock, NULL);

        g_sPoolMgr.list[poolId].used = FALSE;

        g_sPoolMgr.list[poolId].nodeChange = FALSE;

        g_sPoolMgr.list[poolId].stateChange = FALSE;

        g_sPoolMgr.list[poolId].ptChange = FALSE;

        g_sPoolMgr.list[poolId].pool = CmConfigGetPoolInfo(poolId);

        g_sPoolMgr.list[poolId].nodeList = NULL;

        g_sPoolMgr.list[poolId].stateList = NULL;

        g_sPoolMgr.list[poolId].ptEntryList = NULL;

        g_sPoolMgr.list[poolId].calculator = NULL;

        g_sPoolMgr.list[poolId].calcOps = NULL;

        g_sPoolMgr.list[poolId].storer = NULL;

        g_sPoolMgr.list[poolId].storeOps = NULL;

    }

}



int32_t CmServerViewGetNodeState(uint16_t poolId, NodeStateInfo *state)

{

    if (poolId >= MAX_POOL_NUM || state == NULL) {

        CM_LOGERROR("Invalid poolId(%u).", poolId);

        return CM_ERR;

    }

    if (g_sPoolMgr.list[poolId].used == FALSE || state->nodeId >= g_sPoolMgr.list[poolId].pool->maxNodeNum) {

        CM_LOGERROR("Invalid poolId(%u) nodeId(%u).", poolId, state->nodeId);

        return CM_ERR;

    }

    if (g_sPoolMgr.list[poolId].stateList == NULL) {

        CM_LOGERROR("Invalid poolId(%u).", poolId);

        return CM_ERR;

    }

    *state = g_sPoolMgr.list[poolId].stateList->nodeList[state->nodeId];

    return CM_OK;

}



int32_t CmServerViewInit(void)

{

    uint16_t poolId;

    int32_t ret;



    CmServerViewReset();



    CmServerViewRegisterExpiredHandle();



    for (poolId = 0; poolId < MAX_POOL_NUM; poolId++) {

        CmServerPool *spool = &g_sPoolMgr.list[poolId];

        if (spool->pool == NULL) {

            continue;

        }

        ret = CmServerViewInitPool(poolId);

        if (ret != CM_OK) {

            CM_LOGERROR("Init pool failed, poolId(%u) ret(%d).", poolId, ret);

            CmServerViewExit();

            return ret;

        }

    }



    ret = CmServerZkSubRoleChange(CmServerViewRoleChange);

    if (ret != CM_OK) {

        CM_LOGERROR("Select role failed, ret(%d).", ret);

        CmServerViewExit();

        return ret;

    }



    CM_LOGINFO("Cm server view init succeed.");

    return CM_OK;

}



void CmServerViewExit(void)

{

    uint16_t poolId;



    CM_RWLOCK_WRLOCK(&g_sPoolMgr.lock);

    for (poolId = 0; poolId < MAX_POOL_NUM; poolId++) {

        if (g_sPoolMgr.list[poolId].used == FALSE) {

            continue;

        }

        g_sPoolMgr.list[poolId].used = FALSE;

        g_sPoolMgr.list[poolId].stateChange = FALSE;

        g_sPoolMgr.list[poolId].ptChange = FALSE;

        if (g_sPoolMgr.list[poolId].nodeList != NULL) {

            free(g_sPoolMgr.list[poolId].nodeList);

            g_sPoolMgr.list[poolId].nodeList = NULL;

        }

        if (g_sPoolMgr.list[poolId].stateList != NULL) {

            free(g_sPoolMgr.list[poolId].stateList);

            g_sPoolMgr.list[poolId].stateList = NULL;

        }

        if (g_sPoolMgr.list[poolId].ptEntryList != NULL) {

            free(g_sPoolMgr.list[poolId].ptEntryList);

            g_sPoolMgr.list[poolId].ptEntryList = NULL;

        }

        if (g_sPoolMgr.list[poolId].calculator != NULL) {

            g_sPoolMgr.list[poolId].calcOps->destroyCalculator(g_sPoolMgr.list[poolId].calculator);

            g_sPoolMgr.list[poolId].calculator = NULL;

        }

        if (g_sPoolMgr.list[poolId].storer != NULL) {

            g_sPoolMgr.list[poolId].storeOps->destroyStorer(g_sPoolMgr.list[poolId].storer);

            g_sPoolMgr.list[poolId].storer = NULL;

        }

        CM_RWLOCK_DESTROY(&g_sPoolMgr.list[poolId].lock);

    }

    CM_RWLOCK_UNLOCK(&g_sPoolMgr.lock);

    CM_RWLOCK_DESTROY(&g_sPoolMgr.lock);

    CM_LOGINFO("Cm server view exit succeed.");

    return;

}