/*
 * Copyright (c) 2021 Huawei Technologies Co.,Ltd.
 *
 * CM is licensed under 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.
 * -------------------------------------------------------------------------
 *
 * cma_voting_disk.cpp
 *
 *
 * IDENTIFICATION
 *    src/cm_agent/cma_voting_disk.cpp
 *
 * -------------------------------------------------------------------------
 */

#include "cma_global_params.h"
#include "cm_voting_disk.h"
#include "cm_vtable.h"

static void StopCurrentNode()
{
    char command[CM_MAX_COMMAND_LEN];
    int doForce = 1;
    ShutdownMode shutdownModeNum = FAST_MODE;
    int shutdownLevel = SINGLE_NODE;

    errno_t rc = snprintf_s(command, CM_MAX_COMMAND_LEN, CM_MAX_COMMAND_LEN - 1,
        "echo -e \'%d\\n%d\\n%d\' > %s; chmod 600 %s",
        doForce, shutdownModeNum, shutdownLevel, g_cmManualStartPath, g_cmManualStartPath);
    securec_check_intval(rc, (void)rc);
    int ret = system(command);
    if (ret != 0) {
        write_runlog(ERROR, "Stop current node failed, with executing the command: \"%s\","
            " systemReturn=%d, shellReturn=%d, errno=%d.\n", command, ret, SHELL_RETURN_CODE(ret), errno);
    } else {
        write_runlog(LOG, "Stop current node success, with executing the command: \"%s\"\n", command);
    }
    return;
}

static void UpdateVotingDiskStatus(VotingDiskNodeInfo *nodeInfo)
{
    if (g_diskTimeout == 0) {
        write_runlog(DEBUG5, "g_diskTimeout is 0, stop update voting disk status\n");
        return;
    }
    uint32 expiredTime = 0;
    struct timespec startTime = {0, 0};
    struct timespec endTime = {0, 0};
    (void)clock_gettime(CLOCK_MONOTONIC, &startTime);

    while (expiredTime < g_diskTimeout) {
        if (SetVotingDiskSingleNodeInfo(nodeInfo, g_nodeId) == CM_SUCCESS) {
            write_runlog(DEBUG5, "update voting disk status success\n");
            return;
        }
        (void)clock_gettime(CLOCK_MONOTONIC, &endTime);
        expiredTime = (uint32)(endTime.tv_sec - startTime.tv_sec);
        write_runlog(ERROR, "update voting disk status failed, expiredTime=%u, diskTimeout=%u\n",
            expiredTime, g_diskTimeout);
        cm_sleep(1);
    }
    write_runlog(WARNING, "update voting disk status timeout, stop current node!\n");
    StopCurrentNode();
}

void *VotingDiskMain(void *arg)
{
    thread_name = "VotingDisk";
    pthread_t threadId = pthread_self();
    write_runlog(LOG, "Voting disk status check thread start, threadid %lu.\n", threadId);
    
    if (IsBoolCmParamTrue(g_enableVtable)) {
        if (cm_init_vtable() != 0) {
            write_runlog(FATAL, "CM agent init vtable failed!\n");
            exit(-1);
        }
    }

    if (InitVotingDisk(g_votingDiskPath) != CM_SUCCESS) {
        write_runlog(FATAL, "Init voting disk failed!\n");
        exit(-1);
    }
    VotingDiskNodeInfo nodeInfo;

    int index = -1;
    AddThreadActivity(&index, threadId);

    for (;;) {
        if (g_shutdownRequest) {
            cm_sleep(5);
            continue;
        }
        nodeInfo.nodeTime = time(NULL);
        UpdateVotingDiskStatus(&nodeInfo);
        UpdateThreadActivity(index);
        cm_sleep(1);
    }

    return NULL;
}