1d540f44创建于 2021年9月23日历史提交
/*
 * -------------------------------------------------------------------------
 * Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 *
 * openGauss 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.
 * -------------------------------------------------------------------------
 *
 * knl_uheaptest.cpp
 * Implementation for uheap test framework.
 *
 * IDENTIFICATION
 * src/gausskernel/cbb/utils/debug/knl_uheaptest.cpp
 *
 * -------------------------------------------------------------------------
 */

#include "knl/knl_variable.h"
#include "utils/builtins.h"
#include "access/ustore/knl_whitebox_test.h"
#include "port.h"

const uint32 BUFSIZE = 1024;

bool VerifyBeforeTest (const char* newval) 
{
    if (g_instance.whitebox_test_param_instance &&
        strcmp(newval, g_instance.whitebox_test_param_instance->test_file_name) == 0) {
        elog(LOG, "AssignUstoreUnitTest: g_instance.whitebox_test_param_instance is already initialized");
        return false;
    }
    if (!g_instance.whitebox_test_param_instance) {
        g_instance.whitebox_test_param_instance =
            (WhiteboxTestParam *)palloc(sizeof(WhiteboxTestParam) * (MAX_UNIT_TEST));
    }
    g_instance.whitebox_test_param_instance->elevel = WARNING;
    int rc = sprintf_s(g_instance.whitebox_test_param_instance->test_file_name, MAX_NAME_STR_LEN, "%s", newval);
    securec_check_ss_c(rc, "\0", "\0");
    if (strcmp(newval, "") == 0) {
        g_instance.whitebox_test_param_instance->num_testcase = 0;
        elog(LOG, "AssignUstoreUnitTest: ustore_unit_test is empty");
        return false;
    }
    
    return true;
}


void AssignUStoreUnitTest(const char* newval, const void* extra)
{
    FILE *fp;
    char buffer[BUFSIZE];
    int i = 0;
    bool ret = false;

    ret = VerifyBeforeTest(newval);
    if (!ret) {
        return;
    }

    fp = fopen(newval, PG_BINARY_RW);
    if (!fp) {
        g_instance.whitebox_test_param_instance->num_testcase = 0;
        elog(LOG, "AssignUstoreUnitTest: ustore_unit_test does not exist");
        return;
    }
    
    while (fgets(buffer, BUFSIZE, fp) != NULL) {
        char* ptoken = NULL;
        char* psave = NULL;
        char* ptype = NULL;
        char* pvalue = NULL;
        const char* pcomma = ",";
        const char* pequal = "=";

        // skip comment
        if (!buffer || buffer[0] == '#') {
            continue;
        }
        elog(LOG, "ustore_unit_test: %s", buffer);

        // expand array of test param
        g_instance.whitebox_test_param_instance->num_testcase = i + 1;

        // test stub name
        ptoken = strtok_r(buffer, pcomma, &psave);
        int rc = sprintf_s(g_instance.whitebox_test_param_instance[i].test_stub_name, MAX_NAME_STR_LEN, "%s", ptoken);
        securec_check_ss_c(rc, "\0", "\0");
        // test stub type
        ptoken = strtok_r(NULL, pcomma, &psave);
        if (strcmp(ptoken, "PRINT") == 0) {
            g_instance.whitebox_test_param_instance[i].type = WHITEBOX_PRINT;
        } else if (strcmp(ptoken, "SLEEP") == 0) {
            g_instance.whitebox_test_param_instance[i].type = WHITEBOX_SLEEP;
        } else if (strcmp(ptoken, "SUSPEND") == 0) {
            g_instance.whitebox_test_param_instance[i].type = WHITEBOX_SUSPEND;
        } else if (strcmp(ptoken, "ENABLE") == 0) {
            g_instance.whitebox_test_param_instance[i].type = WHITEBOX_ENABLE;
        } else if (strcmp(ptoken, "DISABLE") == 0) {
            g_instance.whitebox_test_param_instance[i].type = WHITEBOX_DISABLE;
        } else if (strcmp(ptoken, "ERROR") == 0) {
            g_instance.whitebox_test_param_instance[i].type = WHITEBOX_ERROR;
        }

        // test stub attributes
        ptoken = strtok_r(NULL, pcomma, &psave);
        while (ptoken) {
            ptype = TrimStr(strtok_r(ptoken, pequal, &pvalue));
            if (!ptype || !pvalue) {
                break;
            }
            if (strcmp(ptype, "TIMEOUT") == 0) {
                g_instance.whitebox_test_param_instance[i].attributes.timeout = pg_strtoint32(pvalue);
            } else if (strcmp(ptype, "ENABLED") == 0) {
                g_instance.whitebox_test_param_instance[i].attributes.enabled = (bool) pg_strtoint32(pvalue);
            } else if (strcmp(ptype, "SKIP_ITERATION") == 0) {
                g_instance.whitebox_test_param_instance[i].attributes.skip_iteration = pg_strtoint32(pvalue);
            } else if (strcmp(ptype, "TARGET_TEST_STUB") == 0) {
                rc = sprintf_s(g_instance.whitebox_test_param_instance[i].attributes.target_test_stub, MAX_NAME_STR_LEN,
                    "%s", TrimStr(pvalue));
                securec_check_ss_c(rc, "\0", "\0");
            }
            ptoken = strtok_r(NULL, pcomma, &psave);
        }
        g_instance.whitebox_test_param_instance[i].attributes.hit_count = 0;
        i++;
    }
    fclose(fp);
}

/**
 * @Description: check whether the test stub can be activated.
 * @in name - the white-box single-point fault fire tag, is a string defined in GUC
 * @in function - callback function
 * @return - true if one or more breakpoints have been activated; false otherwise
 */
bool WhiteboxTestStubActivator(const char* name, whitebox_stub_callback function)
{
    bool result = false;
    if (g_instance.whitebox_test_param_instance == NULL) {
        return false;
    }

    if (t_thrd.proc_cxt.proc_exit_inprogress) {
        return false;
    }

    if (g_instance.whitebox_test_param_instance->num_testcase > MAX_UNIT_TEST) {
        return false;
    }

    for (int i = 0; i < g_instance.whitebox_test_param_instance->num_testcase; i++) {
        if (pg_strcasecmp(name, g_instance.whitebox_test_param_instance[i].test_stub_name) == 0) {
            result = result || (*function)(g_instance.whitebox_test_param_instance[i]);
        }
    }
    return result;
}

/**
 * @Description: default uheap-error emit callback function.
 * @in - a reference to test parameters
 * @return - true if one or more breakpoints have been activated; false otherwise
 */
bool WhiteboxDefaultErrorEmit(WhiteboxTestParam& uheapTestParamInstance)
{
    bool result = false;
    if (g_instance.whitebox_test_param_instance->elevel == PANIC) {
        exit(0);
    }

    switch (uheapTestParamInstance.type) {
        case WHITEBOX_PRINT:
            result = WhiteboxTestPrint(uheapTestParamInstance.test_stub_name);
            break;
        case WHITEBOX_SLEEP:
            result = WhiteboxTestSleep(
                uheapTestParamInstance.test_stub_name,
                uheapTestParamInstance.attributes.timeout,
                uheapTestParamInstance.attributes.skip_iteration,
                uheapTestParamInstance.attributes.hit_count);
            break;
        case WHITEBOX_SUSPEND:
            result = WhiteboxTestSuspend(
                uheapTestParamInstance.test_stub_name,
                uheapTestParamInstance.attributes.timeout,
                uheapTestParamInstance.attributes.enabled);
            break;
        case WHITEBOX_ENABLE:
            result = WhiteboxTestSetEnable(
                uheapTestParamInstance.attributes.target_test_stub, true);
            break;
        case WHITEBOX_DISABLE:
            result = WhiteboxTestSetEnable(
                uheapTestParamInstance.attributes.target_test_stub, false);
            break;
        case WHITEBOX_ERROR:
            result = WhiteboxTestSetError(
                uheapTestParamInstance.test_stub_name,
                uheapTestParamInstance.attributes.enabled);
            break;
        default:
            break;
    }
    return false; // make it always false for now, to mute the message printing at each breakpoint
}

bool WhiteboxTestPrint(const char* functionName)
{
    ereport(NOTICE, (errmsg("Hitting breakpoint %s", functionName)));
    return true;
}

bool WhiteboxTestSetError(const char* functionName, const bool& enabled)
{
    if (enabled) {
        ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Hitting breakpoint %s", functionName)));
        return true;
    } else {
        return false;
    }
}

bool WhiteboxTestSleep(const char* functionName, int timeout, int skipIteration, int& hitCount)
{
    hitCount++;
    if (hitCount > skipIteration) {
        hitCount = 0;
        elog(g_instance.whitebox_test_param_instance->elevel,
            "Suspending at breakpoint %s timeout=%d", functionName, timeout);
        pg_usleep(timeout);
        return true;
    } else {
        return false;
    }
}

bool WhiteboxTestSuspend(const char* functionName, int timeout, const bool& enabled)
{
    int elapseTime  = 0;
    int elapseInterval  = 1000; // 1/1000 second
    if (enabled) {
        elog(g_instance.whitebox_test_param_instance->elevel, "Suspending at breakpoint %s timeout=%d",
            functionName, timeout);
        while (elapseTime < timeout) {
            // check for interrupts
            if (!enabled) {
                break;
            }
            elapseTime += elapseInterval;
            pg_usleep(elapseInterval);
        }
        return true;
    } else {
        return false;
    }
}

bool WhiteboxTestSetEnable(const char* functionName, bool enabled)
{
    for (int i = 0; i < g_instance.whitebox_test_param_instance->num_testcase; i++) {
        if (pg_strcasecmp(functionName, g_instance.whitebox_test_param_instance[i].test_stub_name) == 0) {
            g_instance.whitebox_test_param_instance[i].attributes.enabled = enabled;
            if (enabled) {
                elog(g_instance.whitebox_test_param_instance->elevel, "Enabling breakpoint %s type=%d", functionName,
                    g_instance.whitebox_test_param_instance[i].type);
            } else {
                elog(g_instance.whitebox_test_param_instance->elevel, "Disabling breakpoint %s type=%d", functionName,
                    g_instance.whitebox_test_param_instance[i].type);
            }
        }
    }
    return true;
}