Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Process group API (shared between ndrxd and cpmsrv)
0003  *  Use standard errors here?
0004  *
0005  * @file procgroups.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 #include <string.h>
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <libgen.h>
0039 #include <memory.h>
0040 #include <libxml/xmlreader.h>
0041 #include <errno.h>
0042 
0043 #include <ndrstandard.h>
0044 #include <ndebug.h>
0045 #include <utlist.h>
0046 #include <nstdutil.h>
0047 #include <exenv.h>
0048 #include <libndrxconf.h>
0049 #include <lcfint.h>
0050 #include <ndrxdcmn.h>
0051 #include <ndrx_intdef.h>
0052 #include <exhash.h>
0053 #include <singlegrp.h>
0054 /*---------------------------Externs------------------------------------*/
0055 /*---------------------------Macros-------------------------------------*/
0056 /*---------------------------Enums--------------------------------------*/
0057 /*---------------------------Typedefs-----------------------------------*/
0058 /*---------------------------Globals------------------------------------*/
0059 /*---------------------------Statics------------------------------------*/
0060 /*---------------------------Prototypes---------------------------------*/
0061 
0062 /**
0063  * Desceing sort of the node array
0064  */
0065 exprivate int compare_descending(const void *a, const void *b)
0066 {
0067     char *aa = (char *)a;
0068     char *bb = (char *)b;
0069 
0070     if (*aa > *bb)
0071     {
0072         return -1;
0073     }
0074     else if (*aa < *bb)
0075     {
0076         return 1;
0077     }
0078     else
0079     {
0080         return 0;
0081     }
0082 }
0083 
0084 /**
0085  * Parse process group
0086  * @param config config
0087  * @param doc xml doc
0088  * @param cur current node
0089  * @param is_defaults is defaults section
0090  * @param p_defaults defaults
0091  * @param config_file_short config file name (xml)
0092  * @param err error structure. Contains error codes from the ndrxdcmn.h
0093  * @return EXSUCCEED/EXSUCCEED
0094  */
0095 expublic int ndrx_appconfig_procgroup(ndrx_procgroups_t **config, 
0096     xmlDocPtr doc, xmlNodePtr cur, int is_defaults, ndrx_procgroup_t *p_defaults, 
0097     char *config_file_short, ndrx_ndrxconf_err_t *err)
0098 {
0099     int ret=EXSUCCEED;
0100     xmlAttrPtr attr;
0101     ndrx_procgroup_t *p_grp=NULL;
0102     ndrx_procgroup_t local;
0103     char *p;
0104     char tmp[PATH_MAX+1];
0105     
0106     /* service shall not be defined */
0107     if (is_defaults)
0108     {
0109         p_grp=p_defaults;
0110     }
0111     else
0112     {
0113         p_grp = &local;
0114         memcpy(p_grp, p_defaults, sizeof(ndrx_procgroup_t));
0115     }
0116     
0117     for (attr=cur->properties; attr; attr = attr->next)
0118     {
0119         p = (char *)xmlNodeGetContent(attr->children);
0120         
0121         if (0==strcmp((char *)attr->name, "name"))
0122         {
0123             int len = strlen(p);
0124 
0125             if (len>MAXTIDENT || len < 1)
0126             {
0127                 snprintf(err->error_msg, sizeof(err->error_msg),
0128                     "(%s) invalid length %d for `name' attribute at <procgroup> near line %d", 
0129                     config_file_short, len, cur->line);
0130                 err->error_code = NDRXD_EINVAL;
0131                 NDRX_LOG(log_error, "%s", err->error_msg);
0132                 xmlFree(p);
0133                 EXFAIL_OUT(ret);
0134             }
0135 
0136             if (!ndrx_str_valid_alphanumeric_(p, MAXTIDENT))
0137             {
0138                 snprintf(err->error_msg, sizeof(err->error_msg),
0139                     "(%s) invalid characters used in `name' attribute at <procgroup> near line %d",
0140                     config_file_short, cur->line);
0141                 err->error_code = NDRXD_EINVAL;
0142                 NDRX_LOG(log_error, "%s", err->error_msg);
0143                 xmlFree(p);
0144                 EXFAIL_OUT(ret);
0145             }
0146             NDRX_STRCPY_SAFE(p_grp->grpname, p);
0147         }
0148         else if (0==strcmp((char *)attr->name, "grpno"))
0149         {
0150             p_grp->grpno = atoi(p);
0151             /* check that grpno is in range (the upper range is singleton groups) */
0152             if (!ndrx_sg_is_valid(p_grp->grpno))
0153             {
0154                 if (ndrx_G_libnstd_cfg.pgmax > 0)
0155                 {
0156                     snprintf(err->error_msg, sizeof(err->error_msg), 
0157                         "(%s) Invalid `grpno' %d (valid values 1..%d) in <procgroup> "
0158                         "section near line %d", 
0159                         config_file_short, p_grp->grpno, ndrx_G_libnstd_cfg.pgmax, cur->line);
0160                 }
0161                 else
0162                 {
0163                     snprintf(err->error_msg, sizeof(err->error_msg), 
0164                         "(%s) Process groups are disabled (NDRX_PGMAX=0) near line %d", 
0165                         config_file_short, cur->line);
0166                 }
0167                 err->error_code = NDRXD_EINVAL;
0168                 NDRX_LOG(log_error, "%s", err->error_msg);
0169                 xmlFree(p);
0170                 EXFAIL_OUT(ret);
0171             }
0172         }
0173         else if (0==strcmp((char *)attr->name, "sg_nodes"))
0174         {
0175             ndrx_stdcfgstr_t *parsed=NULL, *el;
0176             /* allow envs to nodes*/
0177             NDRX_QENV_SUBST(tmp, p);
0178 
0179             /* process singleton group node_ids */
0180             if (EXSUCCEED!=ndrx_stdcfgstr_parse(tmp, &parsed))
0181             {
0182                 snprintf(err->error_msg, sizeof(err->error_msg), 
0183                     "(%s) Failed to parse `sg_nodes' %s in <procgroup> section near line %d", 
0184                     config_file_short, p, cur->line);
0185                 err->error_code = NDRXD_EINVAL;
0186                 NDRX_LOG(log_error, "%s", err->error_msg);
0187                 ndrx_stdcfgstr_free(parsed);
0188                 xmlFree(p);
0189                 EXFAIL_OUT(ret);
0190             }
0191 
0192             DL_FOREACH(parsed, el)
0193             {
0194                 int nodeid = atoi(el->key);
0195 
0196                 /* check that node id is in range */
0197                 if (nodeid<CONF_NDRX_NODEID_MIN || nodeid>CONF_NDRX_NODEID_MAX)
0198                 {
0199                     snprintf(err->error_msg, sizeof(err->error_msg), 
0200                         "(%s) Invalid `sg_nodes' %d (valid values 1..%d) in <procgroup> "
0201                         "section near line %d", 
0202                         config_file_short, nodeid, CONF_NDRX_NODEID_MAX, cur->line);
0203                     err->error_code = NDRXD_EINVAL;
0204                     NDRX_LOG(log_error, "%s", err->error_msg);
0205                     xmlFree(p);
0206                     ndrx_stdcfgstr_free(parsed);
0207                     EXFAIL_OUT(ret);
0208                 }
0209 
0210                 /* set group as used */
0211                 p_grp->sg_nodes[nodeid-1]=nodeid;
0212             }
0213             ndrx_stdcfgstr_free(parsed);
0214 
0215             /* snow sort the array, so that we do not need to scan
0216              * all the time the array of seeking for nodes to check
0217              */
0218             qsort(p_grp->sg_nodes, CONF_NDRX_NODEID_COUNT, sizeof(char), compare_descending);
0219         }
0220         else if (0==strcmp((char *)attr->name, "noorder"))
0221         {
0222             /* y/Y */
0223             if (NDRX_SETTING_TRUE1==*p || NDRX_SETTING_TRUE2==*p)
0224             {
0225                 p_grp->flags|=NDRX_SG_NO_ORDER;
0226             } /* n/N */
0227             else if (NDRX_SETTING_FALSE1==*p || NDRX_SETTING_FALSE2==*p)
0228             {
0229                 p_grp->flags&=~NDRX_SG_NO_ORDER;
0230             }
0231             else
0232             {
0233                 snprintf(err->error_msg, sizeof(err->error_msg), 
0234                     "(%s) Invalid `noorder' setting [%s] in "
0235                         "<procgroup> or <defaults> "
0236                         "section, expected values [%c%c%c%c] near line %d", 
0237                         config_file_short, p,
0238                         NDRX_SETTING_TRUE1, NDRX_SETTING_TRUE2,
0239                         NDRX_SETTING_FALSE1, NDRX_SETTING_FALSE2, cur->line);
0240                 err->error_code = NDRXD_EINVAL;
0241                 NDRX_LOG(log_error, "%s", err->error_msg);
0242                 xmlFree(p);
0243                 EXFAIL_OUT(ret);
0244             }
0245         }
0246         else if (0==strcmp((char *)attr->name, "singleton"))
0247         {
0248             /* y/Y */
0249             if (NDRX_SETTING_TRUE1==*p || NDRX_SETTING_TRUE2==*p)
0250             {
0251                 p_grp->flags|=NDRX_SG_SINGLETON;
0252             } /* n/N */
0253             else if (NDRX_SETTING_FALSE1==*p || NDRX_SETTING_FALSE2==*p)
0254             {
0255                 p_grp->flags&=~NDRX_SG_SINGLETON;
0256             }
0257             else
0258             {
0259                 snprintf(err->error_msg, sizeof(err->error_msg), 
0260                     "(%s) Invalid `singleton' setting [%s] in "
0261                         "<procgroup> or <defaults> "
0262                         "section, expected values [%c%c%c%c] near line %d", 
0263                         config_file_short, p,
0264                         NDRX_SETTING_TRUE1, NDRX_SETTING_TRUE2,
0265                         NDRX_SETTING_FALSE1, NDRX_SETTING_FALSE2, cur->line);
0266                 err->error_code = NDRXD_EINVAL;
0267                 NDRX_LOG(log_error, "%s", err->error_msg);
0268                 xmlFree(p);
0269                 EXFAIL_OUT(ret);
0270             }
0271         }
0272         else if (0==strcmp((char *)attr->name, "sg_nodes_verify"))
0273         {
0274             /* y/Y */
0275             if (NDRX_SETTING_TRUE1==*p || NDRX_SETTING_TRUE2==*p)
0276             {
0277                 p_grp->flags|=NDRX_SG_VERIFY;
0278             } /* n/N */
0279             else if (NDRX_SETTING_FALSE1==*p || NDRX_SETTING_FALSE2==*p)
0280             {
0281                 p_grp->flags&=~NDRX_SG_VERIFY;
0282             }
0283             else
0284             {
0285                 snprintf(err->error_msg, sizeof(err->error_msg), 
0286                     "(%s) Invalid `sg_node_verify' setting [%s] in "
0287                         "<procgroup> or <defaults> "
0288                         "section, expected values [%c%c%c%c] near line %d", 
0289                         config_file_short, p,
0290                         NDRX_SETTING_TRUE1, NDRX_SETTING_TRUE2,
0291                         NDRX_SETTING_FALSE1, NDRX_SETTING_FALSE2, cur->line);
0292                 err->error_code = NDRXD_EINVAL;
0293                 NDRX_LOG(log_error, "%s", err->error_msg);
0294                 xmlFree(p);
0295                 EXFAIL_OUT(ret);
0296             }
0297         }
0298         
0299         xmlFree(p);
0300     }
0301     
0302     /* no hashing for defaults */
0303     if (!is_defaults)
0304     {
0305         /* Check that group name is set */
0306         if (EXEOS==p_grp->grpname[0])
0307         {
0308             snprintf(err->error_msg, sizeof(err->error_msg), 
0309                 "(%s) `name' not set in <procgroup> section near line %d", 
0310                 config_file_short, cur->line);
0311             err->error_code = NDRXD_ECFGINVLD;
0312             NDRX_LOG(log_error, "%s", err->error_msg);
0313             EXFAIL_OUT(ret);
0314         }
0315 
0316         /* Check that group no is set */
0317         if (0==p_grp->grpno)
0318         {
0319             snprintf(err->error_msg, sizeof(err->error_msg), 
0320                 "(%s) `grpno' not set in <procgroup> section near line %d", 
0321                 config_file_short, cur->line);
0322             err->error_code = NDRXD_ECFGINVLD;
0323             NDRX_LOG(log_error, "%s", err->error_msg);
0324             EXFAIL_OUT(ret);
0325         }
0326 
0327         /* Check that group name is not duplicate */
0328         if (NULL!=ndrx_ndrxconf_procgroups_resolvenm(*config, p_grp->grpname))
0329         {
0330             snprintf(err->error_msg, sizeof(err->error_msg), 
0331                 "(%s) `name' %s is duplicate in <procgroup> section near line %d", 
0332                 config_file_short, p_grp->grpname, cur->line);
0333             err->error_code = NDRXD_EINVAL;
0334             NDRX_LOG(log_error, "%s", err->error_msg);
0335             EXFAIL_OUT(ret);
0336         }
0337 
0338         /* Check that group id is not duplicate */
0339         if (NULL!=ndrx_ndrxconf_procgroups_resolveno(*config, p_grp->grpno))
0340         {
0341             snprintf(err->error_msg, sizeof(err->error_msg), 
0342                 "(%s) `grpno' %d is duplicate in <procgroup> section near line %d", 
0343                 config_file_short, p_grp->grpno, cur->line);
0344             err->error_code = NDRXD_EINVAL;
0345             NDRX_LOG(log_error, "%s", err->error_msg);
0346             EXFAIL_OUT(ret);
0347         }
0348 
0349         p_grp->flags|=NDRX_SG_IN_USE;
0350 
0351         /* copy stuff config entry */
0352         memcpy(&(*config)->groups_by_no[p_grp->grpno-1], p_grp, sizeof(ndrx_procgroup_t));
0353 
0354         p_grp=&(*config)->groups_by_no[p_grp->grpno-1];
0355 
0356         /* add to hashmap by name */
0357         EXHASH_ADD_STR((*config)->groups_by_name, grpname, p_grp);
0358     }
0359 out:
0360     
0361     return ret;
0362 }
0363 
0364 /**
0365  * Parse singleton group options
0366  * @param config config (to allocate)
0367  * @param doc xml doc
0368  * @param cur current node
0369  * @param last_line last line number in XML parser
0370  * @param config_file_short config file name (xml)
0371  * @param err error structure. Contains error codes from the ndrxdcmn.h
0372  * @return error code (0 - success)
0373  */
0374 expublic int ndrx_ndrxconf_procgroups_parse(ndrx_procgroups_t **config, 
0375     xmlDocPtr doc, xmlNodePtr cur, 
0376     char *config_file_short, ndrx_ndrxconf_err_t *err)
0377 {
0378     int ret=EXSUCCEED;
0379     ndrx_procgroup_t default_opt;
0380 
0381     int is_procgroup;
0382     int is_defaults;
0383     int our_nodeid = ndrx_get_G_atmi_env()->our_nodeid;
0384 
0385     memset(&default_opt, 0, sizeof(default_opt));
0386 
0387     /* Check nodes by default */
0388     default_opt.flags|=NDRX_SG_VERIFY;
0389 
0390     /* set defaults:*/
0391 
0392     /* our node is always in the group...*/
0393     default_opt.sg_nodes[our_nodeid-1]=our_nodeid;
0394 
0395     *config = NDRX_CALLOC(1, sizeof(ndrx_procgroups_t) + 
0396             sizeof(ndrx_procgroup_t) * (ndrx_G_libnstd_cfg.pgmax));
0397 
0398     for (; cur ; cur=cur->next)
0399     {
0400         is_procgroup= (0==strcmp((char*)cur->name, "procgroup"));
0401         is_defaults= (0==strcmp((char*)cur->name, "defaults"));
0402         
0403         if (is_procgroup || is_defaults)
0404         {
0405             /* read the group... */
0406             if (EXSUCCEED!=ndrx_appconfig_procgroup(config, doc, cur,
0407                 is_defaults, &default_opt, config_file_short, err))
0408             {
0409                 EXFAIL_OUT(ret);
0410             }
0411         }
0412     }
0413 out:
0414 
0415     return ret;
0416 }
0417 
0418 /**
0419  * Free process groups structure
0420  * @param handle process group handle to free
0421  */
0422 expublic void ndrx_ndrxconf_procgroups_free(ndrx_procgroups_t *handle)
0423 {
0424     ndrx_procgroup_t *p_grp, *tmp;
0425 
0426     if (NULL!=handle)
0427     {
0428         /* free by name */
0429         EXHASH_ITER(hh, handle->groups_by_name, p_grp, tmp) 
0430         {
0431             EXHASH_DEL(handle->groups_by_name, p_grp);
0432         }
0433 
0434         NDRX_FREE(handle);
0435     }
0436 }
0437 
0438 /**
0439  * Resolve group name to group name
0440  */
0441 expublic ndrx_procgroup_t* ndrx_ndrxconf_procgroups_resolvenm(ndrx_procgroups_t *handle, char *name)
0442 {
0443     ndrx_procgroup_t *ret;
0444 
0445     if (NULL==name || EXEOS==name[0] || NULL==handle)
0446     {
0447         return NULL;
0448     }
0449 
0450     EXHASH_FIND_STR(handle->groups_by_name, name, ret);
0451 
0452     return ret;
0453 }
0454 
0455 /**
0456  * Check if group is singleton
0457  * @param handle configuration handle
0458  * @param procgrp_no group number
0459  * @return EXTRUE (group is singleton)/EXFALSE (group is not singleton)
0460  */
0461 expublic int ndrx_ndrxconf_procgroups_is_singleton(ndrx_procgroups_t *handle, int procgrp_no)
0462 {
0463     ndrx_procgroup_t *p_grp;
0464     int ret = EXFALSE;
0465 
0466     if (NULL==handle)
0467     {
0468         goto out;
0469     }
0470 
0471     p_grp = &handle->groups_by_no[procgrp_no-1];
0472 
0473     if (p_grp->flags & NDRX_SG_SINGLETON)
0474     {
0475         ret=EXTRUE;
0476     }
0477     else
0478     {
0479         ret=EXFALSE;
0480     }
0481     
0482 out:
0483     return ret;
0484 }
0485 
0486 /**
0487  * Resolve group name to group number
0488  */
0489 expublic ndrx_procgroup_t* ndrx_ndrxconf_procgroups_resolveno(ndrx_procgroups_t *handle, int procgrpno)
0490 {
0491     ndrx_procgroup_t *ret=NULL;
0492 
0493     if (procgrpno<1 || procgrpno>ndrx_G_libnstd_cfg.pgmax|| NULL==handle)
0494     {
0495         goto out;
0496     }
0497 
0498     ret=&handle->groups_by_no[procgrpno-1];
0499 
0500     if (!(ret->flags & NDRX_SG_IN_USE))
0501     {
0502         ret=NULL;
0503     }
0504 
0505 out:
0506     return ret;
0507 }
0508 
0509 /**
0510  * Apply settings to singleton groups.
0511  * This will synchronize all group flags to singleton group support library
0512  */
0513 expublic void ndrx_ndrxconf_procgroups_apply_singlegrp(ndrx_procgroups_t *handle)
0514 {
0515     int i;
0516     unsigned short flags;
0517 
0518     /* nothing to-do */
0519     if (NULL==handle)
0520     {
0521         return;
0522     }
0523 
0524     for (i=0; i<ndrx_G_libnstd_cfg.pgmax; i++)
0525     {
0526         ndrx_procgroup_t *p_grp = &handle->groups_by_no[i];
0527         ndrx_sg_flags_set(i+1, p_grp->flags);
0528 
0529         /* set cluster node_ids */
0530         ndrx_sg_nodes_set(i+1, p_grp->sg_nodes);
0531     }
0532 }
0533 
0534 /* vim: set ts=4 sw=4 et smartindent: */