Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief UBF Support for ATMI cache
0003  *
0004  * @file atmi_cache_ubf.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 
0035 /*---------------------------Includes-----------------------------------*/
0036 #include <stdlib.h>
0037 #include <stdio.h>
0038 #include <errno.h>
0039 #include <string.h>
0040 #include <ndrstandard.h>
0041 #include <atmi.h>
0042 #include <atmi_tls.h>
0043 #include <typed_buf.h>
0044 
0045 #include "thlock.h"
0046 #include "userlog.h"
0047 #include "utlist.h"
0048 #include "exregex.h"
0049 #include <exparson.h>
0050 #include <ubfutil.h>
0051 #include <atmi_cache.h>
0052 
0053 /*---------------------------Externs------------------------------------*/
0054 #define NDRX_TPCACHE_MINLIST          100    /* Min number of elements */
0055 /*---------------------------Macros-------------------------------------*/
0056 /*---------------------------Enums--------------------------------------*/
0057 /*---------------------------Typedefs-----------------------------------*/
0058 /*---------------------------Globals------------------------------------*/
0059 /*---------------------------Statics------------------------------------*/
0060 /*---------------------------Prototypes---------------------------------*/
0061 
0062 exprivate int add_proj_field(char **arr, long *arrsz, int idx, BFLDID fid, 
0063         char *errdet, int errdetbufsz);
0064 
0065 /**
0066  * Return key data (read field from UBF...).
0067  * This will read the field from buffer. We detect OK, field not found or error!
0068  * 
0069  * All fields are processed as zero terminated strings. !!!
0070  * 
0071  * @param data1 ptr to UBF buffer
0072  * @param data2 error detail buffer
0073  * @param data3 err det buffer size
0074  * @param data4 NULL
0075  * @param symbol filed to lookup
0076  * @param outbuf output buffer
0077  * @param outbufsz output buffer size
0078  * @return EXSUCCEED/EXFAIL (syserr)/NDRX_TPCACHE_ENOKEYDATA (cannot build key)
0079  */
0080 exprivate int get_key_data (void *data1, void *data2, void *data3, void *data4,
0081         char *symbol, char *outbuf, long outbufsz)
0082 {
0083     int ret = EXSUCCEED;
0084     BFLDID fid;
0085     int *p_errdetbufsz = (int *)data3;
0086     UBFH *p_ub = (UBFH *)data1;
0087     char tmpsymbol[UBFFLDMAX+2+5+1]; /* +2 [] + NNNNN (occ) + EOS */
0088     char *p_start_sq;
0089     char *p_stop_sq;
0090     char tmp[256];
0091     BFLDLEN len = (BFLDLEN)outbufsz;
0092     BFLDOCC occ = 0;
0093     NDRX_STRCPY_SAFE(tmpsymbol, symbol);
0094     
0095     /* extract occurrences by [] */
0096     if (NULL!=(p_start_sq = strchr(tmpsymbol, '[')))
0097     {
0098         p_stop_sq = strchr(tmpsymbol, ']');
0099         
0100         if (NULL==p_stop_sq)
0101         {
0102             NDRX_LOG(log_error, "Invalid field id (%s): cannot "
0103                     "find closing bracket ']'", tmpsymbol);
0104             snprintf(tmp, sizeof(tmp), "Invalid field id (%s): cannot "
0105                     "find closing bracket ']'", tmpsymbol);
0106             NDRX_STRCPY_SAFE_DST(((char *)data2), tmp, *p_errdetbufsz);
0107             EXFAIL_OUT(ret);
0108         }
0109         
0110         if (p_start_sq >= p_stop_sq)
0111         {
0112             NDRX_LOG(log_error, "Invalid/empty field (%s) brackets", 
0113                     tmpsymbol);
0114             snprintf(tmp, sizeof(tmp), "Invalid/empty field (%s) brackets", 
0115                     tmpsymbol);
0116             NDRX_STRCPY_SAFE_DST(((char *)data2), tmp, *p_errdetbufsz);
0117             EXFAIL_OUT(ret);
0118         }
0119         
0120         *p_start_sq = EXEOS;
0121         *p_stop_sq = EXEOS;
0122         
0123         p_start_sq++;
0124         
0125 #ifdef NDRX_TPCACHE_DEBUG
0126         NDRX_LOG(log_debug, "Converting to occurrence: [%s]", p_start_sq);
0127 #endif
0128         occ = atoi(p_start_sq);
0129         
0130     }
0131     /* resolve field id */
0132     if (BBADFLDID==(fid = Bfldid(tmpsymbol)))
0133     {
0134         NDRX_LOG(log_error, "Failed to resolve field [%s] id: %s", 
0135                 tmpsymbol, Bstrerror(Berror));
0136         NDRX_STRCPY_SAFE_DST(((char *)data2), Bstrerror(Berror), *p_errdetbufsz);
0137         EXFAIL_OUT(ret);
0138     }
0139 
0140 #ifdef NDRX_TPCACHE_DEBUG
0141     NDRX_LOG(log_debug, "Reading occurrence: %d", occ);
0142 #endif
0143     
0144     /* we shall extract index if any within a key */    
0145     
0146     if (EXSUCCEED!=CBget(p_ub, fid, occ, outbuf, &len, BFLD_STRING))
0147     {
0148         
0149 #ifdef NDRX_TPCACHE_DEBUG
0150         NDRX_LOG(log_debug, "Failed to get field %d[%d]: %s", 
0151                 fid, occ, Bstrerror(Berror));
0152 #endif
0153         if (BNOTPRES==Berror)
0154         {
0155             ret = NDRX_TPCACHE_ENOKEYDATA;
0156         }
0157         else
0158         {
0159             ret = EXFAIL;
0160         }
0161         goto out;
0162     }
0163     
0164     NDRX_LOG(log_debug, "Field (%s) extracted: [%s]", symbol, outbuf);
0165     
0166 out:
0167 
0168     return ret;    
0169 }
0170 
0171 /**
0172  * Get key for UBF typed buffer
0173  * @param idata input buffer
0174  * @param ilen input buffer len
0175  * @param okey output key
0176  * @param okey_bufsz output key buffer size
0177  * @return EXSUCCEED/EXFAIL (syserr)/NDRX_TPCACHE_ENOKEYDATA (cannot build key)
0178  */
0179 expublic int ndrx_cache_keyget_ubf (ndrx_tpcallcache_t *cache, 
0180         char *idata, long ilen, char *okey, int okey_bufsz, 
0181         char *errdet, int errdetbufsz)
0182 {
0183     int ret = EXSUCCEED;
0184     
0185     if (EXSUCCEED!=(ret=ndrx_str_subs_context(okey, okey_bufsz, '(', ')',
0186         (void *)idata, errdet, &errdetbufsz, NULL, get_key_data)))
0187     {
0188         NDRX_STRCPY_SAFE_DST(errdet, "substitute failure (data extract)", errdetbufsz);
0189         EXFAIL_OUT(ret);
0190     }
0191     
0192 out:
0193     return ret;
0194 }
0195 
0196 /**
0197  * Compile the rule for checking is buffer applicable for cache or not
0198  * @param cache chache to process
0199  * @param errdet error detail out
0200  * @param errdetbufsz errro detail buffer size
0201  * @return EXSUCCEED/EXFAIL
0202  */
0203 expublic int ndrx_cache_rulcomp_ubf (ndrx_tpcallcache_t *cache, 
0204         char *errdet, int errdetbufsz)
0205 {
0206     int ret = EXSUCCEED;
0207     
0208     if (EXEOS!=cache->rule[0])
0209     {
0210         if (NULL==(cache->rule_tree=Bboolco (cache->rule)))
0211         {
0212             snprintf(errdet, errdetbufsz, "%s", Bstrerror(Berror));
0213             EXFAIL_OUT(ret);
0214         }
0215     }
0216     
0217     /* Compile refresh rule too */
0218     
0219     if (EXEOS!=cache->refreshrule[0])
0220     {
0221         if (NULL==(cache->refreshrule_tree=Bboolco (cache->refreshrule)))
0222         {
0223             snprintf(errdet, errdetbufsz, "%s", Bstrerror(Berror));
0224             EXFAIL_OUT(ret);
0225         }
0226     }
0227     
0228 out:
0229     return ret;
0230 }
0231 
0232 /**
0233  * Evaluate the rule of cache. Do we need to cache this record or not?
0234  * @param cache cache on which to test
0235  * @param idata input buffer
0236  * @param ilen input buffer len (if applicable)
0237  * @param errdet error detail out
0238  * @param errdetbufsz error detail buffer size
0239  * @return EXFAIL/EXTRUE/EXFALSE
0240  */
0241 expublic int ndrx_cache_ruleval_ubf (ndrx_tpcallcache_t *cache, 
0242         char *idata, long ilen,  char *errdet, int errdetbufsz)
0243 {
0244     int ret = EXFALSE;
0245     
0246     NDRX_LOG(log_debug, "%s rule=[%s]", __func__, cache->rule);
0247     
0248     if (EXEOS==cache->rule[0])
0249     {
0250         ret=EXTRUE;
0251     }
0252     else if (EXFAIL==(ret=Bboolev((UBFH *)idata, cache->rule_tree)))
0253     {
0254         snprintf(errdet, errdetbufsz, "%s", Bstrerror(Berror));
0255         EXFAIL_OUT(ret);
0256     }
0257     
0258 out:
0259     return ret;
0260 }
0261 
0262 /**
0263  * Refresh rule evaluate
0264  * @param cache cache on which to test
0265  * @param idata input buffer
0266  * @param ilen input buffer len (if applicable)
0267  * @param errdet error detail out
0268  * @param errdetbufsz error detail buffer size
0269  * @return EXFAIL/EXTRUE/EXFALSE
0270  */
0271 expublic int ndrx_cache_refeval_ubf (ndrx_tpcallcache_t *cache, 
0272         char *idata, long ilen,  char *errdet, int errdetbufsz)
0273 {
0274     int ret = EXFALSE;
0275     
0276     if (EXFAIL==(ret=Bboolev((UBFH *)idata, cache->refreshrule_tree)))
0277     {
0278         snprintf(errdet, errdetbufsz, "%s", Bstrerror(Berror));
0279         EXFAIL_OUT(ret);
0280     }
0281     
0282 out:
0283     return ret;
0284 }
0285 
0286 /**
0287  * We receive data from cache
0288  * @param exdata database data
0289  * @param idata incoming xatmi data buffer
0290  * @param ilen incoming xatmi data len
0291  * @param odata output data buffer
0292  * @param olen output len
0293  * @param flags flags
0294  * @return EXSUCCED/EXFAIL
0295  */
0296 expublic int ndrx_cache_get_ubf (ndrx_tpcallcache_t *cache,
0297         ndrx_tpcache_data_t *exdata, typed_buffer_descr_t *buf_type, 
0298         char *idata, long ilen, char **odata, long *olen, long flags)
0299 {
0300     int ret = EXSUCCEED;
0301     UBFH *p_ub;
0302     UBFH *p_ub_cache = NULL;
0303     long olen_merge;
0304     int local_alloc = EXFALSE;
0305     
0306     /* Figure out how data to replace, either full replace or merge */
0307     
0308     if (NULL==idata)
0309     {
0310         if (NULL!=(idata = tpalloc("UBF", 0, 1024)))
0311         {
0312             local_alloc = EXTRUE;
0313         }
0314         else
0315         {
0316             NDRX_LOG(log_error, "Failed to allocate input/output buffer!");
0317             EXFAIL_OUT(ret);
0318         }
0319     }
0320     
0321     if (cache->flags & NDRX_TPCACHE_TPCF_REPL)
0322     {
0323         if (EXSUCCEED!=ndrx_mbuf_prepare_incoming(exdata->atmi_buf, 
0324                 exdata->atmi_buf_len, odata, olen, flags, 0))
0325         {
0326             /* the error shall be set already */
0327             NDRX_LOG(log_error, "Failed to prepare data from cache to buffer");
0328             EXFAIL_OUT(ret);
0329         }
0330     }
0331     else if (cache->flags & NDRX_TPCACHE_TPCF_MERGE)
0332     {
0333         /* So assume data we have normal data buffer in cache
0334          * and we just run update */
0335         
0336         p_ub = (UBFH *)idata;
0337         
0338         if (NULL==(p_ub_cache = (UBFH *)tpalloc("UBF", NULL, 1024)))
0339         {
0340             NDRX_CACHE_ERROR("Failed to realloc input buffer %p to size: %ld: %s", 
0341                     idata, *olen, tpstrerror(tperrno));
0342             EXFAIL_OUT(ret);
0343         }
0344         
0345         /* we cannot do this way, because stored format is different than UBF... */
0346         
0347         if (EXSUCCEED!=ndrx_mbuf_prepare_incoming(exdata->atmi_buf, 
0348                 exdata->atmi_buf_len, (char **)&p_ub_cache, &olen_merge, flags, 0))
0349         {
0350             /* the error shall be set already */
0351             NDRX_LOG(log_error, "Failed to prepare data from cache to buffer");
0352             EXFAIL_OUT(ret);
0353         }
0354         
0355         /* prepare incoming of output buffer from the input buffer... (this is UBF copy
0356          * basically) 
0357          */
0358         if (EXSUCCEED!=buf_type->pf_prepare_incoming(buf_type, idata, 
0359                 Bused((UBFH *)idata), (char **)odata, olen, flags))
0360         {
0361             /* the error shall be set already */
0362             NDRX_LOG(log_error, "Failed to prepare incoming buffer ibuf");
0363             EXFAIL_OUT(ret);
0364         }
0365         
0366         /* reallocate place in output buffer */
0367         
0368         *olen = Bsizeof(p_ub) + exdata->atmi_buf_len + 1024;
0369         if (NULL==(*odata = tprealloc(*odata, *olen)))
0370         {
0371             /* tperror will be set already */
0372             NDRX_CACHE_ERROR("Failed to realloc input buffer %p to size: %ld: %s", 
0373                     idata, *olen, tpstrerror(tperrno));
0374             EXFAIL_OUT(ret);
0375         }
0376         
0377         p_ub = (UBFH *)*odata;
0378         
0379 #ifdef NDRX_TPCACHE_DEBUG
0380         ndrx_debug_dump_UBF(log_debug, "Updating output with", p_ub_cache);
0381 #endif
0382         if (EXSUCCEED!=Bupdate(p_ub, p_ub_cache))
0383         {
0384             NDRX_CACHE_TPERROR(TPESYSTEM, 
0385                             "Failed to update/merge buffer: %s", 
0386                     Bstrerror(Berror));
0387             EXFAIL_OUT(ret);
0388         }
0389     }
0390     else
0391     {
0392         NDRX_CACHE_TPERROR(TPEINVAL, 
0393                         "Invalid buffer get mode: flags %ld", 
0394                 cache->flags);
0395         EXFAIL_OUT(ret);
0396     }
0397     
0398 out:
0399 
0400     if (NULL!=p_ub_cache)
0401     {
0402         tpfree((char *)p_ub_cache);
0403     }
0404 
0405     if (EXSUCCEED!=ret && local_alloc)
0406     {
0407         tpfree((char *)idata);
0408         *odata=NULL;
0409     }
0410 
0411     return ret;
0412 }
0413 
0414 /**
0415  * Prepare UBF buffer projection (for pur or delete)
0416  * @param cache cache descriptor
0417  * @param pb projection descriptor
0418  * @param p_ub_in UBF buffer in
0419  * @param p_ub_out UBF buffer out (if addr not changed, then same as in)
0420  * @param flags_projreg flag of NDRX_TPCACHE_TPCF_*REG
0421  * @param flags_projfull flag of NDRX_TPCACHE_TPCF_*FULL
0422  * @param flags_projsetof flag of NDRX_TPCACHE_TPCF_*SETOF
0423  * @return EXSUCCED/EXFAIL (tp error set)
0424  */
0425 expublic int ndrx_cache_prepproj_ubf (ndrx_tpcallcache_t *cache, 
0426         ndrx_tpcache_projbuf_t *pb,
0427         UBFH *p_ub_in, UBFH **p_ub_out,
0428         long flags_projreg, long flags_projfull, long flags_projsetof)
0429 {
0430     int ret = EXSUCCEED;
0431     char *list = NULL;
0432     long list_len = 0;
0433     BFLDID fid;
0434     BFLDOCC occ;
0435     int idx = 0;
0436     char errdet[MAX_TP_ERROR_LEN+1];
0437     /* Figure out what to put */
0438     
0439     if (cache->flags & flags_projreg)
0440     {
0441         NDRX_LOG(log_debug, "project buffer by regular expression, field by field");
0442         fid = BFIRSTFLDID;
0443         
0444         while(1==Bnext(p_ub_in, &fid, &occ, NULL, NULL))
0445         {
0446             if (0==occ)
0447             {
0448                 /* Test the field against regex */
0449                 char * nm = Bfname(fid);
0450                 
0451                 NDRX_LOG(log_debug, "REX testing [%s]", nm);
0452                 if (EXSUCCEED==ndrx_regexec(&pb->regex, nm))
0453                 {
0454                     NDRX_LOG(log_debug, "Testing [%s] - OK for projection", nm);
0455                     /* loop over, match regexp, if ok, add field to projection list */
0456                     if (EXSUCCEED!=add_proj_field(&list, &list_len, idx, fid, 
0457                             errdet, sizeof(errdet)))
0458                     {
0459                         NDRX_CACHE_TPERROR(TPESYSTEM, 
0460                             "Failed to add field to projection list: %s", 
0461                                 errdet);
0462                         EXFAIL_OUT(ret);
0463                     }
0464                     idx++;
0465                 }
0466             }
0467         } /* loop over the buffer */
0468         /* copy off the projection */
0469         
0470     }
0471     
0472     if (cache->flags & flags_projfull)
0473     {
0474         NDRX_LOG(log_debug, "Project full buffer");
0475         *p_ub_out = p_ub_in;
0476     }
0477     else if (cache->flags & flags_projsetof ||
0478             cache->flags & flags_projreg)
0479     {
0480         BFLDID * cpylist;
0481         
0482         *p_ub_out = (UBFH *)tpalloc("UBF", NULL, Bsizeof((UBFH *)p_ub_in));
0483         
0484         if (NULL==*p_ub_out)
0485         {
0486             NDRX_LOG(log_error, "Failed to alloc temp buffer!");
0487             userlog("Failed to alloc temp buffer: %s", tpstrerror(tperrno));
0488         }
0489         
0490         if (cache->flags & flags_projsetof)
0491         {
0492             NDRX_LOG(log_debug, "Projection set of");
0493             
0494             cpylist = (BFLDID *)pb->typpriv;
0495         }
0496         else
0497         {
0498             NDRX_LOG(log_debug, "Projection regexp");
0499             cpylist = (BFLDID *)list;
0500         }
0501         
0502         /* OK, we have to make a projection copy */
0503         
0504         if (EXSUCCEED!=Bprojcpy(*p_ub_out, (UBFH *)p_ub_in, cpylist))
0505         {
0506             NDRX_CACHE_TPERROR(TPESYSTEM, 
0507                 "Projection copy failed for cache data: %s", Bstrerror(Berror));
0508             
0509             EXFAIL_OUT(ret);
0510         }
0511     }
0512     
0513     ndrx_debug_dump_UBF(log_debug, "Got output UBF",  *p_ub_out);
0514     
0515 out:
0516 
0517     if (NULL!=list)
0518     {
0519         NDRX_FREE(list);
0520     }
0521 
0522     return ret;
0523 }
0524 
0525 /**
0526  * Prepare delete buffer to project to 
0527  * @param cache cache
0528  * @param idata input data
0529  * @param ilen input data len (not used)
0530  * @param odata output data (double ptr) maybe same as input -> not allocated
0531  * @param olen not used
0532  * @return EXSUCCEED/EXFAIL (tperror set)
0533  */
0534 expublic int ndrx_cache_del_ubf (ndrx_tpcallcache_t *cache, char *idata, long ilen,
0535         char **odata, long *olen)
0536 {
0537     int ret = EXSUCCEED;
0538     
0539     if (EXSUCCEED!=ndrx_cache_prepproj_ubf (cache, &cache->delproj,
0540         (UBFH *)idata, (UBFH **)odata,
0541             NDRX_TPCACHE_TPCF_DELREG, 
0542             NDRX_TPCACHE_TPCF_DELFULL, 
0543             NDRX_TPCACHE_TPCF_DELSETOF))
0544     {
0545         NDRX_LOG(log_error, "Failed to prepare outgoing buffer for delete call!");
0546         EXFAIL_OUT(ret);
0547     }
0548     
0549 out:
0550     return ret;    
0551 }
0552 
0553 /**
0554  * Prepare data for saving to UBF buffer
0555  * At this stage we have to filter 
0556  * @param exdata node the len must be set to free space..
0557  * @param descr type description
0558  * @param idata input data
0559  * @param ilen input data len
0560  * @param flags flags used for prepare outgoing (from tpcall)
0561  * @return EXSUCEED/EXFAIL (tp error set)
0562  */
0563 expublic int ndrx_cache_put_ubf (ndrx_tpcallcache_t *cache,
0564         ndrx_tpcache_data_t *exdata, typed_buffer_descr_t *descr, char *idata,
0565         long ilen, long flags)
0566 {
0567     int ret = EXSUCCEED;
0568     char *buf_to_save;
0569     
0570     if (EXSUCCEED!=ndrx_cache_prepproj_ubf (cache, &cache->saveproj,
0571         (UBFH *)idata, (UBFH **)&buf_to_save, 
0572             NDRX_TPCACHE_TPCF_SAVEREG, 
0573             NDRX_TPCACHE_TPCF_SAVEFULL, 
0574             NDRX_TPCACHE_TPCF_SAVESETOF))
0575     {
0576         NDRX_LOG(log_error, "Failed to prepare buffer for save to cache!");
0577         EXFAIL_OUT(ret);
0578     }
0579     
0580     ndrx_debug_dump_UBF(log_debug, "Saving to cache", (UBFH *)buf_to_save);
0581     
0582     if (EXSUCCEED!=ndrx_mbuf_prepare_outgoing (buf_to_save, 
0583                 0, exdata->atmi_buf, &exdata->atmi_buf_len, flags, 
0584             NDRX_MBUF_FLAG_NOCALLINFO))
0585     {
0586         NDRX_LOG(log_error, "Failed to prepare buffer for saving");
0587         userlog("Failed to prepare buffer for saving: %s", tpstrerror(tperrno));
0588         EXFAIL_OUT(ret);
0589     }
0590     
0591 out:
0592 
0593     if (buf_to_save!=idata)
0594     {
0595         tpfree((char *)buf_to_save);
0596     }
0597 
0598     return ret;
0599 }
0600 
0601 /**
0602  * Store UBF field list in dynamic array
0603  * @param arr list to alloc
0604  * @param arsz array size
0605  * @param idx field index zero based
0606  * @param fid field id (compiled)
0607  * @param errdet error detail
0608  * @param errdetbufsz error detail buffer size
0609  * @return EXSUCCEED/EXFAIL
0610  */
0611 exprivate int add_proj_field(char **arr, long *arrsz, int idx, BFLDID fid, 
0612         char *errdet, int errdetbufsz)
0613 {
0614     int ret = EXSUCCEED;
0615     BFLDID *arri;
0616     if (NULL==*arr)
0617     {
0618         /* Allocate it... */
0619         
0620         *arrsz = NDRX_TPCACHE_MINLIST;
0621 #ifdef NDRX_TPCACHE_DEBUG
0622         NDRX_LOG(log_debug, "About to alloc UBF list storage: %ld", 
0623                 (*arrsz)*sizeof(BFLDID));
0624 #endif
0625         *arr = NDRX_MALLOC((*arrsz)*sizeof(BFLDID));
0626         
0627         if (NULL==*arr)
0628         {
0629             int err = errno;
0630             NDRX_LOG(log_error, "%s: Failed to malloc %ld: %s", __func__, 
0631                     (*arrsz)*sizeof(BFLDID), strerror(err));
0632             snprintf(errdet, errdetbufsz, "%s: Failed to malloc %ld: %s", __func__, 
0633                     (*arrsz)*sizeof(BFLDID), strerror(err));
0634             EXFAIL_OUT(ret);        
0635         }
0636         
0637     }
0638     else if (*arrsz<idx+2) /* idx zero based, thus +1 and 1+ for BBADFLDID */
0639     {
0640         
0641         *arrsz = *arrsz + NDRX_TPCACHE_MINLIST;
0642 #ifdef NDRX_TPCACHE_DEBUG
0643         NDRX_LOG(log_debug, "About to realloc UBF list storage: %ld", 
0644                 (*arrsz)*sizeof(BFLDID));
0645 #endif        
0646         *arr = NDRX_REALLOC(*arr, 
0647                 (*arrsz)*sizeof(BFLDID));
0648         
0649         if (NULL==*arr)
0650         {
0651             int err = errno;
0652             NDRX_LOG(log_error, "%s: Failed to realloc (%ld): %s", __func__, 
0653                     (*arrsz)*sizeof(BFLDID), strerror(err));
0654             snprintf(errdet, errdetbufsz, "%s: Failed to malloc (%ld): %s", __func__, 
0655                     (*arrsz)*sizeof(BFLDID), strerror(err));
0656             EXFAIL_OUT(ret);        
0657         }
0658     }
0659     
0660     /* OK we are done... add at index */
0661     arri = (BFLDID *)(*arr);
0662     arri[idx] = fid;
0663     arri[idx+1] = BBADFLDID;
0664     
0665 out:
0666     return ret;
0667 }
0668 
0669 /**
0670  * Process typed flags of the buffer projection
0671  * @param cache cache object
0672  * @param pb projection buffer
0673  * @param op operation (for debug - string)
0674  * @param flags_projreg flag constant for regex save/del
0675  * @param flags_projfull flag constant for proj full
0676  * @param flags_projsetof flag constant for save set of
0677  * @param errdet error detail return
0678  * @param errdetbufsz error buffer size
0679  * @return EXSUCCEED/EXFAIL (TP error not set ar error detail returned)
0680  */
0681 exprivate int proc_flags_typed(ndrx_tpcallcache_t *cache, 
0682         ndrx_tpcache_projbuf_t *pb, char *op,
0683         long flags_projreg, long flags_projfull, long flags_projsetof,
0684         char *errdet, int errdetbufsz)
0685 {
0686    int ret = EXSUCCEED;
0687     char *saveptr1 = NULL;
0688     char *p;
0689     char tmp[PATH_MAX+1];
0690     BFLDID fid;
0691     int idx = 0;
0692     
0693     /* Process some additional rules
0694      * - If no save strategy is given, then '*' means full buffer
0695      * - If '*' is not found, then build a project copy list
0696      */
0697     if (!(cache->flags & flags_projreg) && !(cache->flags & flags_projfull))
0698     {
0699         if (0==strcmp(pb->expression, "*") || EXEOS==pb->expression[0])
0700         {
0701 #ifdef NDRX_TPCACHE_DEBUG
0702             NDRX_LOG(log_debug, "%s strategy defaulted to full UBF buffer", op);
0703 #endif
0704             cache->flags |= flags_projfull;
0705         }
0706         else
0707         {
0708             cache->flags |= flags_projsetof;
0709 #ifdef NDRX_TPCACHE_DEBUG
0710             NDRX_LOG(log_debug, "%s strategy: list of fields - parsing...", op);
0711 #endif
0712             /* expression max = PATH_MAX on given platform */
0713             NDRX_STRCPY_SAFE(tmp, pb->expression);
0714             
0715             /* clean up save string... */            
0716             ndrx_str_strip(tmp, "\t ");
0717             
0718             /* Strtok... & build the list of projection copy fields */
0719             p = strtok_r (tmp, ",", &saveptr1);
0720             while (p != NULL)
0721             {
0722                 /* Lookup the field id,  */
0723                 
0724                 NDRX_LOG(log_debug, "Got field [%s]", p);
0725                 
0726                 if (EXFAIL==(fid=Bfldid(p)))
0727                 {
0728                     NDRX_LOG(log_error, "Failed to resolve filed id: [%s]: %s", 
0729                             p, Bstrerror(Berror));
0730                     snprintf(errdet, errdetbufsz, "Failed to resolve filed id: [%s]: %s", 
0731                             p, Bstrerror(Berror));
0732                     EXFAIL_OUT(ret);
0733                 }
0734                 
0735                 if (EXSUCCEED!=add_proj_field((char **)&pb->typpriv, 
0736                             &pb->typpriv2, idx, fid, errdet, errdetbufsz))
0737                 {
0738                     NDRX_LOG(log_error, "Failed to add field to projection list!");
0739                     EXFAIL_OUT(ret);
0740                 }
0741                 
0742                 p = strtok_r (NULL, ",", &saveptr1);
0743                 idx++;
0744             }
0745         }
0746     }
0747 out:
0748     return ret;    
0749 }
0750 
0751 /**
0752  * Process flags. Here we prepare projection copy if needed.
0753  * @param cache cache on which to execute
0754  * @param errdet error detail
0755  * @param errdetbufsz error buffer size
0756  * @return EXSUCCEED/EXFAIL (no tperror)
0757  */
0758 expublic int ndrx_cache_proc_flags_ubf(ndrx_tpcallcache_t *cache, 
0759         char *errdet, int errdetbufsz)
0760 {
0761     int ret = EXSUCCEED;
0762     
0763     if (EXSUCCEED!=(ret = proc_flags_typed(cache, 
0764         &cache->saveproj, "save",
0765         NDRX_TPCACHE_TPCF_SAVEREG, 
0766         NDRX_TPCACHE_TPCF_SAVEFULL,
0767         NDRX_TPCACHE_TPCF_SAVESETOF,
0768         errdet, errdetbufsz)))
0769     {
0770         EXFAIL_OUT(ret);
0771     }
0772     
0773     if (EXSUCCEED!=(ret = proc_flags_typed(cache, 
0774         &cache->delproj, "delete",
0775         NDRX_TPCACHE_TPCF_DELREG, 
0776         NDRX_TPCACHE_TPCF_DELFULL,
0777         NDRX_TPCACHE_TPCF_DELSETOF,
0778         errdet, errdetbufsz)))
0779     {
0780         EXFAIL_OUT(ret);
0781     }
0782     
0783     
0784     /* Process reject buffer if any */
0785     
0786     if (NULL!=cache->keygroupmrej)
0787     {
0788         /* parse it. JSON2UBF */
0789         UBFH *p_ub = (UBFH *)tpalloc("UBF", NULL, strlen(cache->keygroupmrej)*3+1024);
0790         
0791         if (EXSUCCEED!=ndrx_tpjsontoubf(p_ub, cache->keygroupmrej, NULL))
0792         {
0793             snprintf(errdet, errdetbufsz, "%s: Failed to parse json: [%s]", 
0794                     __func__, cache->keygroupmrej);
0795             NDRX_LOG(log_error, errdet);
0796             EXFAIL_OUT(ret);
0797         }
0798         
0799         
0800         /* reallocate the buffer to exact size */
0801         
0802         if (NULL==(p_ub = (UBFH *)tprealloc((char *)p_ub, Bused(p_ub)+1024)))
0803         {
0804             snprintf(errdet, errdetbufsz, "%s: to reallocate reject buffer: %s", 
0805                     __func__, tpstrerror(tperrno));
0806             EXFAIL_OUT(ret);
0807         }
0808         
0809         cache->keygroupmrej_abuf = (char *)p_ub;
0810         
0811     }
0812 out:
0813     return ret;
0814 }
0815 
0816 /**
0817  * Free up internal resources
0818  * @param cache cache to free-up
0819  * @return EXSUCCEED
0820  */
0821 expublic int ndrx_cache_delete_ubf(ndrx_tpcallcache_t *cache)
0822 {
0823     if (NULL!=cache->rule_tree)
0824     {
0825         Btreefree(cache->rule_tree);
0826     }
0827     
0828     if (NULL!=cache->refreshrule_tree)
0829     {
0830         Btreefree(cache->refreshrule_tree);
0831     }
0832     
0833     if (NULL!=cache->saveproj.typpriv)
0834     {
0835         NDRX_FREE(cache->saveproj.typpriv);
0836     }
0837     
0838     if (NULL!=cache->delproj.typpriv)
0839     {
0840         NDRX_FREE(cache->delproj.typpriv);
0841     }
0842     
0843     return EXSUCCEED;
0844 }
0845 
0846 /**
0847  * Reject request when max reached
0848  * @param cache
0849  * @param idata
0850  * @param ilen
0851  * @param odata
0852  * @param olen
0853  * @param flags
0854  * @param [in] buf_type buffer type of processing
0855  * @return 
0856  */
0857 expublic int ndrx_cache_maxreject_ubf(ndrx_tpcallcache_t *cache, char *idata, long ilen, 
0858         char **odata, long *olen, long flags, typed_buffer_descr_t *buf_type)
0859 {
0860     int ret = EXSUCCEED;
0861     long ibuf_bufsz;
0862     long rej_bufsz;
0863     
0864     UBFH *p_ub = (UBFH *)idata;
0865     UBFH *p_rej_ub = (UBFH *)cache->keygroupmrej_abuf;
0866     
0867     /* we have a buffer already stored in config. */
0868     
0869     NDRX_LOG(log_debug, "%s enter", __func__);
0870     
0871     if ((rej_bufsz = Bsizeof(p_rej_ub)) < 0)
0872     {
0873         NDRX_CACHE_TPERROR(TPEINVAL, "Invalid reject buffer - failed "
0874                 "to get size: %s", Bstrerror(Berror));
0875         EXFAIL_OUT(ret);
0876     }
0877     
0878     if ((ibuf_bufsz = Bsizeof(p_ub)) < 0)
0879     {
0880         NDRX_CACHE_TPERRORNOU(TPEINVAL, "Invalid user buffer - failed "
0881                 "to get size: %s", Bstrerror(Berror));
0882         EXFAIL_OUT(ret);
0883     }
0884 
0885     
0886     if (cache->flags & NDRX_TPCACHE_TPCF_REPL)
0887     {    
0888 #if 0
0889         /* if we look on replace then we need buffer size to be atleast in size
0890          * of reject buffer */
0891         if (ibuf_bufsz<rej_bufsz)
0892         { 
0893             if (NULL==(p_ub = (UBFH *)tprealloc((char *)p_ub, rej_bufsz)))
0894             {
0895                 NDRX_CACHE_TPERROR(TPEINVAL, "Failed to reallocate user buffer: %s",
0896                             tpstrerror(tperrno));
0897                 EXFAIL_OUT(ret);
0898             }
0899         }
0900 #endif
0901         
0902         ndrx_debug_dump_UBF(log_debug, "Error response (replacing rsp with)", 
0903                 p_rej_ub);
0904 #if 0  
0905         if (EXSUCCEED!=Bcpy(p_ub, p_rej_ub))
0906         {
0907             NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Failed to preapre response buffer: %s", 
0908                     __func__, Bstrerror(Berror));
0909             EXFAIL_OUT(ret);
0910         }
0911 #endif
0912         if (EXSUCCEED!=ndrx_mbuf_prepare_incoming((char *)p_rej_ub, 
0913                 Bused(p_rej_ub), odata, olen, flags, 0))
0914         {
0915             /* the error shall be set already */
0916             NDRX_LOG(log_error, "Failed to prepare data from cache to buffer");
0917             EXFAIL_OUT(ret);
0918         }
0919 
0920         
0921     }
0922     else if (cache->flags & NDRX_TPCACHE_TPCF_MERGE)
0923     {
0924         
0925         ndrx_debug_dump_UBF(log_debug, "Error response (updating response with)", 
0926                 p_rej_ub);
0927         
0928         /* Ensure that in buffer we have enough space */
0929         
0930         if (EXSUCCEED!=buf_type->pf_prepare_incoming(buf_type, (char *)p_ub, 
0931                 Bused(p_ub), odata, olen, flags))
0932         {
0933             /* the error shall be set already */
0934             NDRX_LOG(log_error, "Failed to prepare data from cache to buffer");
0935             EXFAIL_OUT(ret);
0936         }
0937         
0938         if (NULL==(*odata = tprealloc(*odata, ibuf_bufsz+rej_bufsz+1024)))
0939         {
0940             NDRX_CACHE_TPERROR(TPEINVAL, "Failed to reallocate user buffer: %s",
0941                         tpstrerror(tperrno));
0942             EXFAIL_OUT(ret);
0943         }
0944 
0945         if (EXSUCCEED!=Bupdate((UBFH *)*odata, p_rej_ub))
0946         {
0947             NDRX_CACHE_TPERROR(TPESYSTEM, 
0948                             "Failed to update/merge buffer: %s", 
0949                     Bstrerror(Berror));
0950             EXFAIL_OUT(ret);
0951         }
0952         
0953         ndrx_debug_dump_UBF(log_debug, "Got merged response",  p_rej_ub);
0954         
0955     }
0956     else
0957     {
0958         NDRX_CACHE_TPERROR(TPEINVAL, 
0959                         "Invalid buffer get mode: flags %ld", 
0960                 cache->flags);
0961         EXFAIL_OUT(ret);
0962     }
0963     
0964 out:
0965 
0966     return ret;
0967 }
0968 /* vim: set ts=4 sw=4 et smartindent: */