* 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.
* -------------------------------------------------------------------------
*
* cm_client_api.cpp
*
*
* IDENTIFICATION
* src/cm_client/cm_client_api.cpp
*
* -------------------------------------------------------------------------
*/
#include <stdlib.h>
#include "cm/cm_elog.h"
#include "cm/cm_msg.h"
#include "cm_client.h"
#include "cm_client_api.h"
static char *g_jsonStrPtr = NULL;
static bool IsStrOverLength(const char *str, uint32 maxLen)
{
uint32 len = 0;
while (len < maxLen) {
if (str[len++] == '\0') {
return true;
}
}
return false;
}
static bool CanDoCmInit(const char *resName)
{
if (GetIsClientInit()) {
write_runlog(LOG, "cm_client has init, can't do init again.\n");
return false;
}
if (resName == NULL) {
(void)printf(_("resName length is NULL.\n"));
return false;
}
if (!IsStrOverLength(resName, CM_MAX_RES_NAME)) {
(void)printf(_("resName length >= %d.\n"), CM_MAX_RES_NAME);
return false;
}
return true;
}
ClientCmLockMsg *GetLockSendMsg(const char *lockName, LockOption opt)
{
ClientCmLockMsg *sendMsg = (ClientCmLockMsg*) malloc(sizeof(ClientCmLockMsg));
if (sendMsg == NULL) {
write_runlog(ERROR, "out of memory, lock option = %u.\n", (uint32)opt);
return NULL;
}
sendMsg->head.msgType = (uint32)MSG_CM_RES_LOCK;
sendMsg->info.lockOpt = (uint32)opt;
errno_t rc = strcpy_s(sendMsg->info.lockName, CM_MAX_LOCK_NAME, lockName);
securec_check_errno(rc, (void)rc);
return sendMsg;
}
int ResLockCore(const char *lockName)
{
if (access(g_manualPausePath, F_OK) == 0 && strcmp(lockName, "dms_reformer_lock") == 0) {
write_runlog(LOG, "cm is pause, don't lock(%s).\n", lockName);
return 1;
}
ClientCmLockMsg *sendMsg = GetLockSendMsg(lockName, CM_RES_LOCK);
if (sendMsg == NULL) {
write_runlog(ERROR, "generate (%s)lock msg failed.\n", lockName);
return 1;
}
ClientLockResult lockResult = SendLockMsgAndWaitResult((char*)sendMsg, sizeof(ClientCmLockMsg));
if (lockResult.error != 0) {
write_runlog(ERROR, "(%s)lock fail, error=%u.\n", lockName, lockResult.error);
} else {
write_runlog(LOG, "(%s)lock success.\n", lockName);
}
return (int)lockResult.error;
}
int ResUnlockCore(const char *lockName)
{
ClientCmLockMsg *sendMsg = GetLockSendMsg(lockName, CM_RES_UNLOCK);
if (sendMsg == NULL) {
write_runlog(ERROR, "generate (%s) unlock msg failed.\n", lockName);
return 1;
}
ClientLockResult lockResult = SendLockMsgAndWaitResult((char*)sendMsg, sizeof(ClientCmLockMsg));
if (lockResult.error != 0) {
write_runlog(ERROR, "unlock fail, error=%u.\n", lockResult.error);
} else {
write_runlog(LOG, "unlock success.\n");
}
return (int)lockResult.error;
}
int ResGetLockOwnerCore(const char *lockName, unsigned int *instId)
{
ClientCmLockMsg *sendMsg = GetLockSendMsg(lockName, CM_RES_GET_LOCK_OWNER);
if (sendMsg == NULL) {
write_runlog(ERROR, "generate (%s) get lock owner msg failed.\n", lockName);
return 1;
}
ClientLockResult lockResult = SendLockMsgAndWaitResult((char*)sendMsg, sizeof(ClientCmLockMsg));
if (lockResult.error != 0) {
write_runlog(ERROR, "get lock owner fail, error=%u.\n", lockResult.error);
} else {
*instId = lockResult.ownerId;
}
return (int)lockResult.error;
}
int ResTransLockCore(const char *lockName, unsigned int instId)
{
ClientCmLockMsg *sendMsg = GetLockSendMsg(lockName, CM_RES_LOCK_TRANS);
if (sendMsg == NULL) {
write_runlog(ERROR, "generate (%s) get lock owner msg failed.\n", lockName);
return 1;
}
sendMsg->info.transInstId = instId;
ClientLockResult lockResult = SendLockMsgAndWaitResult((char*)sendMsg, sizeof(ClientCmLockMsg));
if (lockResult.error != 0) {
write_runlog(ERROR, "trans lock owner failed, error=%u.\n", lockResult.error);
} else {
write_runlog(LOG, "trans lock owner to %u success.\n", instId);
}
return (int)lockResult.error;
}
bool CanDoLockOperate(const char *lockName)
{
if (!GetIsClientInit()) {
(void)printf(_("cm_client is not alive, please init cm_client first.\n"));
return false;
}
if (lockName == NULL) {
write_runlog(ERROR, "lock name is NULL.\n");
return false;
}
if (!IsStrOverLength(lockName, CM_MAX_LOCK_NAME)) {
write_runlog(ERROR, "lock name is too long, max len is %d.\n", CM_MAX_LOCK_NAME);
return false;
}
return true;
}
bool CanDoGetLockOwner(const char *lockName, const unsigned int *instId)
{
if (!CanDoLockOperate(lockName)) {
return false;
}
if (instId == NULL) {
write_runlog(ERROR, "input parameter is NULL, can't get lock owner.\n");
return false;
}
return true;
}
#ifdef __cplusplus
extern "C" {
#endif
int CmInit(unsigned int instId, const char *resName, CmNotifyFunc func)
{
static bool isFirstInit = true;
if (!CanDoCmInit(resName)) {
return -1;
}
if (PreInit(instId, resName, func, &isFirstInit) != CM_SUCCESS) {
(void)printf(_("resName(%s) instanceId(%u) init cm_client failed.\n"), resName, instId);
return -1;
}
bool &isClientInit = GetIsClientInit();
isClientInit = false;
if (CreateConnectAgentThread() != CM_SUCCESS || CreateSendMsgThread() != CM_SUCCESS ||
CreateRecvMsgThread() != CM_SUCCESS) {
write_runlog(LOG, "cm_client create thread failed.\n");
ShutdownClient();
return -1;
}
bool isSuccess = SendInitMsgAndGetResult(resName, instId);
if (!isSuccess) {
write_runlog(ERROR, "resName(%s) instanceId(%u) init client failed, can check agent.\n", resName, instId);
ShutdownClient();
return -1;
}
write_runlog(LOG, "resName(%s) instanceId(%u) init cm_client success.\n", resName, instId);
isClientInit = true;
return 0;
}
void CmClientFini()
{
ShutdownClient();
FreeClientMemory();
}
static void GetResStatJsonHead(char *jsonStr, uint32 strLen, const OneResStatList *statList)
{
int ret = snprintf_s(jsonStr,
strLen,
strLen - 1,
"{\"version\":%llu,\"res_name\":\"%s\",\"inst_count\":%u,\"inst_status\":[",
statList->version,
statList->resName,
statList->instanceCount);
securec_check_intval(ret, (void)ret);
}
static void GetResStatJsonInst(char *instInfo, uint32 strLen, const CmResStatInfo *instStat, bool isEnd)
{
int ret = snprintf_s(instInfo,
strLen,
strLen - 1,
"{\"node_id\":%u,\"cm_instance_id\":%u,\"res_instance_id\":%u,\"is_work_member\":%u,\"status\":%u}",
instStat->nodeId,
instStat->cmInstanceId,
instStat->resInstanceId,
instStat->isWorkMember,
instStat->status);
securec_check_intval(ret, (void)ret);
if (!isEnd) {
errno_t rc = strcat_s(instInfo, MAX_PATH_LEN, ",");
securec_check_errno(rc, (void)rc);
}
}
static void ResStatusToJsonStr(const OneResStatList *statList)
{
const int maxJsonStrLen = 10240;
char jsonStr[maxJsonStrLen] = {0};
GetResStatJsonHead(jsonStr, maxJsonStrLen, statList);
errno_t rc;
for (uint32 i = 0; i < statList->instanceCount; ++i) {
char instInfo[MAX_PATH_LEN] = {0};
GetResStatJsonInst(instInfo, MAX_PATH_LEN, &statList->resStat[i], (i == (statList->instanceCount - 1)));
rc = strcat_s(jsonStr, maxJsonStrLen, instInfo);
securec_check_errno(rc, (void)rc);
}
rc = strcat_s(jsonStr, maxJsonStrLen, "]}");
securec_check_errno(rc, (void)rc);
g_jsonStrPtr = strdup(jsonStr);
}
char *CmGetResStats()
{
OneResStatList *statusList = GetClientStatusList();
if (statusList->version == 0) {
write_runlog(LOG, "version is 0, statList is invalid.\n");
return NULL;
}
ResStatusToJsonStr(statusList);
return g_jsonStrPtr;
}
int CmFreeResStats(char *resStats)
{
if (resStats == NULL) {
write_runlog(ERROR, "res stat ptr is NULL, can't free.\n");
return 1;
}
if (resStats != g_jsonStrPtr) {
write_runlog(ERROR, "res stat ptr is not stat list ptr, can't free.\n");
return 1;
}
FREE_AND_RESET(g_jsonStrPtr);
return 0;
}
int CmResLock(const char *lockName)
{
if (!CanDoLockOperate(lockName)) {
return 1;
}
return ResLockCore(lockName);
}
int CmResUnlock(const char *lockName)
{
if (!CanDoLockOperate(lockName)) {
return 1;
}
return ResUnlockCore(lockName);
}
int CmResGetLockOwner(const char *lockName, unsigned int *instId)
{
if (!CanDoGetLockOwner(lockName, instId)) {
return 1;
}
return ResGetLockOwnerCore(lockName, instId);
}
int CmResTransLock(const char *lockName, unsigned int instId)
{
if (!CanDoLockOperate(lockName)) {
return 1;
}
return ResTransLockCore(lockName, instId);
}
#ifdef __cplusplus
}
#endif