Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Library for keeping snapshoot cursor data
0003  *
0004  * @file snapshoot.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 #include <stdio.h>
0035 #include <stdlib.h>
0036 #include <string.h>
0037 #include <errno.h>
0038 #include <regex.h>
0039 #include <utlist.h>
0040 #include <unistd.h>
0041 #include <signal.h>
0042 
0043 #include <ndebug.h>
0044 #include <atmi.h>
0045 #include <atmi_int.h>
0046 #include <typed_buf.h>
0047 #include <ndrstandard.h>
0048 #include <ubf.h>
0049 #include <Exfields.h>
0050 #include <Excompat.h>
0051 #include <ubfutil.h>
0052 #include <tpadm.h>
0053 #include <exhash.h>
0054 #include "tpadmsv.h"
0055 /*---------------------------Externs------------------------------------*/
0056 /*---------------------------Macros-------------------------------------*/
0057 /*---------------------------Enums--------------------------------------*/
0058 /*---------------------------Typedefs-----------------------------------*/
0059 /*---------------------------Globals------------------------------------*/
0060 /*---------------------------Statics------------------------------------*/
0061 exprivate long M_cntr = 0; /**< Counter of the cursor ID */
0062 exprivate ndrx_adm_cursors_t *M_cursors = NULL; /**< List of open cursors */
0063 exprivate int M_nr_cursor = 0;  /**< Number of cursor open. */
0064 /*---------------------------Prototypes---------------------------------*/
0065 
0066 
0067 /**
0068  * Housekeep routines
0069  * @return EXSUCCEED/EXFAIL
0070  */
0071 expublic int ndrx_adm_curs_housekeep(void)
0072 {
0073     long delta;
0074     ndrx_adm_cursors_t *el, *elt;
0075     
0076     EXHASH_ITER(hh, M_cursors, el, elt)
0077     {
0078         if ((delta=ndrx_stopwatch_get_delta_sec(&el->w)) > ndrx_G_adm_config.validity)
0079         {
0080             NDRX_LOG(log_error, "Cursor [%s] expired (%d sec)", el->cursorid, delta);
0081             ndrx_adm_curs_close(el);
0082         }
0083     }
0084     
0085     return EXSUCCEED;
0086 }
0087 
0088 
0089 /**
0090  * Find the cursor stored locally
0091  * @param cursid cursor id string
0092  * @return ptr or NULL
0093  */
0094 expublic ndrx_adm_cursors_t* ndrx_adm_curs_get(char *cursid)
0095 {
0096     ndrx_adm_cursors_t* ret;
0097     
0098     EXHASH_FIND_STR(M_cursors, cursid, ret);
0099     
0100     NDRX_LOG(log_debug, "Find cursor [%s] result: %p", cursid, ret);
0101     
0102     return ret;
0103 }
0104 
0105 /**
0106  * Open new cursor. Assign the cursor id
0107  * @param p_ub UBF buffer where to install error, if any
0108  * @param map class map
0109  * @param clazz
0110  * @param data data to load into cursor
0111  * @return cursor object
0112  */
0113 expublic ndrx_adm_cursors_t* ndrx_adm_curs_new(UBFH *p_ub, ndrx_adm_class_map_t *class_map,
0114         ndrx_adm_cursors_t *data)
0115 {
0116     int ret = EXSUCCEED;
0117     ndrx_adm_cursors_t *el = NULL;
0118     
0119     if (M_nr_cursor+1 > ndrx_G_adm_config.cursors_max)
0120     {
0121         NDRX_LOG(log_error, "Currently open cursor limit (%d) reached - wait for houskeep, "
0122                 "check program defects", ndrx_G_adm_config.cursors_max);
0123         ndrx_adm_error_set(p_ub, TAELIMIT, BBADFLDID, 
0124                 "Currently open cursor limit (%d) reached - wait for houskeep, "
0125                 "check program defects", ndrx_G_adm_config.cursors_max);
0126         EXFAIL_OUT(ret);
0127     }
0128     
0129     M_cntr++;
0130     
0131     if (M_cntr > 999999999)
0132     {
0133         M_cntr=1;
0134     }
0135     
0136     /* Cursor format:
0137      * .TMIB-N-S_CCNNNNNN
0138      * Where:
0139      * - N -> Node id;
0140      * - S -> Service ID
0141      */
0142     snprintf(data->cursorid, sizeof(data->cursorid), "%s_%s%09ld", ndrx_G_svcnm2, 
0143             class_map->clazzshort, M_cntr);
0144     
0145     /* Allocate the hash. */
0146     
0147     el = NDRX_MALLOC(sizeof(ndrx_adm_cursors_t));
0148     
0149     if (NULL==el)
0150     {
0151         NDRX_LOG(log_error, "Failed to malloc %d bytes: %s", sizeof(ndrx_adm_cursors_t),
0152                 strerror(errno));
0153         EXFAIL_OUT(ret);
0154     }
0155     
0156     memcpy(el, data, sizeof(ndrx_adm_cursors_t));
0157     ndrx_stopwatch_reset(&el->w);
0158     
0159     EXHASH_ADD_STR( M_cursors, cursorid, el );
0160     M_nr_cursor++;
0161 out:
0162     
0163     if (EXSUCCEED!=ret && NULL!=el)
0164     {
0165         NDRX_FREE(el);
0166         el = NULL;
0167     }
0168     
0169     return el;
0170 }
0171 
0172 /**
0173  * Delete the cursor
0174  */
0175 expublic void ndrx_adm_curs_close(ndrx_adm_cursors_t *curs)
0176 {
0177     NDRX_LOG(log_debug, "Close/remove: [%s]", curs->cursorid);
0178     
0179     /* Remove from hash */
0180     EXHASH_DELETE(hh, M_cursors, curs);
0181     ndrx_growlist_free(&curs->list);
0182     NDRX_FREE(curs);
0183     M_nr_cursor--;
0184     
0185 }
0186 
0187 /**
0188  * This shall find the cursor, and perform the buffer mappings according to tables
0189  *  and structures.
0190  *  The buffer shall be received and filled accordingly. If fetched till the end
0191  *  the data item shall be deleted.
0192  * @param[out] p_ub where to fetch the cursor data
0193  * @param[in] curs which cursor to fetch
0194  * @param[out] ret_occurs number of occurrences loaded into buffer
0195  * @param[out] ret_more number of items left in buffer
0196  * @return EXSUCCEED/EXFAIL
0197  */
0198 expublic int ndrx_adm_curs_fetch(UBFH *p_ub, ndrx_adm_cursors_t *curs,
0199         long *ret_occurs, long *ret_more)
0200 {
0201     int ret = EXSUCCEED;
0202     int i;
0203     long freesz;
0204     void *cur_pos;
0205     ndrx_adm_elmap_t *map;
0206     int start_pos = curs->curspos;
0207     int req;
0208     
0209     /*
0210      * - estimate free size one block + error block.
0211      * Load and step forward
0212      */
0213     
0214     NDRX_LOG(log_info, "Cursor [%s] curpos=%d total=%d", curs->cursorid, 
0215             curs->curspos, curs->list.maxindexused+1);
0216     *ret_occurs = 0;
0217     *ret_more = 0;
0218     for (i=start_pos; i<=curs->list.maxindexused; i++)
0219     {
0220         freesz = Bunused(p_ub);
0221         
0222         if (freesz < (req=((curs->list.size*2) + TPADM_ERROR_MINSZ)))
0223         {
0224             NDRX_LOG(log_debug, "Free: %ld, require: %d", freesz, req);
0225             break;
0226         }
0227         
0228         /* Load the data according to current position & mapping */
0229         cur_pos = curs->list.mem + (curs->list.size*i);
0230         
0231         /* drive the mappings.. */
0232         map = curs->map;
0233         
0234         
0235         while (BBADFLDID!=map->fid)
0236         {
0237             BFLDOCC occ = i - start_pos;
0238             void *elm = cur_pos + map->c_offset;
0239             
0240             /* the C types matches UBF types! */
0241             if (EXSUCCEED!=Bchg(p_ub, map->fid, occ, elm, 0L))
0242             {
0243                 NDRX_LOG(log_error, "Failed to set [%s] for occ %d: %s",
0244                         Bfname(map->fid), Bstrerror(Berror));
0245                 EXFAIL_OUT(ret);
0246             }
0247             
0248             map++;
0249         }
0250         
0251         NDRX_LOG(log_debug, "OCC %d loaded", curs->curspos);
0252         curs->curspos++;
0253         (*ret_occurs)++;
0254     }
0255     
0256     NDRX_LOG(log_info, "Cursor [%s] fetch end at curpos=%d total=%d (0 base)", 
0257             curs->cursorid, curs->curspos, curs->list.maxindexused);
0258     
0259     if (curs->curspos > curs->list.maxindexused)
0260     {
0261         NDRX_LOG(log_debug, "Cursor %d fetched fully -> remove", curs->cursorid);
0262         ndrx_adm_curs_close(curs);
0263     }
0264     else
0265     {
0266         *ret_more = (curs->list.maxindexused+1) - *ret_occurs;
0267     }
0268     
0269 out:
0270     return ret;
0271 }
0272 
0273 
0274 /* vim: set ts=4 sw=4 et smartindent: */