* 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.
* -------------------------------------------------------------------------
*
* gscgroup.cpp
* provide the external function for init/free/print cgroup and
* attach task into cgroup.
*
* IDENTIFICATION
* src/gausskernel/cbb/workload/gscgroup.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include <libcgroup.h>
#include <sys/mman.h>
#include "pgstat.h"
#include "pgxc/pgxc.h"
#include "pgxc/poolmgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "workload/commgr.h"
#include "workload/gscgroup.h"
#include "workload/workload.h"
#include "workload/ctxctl.h"
#define WLM_CGROUP_HASH_SIZE 32
static THR_LOCAL struct cgroup* gscgroup_topwd = NULL;
static THR_LOCAL struct cgroup* gscgroup_curwd = NULL;
* **************** STATIC FUNCTIONS ************************
*/
* function name: gscgroup_parse_config_file
* description : parse the configuration file of Cgroups
* return value :
* -1: abnormal
* 0: normal
*
*/
static int gscgroup_parse_config_file(const char* ngname, gscgroup_grp_t** ngaddr)
{
long fsize = 0;
void* vaddr = NULL;
size_t cglen = GSCGROUP_ALLNUM * sizeof(gscgroup_grp_t);
int i = 0;
int sret;
char* cfgpath = NULL;
char* exepath = NULL;
char real_exepath[PATH_MAX + 1] = {'\0'};
size_t cfgpath_len = 0;
struct passwd* passwd_user = NULL;
passwd_user = getpwuid(geteuid());
if (!passwd_user) {
ereport(WARNING,
(errmsg("can't get the passwd_user by euid %u."
"please check the running user!",
geteuid())));
return -1;
}
exepath = gs_getenv_r("GAUSSHOME");
if (!exepath || realpath(exepath, real_exepath) == NULL) {
ereport(WARNING, (errmsg("environment variable $GAUSSHOME is not set!")));
return -1;
}
check_backend_env(real_exepath);
if (!ngname) {
cfgpath_len = strlen(real_exepath) + 1 + sizeof(GSCGROUP_CONF_DIR) + 1 + sizeof(GSCFG_PREFIX) + 1 +
USERNAME_LEN + sizeof(GSCFG_SUFFIX) + 1;
} else {
cfgpath_len = strlen(real_exepath) + 1 + sizeof(GSCGROUP_CONF_DIR) + 1 + strlen(ngname) + 1 +
sizeof(GSCFG_PREFIX) + 1 + USERNAME_LEN + sizeof(GSCFG_SUFFIX) + 1;
}
cfgpath = (char*)malloc(cfgpath_len);
if (cfgpath == NULL) {
return -1;
}
if (!ngname) {
sret = snprintf_s(cfgpath,
cfgpath_len,
cfgpath_len - 1,
"%s/%s/%s_%s%s",
real_exepath,
GSCGROUP_CONF_DIR,
GSCFG_PREFIX,
passwd_user->pw_name,
GSCFG_SUFFIX);
} else {
sret = snprintf_s(cfgpath,
cfgpath_len,
cfgpath_len - 1,
"%s/%s/%s.%s_%s%s",
real_exepath,
GSCGROUP_CONF_DIR,
ngname,
GSCFG_PREFIX,
passwd_user->pw_name,
GSCFG_SUFFIX);
}
securec_check_intval(sret, free(cfgpath), -1);
fsize = gsutil_filesize(cfgpath);
if (fsize != (long)cglen) {
ereport(LOG,
(errmsg("the configure file %s doesn't exist or "
"the size of configure file has changed. "
"Please create it by root user!",
cfgpath)));
free(cfgpath);
cfgpath = NULL;
return -1;
} else {
vaddr = gsutil_filemap(cfgpath, cglen, (PROT_READ | PROT_WRITE), MAP_SHARED, passwd_user);
if (NULL == vaddr) {
ereport(LOG,
(errmsg("failed to create and map "
"the configure file %s!",
cfgpath)));
free(cfgpath);
cfgpath = NULL;
return -1;
}
for (i = 0; i < GSCGROUP_ALLNUM; i++) {
if (NULL == ngaddr) {
g_instance.wlm_cxt->gscgroup_vaddr[i] = (gscgroup_grp_t*)vaddr + i;
} else {
ngaddr[i] = (gscgroup_grp_t*)((gscgroup_grp_t*)vaddr + i);
}
}
}
free(cfgpath);
cfgpath = NULL;
return 0;
}
* function name: gscgroup_get_group_type
* description : return the group type string for later displaying
* return value :
* NULL: abnormal
* other: normal
*
*/
char* gscgroup_get_group_type(group_type gtype)
{
if (gtype == GROUP_TOP) {
return "Top";
} else if (gtype == GROUP_CLASS) {
return "CLASS";
} else if (gtype == GROUP_BAKWD) {
return "BAKWD";
} else if (gtype == GROUP_DEFWD) {
return "DEFWD";
} else if (gtype == GROUP_TSWD) {
return "TSWD";
}
return NULL;
}
static void gscgroup_print_exception_detail(StringInfoData* buf, int gid, int kinds)
{
int i = 0;
WLMNodeGroupInfo* MyNodeGroup = t_thrd.wlm_cxt.thread_node_group;
for (i = 0; i < kinds; ++i) {
if (MyNodeGroup->vaddr == NULL || gsutil_exception_kind_is_valid(MyNodeGroup->vaddr[gid], i) == 0) {
continue;
}
if (i == EXCEPT_ABORT) {
appendStringInfo(buf, _("%s: "), gsutil_print_exception_flag(i));
if (MyNodeGroup->vaddr[gid]->except[i].blocktime > 0) {
appendStringInfo(buf, _("BlockTime=%u "), MyNodeGroup->vaddr[gid]->except[i].blocktime);
}
if (MyNodeGroup->vaddr[gid]->except[i].elapsedtime > 0) {
appendStringInfo(buf, _("ElapsedTime=%u "), MyNodeGroup->vaddr[gid]->except[i].elapsedtime);
}
if (MyNodeGroup->vaddr[gid]->except[i].spoolsize > 0) {
appendStringInfo(buf, _("SpillSize=%ld "), MyNodeGroup->vaddr[gid]->except[i].spoolsize);
}
if (MyNodeGroup->vaddr[gid]->except[i].broadcastsize > 0) {
appendStringInfo(buf, _("BroadcastSize=%ld "), MyNodeGroup->vaddr[gid]->except[i].broadcastsize);
}
if (MyNodeGroup->vaddr[gid]->except[i].allcputime > 0) {
appendStringInfo(buf, _("AllCpuTime=%u "), MyNodeGroup->vaddr[gid]->except[i].allcputime);
}
if (MyNodeGroup->vaddr[gid]->except[i].qualitime > 0) {
appendStringInfo(buf, _("QualificationTime=%u "), MyNodeGroup->vaddr[gid]->except[i].qualitime);
}
if (MyNodeGroup->vaddr[gid]->except[i].skewpercent > 0) {
appendStringInfo(buf, _("CPUSkewPercent=%u "), MyNodeGroup->vaddr[gid]->except[i].skewpercent);
}
} else {
appendStringInfo(buf, _("%s: "), gsutil_print_exception_flag(i));
if (MyNodeGroup->vaddr[gid]->except[i].allcputime > 0) {
appendStringInfo(buf, _("AllCpuTime=%u "), MyNodeGroup->vaddr[gid]->except[i].allcputime);
}
if (MyNodeGroup->vaddr[gid]->except[i].qualitime > 0) {
appendStringInfo(buf, _("QualificationTime=%u "), MyNodeGroup->vaddr[gid]->except[i].qualitime);
}
if (MyNodeGroup->vaddr[gid]->except[i].skewpercent > 0) {
appendStringInfo(buf, _("CPUSkewPercent=%u "), MyNodeGroup->vaddr[gid]->except[i].skewpercent);
}
}
appendStringInfo(buf, _("\n"));
}
}
void gscgroup_print_exception(StringInfoData* buf)
{
int cls = 0;
int wd = 0;
int flag = 0;
int pflag = 0;
int kinds = EXCEPT_ALL_KINDS;
WLMNodeGroupInfo* MyNodeGroup = t_thrd.wlm_cxt.thread_node_group;
appendStringInfo(buf, _("\n\nGroup Exception information is listed:"));
for (cls = CLASSCG_START_ID; cls <= CLASSCG_END_ID; cls++) {
#ifdef ENABLE_UT
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[cls] == NULL) {
break;
}
#endif
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[cls]->used == 0) {
continue;
}
flag = 0;
if (gsutil_exception_is_valid(MyNodeGroup->vaddr[cls], kinds) != 0) {
appendStringInfo(buf,
_("\nGID: %3d Type: %-6s Class: %-16s\n"),
MyNodeGroup->vaddr[cls]->gid,
"EXCEPTION",
MyNodeGroup->vaddr[cls]->grpname);
gscgroup_print_exception_detail(buf, cls, kinds);
++flag;
++pflag;
}
for (wd = WDCG_START_ID; wd <= WDCG_END_ID; wd++) {
#ifdef ENABLE_UT
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[wd] == NULL) {
break;
}
#endif
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[wd]->used == 0 || MyNodeGroup->vaddr[wd]->ginfo.wd.cgid != cls ||
gsutil_exception_is_valid(MyNodeGroup->vaddr[wd], kinds) == 0) {
continue;
}
if (flag == 0) {
appendStringInfo(buf,
_("\nGID: %3d Type: %-6s Class: %-16s"),
MyNodeGroup->vaddr[cls]->gid,
"EXCEPTION",
MyNodeGroup->vaddr[cls]->grpname);
++flag;
}
appendStringInfo(buf,
_("\nGID: %3d Type: %-6s Group: %s:%-16s\n"),
MyNodeGroup->vaddr[wd]->gid,
"EXCEPTION",
MyNodeGroup->vaddr[cls]->grpname,
MyNodeGroup->vaddr[wd]->grpname);
gscgroup_print_exception_detail(buf, wd, kinds);
++pflag;
}
}
if (pflag == 0) {
appendStringInfo(buf, _("\n"));
}
}
* function name: gscgroup_print
* description : print the configuration file information
*
*/
static char* gscgroup_print(void)
{
StringInfoData buf;
int i;
WLMNodeGroupInfo* MyNodeGroup = t_thrd.wlm_cxt.thread_node_group;
initStringInfo(&buf);
if (buf.len != 0) {
appendStringInfoChar(&buf, '\n');
}
if (g_instance.wlm_cxt->gscgroup_init_done != 1) {
appendStringInfo(&buf,
_("\nThere is no Cgroup configuration information "
"for without initialization!"));
return buf.data;
}
appendStringInfo(&buf, _("\nTop Group information is listed:"));
for (i = 0; i <= TOPCG_END_ID; i++) {
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[i]->used == 0) {
continue;
}
appendStringInfo(&buf,
_("\nGID: %3d Type: %-6s Percent(%%): %4u(%3d) "
"Name: %-20s"),
MyNodeGroup->vaddr[i]->gid,
gscgroup_get_group_type(MyNodeGroup->vaddr[i]->gtype),
MyNodeGroup->vaddr[i]->percent,
MyNodeGroup->vaddr[i]->ginfo.top.percent,
MyNodeGroup->vaddr[i]->grpname);
if (MyNodeGroup->vaddr[i]->ainfo.quota && MyNodeGroup->vaddr[i]->ainfo.quota > 0) {
appendStringInfo(&buf, _("Quota(%%): %2d"), MyNodeGroup->vaddr[i]->ainfo.quota);
}
}
appendStringInfo(&buf, _("\n\nBackend Group information is listed:"));
for (i = BACKENDCG_START_ID; i <= BACKENDCG_END_ID; i++) {
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[i]->used == 0) {
continue;
}
appendStringInfo(&buf,
_("\nGID: %3d Type: %-6s Name: %-16s "
"TopGID: %3d Percent(%%): %3u(%2d)"),
MyNodeGroup->vaddr[i]->gid,
gscgroup_get_group_type(MyNodeGroup->vaddr[i]->gtype),
MyNodeGroup->vaddr[i]->grpname,
MyNodeGroup->vaddr[i]->ginfo.cls.tgid,
MyNodeGroup->vaddr[i]->percent,
MyNodeGroup->vaddr[i]->ginfo.cls.percent);
if (MyNodeGroup->vaddr[i]->ainfo.quota > 0) {
appendStringInfo(&buf, _("Quota(%%): %2d"), MyNodeGroup->vaddr[i]->ainfo.quota);
}
}
appendStringInfo(&buf, _("\n\nClass Group information is listed:"));
for (i = CLASSCG_START_ID; i <= CLASSCG_END_ID; i++) {
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[i]->used == 0) {
continue;
}
appendStringInfo(&buf,
_("\nGID: %3d Type: %-6s Name: %-16s TopGID: %3d "
"Percent(%%): %3u(%2d) MaxLevel: %d RemPCT: %2d"),
MyNodeGroup->vaddr[i]->gid,
gscgroup_get_group_type(MyNodeGroup->vaddr[i]->gtype),
MyNodeGroup->vaddr[i]->grpname,
MyNodeGroup->vaddr[i]->ginfo.cls.tgid,
MyNodeGroup->vaddr[i]->percent,
MyNodeGroup->vaddr[i]->ginfo.cls.percent,
MyNodeGroup->vaddr[i]->ginfo.cls.maxlevel,
MyNodeGroup->vaddr[i]->ginfo.cls.rempct);
if (MyNodeGroup->vaddr[i]->ainfo.quota > 0) {
appendStringInfo(&buf, _("Quota(%%): %2d"), MyNodeGroup->vaddr[i]->ainfo.quota);
}
}
appendStringInfo(&buf, _("\n\nWorkload Group information is listed:"));
for (i = WDCG_START_ID; i <= WDCG_END_ID; i++) {
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[i]->used == 0) {
continue;
}
appendStringInfo(&buf,
_("\nGID: %3d Type: %-6s Name: %-16s ClsGID: %3d "
"Percent(%%): %3u(%2d) WDLevel: %d "),
MyNodeGroup->vaddr[i]->gid,
gscgroup_get_group_type(MyNodeGroup->vaddr[i]->gtype),
MyNodeGroup->vaddr[i]->grpname,
MyNodeGroup->vaddr[i]->ginfo.wd.cgid,
MyNodeGroup->vaddr[i]->percent,
MyNodeGroup->vaddr[i]->ginfo.wd.percent,
MyNodeGroup->vaddr[i]->ginfo.wd.wdlevel);
if (MyNodeGroup->vaddr[i]->ainfo.quota > 0) {
appendStringInfo(&buf, _("Quota(%%): %2d"), MyNodeGroup->vaddr[i]->ainfo.quota);
}
}
appendStringInfo(&buf, _("\n\nTimeshare Group information is listed:"));
for (i = TSCG_START_ID; i <= TSCG_END_ID; i++) {
if (MyNodeGroup->vaddr == NULL || MyNodeGroup->vaddr[i]->used == 0) {
continue;
}
appendStringInfo(&buf,
_("\nGID: %3d Type: %-6s Name: %-16s Rate: %d"),
MyNodeGroup->vaddr[i]->gid,
gscgroup_get_group_type(MyNodeGroup->vaddr[i]->gtype),
MyNodeGroup->vaddr[i]->grpname,
MyNodeGroup->vaddr[i]->ginfo.ts.rate);
}
gscgroup_print_exception(&buf);
appendStringInfo(&buf, _("\n"));
return buf.data;
}
* function name: gscgroup_initialize_hashtbl
* description : initialize the hash table for Cgroups
*
*/
static void gscgroup_initialize_hashtbl(HTAB** htab)
{
HASHCTL hash_ctl;
errno_t rc = memset_s(&hash_ctl, sizeof(hash_ctl), 0, sizeof(hash_ctl));
securec_check(rc, "\0", "\0");
hash_ctl.keysize = sizeof(u_sess->wlm_cxt->group_keyname);
hash_ctl.hcxt = g_instance.wlm_cxt->workload_manager_mcxt;
hash_ctl.entrysize = sizeof(gscgroup_entry_t);
hash_ctl.hash = string_hash;
hash_ctl.alloc = WLMAlloc0NoExcept4Hash;
hash_ctl.dealloc = pfree;
*htab = hash_create("wlm cgroup hash table",
WLM_CGROUP_HASH_SIZE,
&hash_ctl,
HASH_ELEM | HASH_SHRCTX | HASH_FUNCTION | HASH_ALLOC | HASH_DEALLOC);
}
* function name: gscgroup_enter_hashtbl
* description : register the key-values into hash table
* arguments :
* name: the string of "classname:workloadname"
* cg: cgroup structure
* return value :
* -1: abnormal
* 0: normal
*
*/
static int gscgroup_enter_hashtbl(WLMNodeGroupInfo* ng, const char* name, struct cgroup* cg)
{
bool found = false;
gscgroup_entry_t* cgentry = NULL;
int sret;
Assert(ng != NULL);
if (ng->cgroups_htab == NULL || cg == NULL) {
return -1;
}
USE_AUTO_LWLOCK(WorkloadCGroupHashLock, LW_EXCLUSIVE);
cgentry = (gscgroup_entry_t*)hash_search(ng->cgroups_htab, name, HASH_ENTER_NULL, &found);
if (cgentry == NULL) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"when entering new hash value! ")));
return -1;
}
if (!found) {
cgentry->cg = cg;
cgentry->percent = gscgroup_get_percent(ng, name);
sret = snprintf_s(cgentry->name, sizeof(cgentry->name), sizeof(cgentry->name) - 1, "%s", name);
securec_check_intval(sret, , -1);
cgentry->oldcg = NULL;
} else {
cgentry->oldcg = cgentry->cg;
cgentry->cg = cg;
cgentry->percent = gscgroup_get_percent(ng, name);
sret = snprintf_s(cgentry->name, sizeof(cgentry->name), sizeof(cgentry->name) - 1, "%s", name);
securec_check_intval(sret, , -1);
}
cgentry->cpuUsedAcct = 0;
cgentry->cpuUtil = 0;
cgentry->cpuCount = 0;
cgentry->usedCpuCount = 0;
cgentry->cpuLastAcct = 0;
cgentry->lastTime = 0;
return 0;
}
* function name: gscgroup_lookup_hashtbl
* description : retrieve cgroup structure based on keyname
* arguments :
* name: the string of "classname:workloadname"
* return value :
* NULL: abnormal
* other: normal
*
*/
gscgroup_entry_t* gscgroup_lookup_hashtbl(WLMNodeGroupInfo* ng, const char* name)
{
gscgroup_entry_t* cgentry = NULL;
if (ng->cgroups_htab == NULL || !StringIsValid(name)) {
return NULL;
}
USE_AUTO_LWLOCK(WorkloadCGroupHashLock, LW_SHARED);
cgentry = (gscgroup_entry_t*)hash_search(ng->cgroups_htab, name, HASH_FIND, NULL);
return cgentry;
}
* function name: gscgroup_get_cgroup
* description : retrieve cgroup structure based on relative path
* arguments :
* relpath: the relative path of cgroup
* return value :
* NULL: abnormal
* other: normal
*
*/
static struct cgroup* gscgroup_get_cgroup(char* relpath)
{
int ret = 0;
struct cgroup* cg = NULL;
cg = cgroup_new_cgroup(relpath);
if (cg == NULL) {
ereport(WARNING, (errmsg("Cgroup %s failed to call cgroup_new_cgroup", relpath)));
return NULL;
}
ret = cgroup_get_cgroup(cg);
if (ret != 0) {
ereport(WARNING, (errmsg("Cgroup get_cgroup %s information: %s(%d)", relpath, cgroup_strerror(ret), ret)));
cgroup_free(&cg);
return NULL;
}
return cg;
}
* function name: gscgroup_is_timeshare
* description : check if the specified name is timeshare Cgroup
* arguments :
* gname: group name
* return value :
* -1: abnormal
* other: normal
*
*/
int gscgroup_is_timeshare(const char* gname)
{
int i = 0;
if (g_instance.wlm_cxt->gscgroup_config_parsed <= 0) {
return -1;
}
for (i = TSCG_START_ID; i <= TSCG_END_ID; i++) {
if (0 == strcmp(gname, g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname)) {
break;
}
}
if (i > TSCG_END_ID) {
return -1;
}
return i;
}
* function name: gscgroup_is_class
* description : check if the specified name is class Cgroup
* arguments :
* gname: group name
* return value :
* -1: abnormal
* other: normal
*
*/
int gscgroup_is_class(WLMNodeGroupInfo* ng, const char* gname)
{
int i = 0;
if (ng == NULL) {
ng = &g_instance.wlm_cxt->MyDefaultNodeGroup;
}
for (i = CLASSCG_START_ID; i <= CLASSCG_END_ID; i++) {
if (ng->vaddr[i] == NULL) {
continue;
}
if (ng->vaddr[i]->used && (0 == strcmp(ng->vaddr[i]->grpname, gname))) {
break;
}
}
if (i > CLASSCG_END_ID) {
return -1;
}
return i;
}
* function name: gscgroup_is_workload
* description : check if the specified name is workload Cgroup
* arguments :
* cls: the class group id
* gname: group name
* return value :
* -1: abnormal
* other: normal
*
*/
int gscgroup_is_workload(WLMNodeGroupInfo* ng, int cls, const char* gname)
{
int i = 0;
int wd = -1;
int cmp = -1;
size_t len;
char* tmpstr = NULL;
if (ng == NULL) {
ng = &g_instance.wlm_cxt->MyDefaultNodeGroup;
}
len = strlen(gname);
tmpstr = strchr((char*)gname, ':');
for (i = WDCG_START_ID; i <= WDCG_END_ID; i++) {
if (ng->vaddr[i]->used == 0 || ng->vaddr[i]->ginfo.wd.cgid != cls) {
continue;
}
if (tmpstr != NULL) {
if (ng->vaddr[i]->grpname[tmpstr - gname] == ':') {
cmp = strncmp(ng->vaddr[i]->grpname, gname, tmpstr - gname);
}
} else {
if (ng->vaddr[i]->grpname[len] == ':') {
cmp = strncmp(ng->vaddr[i]->grpname, gname, len);
}
}
if (cmp == 0) {
wd = i;
break;
}
}
return wd;
}
* function name: gscgroup_check_level
* description : check whether workload level is larger than max level of the class
* arguments :
* cls: the class group id
* level: workload level
* return value :
* -1: abnormal
* other: normal
*
*/
int gscgroup_check_level(int cls, const char* level)
{
int a = -1;
char* bad = NULL;
a = (int)strtol(level, &bad, 10);
if (bad && *bad) {
return -1;
}
if (a > MAX_WD_LEVEL || (a < 1)) {
return -1;
}
return a;
}
* function name: gscgroup_lookup_cgroup
* description : retrieve the cgroup structure based on the control group name;
* If the control group doesn't exist, return the cgroup of
* default workload;
* If it can be found in the configuration file, it should enter
* the new workload cgroup into hash table;
* If the class of workload has been deleted, it should give
* an warning to mention that;
* arguments :
* gname: the control_group string in the resource pool
* found: find cgroup or not
* return value :
* the default workload value if it can't be found;
* other: normal
*
*/
struct cgroup* gscgroup_lookup_cgroup(WLMNodeGroupInfo* ng, const char* gname, bool* found)
{
struct cgroup* cg = NULL;
gscgroup_entry_t* cg_entry = NULL;
char *p = NULL;
char *q = NULL;
int cls, sret;
if (found != NULL) {
*found = false;
}
gscgroup_topwd = g_instance.wlm_cxt->gscgroup_deftopwdcg;
if (!StringIsValid(gname) || !CGroupIsValid(gname) || (ng == NULL && 0 == strcmp(gname, GSCGROUP_DEFAULT_CGNAME))) {
return g_instance.wlm_cxt->gscgroup_defwdcg;
}
if ((ng == NULL) || ((cg_entry = gscgroup_lookup_hashtbl(ng, gname)) == NULL)) {
return g_instance.wlm_cxt->gscgroup_defwdcg;
}
cg = cg_entry->cg;
if (u_sess->attr.attr_resource.enable_cgroup_switch) {
q = pstrdup(gname);
p = strchr(q, ':');
if (p && (*p++ = '\0', (cls = gscgroup_is_class(ng, q)) != -1)) {
char keyname[GPNAME_LEN];
sret = snprintf_s(keyname,
sizeof(keyname),
sizeof(keyname) - 1,
"%s:%s:%d",
ng->vaddr[cls]->grpname,
GSCGROUP_TOP_WORKLOAD,
WD_TOP_LEVEL);
securec_check_intval(sret, pfree(q), cg);
if ((cg_entry = gscgroup_lookup_hashtbl(ng, keyname)) != NULL) {
gscgroup_topwd = cg_entry->cg;
}
}
pfree(q);
}
if (found != NULL) {
*found = true;
}
return cg;
}
static int GscgroupParseCpuinfo(const char* cpuset)
{
int len = strlen(cpuset);
int count = 0;
int low = 0;
int num = 0;
bool is_range = false;
int i;
for (i = 0; i < len; i++) {
if (cpuset[i] == ',') {
if (is_range) {
count += num - low + 1;
} else {
count += 1;
}
num = 0;
is_range = false;
} else if (cpuset[i] == '-') {
low = num;
num = 0;
is_range = true;
} else if (cpuset[i] >= '0' && cpuset[i] <= '9') {
num = num * 10 + cpuset[i] - '0';
} else {
ereport(WARNING, (errmsg("Unknow character %c for cpuset.", cpuset[i])));
return 1;
}
}
if (is_range) {
count += num - low + 1;
} else {
count += 1;
}
return (count == 0) ? 1 : count;
}
* function name: gscgroup_get_cgroup_cpuinfo
* description : get control group cpu info, include cpuset and cpuacct
* arguments :
* _in_ cg : control_group
* _out_ setcnt : how many cores of the control group
* _out_ usage : cpu usage of the control group
* return value : -1: abnormal
* other: normal
*
*/
int gscgroup_get_cgroup_cpuinfo(struct cgroup* cg, int* setcnt, int64* usage)
{
struct cgroup_controller* cgc_set = NULL;
struct cgroup_controller* cgc_acct = NULL;
char* cpuset = NULL;
char* relpath = gsutil_get_cgroup_name(cg);
if (relpath == NULL) {
return -1;
}
struct cgroup* new_cg = cgroup_new_cgroup(relpath);
if (new_cg == NULL) {
return -1;
}
if (cgroup_get_cgroup(new_cg) != 0) {
cgroup_free(&new_cg);
return -1;
}
if (setcnt && (cgc_set = cgroup_get_controller(new_cg, MOUNT_CPUSET_NAME)) != NULL &&
cgroup_get_value_string(cgc_set, CPUSET_CPUS, &cpuset) == 0) {
*setcnt = GscgroupParseCpuinfo(cpuset);
}
free(cpuset);
if (usage && ((cgc_acct = cgroup_get_controller(new_cg, MOUNT_CPUACCT_NAME)) == NULL ||
cgroup_get_value_int64(cgc_acct, CPUACCT_USAGE, usage) != 0)) {
cgroup_free(&new_cg);
return -1;
}
cgroup_free(&new_cg);
return 0;
}
* *************** EXTERNAL FUNCTION ********************************
*/
* function name: gscgroup_free
* description : free hash table and the mapping file when exiting process
*/
void gscgroup_free(void)
{
* if other threads are running.
* It may cause other threads to use the freed memory.
* So this function skips the free operation and let OS to do that.
*/
}
* function name: gscgroup_build_cgroups_htab
* description : build cgroup hash table for one logical cluster
*/
int gscgroup_build_cgroups_htab(WLMNodeGroupInfo* ng)
{
int sret;
char *relpath = NULL;
char *toppath = NULL;
char keyname[GPNAME_LEN] = {0};
char tmpname[GPNAME_LEN] = {0};
struct cgroup* cg = NULL;
for (int i = CLASSCG_START_ID; i <= CLASSCG_END_ID; i++) {
if (ng->vaddr[i]->used) {
if (i == CLASSCG_START_ID) {
sret = snprintf_s(
tmpname, sizeof(tmpname), sizeof(tmpname) - 1, "%s:%d", GSCGROUP_TOP_WORKLOAD, WD_TOP_LEVEL);
securec_check_intval(sret, , -1);
}
relpath = gscgroup_get_relative_path(i, ng->vaddr, ng->group_name);
if (!relpath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
ng->vaddr[i]->grpname)));
return -1;
}
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
return -1;
}
(void)gscgroup_enter_hashtbl(ng, ng->vaddr[i]->grpname, cg);
free(relpath);
relpath = NULL;
for (int j = WDCG_START_ID; j <= WDCG_END_ID; j++) {
if (ng->vaddr[j]->used && ng->vaddr[j]->ginfo.wd.cgid == i) {
relpath = gscgroup_get_relative_path(j, ng->vaddr, ng->group_name);
if (!relpath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
ng->vaddr[j]->grpname)));
return -1;
}
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
return -1;
}
sret = snprintf_s(keyname,
sizeof(keyname),
sizeof(keyname) - 1,
"%s:%s",
ng->vaddr[i]->grpname,
ng->vaddr[j]->grpname);
securec_check_intval(sret, free(relpath), -1);
(void)gscgroup_enter_hashtbl(ng, gscgroup_convert_cgroup(keyname), cg);
free(relpath);
relpath = NULL;
}
}
relpath = NULL;
toppath = gscgroup_get_topts_path(i, ng->vaddr, ng->group_name);
if (!toppath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for Timeshare path of %s Group!",
ng->vaddr[i]->grpname)));
return -1;
}
if (!(relpath = (char*)malloc(GPNAME_PATH_LEN))) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for timeshare path of %s Group!",
ng->vaddr[i]->grpname)));
free(toppath);
toppath = NULL;
return -1;
}
for (int j = TSCG_START_ID; j <= TSCG_END_ID; j++) {
sret =
snprintf_s(relpath, GPNAME_PATH_LEN, GPNAME_PATH_LEN - 1, "%s/%s", toppath, ng->vaddr[j]->grpname);
securec_check_intval(sret, free(relpath); free(toppath), -1);
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
free(toppath);
toppath = NULL;
return -1;
}
sret = snprintf_s(keyname,
sizeof(keyname),
sizeof(keyname) - 1,
"%s:%s",
ng->vaddr[i]->grpname,
ng->vaddr[j]->grpname);
securec_check_intval(sret, free(relpath); free(toppath), -1);
(void)gscgroup_enter_hashtbl(ng, gscgroup_convert_cgroup(keyname), cg);
}
free(relpath);
relpath = NULL;
free(toppath);
toppath = NULL;
}
}
return 0;
}
* function name: gscgroup_map_node_group
* description : map the node group configuration file
*/
int gscgroup_map_node_group(WLMNodeGroupInfo* ng)
{
int ret = 0;
if (ng == NULL) {
return -1;
}
if ((ret = gscgroup_parse_config_file(ng->group_name, ng->vaddr)) == -1) {
return -1;
}
if (ng->cgroups_htab == NULL) {
gscgroup_initialize_hashtbl(&ng->cgroups_htab);
pthread_mutex_init(&ng->cgroups_mutex, NULL);
}
if ((ret = gscgroup_build_cgroups_htab(ng)) == -1) {
return -1;
}
return 0;
}
* function name: gscgroup_map_ng_conf
* description : map the node group configuration file
*/
int gscgroup_map_ng_conf(char* ngname)
{
int ret = 0;
WLMNodeGroupInfo* ng = WLMMustGetNodeGroupFromHTAB(ngname);
if (ng->cgroups_htab == NULL) {
gscgroup_initialize_hashtbl(&ng->cgroups_htab);
pthread_mutex_init(&ng->cgroups_mutex, NULL);
}
if (-1 == (ret = gscgroup_parse_config_file(ngname, ng->vaddr))) {
ereport(LOG, (errmsg("Failed to parse cgroup config file for %s virtual cluster.", ngname)));
return -1;
}
if (!g_instance.wlm_cxt->gscgroup_init_done) {
ereport(LOG, (errmsg("Please mount Cgroup before mapping %s node group configuration.", ngname)));
return -1;
}
if (-1 == (ret = gscgroup_build_cgroups_htab(ng))) {
ereport(LOG, (errmsg("Failed to build cgroup hash table for %s virtual cluster.", ngname)));
return -1;
}
return 0;
}
Datum gs_cgroup_map_ng_conf(PG_FUNCTION_ARGS)
{
int ret = 0;
int i = 0;
const char* danger_character_list[] = {";", "`", "\\", "'", "\"", ">", "<", "$", "&", "|", "!", "\n", "/", "..", NULL};
char* ngname = PG_GETARG_CSTRING(0);
if (!superuser()) {
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("Only system admin user can use this function")));
}
if (NULL == ngname || *ngname == '\0') {
ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name of node group: NULL or \"\"")));
PG_RETURN_BOOL(false);
}
for (i = 0; danger_character_list[i] != NULL; i++) {
if (strstr((const char*)ngname, danger_character_list[i])) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Error: environment variable \"%s\" contain invaild symbol \"%s\".\n",
ngname, danger_character_list[i])));
}
}
if (!g_instance.wlm_cxt->gscgroup_init_done) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TRANSACTION_INITIATION),
errmsg("Cgroup is not mounted or enable_control_group is false")));
PG_RETURN_BOOL(false);
}
ret = gscgroup_map_ng_conf(ngname);
if (ret == -1) {
PG_RETURN_BOOL(false);
}
PG_RETURN_BOOL(true);
}
* function name: gscgroup_init
* description : init the cgroup and parse configuration file
*/
void gscgroup_init(void)
{
int ret = 0;
int i, j, bkd, sret;
char *relpath = NULL;
char *toppath = NULL;
char keyname[GPNAME_LEN] = {0};
char tmpname[GPNAME_LEN] = {0};
struct cgroup* cg = NULL;
ret = cgroup_init();
if (ret) {
ereport(WARNING, (errmsg("Cgroup initialization failed: %s", cgroup_strerror(ret))));
return;
}
if (-1 == (ret = gscgroup_parse_config_file(NULL, NULL))) {
ereport(LOG, (errmsg("Failed to parse cgroup config file.")));
return;
}
gscgroup_initialize_hashtbl(&g_instance.wlm_cxt->MyDefaultNodeGroup.cgroups_htab);
errno_t errval = memcpy_s(g_instance.wlm_cxt->MyDefaultNodeGroup.vaddr,
sizeof(g_instance.wlm_cxt->MyDefaultNodeGroup.vaddr),
g_instance.wlm_cxt->gscgroup_vaddr,
sizeof(g_instance.wlm_cxt->MyDefaultNodeGroup.vaddr));
securec_check_errval(errval, , LOG);
g_instance.wlm_cxt->gscgroup_cpucnt = gsutil_get_cpu_count();
relpath = gscgroup_get_relative_path(TOPCG_GAUSSDB, g_instance.wlm_cxt->gscgroup_vaddr);
if (relpath != NULL) {
g_instance.wlm_cxt->gscgroup_rootcg = gscgroup_get_cgroup(relpath);
free(relpath);
relpath = NULL;
}
for (i = CLASSCG_START_ID; i <= CLASSCG_END_ID; i++) {
if (g_instance.wlm_cxt->gscgroup_vaddr[i]->used) {
if (i == CLASSCG_START_ID) {
sret = snprintf_s(
tmpname, sizeof(tmpname), sizeof(tmpname) - 1, "%s:%d", GSCGROUP_TOP_WORKLOAD, WD_TOP_LEVEL);
securec_check_intval(sret, ,);
}
relpath = gscgroup_get_relative_path(i, g_instance.wlm_cxt->gscgroup_vaddr);
if (!relpath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname)));
return;
}
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
return;
}
(void)gscgroup_enter_hashtbl(
&g_instance.wlm_cxt->MyDefaultNodeGroup, g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname, cg);
free(relpath);
relpath = NULL;
for (j = WDCG_START_ID; j <= WDCG_END_ID; j++) {
if (g_instance.wlm_cxt->gscgroup_vaddr[j]->used &&
g_instance.wlm_cxt->gscgroup_vaddr[j]->ginfo.wd.cgid == i) {
relpath = gscgroup_get_relative_path(j, g_instance.wlm_cxt->gscgroup_vaddr);
if (!relpath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
g_instance.wlm_cxt->gscgroup_vaddr[j]->grpname)));
return;
}
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
return;
}
if (g_instance.wlm_cxt->gscgroup_deftopwdcg == NULL && *tmpname &&
0 == strcmp(g_instance.wlm_cxt->gscgroup_vaddr[j]->grpname, tmpname)) {
g_instance.wlm_cxt->gscgroup_deftopwdcg = cg;
}
sret = snprintf_s(keyname,
sizeof(keyname),
sizeof(keyname) - 1,
"%s:%s",
g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname,
g_instance.wlm_cxt->gscgroup_vaddr[j]->grpname);
securec_check_intval(sret, free(relpath), );
(void)gscgroup_enter_hashtbl(
&g_instance.wlm_cxt->MyDefaultNodeGroup, gscgroup_convert_cgroup(keyname), cg);
free(relpath);
relpath = NULL;
}
}
relpath = NULL;
toppath = gscgroup_get_topts_path(i, g_instance.wlm_cxt->gscgroup_vaddr);
if (!toppath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for Timeshare path of %s Group!",
g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname)));
return;
}
if (!(relpath = (char*)malloc(GPNAME_PATH_LEN))) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for timeshare path of %s Group!",
g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname)));
free(toppath);
toppath = NULL;
return;
}
for (j = TSCG_START_ID; j <= TSCG_END_ID; j++) {
sret = snprintf_s(relpath,
GPNAME_PATH_LEN,
GPNAME_PATH_LEN - 1,
"%s/%s",
toppath,
g_instance.wlm_cxt->gscgroup_vaddr[j]->grpname);
securec_check_intval(sret, free(relpath); free(toppath), );
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
free(toppath);
toppath = NULL;
return;
}
if (i == CLASSCG_START_ID &&
strcmp(g_instance.wlm_cxt->gscgroup_vaddr[j]->grpname, GSCGROUP_DEFAULT_CGNAME) == 0) {
g_instance.wlm_cxt->gscgroup_defwdcg = cg;
}
sret = snprintf_s(keyname,
sizeof(keyname),
sizeof(keyname) - 1,
"%s:%s",
g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname,
g_instance.wlm_cxt->gscgroup_vaddr[j]->grpname);
securec_check_intval(sret, free(relpath); free(toppath), );
(void)gscgroup_enter_hashtbl(
&g_instance.wlm_cxt->MyDefaultNodeGroup, gscgroup_convert_cgroup(keyname), cg);
}
free(relpath);
relpath = NULL;
free(toppath);
toppath = NULL;
}
}
bkd = BACKENDCG_START_ID;
relpath = gscgroup_get_relative_path(bkd, g_instance.wlm_cxt->gscgroup_vaddr);
if (!relpath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
g_instance.wlm_cxt->gscgroup_vaddr[bkd]->grpname)));
return;
}
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
return;
}
free(relpath);
relpath = NULL;
g_instance.wlm_cxt->gscgroup_bkdcg = cg;
if (g_instance.attr.attr_resource.enable_vacuum_control) {
for (i = BACKENDCG_START_ID; i <= BACKENDCG_END_ID; ++i) {
if (g_instance.wlm_cxt->gscgroup_vaddr[i]->used == 0) {
continue;
}
if (0 == strcmp(g_instance.wlm_cxt->gscgroup_vaddr[i]->grpname, GSCGROUP_VACUUM)) {
bkd = i;
break;
}
}
relpath = gscgroup_get_relative_path(bkd, g_instance.wlm_cxt->gscgroup_vaddr);
if (relpath == NULL) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
g_instance.wlm_cxt->gscgroup_vaddr[bkd]->grpname)));
return;
}
ereport(DEBUG1, (errmsg("vacuum group path: %s", relpath)));
if ((cg = gscgroup_get_cgroup(relpath)) == NULL) {
free(relpath);
relpath = NULL;
return;
}
free(relpath);
relpath = NULL;
g_instance.wlm_cxt->gscgroup_vaccg = cg;
} else {
g_instance.wlm_cxt->gscgroup_vaccg = g_instance.wlm_cxt->gscgroup_bkdcg;
}
g_instance.wlm_cxt->gscgroup_config_parsed = 1;
if (u_sess->attr.attr_resource.use_workload_manager && u_sess->attr.attr_resource.enable_control_group) {
g_instance.wlm_cxt->gscgroup_init_done = 1;
}
}
* function name: gscgroup_attach_backend_task
* description : attach backend thread into the specified Cgroup
*/
int gscgroup_attach_backend_task(const char* gname, bool is_noexcept)
{
int ret;
struct cgroup* cg = NULL;
if (g_instance.wlm_cxt->gscgroup_vaddr[0] == NULL || gname == NULL || '\0' == *gname) {
return 0;
}
if (0 == strcmp(gname, GSCGROUP_DEFAULT_BACKEND)) {
cg = g_instance.wlm_cxt->gscgroup_bkdcg;
} else if (0 == strcmp(gname, GSCGROUP_VACUUM)) {
cg = g_instance.wlm_cxt->gscgroup_vaccg;
} else if (0 == strcmp(gname, GSCGROUP_TOP_DATABASE)) {
cg = g_instance.wlm_cxt->gscgroup_rootcg;
}
if (cg == NULL) {
return 0;
}
ret = cgroup_attach_task(cg);
if (ret != 0 && !is_noexcept) {
ereport(WARNING,
(errmsg("Cgroup failed to attach (tid %d) "
"into \"%s\" group: %s(%d)",
gettid(),
gname,
cgroup_strerror(ret),
ret)));
}
return ret;
}
* function name: gscgroup_attach_task
* description : attach current query thread into the specified Cgroup
*/
void gscgroup_attach_task(WLMNodeGroupInfo* ng, const char* gname)
{
int ret;
struct cgroup* cg = NULL;
cg = gscgroup_lookup_cgroup(ng, gname);
gscgroup_curwd = cg;
ret = cgroup_attach_task(cg);
if (ret != 0) {
ereport(WARNING, (errmsg("Cgroup failed to attach (tid %d) into \"%s\" group: %s(%d)",
gettid(), gname, cgroup_strerror(ret), ret),
errhint("Maybe the path of Cgroup \"%s\" has been changed or removed.", gname)));
}
u_sess->wlm_cxt->cgroup_state = CG_USING;
}
* function name: gscgroup_attach_task_batch
* description : attach query threads into a group
* arguments :
* _in_ gname: group name
* _in_ tid: thread pid
* __inout is_first: a flag, it must be set 1 as first flag
* return value : -1: attach failed
* 0 : attach success
*/
int gscgroup_attach_task_batch(WLMNodeGroupInfo* ng, const char* gname, pid_t tid, int* is_first)
{
static THR_LOCAL struct cgroup* cg = NULL;
int ret = 0;
* Is it first time to attach this group? If yes, we need
* get the cgroup info with group name from the group hash
* table. If not, we will use the last cgroup info to attach.
*/
if (*is_first > 0) {
cg = gscgroup_lookup_cgroup(ng, gname);
*is_first = 0;
}
* We must check the cgroup info whether is valid,
* because 'is_first' maybe is not a correct value
* first time.
*/
if (!cg) {
return -1;
}
ret = cgroup_attach_task_pid(cg, tid);
if (ret != 0) {
ereport(WARNING,
(errmsg("Cgroup failed to attach (tid %d) "
"into \"%s\" group: %s(%d)",
tid,
gname,
cgroup_strerror(ret),
ret)));
}
return ret;
}
* function name: gscgroup_switch_topwd
* description : attach current query thread into topwd Cgroup
*/
void gscgroup_switch_topwd(WLMNodeGroupInfo* ng)
{
int ret;
(void)gscgroup_lookup_cgroup(ng, u_sess->wlm_cxt->control_group);
ret = cgroup_attach_task(gscgroup_topwd);
if (ret != 0) {
ereport(WARNING,
(errmsg("Cgroup failed to attach (tid %d) "
"into \"%s\" group: %s(%d)",
gettid(),
GSCGROUP_TOP_WORKLOAD,
cgroup_strerror(ret),
ret)));
} else {
ereport(LOG,
(errmsg("Switch cgroup from \"%s\" to \"%s\"", u_sess->wlm_cxt->control_group, GSCGROUP_TOP_WORKLOAD)));
}
u_sess->wlm_cxt->cgroup_state = CG_USING;
}
* function name: gscgroup_switch_curwd
* description : attach current query thread into current Cgroup
*/
void gscgroup_switch_vacuum(void)
{
int ret = 0;
if (g_instance.wlm_cxt->gscgroup_vaddr[0] == NULL || g_instance.wlm_cxt->gscgroup_vaccg == NULL) {
return;
}
ret = cgroup_attach_task(g_instance.wlm_cxt->gscgroup_vaccg);
if (ret != 0) {
ereport(WARNING,
(errmsg("Cgroup failed to attach (tid %d) "
"into \"%s\" group: %s(%d)",
gettid(),
GSCGROUP_VACUUM,
cgroup_strerror(ret),
ret)));
}
ereport(LOG, (errmsg("Switch cgroup from \"%s\" to \"%s\"", u_sess->wlm_cxt->control_group, GSCGROUP_VACUUM)));
u_sess->wlm_cxt->cgroup_state = CG_USING;
}
* function name: gscgroup_get_next_group
* description : get the next timeshare group, like this:
* Medium -> Low, High -> Medium
*/
int gscgroup_get_next_group(WLMNodeGroupInfo* ng, char* gname)
{
char *p = NULL;
char *q = NULL;
char *name = NULL;
int cls, wd, sret;
if (g_instance.wlm_cxt->gscgroup_init_done <= 0) {
return -1;
}
if (0 == strcmp(gname, GSCGROUP_DEFAULT_CGNAME)) {
sret = snprintf_s(gname, NAMEDATALEN, NAMEDATALEN - 1, "%s", GSCGROUP_LOW_TIMESHARE);
securec_check_intval(sret, , 1);
return 1;
}
q = name = pstrdup(gname);
p = strchr(q, ':');
if (!p) {
if (-1 != (wd = gscgroup_is_timeshare(q))) {
int i = 0;
pfree(name);
for (i = wd - 1; i >= TSCG_START_ID; --i) {
if (StringIsValid(ng->vaddr[i]->grpname)) {
sret = snprintf_s(gname, NAMEDATALEN, NAMEDATALEN - 1, "%s", ng->vaddr[i]->grpname);
securec_check_intval(sret, , 1);
return 1;
}
}
return 0;
}
return -1;
}
*p++ = '\0';
if (-1 == (cls = gscgroup_is_class(ng, q))) {
ereport(WARNING, (errmsg("%s cgroup has been delete from OS. ", gname)));
pfree(name);
return -1;
}
if (-1 != (wd = gscgroup_is_timeshare(p))) {
int i = 0;
pfree(name);
for (i = wd - 1; i >= TSCG_START_ID; --i) {
if (StringIsValid(ng->vaddr[i]->grpname)) {
sret = snprintf_s(
gname, NAMEDATALEN, NAMEDATALEN - 1, "%s:%s", ng->vaddr[cls]->grpname, ng->vaddr[i]->grpname);
securec_check_intval(sret, , 1);
return 1;
}
}
return 0;
}
pfree(name);
return -1;
}
* function name: gscgroup_get_top_group_name
* description : get the top workload group name
*/
char* gscgroup_get_top_group_name(WLMNodeGroupInfo* ng, char* gname, int len)
{
char *p = NULL;
char *q = NULL;
char name[NAMEDATALEN];
int sret;
if (!StringIsValid(gname)) {
return NULL;
}
sret = snprintf_s(name, sizeof(name), sizeof(name) - 1, "%s", gname);
securec_check_intval(sret, , NULL);
q = name;
p = strchr(q, ':');
if (!p) {
sret = snprintf_s(gname, len, len - 1, "%s:%s", GSCGROUP_DEFAULT_CLASS, GSCGROUP_TOP_WORKLOAD);
securec_check_intval(sret, , gname);
return gname;
}
*p++ = '\0';
if (-1 == gscgroup_is_class(ng, q)) {
ereport(LOG, (errmsg("%s cgroup has been delete from OS. ", gname)));
return NULL;
}
sret = snprintf_s(gname, len, len - 1, "%s:%s", q, GSCGROUP_TOP_WORKLOAD);
securec_check_intval(sret, , gname);
return gname;
}
* pg_control_group_config: print the cgroup config on current node
*/
Datum pg_control_group_config(PG_FUNCTION_ARGS)
{
if (!superuser()) {
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
"pg_control_group_config");
}
char* config = gscgroup_print();
text* result_config = cstring_to_text(config);
pfree_ext(config);
PG_RETURN_TEXT_P(result_config);
}
* function name: gscgroup_check_group_name
* description : check if the group name has been set
* arguments : control group name
* return value : -1: abnormal value
* 0: normal value
* 1: need handle as a parent resource pool
*/
int gscgroup_check_group_name(WLMNodeGroupInfo* ng, const char* gname)
{
char *p = NULL;
char *q = NULL;
char *name = NULL;
char *r = NULL;
int cls, wd, sret;
if (g_instance.wlm_cxt->gscgroup_config_parsed == 0 || !StringIsValid(gname)) {
sret = snprintf_s(u_sess->wlm_cxt->group_keyname,
sizeof(u_sess->wlm_cxt->group_keyname),
sizeof(u_sess->wlm_cxt->group_keyname) - 1,
"%s",
GSCGROUP_INVALID_GROUP);
securec_check_intval(sret, , -1);
return -1;
}
q = name = pstrdup(gname);
if (q == NULL) {
return -1;
}
p = strchr(q, ':');
if (!p) {
if (-1 != gscgroup_is_timeshare(q)) {
sret = snprintf_s(u_sess->wlm_cxt->group_keyname,
sizeof(u_sess->wlm_cxt->group_keyname),
sizeof(u_sess->wlm_cxt->group_keyname) - 1,
"%s:%s",
GSCGROUP_DEFAULT_CLASS,
q);
securec_check_intval(sret, pfree(name), -1);
pfree(name);
return 0;
}
if (-1 != gscgroup_is_class(ng, q)) {
sret = snprintf_s(u_sess->wlm_cxt->group_keyname,
sizeof(u_sess->wlm_cxt->group_keyname),
sizeof(u_sess->wlm_cxt->group_keyname) - 1,
"%s:%s",
q,
GSCGROUP_MEDIUM_TIMESHARE);
securec_check_intval(sret, pfree(name), -1);
pfree(name);
return 1;
}
sret = snprintf_s(u_sess->wlm_cxt->group_keyname,
sizeof(u_sess->wlm_cxt->group_keyname),
sizeof(u_sess->wlm_cxt->group_keyname) - 1,
"%s",
GSCGROUP_INVALID_GROUP);
securec_check_intval(sret, pfree(name), -1);
ereport(LOG, (errmsg("%s isn't the name of timeshare group!", gname)));
pfree(name);
return -1;
}
*p++ = '\0';
if (-1 == (cls = gscgroup_is_class(ng, q))) {
sret = snprintf_s(u_sess->wlm_cxt->group_keyname,
sizeof(u_sess->wlm_cxt->group_keyname),
sizeof(u_sess->wlm_cxt->group_keyname) - 1,
"%s",
GSCGROUP_INVALID_GROUP);
securec_check_intval(sret, pfree(name), -1);
ereport(LOG, (errmsg("%s in %s isn't the name of class group!", q, gname)));
pfree(name);
return -1;
}
r = strchr((char*)p, ':');
if (r != NULL) {
*r++ = '\0';
}
if (-1 != (wd = gscgroup_is_timeshare(p)) ||
(-1 != (wd = gscgroup_is_workload(ng, cls, p)) && (r == NULL || (-1 != gscgroup_check_level(cls, r))))) {
sret = snprintf_s(u_sess->wlm_cxt->group_keyname,
sizeof(u_sess->wlm_cxt->group_keyname),
sizeof(u_sess->wlm_cxt->group_keyname) - 1,
"%s:%s",
q,
p);
securec_check_intval(sret, pfree(name), -1);
pfree(name);
return 0;
}
sret = snprintf_s(u_sess->wlm_cxt->group_keyname,
sizeof(u_sess->wlm_cxt->group_keyname),
sizeof(u_sess->wlm_cxt->group_keyname) - 1,
"%s",
GSCGROUP_INVALID_GROUP);
securec_check_intval(sret, pfree(name), -1);
ereport(LOG,
(errmsg("%s in %s isn't the name of timeshare group "
"or workload group!",
p,
gname)));
pfree(name);
return -1;
}
* function name: gscgroup_get_percent
* description : retrieve the percentage value based on the control group
* return value :
* -1: abnormal value
* other: normal value
*/
int gscgroup_get_percent(WLMNodeGroupInfo* ng, const char* gname)
{
char *p = NULL;
char *q = NULL;
char *name = NULL;
int cls, wd, pct;
if (g_instance.wlm_cxt->gscgroup_init_done == 0 || !StringIsValid(gname) || !CGroupIsValid(gname)) {
return -1;
}
q = name = pstrdup(gname);
p = strchr(q, ':');
if (!p) {
cls = CLASSCG_START_ID;
if (-1 != (wd = gscgroup_is_timeshare(name))) {
pct = ng->vaddr[cls]->percent * ng->vaddr[wd]->ginfo.ts.rate / TS_ALL_RATE;
pfree(name);
return pct;
}
return -1;
}
*p++ = '\0';
if (-1 == (cls = gscgroup_is_class(ng, q))) {
pfree(name);
return -1;
}
if (-1 != (wd = gscgroup_is_timeshare(p))) {
pct = ng->vaddr[cls]->ginfo.cls.rempct * ng->vaddr[cls]->percent * ng->vaddr[wd]->ginfo.ts.rate /
(GROUP_ALL_PERCENT * TS_ALL_RATE);
pfree(name);
return pct;
}
if (-1 != (wd = gscgroup_is_workload(ng, cls, p))) {
pfree(name);
return ng->vaddr[wd]->percent;
}
pfree(name);
return -1;
}
* function name: gscgroup_get_grpconf
* description : retrieve the group configuration information based on gname string
* return value :
* NULL: abnormal value
* other: normal value
*/
gscgroup_grp_t* gscgroup_get_grpconf(WLMNodeGroupInfo* ng, const char* gname)
{
char *p = NULL;
char *q = NULL;
char name[NAMEDATALEN];
int cls, wd;
if (g_instance.wlm_cxt->gscgroup_init_done <= 0 || !StringIsValid(gname)) {
return NULL;
}
errno_t rc = strcpy_s(name, sizeof(name), gname);
securec_check(rc, "\0", "\0");
q = name;
p = strchr(q, ':');
if (!p) {
return (gscgroup_is_timeshare(name) != -1) ? ng->vaddr[CLASSCG_START_ID] : NULL;
}
*p++ = '\0';
if (-1 == (cls = gscgroup_is_class(ng, q))) {
return NULL;
}
if (-1 != (wd = gscgroup_is_timeshare(p))) {
return ng->vaddr[cls];
}
if (-1 != (wd = gscgroup_is_workload(ng, cls, p))) {
return ng->vaddr[wd];
}
return NULL;
}
* function name: gscgroup_get_timeshare_relpath
* description : get relative path for the timeshare group
* arguments :
* _in_ cls: class id
* _in_ wd: workload group id
* _out_ relpath: the relative path
* return value : relative path
*/
char* gscgroup_get_timeshare_relpath(WLMNodeGroupInfo* ng, int cls, int wd, char* relpath)
{
int sret;
char* toppath = NULL;
toppath = gscgroup_get_topts_path(cls, ng->vaddr, ng->group_name);
if (!toppath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for Timeshare path of %s Group!",
ng->vaddr[cls]->grpname)));
return NULL;
}
sret = snprintf_s(relpath, GPNAME_PATH_LEN, GPNAME_PATH_LEN - 1, "%s/%s", toppath, ng->vaddr[wd]->grpname);
securec_check_intval(sret, free(toppath), NULL);
free(toppath);
toppath = NULL;
return relpath;
}
* function name: gscgroup_get_workload_relpath
* description : get relative path for the workload group
* arguments :
* _in_ wd: workload group id
_out_ relpath: the relative path
* return value : relative path
*/
char* gscgroup_get_workload_relpath(WLMNodeGroupInfo* ng, int wd, char* relpath)
{
int sret;
char* tmppath = gscgroup_get_relative_path(wd, ng->vaddr, ng->group_name);
if (tmppath == NULL) {
return NULL;
}
sret = snprintf_s(relpath, GPNAME_PATH_LEN, GPNAME_PATH_LEN - 1, "%s", tmppath);
securec_check_intval(sret, free(tmppath), NULL);
free(tmppath);
tmppath = NULL;
return relpath;
}
* function name: gscgroup_get_cgroup_relpath
* description : get relative path for the control group
* arguments :
* _in_ cgname: group name
* _out_ relpath: the relative path
* return value : relative path
*/
char* gscgroup_get_cgroup_relpath(WLMNodeGroupInfo* ng, const char* cgname, char* relpath)
{
char *p = NULL;
char *q = NULL;
char name[GPNAME_LEN];
int cls, wd, sret;
sret = snprintf_s(name, sizeof(name), sizeof(name) - 1, "%s", cgname);
securec_check_intval(sret, , NULL);
q = name;
if ((p = strchr(q, ':')) == NULL) {
if ((cls = gscgroup_is_class(ng, q)) == -1) {
return NULL;
}
return gscgroup_get_workload_relpath(ng, cls, relpath);
}
*p++ = '\0';
if ((cls = gscgroup_is_class(ng, q)) == -1) {
return NULL;
}
if ((wd = gscgroup_is_timeshare(p)) != -1) {
return gscgroup_get_timeshare_relpath(ng, cls, wd, relpath);
} else if ((wd = gscgroup_is_workload(ng, cls, p)) != -1) {
return gscgroup_get_workload_relpath(ng, wd, relpath);
}
return NULL;
}
* function name: gscgroup_check_and_update_entry
* description : check and update relative path for the control group
* in the group hash table
* arguments :
* _in_ entry: group entry info
* return value : void
*/
void gscgroup_check_and_update_entry(WLMNodeGroupInfo* ng, gscgroup_entry_t* entry)
{
char relpath[GPNAME_PATH_LEN] = {0};
char* path = NULL;
if (gscgroup_get_cgroup_relpath(ng, entry->name, relpath) == NULL) {
ereport(DEBUG1, (errmsg("Cannot find the relative path for the group \"%s\"", entry->name)));
return;
}
if ((path = gsutil_get_cgroup_name(entry->cg)) == NULL) {
ereport(LOG, (errmsg("Cannot get current cgroup relpath.")));
return;
}
if (strcmp(relpath, path) != 0) {
struct cgroup* cg = NULL;
if ((cg = gscgroup_get_cgroup(relpath)) == NULL) {
return;
}
ereport(DEBUG2, (errmsg("change group \'%s\' relpath to %s", entry->name, relpath)));
if (entry->oldcg) {
cgroup_free(&entry->oldcg);
}
entry->oldcg = entry->cg;
entry->cg = cg;
}
return;
}
* @Description: get cpu jiffies from the file "/proc/stat"
* @IN: cpu_count_down: need collect cpustat.
* cpustat is collected every 8 seconds,
* and checking 'cpu' total jiffies and 'user' jiffies are needed for iostat.
* iostat is collected every second,
* and checking 'cpu0' total jiffies is enough for iostat.
* @Return: void
* @See also:
*/
uint64 gscgroup_read_stat_cpu(void)
{
errno_t rc;
FILE* cpufp = NULL;
char line[8192];
uint64 cpu_user, cpu_nice, cpu_sys, cpu_idle, cpu_iowait, cpu_hardirq;
uint64 cpu_softirq, cpu_steal, cpu_guest, cpu_guest_nice;
uint64 all = 0;
if ((cpufp = fopen("/proc/stat", "r")) == NULL) {
ereport(LOG, (errmsg("cannot open file: %s \n", FILE_CPUSTAT)));
return -1;
}
while (fgets(line, sizeof(line), cpufp) != NULL) {
if (strncmp(line, "cpu ", 4) == 0) {
rc = sscanf_s(line + 5,
"%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&cpu_user,
&cpu_nice,
&cpu_sys,
&cpu_idle,
&cpu_iowait,
&cpu_hardirq,
&cpu_softirq,
&cpu_steal,
&cpu_guest,
&cpu_guest_nice);
if (rc != 10) {
fprintf(stderr,
"%s:%d failed on calling "
"security function.\n",
__FILE__,
__LINE__);
fclose(cpufp);
return -1;
}
all = cpu_user + cpu_nice + cpu_sys + cpu_idle + cpu_iowait + cpu_hardirq + cpu_steal + cpu_softirq;
break;
}
}
fclose(cpufp);
return all;
}
* @Description: udpate cpu info for a cgroup.
* @OUT entry: cgroup entry
* @Return: void
* @See also:
*/
void gscgroup_get_cpuinfo(gscgroup_entry_t* entry)
{
int setcnt = 0;
int64 usage = 0;
int64 usageAcct = 0;
long secs;
int usecs;
int sleeptime = 1;
TimestampTz stop_time = GetCurrentTimestamp();
if (entry->lastTime) {
TimestampDifference(entry->lastTime, stop_time, &secs, &usecs);
sleeptime = secs * 1000 + usecs / 1000 + 1;
}
if (gscgroup_get_cgroup_cpuinfo(entry->cg, &setcnt, &usage) == -1) {
return;
}
if (setcnt > 0 && entry->lastTime) {
entry->cpuCount = setcnt;
usageAcct = usage - entry->cpuLastAcct;
if (usageAcct >= 0) {
entry->cpuUsedAcct = usageAcct;
} else {
entry->cpuUsedAcct = 0;
ereport(LOG, (errmsg("Cgroup %s is probably reset, please check if it is avalaible.", entry->name)));
}
entry->usedCpuCount = entry->cpuUsedAcct * 1000 / sleeptime * GROUP_ALL_PERCENT / NANOSECS_PER_SEC;
entry->cpuUtil = entry->usedCpuCount * GROUP_ALL_PERCENT / entry->cpuCount;
}
entry->lastTime = stop_time;
entry->cpuLastAcct = usage;
ereport(DEBUG3,
(errmsg("group name: %s, setcnt: %d, usage %ld, cpuUsedAcct: %ld, usedCpuCount: %d, cpuUtil: %d, "
"cpuLastAcct: %ld",
entry->name,
setcnt,
usage,
entry->cpuUsedAcct,
entry->usedCpuCount,
entry->cpuUtil,
entry->cpuLastAcct)));
}
* function name: gscgroup_update_hashtbl_cpuinfo
* description : check and update relative path for the control group
* arguments : void
* return value : void
*/
void gscgroup_update_hashtbl_cpuinfo(WLMNodeGroupInfo* ng)
{
gscgroup_entry_t* entry = NULL;
HASH_SEQ_STATUS hash_seq;
hash_seq_init(&hash_seq, ng->cgroups_htab);
while ((entry = (gscgroup_entry_t*)hash_seq_search(&hash_seq)) != NULL) {
gscgroup_check_and_update_entry(ng, entry);
if (IS_PGXC_DATANODE) {
gscgroup_get_cpuinfo(entry);
}
}
}
* function name: gscgroup_get_cpu_usage_percent
* description : get cpu usage percent
* arguments :
* _in_ gname: group name
* return value : cpu usage percent
*/
int gscgroup_get_cpu_usage_percent(WLMNodeGroupInfo* ng, const char* gname)
{
gscgroup_entry_t* cgentry = NULL;
if (!CGroupIsValid(gname) || (cgentry = gscgroup_lookup_hashtbl(ng, gname)) == NULL) {
return -1;
}
ereport(DEBUG2, (errmsg("usagepct: %d, setcnt: %d", cgentry->cpuUtil, cgentry->cpuCount)));
return (GROUP_ALL_PERCENT - cgentry->cpuUtil) * cgentry->cpuCount / GROUP_ALL_PERCENT;
}
* function name: gscgroup_update_hashtbl
* description : update cgroup info in the hash table
* return value : void
*/
void gscgroup_update_hashtbl(WLMNodeGroupInfo* ng, const char* keyname)
{
int cls, wd, sret;
char *relpath = NULL;
char *p = NULL;
char *q = NULL;
char tmpname[GPNAME_LEN] = {0};
struct cgroup* cg = NULL;
gscgroup_entry_t* cgentry = NULL;
if (!CGroupIsValid(keyname) || (cgentry = gscgroup_lookup_hashtbl(ng, keyname)) != NULL) {
return;
}
errno_t rc = strcpy_s(tmpname, sizeof(tmpname), keyname);
securec_check(rc, "\0", "\0");
q = tmpname;
p = strchr(q, ':');
if (!p) {
if (-1 == (cls = gscgroup_is_class(ng, q))) {
return;
}
relpath = gscgroup_get_relative_path(cls, ng->vaddr, ng->group_name);
if (!relpath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
g_instance.wlm_cxt->gscgroup_vaddr[cls]->grpname)));
return;
}
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
return;
}
(void)gscgroup_enter_hashtbl(ng, keyname, cg);
free(relpath);
relpath = NULL;
return;
}
*p++ = '\0';
if (-1 == (cls = gscgroup_is_class(ng, q))) {
return;
}
if (-1 != (wd = gscgroup_is_timeshare(p))) {
relpath = NULL;
char* toppath = gscgroup_get_topts_path(cls, ng->vaddr, ng->group_name);
if (!toppath) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for Timeshare path of %s Group!",
ng->vaddr[cls]->grpname)));
return;
}
if (!(relpath = (char*)malloc(GPNAME_PATH_LEN))) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for timeshare path of %s Group!",
ng->vaddr[cls]->grpname)));
free(toppath);
toppath = NULL;
return;
}
sret = snprintf_s(relpath, GPNAME_PATH_LEN, GPNAME_PATH_LEN - 1, "%s/%s", toppath, ng->vaddr[wd]->grpname);
securec_check_intval(sret, free(relpath); free(toppath),);
free(toppath);
toppath = NULL;
if (!(cg = gscgroup_get_cgroup(relpath))) {
free(relpath);
relpath = NULL;
return;
}
} else if (-1 != (wd = gscgroup_is_workload(ng, cls, p))) {
if ((relpath = gscgroup_get_relative_path(wd, ng->vaddr, ng->group_name)) == NULL) {
ereport(LOG,
(errmsg("Failed to allocate memory "
"for relative path of %s Group!",
ng->vaddr[wd]->grpname)));
return;
}
if ((cg = gscgroup_get_cgroup(relpath)) == NULL) {
free(relpath);
relpath = NULL;
return;
}
}
if (strncmp(p, GSCGROUP_TOP_WORKLOAD, sizeof(GSCGROUP_TOP_WORKLOAD) - 1) != 0) {
sret = snprintf_s(tmpname,
sizeof(tmpname),
sizeof(tmpname) - 1,
"%s:%s:%d",
ng->vaddr[cls]->grpname,
GSCGROUP_TOP_WORKLOAD,
WD_TOP_LEVEL);
securec_check_intval(sret, free(relpath), );
gscgroup_update_hashtbl(ng, tmpname);
}
(void)gscgroup_enter_hashtbl(ng, keyname, cg);
free(relpath);
relpath = NULL;
}
* @Description: get cgroup info internal.
* @IN cg: cgroup
* @OUT info: cgroup info, include cpu shares, cpuset, cpu account
* @Return: cgroup info
* @See also:
*/
gscgroup_info_t* gscgroup_get_cgroup_info_internal(struct cgroup* cg, gscgroup_info_t* info)
{
struct cgroup_controller* cgc = NULL;
struct cgroup_controller* cgc_set = NULL;
struct cgroup_controller* cgc_acct = NULL;
char* cpuset = NULL;
int64 usage;
int64 shares;
const int ret = 0;
errno_t sret;
char* relpath = gsutil_get_cgroup_name(cg);
if (relpath == NULL) {
return info;
}
struct cgroup* new_cg = cgroup_new_cgroup(relpath);
if (new_cg == NULL) {
return info;
}
if (cgroup_get_cgroup(new_cg) != 0) {
ereport(LOG,
(errmsg("get cgroup failed. errno: %d, "
"reason: %s",
ret,
cgroup_strerror(ret))));
cgroup_free(&new_cg);
return info;
}
if ((cgc = cgroup_get_controller(new_cg, MOUNT_CPU_NAME)) != NULL &&
(cgroup_get_value_int64(cgc, CPU_SHARES, &shares) == 0)) {
info->shares = shares;
}
if ((cgc_set = cgroup_get_controller(new_cg, MOUNT_CPUSET_NAME)) != NULL &&
(cgroup_get_value_string(cgc_set, CPUSET_CPUS, &cpuset) == 0)) {
sret = snprintf_s(info->cpuset, sizeof(info->cpuset), sizeof(info->cpuset) - 1, "%s", cpuset);
if (cpuset != NULL) {
free(cpuset);
cpuset = NULL;
}
securec_check_intval(sret, cgroup_free(&new_cg), info);
}
if ((cgc_acct = cgroup_get_controller(new_cg, MOUNT_CPUACCT_NAME)) != NULL &&
(cgroup_get_value_int64(cgc_acct, CPUACCT_USAGE, &usage) == 0)) {
info->entry.cpuUsedAcct = usage;
}
cgroup_free(&new_cg);
return info;
}
* @Description: get cgroup info
* @OUT num: count of cgroup info
* @Return: cgroup info
* @See also:
*/
gscgroup_info_t* gscgroup_get_cgroup_info(int* num)
{
gscgroup_info_t* info_list = NULL;
gscgroup_entry_t* entry = NULL;
HASH_SEQ_STATUS hash_seq;
int i = 0;
int sret;
if (g_instance.wlm_cxt->gscgroup_init_done <= 0) {
ereport(WARNING, (errmsg("There is no Cgroup information for without initialization!")));
return NULL;
}
WLMNodeGroupInfo* ng = &g_instance.wlm_cxt->MyDefaultNodeGroup;
USE_AUTO_LWLOCK(WorkloadCGroupHashLock, LW_SHARED);
if ((*num = hash_get_num_entries(ng->cgroups_htab)) <= 0) {
return NULL;
}
info_list = (gscgroup_info_t*)palloc0(*num * sizeof(gscgroup_info_t));
hash_seq_init(&hash_seq, ng->cgroups_htab);
while ((entry = (gscgroup_entry_t*)hash_seq_search(&hash_seq)) != NULL) {
gscgroup_info_t* info = info_list + i;
info->valid = true;
(void)gscgroup_get_cgroup_info_internal(entry->cg, info);
info->entry.percent = gscgroup_get_percent(ng, entry->name);
info->entry.cpuUtil = entry->cpuUtil;
sret = snprintf_s(info->entry.name, sizeof(info->entry.name), sizeof(info->entry.name) - 1, "%s", entry->name);
securec_check_intval(sret, pfree(info_list), NULL);
sret = snprintf_s(
info->relpath, sizeof(info->relpath), sizeof(info->relpath) - 1, "%s", gsutil_get_cgroup_name(entry->cg));
securec_check_intval(sret, pfree(info_list), NULL);
if (info->entry.percent < 0 || info->shares == 0) {
info->valid = false;
}
sret = snprintf_s(info->nodegroup, sizeof(info->nodegroup), sizeof(info->nodegroup) - 1, "%s", ng->group_name);
securec_check_intval(sret, pfree(info_list), NULL);
++i;
}
*num = i;
return info_list;
}
* @Description: check whether the parent_group and the child_group share the same class or not.
* @IN cgroup1: left cgroup
* @IN cgroup2: right cgroup
* @Return: whether is in a same class
* @See also:
*/
bool gscgroup_is_brother_group(const char* cgroup1, const char* cgroup2)
{
const char* p = NULL;
const char* q = NULL;
p = strchr(cgroup1, ':');
q = strchr(cgroup2, ':');
if ((p == NULL) && (q == NULL)) {
return strcmp(cgroup1, cgroup2) == 0;
}
if ((q == NULL) || (p == NULL)) {
return false;
}
if (p - cgroup1 != q - cgroup2) {
return false;
}
return strncmp(cgroup1, cgroup2, p - cgroup1) == 0;
}
* @Description: check whether the parent_group and the child_group share the same class or not.
* @IN parentcg: parent cgroup
* @IN childcg: child cgroup
* @Return: whether is in a same class
* @See also:
*/
bool gscgroup_is_child_group(const char* parentcg, const char* childcg)
{
const char* q = NULL;
if ((strchr(parentcg, ':') != NULL) || ((q = strchr(childcg, ':')) == NULL)) {
return false;
}
if ((int)strlen(parentcg) != q - childcg) {
return false;
}
return strncmp(parentcg, childcg, q - childcg) == 0;
}
* @Description: remove level info of the cgroup name
* @IN gname: group name
* @Return: new group name
* @See also:
*/
char* gscgroup_convert_cgroup(char* gname)
{
char* p = strchr(gname, ':');
char* q = strrchr(gname, ':');
if (p != q) {
*q = '\0';
}
return gname;
}