Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Singleton group support routines
0003  *  Internal library, assumes that group number is pre-valdiated (i.e. >0 && <=pgmax)
0004  *
0005  * @file singlegrp.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 <ndrx_config.h>
0036 #include <ndrstandard.h>
0037 #include <ndebug.h>
0038 #include <singlegrp.h>
0039 #include <lcfint.h>
0040 #include <sys/stat.h>
0041 #include <sys_unix.h>
0042 #include <sys/time.h>
0043 #include <sys_test.h>
0044 #include <exatomic.h>
0045 /*---------------------------Externs------------------------------------*/
0046 /*---------------------------Macros-------------------------------------*/
0047 
0048 /* have macro to get the pointer to the group in shared memory */
0049 #define NDRX_SG_GET_PTR(sg_no) \
0050     (ndrx_sg_shm_t *)((char *)ndrx_G_shmcfg->commands \
0051             + sizeof(ndrx_G_shmcfg->commands[0])*ndrx_G_libnstd_cfg.lcfmax \
0052             + sizeof(ndrx_sg_shm_t)*(sg_no-1))
0053 
0054 /*---------------------------Enums--------------------------------------*/
0055 /*---------------------------Typedefs-----------------------------------*/
0056 /*---------------------------Globals------------------------------------*/
0057 /*---------------------------Statics------------------------------------*/
0058 /*---------------------------Prototypes---------------------------------*/
0059 exprivate int  ndrx_sg_chk_timestamp(int singlegrp_no, ndrx_sg_shm_t *sg);
0060 
0061 /**
0062  * Perform init of the singleton group support
0063 */
0064 expublic int ndrx_sg_init(void)
0065 {
0066     return EXSUCCEED;
0067 }
0068 
0069 /** 
0070  * Return the ptr to singleton group in shared memory 
0071  * Check against group number limits
0072  * Check is the LCF shared memory actually attached (as it is optional)
0073  * The group numbers start from 1. Group 0 is reserved for internal use,
0074  *  for cases when no group is specified.
0075  * Finally calculate the offset in shared memory
0076  * @param singlegrp_no single group number
0077  * @return ptr to single group in shared memory or NULL if not found
0078  */
0079 expublic ndrx_sg_shm_t *ndrx_sg_get(int singlegrp_no)
0080 {
0081     ndrx_sg_shm_t *ret = NULL;
0082 
0083     /* Check against group number limits */
0084     if (singlegrp_no < 0 || singlegrp_no > ndrx_G_libnstd_cfg.pgmax)
0085     {
0086         NDRX_LOG(log_error, "Invalid single group number: %d", singlegrp_no);
0087         goto out;
0088     }
0089 
0090     /* Check is the LCF shared memory actually attached (as it is optional) */
0091     if (NULL==ndrx_G_shmcfg)
0092     {
0093         NDRX_LOG(log_error, "LCF shared memory is not attached!");
0094         goto out;
0095     }
0096 
0097     /* Finally calculate the offset in shared memory 
0098      * as group numbers go from 1, we need to subtract 1, to keep the offset 0 utilised
0099      */
0100     ret = (ndrx_sg_shm_t *)((char *)ndrx_G_shmcfg->commands 
0101             + sizeof(ndrx_G_shmcfg->commands[0])*ndrx_G_libnstd_cfg.lcfmax
0102             + sizeof(ndrx_sg_shm_t)*(singlegrp_no-1));
0103 out:
0104     return ret;
0105 }
0106 
0107 /**
0108  * Reset singleton group infos
0109  */
0110 expublic void ndrx_sg_reset(void)
0111 {
0112     if (NULL!=ndrx_G_shmcfg)
0113     {
0114         memset( (char *)ndrx_G_shmcfg->commands 
0115                     + sizeof(ndrx_G_shmcfg->commands[0])*ndrx_G_libnstd_cfg.lcfmax,
0116                     0, sizeof(ndrx_sg_shm_t)*ndrx_G_libnstd_cfg.pgmax);
0117         /* remove from maintenance mode too */
0118         ndrx_G_shmcfg->is_mmon=EXFALSE;
0119     }
0120 }
0121 
0122 /**
0123  * If group was locked, but for some reason
0124  * we face a condition that we group shall be unlocked.
0125  * This resets key statistics of the group entry.
0126  * if already unlocked, leave the original data there in shm.
0127  * @param sg resolved group ptr
0128  * @param reason reason code, why group was unlocked
0129  */
0130 expublic void ndrx_sg_unlock(ndrx_sg_shm_t * sg, int reason)
0131 {
0132     unsigned char is_locked = NDRX_ATOMIC_LOAD(&sg->is_locked);
0133     
0134 #if 0
0135     /* QA testing: */
0136     if (ndrx_G_systest_lockloss > 0)
0137     {
0138         NDRX_LOG(log_error, "SYSTEST: no-unlock (lockloss)");
0139     }
0140     else if (is_locked)
0141     {
0142 #endif
0143         NDRX_ATOMIC_STORE(&sg->is_srv_booted, EXFALSE);
0144         NDRX_ATOMIC_STORE(&sg->is_clt_booted, EXFALSE);
0145         NDRX_ATOMIC_STORE(&sg->is_locked, EXFALSE);
0146         NDRX_ATOMIC_STORE(&sg->reason, reason);
0147 #if 0
0148     }
0149 #endif
0150 }
0151 
0152 /**
0153  * Refresh lock for given group
0154  * @param singlegrp_no single group number
0155  * @param sg resolved group ptr
0156  * @param nodeid cluster node id (current one, but now known in standard libary)
0157  * @param srvid server id (also current one, but now known in standard libary)
0158  * @param chk_lock check lock status (match current lock provider)
0159  * @param new_last_refresh new refresh time
0160  * @param new_sequence new sequence number
0161  * @return EXSUCCEED if successfull, EXFAIL if failed
0162 */
0163 exprivate int ndrx_sg_do_refresh_int(int singlegrp_no, ndrx_sg_shm_t * sg, 
0164     short nodeid, int srvid, int chk_lock, time_t new_last_refresh, long new_sequence)
0165 {
0166     int ret = EXSUCCEED;
0167     ndrx_sg_shm_t sg_local;
0168     pid_t pid;
0169     ndrx_sg_shm_t * sg_shm = NDRX_SG_GET_PTR(singlegrp_no);
0170 
0171     if (NULL==sg)
0172     {
0173         /* copy of the shm.. */
0174         ndrx_sg_load(&sg_local, sg_shm);
0175         sg=&sg_local;
0176     }
0177 
0178     if (chk_lock)
0179     {
0180         if (!sg->is_locked)
0181         {
0182             NDRX_LOG(log_error, "ERROR Group %d is not locked, but "
0183                 "must be - terminating!", singlegrp_no);
0184             userlog("ERROR Group %d is not locked, but "
0185                 "must be - terminating!", singlegrp_no);
0186             EXFAIL_OUT(ret);
0187         }
0188 
0189         /* Check lockserver pid, nodeid, srvid -> must be ours... */
0190         if (sg->lockprov_pid!=(pid=getpid()))
0191         {
0192             NDRX_LOG(log_error, "ERROR Group %d is locked by PID %d, "
0193                 "but must be locked by PID %d - terminating!", 
0194                 singlegrp_no, sg->lockprov_pid, (int)pid);
0195             userlog("ERROR Group %d is locked by PID %d, "
0196                 "but must be locked by PID %d - terminating!", 
0197                 singlegrp_no, sg->lockprov_pid, (int)pid);
0198             EXFAIL_OUT(ret);
0199         }
0200 
0201         if (sg->lockprov_nodeid!=nodeid)
0202         {
0203             NDRX_LOG(log_error, "ERROR Group %d is locked by Node %hd, "
0204                 "but must be locked by Node %hd - terminating!", 
0205                 singlegrp_no, sg->lockprov_nodeid, nodeid);
0206             userlog("ERROR Group %d is locked by Node %hd, "
0207                 "but must be locked by Node %hd - terminating!", 
0208                 singlegrp_no, sg->lockprov_nodeid, nodeid);
0209             EXFAIL_OUT(ret);
0210         }
0211 
0212         if (sg->lockprov_srvid!=srvid)
0213         {
0214             NDRX_LOG(log_error, "ERROR Group %d is locked by Server id %d, "
0215                 "but must be locked by Server %d - terminating!", 
0216                 singlegrp_no, sg->lockprov_srvid, srvid);
0217             userlog("ERROR Group %d is locked by Server is %d, "
0218                 "but must be locked by Server %d - terminating!", 
0219                 singlegrp_no, sg->lockprov_srvid, srvid);
0220             EXFAIL_OUT(ret);
0221         }
0222 
0223         if (EXSUCCEED!=ndrx_sg_chk_timestamp(singlegrp_no, sg))
0224         {
0225             EXFAIL_OUT(ret);
0226         }
0227     }
0228 
0229     NDRX_ATOMIC_STORE(&sg_shm->last_refresh, new_last_refresh);
0230     NDRX_ATOMIC_STORE(&sg_shm->sequence, new_sequence);
0231 
0232 out:
0233     return ret;
0234 }
0235 
0236 /**
0237  * Refresh lock for given group
0238  * @param singlegrp_no single group number
0239  * @param nodeid cluster node id (current one, but now known in standard libary)
0240  * @param srvid server id (also current one, but now known in standard libary)
0241  * @param new_last_refresh new refresh time
0242  * @param new_sequence new sequence number
0243  * @return EXSUCCEED if successfull, EXFAIL if failed!
0244  */
0245 expublic int ndrx_sg_do_refresh(int singlegrp_no, ndrx_sg_shm_t * sg, 
0246     short nodeid, int srvid, time_t new_last_refresh, long new_sequence)
0247 {
0248     return ndrx_sg_do_refresh_int(singlegrp_no, sg, nodeid, srvid, 
0249         EXTRUE, new_last_refresh, new_sequence);
0250 }
0251 
0252 /**
0253  * Perform group locking (by the lock provider)
0254  * @param singlegrp_no single group number
0255  * @param nodeid cluster node id (current one, but now known in standard libary)
0256  * @param srvid server id
0257  * @param procname process name
0258  * @param new_last_refresh lock time (when checks were started...)
0259  * @param new_sequence new sequence number
0260  * @return EXSUCCEED if successfull, EXFAIL if failed
0261  */
0262 expublic int ndrx_sg_do_lock(int singlegrp_no, short nodeid, int srvid, char *procname,
0263         time_t new_last_refresh, long new_sequence)
0264 {
0265     int ret = EXSUCCEED;
0266     ndrx_sg_shm_t * sg_shm, sg;
0267 
0268     sg_shm = NDRX_SG_GET_PTR(singlegrp_no);
0269     ndrx_sg_load(&sg, sg_shm);
0270 
0271     if (sg.is_locked)
0272     {
0273         NDRX_LOG(log_error, "ERROR: Group %d already locked by Node %hd, PID %d, Procname [%s] - terminating",
0274                 singlegrp_no, sg.lockprov_nodeid, sg.lockprov_pid, sg.lockprov_procname);
0275         userlog("ERROR: Group %d already locked by Node %hd, PID %d, Procname [%s] - terminating",
0276                 singlegrp_no, sg.lockprov_nodeid, sg.lockprov_pid, sg.lockprov_procname);
0277         EXFAIL_OUT(ret);
0278     }
0279 
0280     if (EXSUCCEED != ndrx_sg_do_refresh_int(singlegrp_no, 
0281         &sg, nodeid, srvid, EXFALSE, new_last_refresh, new_sequence))
0282     {
0283         EXFAIL_OUT(ret);   
0284     }
0285 
0286     /* store current proc info */
0287     ndrx_volatile_strcpy(sg_shm->lockprov_procname, procname, sizeof(sg.lockprov_procname));
0288     __sync_synchronize();
0289 
0290     NDRX_ATOMIC_STORE(&sg_shm->lockprov_nodeid, nodeid);
0291     NDRX_ATOMIC_STORE(&sg_shm->lockprov_pid, getpid());
0292     NDRX_ATOMIC_STORE(&sg_shm->lockprov_srvid, srvid);
0293     NDRX_ATOMIC_STORE(&sg_shm->is_locked, EXTRUE);
0294     NDRX_ATOMIC_STORE(&sg_shm->reason, 0);
0295 
0296     NDRX_LOG(log_debug, "Group %d locked on node %hd", singlegrp_no, nodeid);
0297     userlog("Group %d locked on node %hd", singlegrp_no, nodeid);
0298 
0299 out:
0300     return ret;
0301 }
0302 
0303 /**
0304  * Load all fields from shared memory to local copy
0305  * in atomic way.
0306  * @param sg local copy
0307  * @param sg_shm shared memory data
0308  */
0309 expublic void ndrx_sg_load(ndrx_sg_shm_t * sg, ndrx_sg_shm_t * sg_shm)
0310 {
0311     /* atomic load multi-byte fields */
0312     sg->is_locked = NDRX_ATOMIC_LOAD(&sg_shm->is_locked);
0313     sg->is_mmon = NDRX_ATOMIC_LOAD(&sg_shm->is_mmon);
0314     sg->is_srv_booted = NDRX_ATOMIC_LOAD(&sg_shm->is_srv_booted);
0315     sg->is_clt_booted = NDRX_ATOMIC_LOAD(&sg_shm->is_clt_booted);
0316     sg->flags = NDRX_ATOMIC_LOAD(&sg_shm->flags);
0317     sg->last_refresh = NDRX_ATOMIC_LOAD(&sg_shm->last_refresh);
0318     sg->sequence = NDRX_ATOMIC_LOAD(&sg_shm->sequence);
0319     sg->lockprov_nodeid = NDRX_ATOMIC_LOAD(&sg_shm->lockprov_nodeid);
0320     sg->lockprov_pid = NDRX_ATOMIC_LOAD(&sg_shm->lockprov_pid);
0321     sg->lockprov_srvid = NDRX_ATOMIC_LOAD(&sg_shm->lockprov_srvid);
0322     ndrx_volatile_strcpy(sg->lockprov_procname, sg_shm->lockprov_procname,
0323         sizeof(sg->lockprov_procname));
0324 
0325     ndrx_volatile_memcy(sg->sg_nodes, sg_shm->sg_nodes, sizeof(sg->sg_nodes));
0326 
0327     sg->reason = NDRX_ATOMIC_LOAD(&sg_shm->reason);
0328 }
0329 
0330 /**
0331  * Check is shared memory timestmap still valid.
0332  * @param singlegrp_no single group number
0333  * @param sg local copy of the shared memory entry
0334  * @return EXSUCCEED if successfull (still valid), EXFAIL if failed
0335  */
0336 exprivate int ndrx_sg_chk_timestamp(int singlegrp_no, ndrx_sg_shm_t *sg)
0337 {
0338     int ret=EXSUCCEED;
0339     struct timespec ts;
0340     long long time_diff;
0341 
0342     ndrx_realtime_get(&ts);
0343 
0344     time_diff=(long long)ts.tv_sec-(long long)sg->last_refresh;
0345 
0346     /* validate the lock */
0347     if (llabs(time_diff) > ndrx_G_libnstd_cfg.sgrefreshmax)
0348     {
0349         /* Mark system as not locked anymore! */
0350         ndrx_sg_unlock(NDRX_SG_GET_PTR(singlegrp_no), NDRX_SG_RSN_EXPIRED);
0351 
0352         NDRX_LOG(log_error, "ERROR: Lock for singleton group %d is inconsistent "
0353                 "(did not refresh in %d sec, diff %lld sec)! "
0354                 "Marking group as not locked!", singlegrp_no, ndrx_G_libnstd_cfg.sgrefreshmax,
0355                 time_diff);
0356 
0357         userlog("ERROR: Lock for singleton group %d is inconsistent "
0358                 "(did not refresh in %d sec, diff %lld sec)! "
0359                 "Marking group as not locked!", singlegrp_no, ndrx_G_libnstd_cfg.sgrefreshmax,
0360                 time_diff);
0361 
0362         EXFAIL_OUT(ret);
0363     }
0364 out:
0365     return ret;
0366 }
0367 
0368 /**
0369  * Check is group locked (internal version)
0370  * @param singlegrp_no single group number
0371  * @param sg optional resolved group from shared memory 
0372  *  (will be used if not NULL, instead of the lookup by no)
0373  * @param reference_file file for which to check future modification date
0374  * @param flags NDRX_SG_CHK_PID check for pid, default 0
0375  * @return EXTRUE/EXFALSE/EXFAIL
0376  */
0377 expublic int ndrx_sg_is_locked_int(int singlegrp_no, ndrx_sg_shm_t * sg,
0378     char *reference_file, long flags)
0379 {
0380     int ret = EXFALSE;
0381     ndrx_sg_shm_t sg_local;
0382     
0383     if (NULL==sg)
0384     {
0385         sg=ndrx_sg_get(singlegrp_no);
0386 
0387         if (NULL==sg)
0388         {
0389             NDRX_LOG(log_error, "singleton group %d not found", singlegrp_no);
0390             ret=EXFAIL;
0391             goto out;
0392         }
0393     }
0394 
0395     if (!sg->is_locked)
0396     {
0397         ret=EXFALSE;
0398         goto out;
0399     }
0400 
0401     /* load all fields from shared memory to local copy */
0402     ndrx_sg_load(&sg_local, sg);
0403 
0404     if (EXSUCCEED!=ndrx_sg_chk_timestamp(singlegrp_no, &sg_local))
0405     {
0406         ret=EXFALSE;
0407         goto out;
0408     }
0409 
0410     if (flags & NDRX_SG_SRVBOOTCHK 
0411         && !(sg_local.flags & NDRX_SG_NO_ORDER) 
0412         && !sg_local.is_srv_booted)
0413     {
0414         /* if servers are not booted, but order required, 
0415          * report group as not locked
0416          */
0417         NDRX_LOG(log_debug, "Singleton group %d servers not booted",
0418             singlegrp_no);
0419         ret=EXFALSE;
0420         goto out;
0421     }
0422     /* validate the PID if requested so */
0423     else if (flags & NDRX_SG_CHK_PID)
0424     {
0425         if (!ndrx_sys_is_process_running_by_pid(sg_local.lockprov_pid))
0426         {
0427             /* Mark system as not locked anymor! */
0428             ndrx_sg_unlock(sg, NDRX_SG_RSN_NOPID);
0429 
0430             NDRX_LOG(log_error, "ERROR: Lock for singleton group %d is inconsistent "
0431                     "(lock provider PID %d is not running)! "
0432                     "Marking group as not locked!", singlegrp_no, sg_local.lockprov_pid);
0433 
0434             userlog("ERROR: Lock for singleton group %d is inconsistent "
0435                     "(lock provider PID %d is not running)! "
0436                     "Marking group as not locked!", singlegrp_no, sg_local.lockprov_pid);
0437 
0438             ret=EXFALSE;
0439             goto out;
0440         }
0441     }
0442 
0443     /* stat() the file, in case if modification date is future or file is
0444      * unlock the group!
0445      */
0446     if (NULL!=reference_file)
0447     {
0448         struct stat st;
0449         int rc;
0450         struct timeval now;
0451 
0452         rc = stat(reference_file, &st);
0453 
0454         if (0!=rc)
0455         {
0456             int err=errno;
0457             /* Mark system as not locked anymore! */
0458             ndrx_sg_unlock(sg, NDRX_SG_RSN_REFNOFILE);
0459 
0460             NDRX_LOG(log_error, "ERROR: Lock for singleton group %d is inconsistent "
0461                     "(reference file [%s] failed to open: %s)! "
0462                     "Marking group as not locked!", singlegrp_no, reference_file, strerror(err));
0463 
0464             userlog("ERROR: Lock for singleton group %d is inconsistent "
0465                     "(reference file [%s] is missing: %s)! "
0466                     "Marking group as not locked!", singlegrp_no, reference_file, strerror(err));
0467 
0468             ret=EXFALSE;
0469             goto out;
0470         }
0471 
0472         /* get current time of day... 
0473          * due to NTP gettimeofday() might actually be in the past.
0474          * thus we can detect that other node has taken over.
0475          */
0476         gettimeofday(&now,NULL);
0477 
0478         if (st.st_mtime > now.tv_sec)
0479         {
0480             /* Mark system as not locked anymor! */
0481             ndrx_sg_unlock(sg, NDRX_SG_RSN_REFFFUT);
0482 
0483             NDRX_LOG(log_error, "ERROR: Lock for singleton group %d is inconsistent "
0484                     "(reference file %s is in future)! "
0485                     "Marking group as not locked!", singlegrp_no, reference_file);
0486 
0487             userlog("ERROR: Lock for singleton group %d is inconsistent "
0488                     "(reference file %s is in future)! "
0489                     "Marking group as not locked!", singlegrp_no, reference_file);
0490 
0491             ret=EXFALSE;
0492             goto out;
0493         }
0494     }
0495 
0496     /* finally we are done, and we are locked */
0497     ret=EXTRUE;
0498 
0499 out:
0500     return ret;
0501 }
0502 
0503 /**
0504  * Is given group locked?
0505  * Get the ptr to ndrx_sg_shm_t and check following items:
0506  * - field is_locked is EXTRUE
0507  * - last_refresh (substracted current boot time / gettimeofday()) is less ndrx_G_libnstd_cfg.sgrefresh
0508  * - if maintenance mode is enabled, then we do not perform any further checks, other than lock status.
0509  * @param singlegrp_no single group number
0510  * @param reference_file this is refrence file name, used to check arn't there any future modifications
0511  *  applied, or file missing?
0512  * @param flags biwtise flags, NDRX_SG_CHK_PID used for additional check of exsinglesv running.
0513  * @return EXFAIL/EXFALSE (not locked)/EXTRUE (locked)
0514  */
0515 
0516 expublic int ndrx_sg_is_locked(int singlegrp_no, char *reference_file, long flags)
0517 {
0518     return ndrx_sg_is_locked_int(singlegrp_no, NULL, reference_file, flags);
0519 }
0520 
0521 /**
0522  * Number of singleton groups.
0523  */
0524 expublic int ndrx_sg_nrgroups()
0525 {
0526     return ndrx_G_libnstd_cfg.pgmax;
0527 }
0528 
0529 /**
0530  * Take a snapshoot of all groups, to be used by
0531  * batch startup processes (so that batch is started with the single status)
0532  * @param lock_status_out where to put the group statuses
0533  * @param lock_status_out_len length of the lock_status_out
0534  * @param flags passed to lock status check
0535  *  additonally may pass NDRX_SG_CHK_PID to check for lock provider pid
0536  * @return returns array of single group statuses. May contain 0, if not locked,
0537  *   NDRX_SG_NO_ORDER if locked, but no order required, NDRX_SG_IN_USE if locked.
0538  */
0539 expublic void ndrx_sg_get_lock_snapshoot(int *lock_status_out, int *lock_status_out_len, long flags)
0540 {
0541     int i=0;
0542     int locked;
0543     ndrx_sg_shm_t *p;
0544 
0545     /* fix up the output len */
0546     if (*lock_status_out_len>ndrx_G_libnstd_cfg.pgmax)
0547     {
0548         *lock_status_out_len = ndrx_G_libnstd_cfg.pgmax;
0549     }
0550 
0551     memset(lock_status_out, 0, sizeof(int)*(*lock_status_out_len));
0552 
0553     for (i=0; i<*lock_status_out_len; i++)
0554     {
0555         p=ndrx_sg_get(i+1);
0556 
0557         if (EXTRUE==ndrx_sg_is_locked_int(i+1, p, NULL, flags))
0558         {
0559             if (p->flags & NDRX_SG_NO_ORDER)
0560             {
0561                 lock_status_out[i]=NDRX_SG_NO_ORDER;
0562             }
0563             else
0564             {
0565                 lock_status_out[i]=NDRX_SG_IN_USE;
0566             }
0567             NDRX_LOG(log_debug, "Group %d lock flag: 0x%x", i+1, lock_status_out[i]);
0568         }
0569     }
0570 
0571     return;
0572 }
0573 
0574 /**
0575  * Set the bootflag on.
0576  * This assumes that shared memory is already attached.
0577  * If the LCF was not attached, then ndrxd would not get so far.
0578  * @param singlegrp_no single group number
0579  */
0580 expublic void ndrx_sg_bootflag_clt_set(int singlegrp_no)
0581 {
0582     ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0583     NDRX_ATOMIC_STORE(&sg->is_clt_booted, EXTRUE);
0584 }
0585 
0586 /**
0587  * Get the boot flag
0588  * @param singlegrp_no single group number
0589  */
0590 expublic unsigned char ndrx_sg_bootflag_clt_get(int singlegrp_no)
0591 {
0592     ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0593     return NDRX_ATOMIC_LOAD(&sg->is_clt_booted);
0594 }
0595 
0596 /**
0597  * Set the bootflag on.
0598  * This assumes that shared memory is already attached.
0599  * If the LCF was not attached, then ndrxd would not get so far.
0600  * @param singlegrp_no single group number
0601  */
0602 expublic void ndrx_sg_bootflag_srv_set(int singlegrp_no)
0603 {
0604     ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0605     NDRX_ATOMIC_STORE(&sg->is_srv_booted, EXTRUE);
0606 }
0607 
0608 /**
0609  * Get server boot flag
0610  * @param singlegrp_no single group number
0611  */
0612 expublic unsigned char ndrx_sg_bootflag_srv_get(int singlegrp_no)
0613 {
0614     ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0615     return NDRX_ATOMIC_LOAD(&sg->is_srv_booted);
0616 }
0617 
0618 /**
0619  * Check the singleton group validity
0620  * @param singlegrp_no number to check
0621  * @return EXTRUE/EXFALSE
0622  */
0623 expublic int ndrx_sg_is_valid(int singlegrp_no)
0624 {
0625     int ret = EXTRUE;
0626 
0627     if (singlegrp_no <= 0 || singlegrp_no > ndrx_G_libnstd_cfg.pgmax)
0628     {
0629         NDRX_LOG(log_error, "Invalid single group number: %d", singlegrp_no);
0630         ret=EXFALSE;
0631         goto out;
0632     }
0633 
0634 out:
0635     return ret;
0636 }
0637 
0638 /**
0639  * Store flags for the group
0640  * @param singlegrp_no group number
0641  * @param flags new flags value
0642  */
0643 expublic void ndrx_sg_flags_set(int singlegrp_no, unsigned short flags)
0644 {
0645     ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0646     NDRX_ATOMIC_STORE(&sg->flags, flags);
0647 }
0648 
0649 /**
0650  * Return the singleton group flags
0651  * @return group flags
0652  */
0653 expublic unsigned short ndrx_sg_flags_get(int singlegrp_no)
0654 {
0655     ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0656     return NDRX_ATOMIC_LOAD(&sg->flags);
0657 }
0658 
0659 /**
0660  * Set the used cluster nodes
0661  */
0662 expublic void ndrx_sg_nodes_set(int singlegrp_no, char *sg_nodes)
0663 {
0664     ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0665     ndrx_volatile_memcy(sg->sg_nodes, sg_nodes, sizeof(sg->sg_nodes));
0666 }
0667 
0668 /**
0669  * Test is group singleton...
0670  * @param singlegrp_no singleton group number
0671  */
0672 expublic int ndrx_sg_is_singleton(int singlegrp_no)
0673 {
0674     int ret = EXFALSE;
0675     if (ndrx_sg_is_valid(singlegrp_no))
0676     {
0677         unsigned char flags;
0678         ndrx_sg_shm_t * sg = NDRX_SG_GET_PTR(singlegrp_no);
0679         flags = NDRX_ATOMIC_LOAD(&sg->flags);
0680 
0681         if (flags & NDRX_SG_SINGLETON)
0682         {
0683             ret=EXTRUE;
0684         }
0685     }
0686 
0687     return ret;
0688 }
0689 
0690 /* vim: set ts=4 sw=4 et smartindent: */