Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief ATMI level cache - operations.
0003  *   Inval - their change only at point when we are going to save the results
0004  *   in DB. And hopefully we get hopefully we get the newest result?
0005  *   In case of keygroup if keyitem is deleted, then all items shall be deleted,
0006  *   and keygroup shall be removed.
0007  *
0008  * @file atmi_cache_ops.c
0009  */
0010 /* -----------------------------------------------------------------------------
0011  * Enduro/X Middleware Platform for Distributed Transaction Processing
0012  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0013  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0014  * This software is released under one of the following licenses:
0015  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0016  * See LICENSE file for full text.
0017  * -----------------------------------------------------------------------------
0018  * AGPL license:
0019  *
0020  * This program is free software; you can redistribute it and/or modify it under
0021  * the terms of the GNU Affero General Public License, version 3 as published
0022  * by the Free Software Foundation;
0023  *
0024  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0025  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0026  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0027  * for more details.
0028  *
0029  * You should have received a copy of the GNU Affero General Public License along 
0030  * with this program; if not, write to the Free Software Foundation, Inc.,
0031  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0032  *
0033  * -----------------------------------------------------------------------------
0034  * A commercial use license is available from Mavimax, Ltd
0035  * contact@mavimax.com
0036  * -----------------------------------------------------------------------------
0037  */
0038 
0039 /*---------------------------Includes-----------------------------------*/
0040 #include <stdlib.h>
0041 #include <stdio.h>
0042 #include <errno.h>
0043 #include <string.h>
0044 #include <ndrstandard.h>
0045 #include <atmi.h>
0046 #include <atmi_tls.h>
0047 #include <typed_buf.h>
0048 
0049 #include "thlock.h"
0050 #include "userlog.h"
0051 #include "utlist.h"
0052 #include "exregex.h"
0053 #include <exparson.h>
0054 #include <atmi_cache.h>
0055 #include <Exfields.h>
0056 /*---------------------------Externs------------------------------------*/
0057 /*---------------------------Macros-------------------------------------*/
0058 /*---------------------------Enums--------------------------------------*/
0059 /*---------------------------Typedefs-----------------------------------*/
0060 /*---------------------------Globals------------------------------------*/
0061 /*---------------------------Statics------------------------------------*/
0062 /*---------------------------Prototypes---------------------------------*/
0063 /**
0064  * Check response rule, should we cache this or not
0065  * @param cache cache object
0066  * @param save_tperrno tperror number
0067  * @param save_tpurcode user return code
0068  * @return EXFAIL/EXFALSE/EXTRUE
0069  */
0070 exprivate int ndrx_cache_chkrsprule(ndrx_tpcallcache_t *cache, 
0071             long save_tperrno, long save_tpurcode)
0072 {
0073     int ret = EXFALSE;
0074     char buf[512];
0075     UBFH *p_ub = (UBFH *)buf;
0076     
0077     if (EXSUCCEED!=Binit(p_ub, sizeof(buf)))
0078     {
0079         NDRX_CACHE_TPERROR(TPESYSTEM, "cache: failed to init response check buffer: %s",
0080                 Bstrerror(Berror));
0081         EXFAIL_OUT(ret);
0082     }
0083     
0084     /* Load the data into buffer */
0085     
0086     if (EXSUCCEED!=Bchg(p_ub, EX_TPERRNO, 0, (char *)&save_tperrno, 0L))
0087     {
0088         NDRX_CACHE_TPERROR(TPESYSTEM, "cache: Failed to set EX_TPERRNO[0] to %ld: %s",
0089                 save_tperrno, Bstrerror(Berror));
0090         EXFAIL_OUT(ret);
0091     }
0092     
0093     if (EXSUCCEED!=Bchg(p_ub, EX_TPURCODE, 0, (char *)&save_tpurcode, 0L))
0094     {
0095         NDRX_CACHE_TPERROR(TPESYSTEM, "cache: Failed to set EX_TPURCODE[0] to %ld: %s",
0096                 save_tpurcode, Bstrerror(Berror));
0097         EXFAIL_OUT(ret);
0098     }
0099     
0100     /* Finally evaluate the expression */
0101     
0102     if (EXFAIL==(ret=Bboolev(p_ub, cache->rsprule_tree)))
0103     {
0104         NDRX_CACHE_TPERROR(TPESYSTEM, "cache: Failed to evalute [%s] "
0105                 "tree: %p expression: %s",
0106                 cache->rsprule, cache->rsprule_tree, Bstrerror(Berror));
0107         EXFAIL_OUT(ret);
0108     }
0109     
0110     NDRX_LOG(log_debug, "Response expression [%s]: %s", cache->rsprule,
0111             (EXTRUE==ret?"TRUE":"FALSE"));
0112     
0113 out:
0114             
0115     return ret;
0116 
0117 }
0118 
0119 /**
0120  * Save data to cache. If doing save and this is key item. then we shall update
0121  * the key group (add new key to keygroup...).
0122  * @param idata
0123  * @param ilen
0124  * @param save_tperrno
0125  * @param save_tpurcode
0126  * @param nodeid cluster node id who put the message in cache
0127  * @param t time stamp sec from EPOCH
0128  * @param tusec micro seconds of ECPOCH time
0129  * @param is_event did we receive this from event server?
0130  * @return EXSUCCEED/EXFAIL/NDRX_TPCACHE_ENOCACHE
0131  */
0132 expublic int ndrx_cache_save (char *svc, char *idata, 
0133         long ilen, int save_tperrno, long save_tpurcode, int nodeid, long flags,
0134         int tusec, long t, int is_event)
0135 {
0136     int ret = EXSUCCEED;
0137     /* have a buffer in size of ATMI message */
0138     char *buf=NULL;
0139     size_t buf_len;
0140     ndrx_tpcache_svc_t *svcc = NULL;
0141     typed_buffer_descr_t *buf_type;
0142     buffer_obj_t *buffer_info;
0143     ndrx_tpcallcache_t *cache;
0144     ndrx_tpcache_data_t *exdata;
0145     int tran_started = EXFALSE;
0146     EDB_txn *txn;
0147     char key[NDRX_CACHE_KEY_MAX+1];
0148     char errdet[MAX_TP_ERROR_LEN+1];
0149     EDB_val cachedata;
0150     int is_matched=EXFALSE;
0151     
0152     NDRX_SYSBUF_MALLOC_WERR_OUT(buf, buf_len, ret);
0153     exdata = (ndrx_tpcache_data_t *)buf;
0154             
0155     memset(exdata, 0, sizeof(ndrx_tpcache_data_t));
0156     
0157     exdata->magic = NDRX_CACHE_MAGIC;
0158     NDRX_STRCPY_SAFE(exdata->svcnm, svc);
0159     exdata->nodeid = nodeid;
0160     exdata->saved_tperrno = save_tperrno;
0161     exdata->saved_tpurcode = save_tpurcode;
0162     
0163     /* get current timestamp */
0164     if (EXFAIL==t)
0165     {
0166         ndrx_utc_tstamp2(&exdata->t, &exdata->tusec);
0167     }
0168     else
0169     {
0170         exdata->t = t;
0171         exdata->tusec = (long)tusec;
0172     }
0173     
0174 #ifdef NDRX_TPCACHE_DEBUG
0175     NDRX_LOG(log_debug, "Cache time: t=%ld tusec=%ld",
0176             exdata->t, exdata->tusec);
0177 #endif
0178         
0179     /* OK now translate the thing to db format (i.e. make outgoing message) */
0180     
0181     /* Find service in cache */
0182     EXHASH_FIND_STR(ndrx_G_tpcache_svc, svc, svcc);
0183     
0184     if (NULL==svcc)
0185     {
0186 #ifdef NDRX_TPCACHE_DEBUG
0187         NDRX_LOG(log_debug, "No cache defined for [%s]", svc);
0188 #endif
0189         ret = NDRX_TPCACHE_ENOCACHE;
0190         goto out;
0191     }
0192     
0193     if (NULL==(buffer_info = ndrx_find_buffer(idata)))
0194     {
0195         ndrx_TPset_error_fmt(TPEINVAL, "%s: Buffer %p not known to system!", 
0196                 __func__, idata);
0197         EXFAIL_OUT(ret);
0198     }
0199     
0200     buf_type = &G_buf_descr[buffer_info->type_id];
0201     
0202     DL_FOREACH(svcc->caches, cache)
0203     {
0204         is_matched = EXFALSE;
0205         
0206         if (cache->buf_type->type_id == buf_type->type_id)
0207         {
0208             if (ndrx_G_tpcache_types[cache->buf_type->type_id].pf_rule_eval)
0209             {
0210                 ret = ndrx_G_tpcache_types[cache->buf_type->type_id].pf_rule_eval(
0211                         cache, idata, ilen, errdet, sizeof(errdet));
0212                 if (EXFAIL==ret)
0213                 {
0214                     NDRX_CACHE_TPERROR(TPEINVAL, "%s: Failed to evaluate buffer [%s]: %s", 
0215                             __func__, cache->rule, errdet);
0216                     
0217                     EXFAIL_OUT(ret);
0218                 }
0219                 else if (EXFALSE==ret)
0220                 {
0221 #ifdef NDRX_TPCACHE_DEBUG
0222                     NDRX_LOG(log_debug, "Buffer RULE FALSE [%s] - continue", cache->rule);
0223 #endif
0224                     continue;
0225                 }
0226                 
0227                 is_matched = EXTRUE;
0228                 ret = EXSUCCEED;
0229             }
0230             else
0231             {
0232                 /* We should not get here! */
0233                 NDRX_CACHE_TPERROR(TPEINVAL,"%s: Unsupported buffer type [%s] for cache", 
0234                                 __func__, cache->buf_type->type);
0235                 EXFAIL_OUT(ret);
0236             }
0237         }
0238         
0239         /* Test the rule, if and not found then stage to NDRX_TPCACHE_ENOTFOUNADD 
0240          * OK, we need to build a key
0241          */
0242 
0243         NDRX_STRCPY_SAFE(key, cache->keyfmt);
0244 
0245         /* Build the key... */
0246         if (EXSUCCEED!=(ret = ndrx_G_tpcache_types[buffer_info->type_id].pf_get_key(
0247                 cache, idata, ilen, key, sizeof(key), errdet, sizeof(errdet))))
0248         {
0249             if (NDRX_TPCACHE_ENOKEYDATA==ret)
0250             {
0251                 NDRX_LOG(log_debug, "Failed to build key (no data for key): %s", errdet);
0252                 goto out;
0253             }
0254             else
0255             {
0256                 NDRX_CACHE_TPERRORNOU(TPESYSTEM, "%s: Failed to build cache key: %s", 
0257                         __func__, errdet);
0258                 goto out;
0259             }
0260         }
0261         
0262         if (cache->flags & NDRX_TPCACHE_TPCF_INVAL)
0263         {
0264             /* Invalidate their cache */
0265             if (EXSUCCEED!=ndrx_cache_inval_their(svc, cache, key, idata, ilen))
0266             {
0267                 NDRX_LOG(log_error, "Failed to invalidate their cache!");
0268             }
0269             
0270             is_matched=EXFALSE;
0271         }
0272         
0273         if (cache->flags & NDRX_TPCACHE_TPCF_NEXT)
0274         {
0275 #ifdef NDRX_TPCACHE_DEBUG
0276             NDRX_LOG(log_debug, "Next flag present, go to next cache (if have one)");
0277 #endif
0278             is_matched=EXFALSE;
0279             continue;
0280         }
0281         else
0282         {
0283             break;
0284         }
0285     }
0286     
0287     /* cache not found */
0288     if (!is_matched)
0289     {
0290         
0291 #ifdef NDRX_TPCACHE_DEBUG
0292         NDRX_LOG(log_debug, "No cache defined for [%s], buffer type [%s] "
0293                 "or all was invalidate", svc, buf_type->type);
0294 #endif
0295         ret = NDRX_TPCACHE_ENOCACHE;
0296         goto out;
0297     }
0298     
0299     exdata->flags = cache->flags;
0300     exdata->cache_idx = cache->idx;
0301     exdata->atmi_type_id = buffer_info->type_id;
0302     exdata->atmi_buf_len = NDRX_MSGSIZEMAX - sizeof(ndrx_tpcache_data_t);
0303             
0304     if (NULL==ndrx_G_tpcache_types[cache->buf_type->type_id].pf_cache_put)
0305     {
0306         ret = NDRX_TPCACHE_ENOTYPESUPP;
0307         goto out;
0308         
0309     }
0310     
0311     /* Check the response rule if defined */
0312     
0313     if (NULL!=cache->rsprule_tree)
0314     {
0315         if (EXFAIL==(ret=ndrx_cache_chkrsprule(cache, (long)save_tperrno, 
0316                 save_tpurcode)))
0317         {
0318             NDRX_LOG(log_error, "Failed to test response code");
0319             EXFAIL_OUT(ret);
0320         }
0321         
0322         if (EXFALSE==ret)
0323         {
0324             NDRX_LOG(log_info, "Response shall not be saved according to rsp rule");
0325             ret = EXSUCCEED;
0326             goto out;
0327         }
0328         
0329         ret = EXSUCCEED;
0330     }
0331     else if (0!=save_tperrno)
0332     {
0333         NDRX_LOG(log_info, "Not storing error responses (by default)");
0334         ret = EXSUCCEED;
0335         goto out;
0336     }
0337     
0338     if (EXSUCCEED!=ndrx_G_tpcache_types[cache->buf_type->type_id].pf_cache_put(
0339             cache, exdata, buf_type, idata, ilen, flags))
0340     {
0341         /* Error shall be set by func */
0342         NDRX_LOG(log_error, "Failed to convert to cache format!!!");
0343         EXFAIL_OUT(ret);
0344         
0345     }
0346     
0347     NDRX_LOG(log_info, "About to cache data for service: [%s]", svc);
0348     
0349     
0350     NDRX_STRCPY_SAFE(key, cache->keyfmt);
0351        
0352     /* Build the key... */
0353     if (EXSUCCEED!=(ret = ndrx_G_tpcache_types[buffer_info->type_id].pf_get_key(cache, idata, 
0354             ilen, key, sizeof(key), errdet, sizeof(errdet))))
0355     {
0356         if (NDRX_TPCACHE_ENOKEYDATA==ret)
0357         {
0358             NDRX_LOG(log_debug, "Failed to build key (no data for key): %s", errdet);
0359             goto out;
0360         }
0361         else
0362         {
0363             NDRX_LOG(log_error, "Failed to build key: ", errdet);
0364             
0365             /* generate TP error here! */
0366             ndrx_TPset_error_fmt(TPESYSTEM, "%s: Failed to build cache key: %s", 
0367                     __func__, errdet);
0368             goto out;
0369         }
0370             
0371     }
0372     
0373     if (EXSUCCEED!=(ret=ndrx_cache_edb_begin(cache->cachedb, &txn, 0)))
0374     {
0375         NDRX_LOG(log_error, "%s: failed to start tran", __func__);
0376         goto out;
0377     }
0378     tran_started = EXTRUE;
0379     
0380     /* Firstly add record to the key group if needed */
0381     
0382     if (cache->flags & NDRX_TPCACHE_TPCF_KEYITEMS)
0383     {
0384         if (EXSUCCEED!=(ret=ndrx_cache_keygrp_addupd(cache, idata, ilen, 
0385                 key, NULL, EXFALSE, txn)))
0386         {
0387             NDRX_LOG(log_error, "Failed to add keygroup record!");
0388             goto out;
0389         }
0390     }
0391     
0392     
0393     /* Add the record to the DB, to specific key! */
0394 #if 0
0395     if (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_TIMESYNC)
0396     {
0397         dbflags = EDB_APPENDDUP;
0398     }
0399     else
0400     {
0401         dbflags = 0;
0402     }
0403 #endif
0404     
0405     cachedata.mv_data = (void *)exdata;
0406     cachedata.mv_size = exdata->atmi_buf_len + sizeof(ndrx_tpcache_data_t);
0407     
0408     
0409     NDRX_LOG(log_info, "About to put to cache: svc: [%s] key: [%s]: size: %ld",
0410             svcc->svcnm, key, (long)cachedata.mv_size);
0411     
0412     if (EXSUCCEED!=(ret=ndrx_cache_edb_put (cache->cachedb, txn, 
0413             key, &cachedata, 0, EXFALSE)))
0414     {
0415         NDRX_LOG(log_debug, "Failed to put DB record!");
0416         goto out;
0417     }
0418     
0419     NDRX_LOG(log_debug, "Data cached, key [%s]", key);
0420     
0421     if ((cache->cachedb->flags & NDRX_TPCACHE_FLAGS_BCASTPUT)
0422         && !is_event)
0423     {
0424         if (EXSUCCEED!=ndrx_cache_broadcast(cache, svc, idata, ilen, 
0425                 NDRX_CACHE_BCAST_MODE_PUT, NDRX_TPCACHE_BCAST_DFLT, 
0426                 (int)exdata->tusec, (long)exdata->t, 
0427                 save_tperrno, save_tpurcode))
0428         {
0429             NDRX_LOG(log_error, "WARNING ! Failed to broadcast put event - continue");
0430         }
0431     }
0432     
0433 out:
0434 
0435     if (tran_started)
0436     {
0437         /* in case if no cache, we might have done invalidate... */
0438         if (EXSUCCEED==ret || NDRX_TPCACHE_ENOCACHE==ret)
0439         {
0440             ndrx_cache_edb_commit(cache->cachedb, txn);
0441         }
0442         else
0443         {
0444             ndrx_cache_edb_abort(cache->cachedb, txn);
0445         }
0446     }
0447 
0448     if (NULL!=buf)
0449     {
0450         NDRX_SYSBUF_FREE(buf);
0451     }
0452 
0453     return ret;
0454 }
0455 
0456 /**
0457  * Lookup service in cache.
0458  * We do not do writes here, thus we can use read only cursors...
0459  * @param svc service to call
0460  * @param idata input data buffer
0461  * @param ilen input len
0462  * @param odata output data buffer
0463  * @param olen output len
0464  * @param flags flags
0465  * @param should_cache should record be cached?
0466  * @param seterror_not_found should we generate error if record is not found?
0467  * @param[in] noenterr is no entry error currently?
0468  * @return EXSUCCEED/EXFAIL (syserr)/NDRX_TPCACHE_ENOKEYDATA (cannot build key)
0469  */
0470 expublic int ndrx_cache_lookup(char *svc, char *idata, long ilen, 
0471         char **odata, long *olen, long flags, int *should_cache, 
0472         int *saved_tperrno, long *saved_tpurcode, int seterror_not_found,
0473         int noenterr)
0474 {
0475     int ret = EXSUCCEED;
0476     ndrx_tpcache_svc_t *svcc = NULL;
0477     typed_buffer_descr_t *buf_type;
0478     buffer_obj_t *buffer_info;
0479     ndrx_tpcallcache_t *cache;
0480     char key[NDRX_CACHE_KEY_MAX+1];
0481     char errdet[MAX_TP_ERROR_LEN+1];
0482     EDB_txn *txn;
0483     int cursor_open = EXFALSE;
0484     EDB_cursor *cursor;
0485     int tran_started = EXFALSE;
0486     EDB_val cachedata;
0487     EDB_val cachedata_update;
0488     EDB_val cachedata_delete;
0489     ndrx_tpcache_data_t *exdata;
0490     ndrx_tpcache_data_t *exdata_update;
0491     int is_matched;
0492     int align;
0493     char *defer_free = NULL;
0494     unsigned int flagsdb;
0495     int force_abort = EXFALSE;
0496     /* Key size - assume 16K should be fine */
0497     /* get buffer type & sub-type */
0498     cachedata_update.mv_size = 0;
0499     cachedata_update.mv_data = NULL;
0500         
0501     /* Find service in cache */
0502     EXHASH_FIND_STR(ndrx_G_tpcache_svc, svc, svcc);
0503     
0504     if (NULL==svcc)
0505     {
0506 #ifdef NDRX_TPCACHE_DEBUG
0507         NDRX_LOG(log_debug, "No cache defined for [%s]", svc);
0508 #endif
0509         ret = NDRX_TPCACHE_ENOCACHE;
0510         goto out;
0511     }
0512     
0513     if (NULL==(buffer_info = ndrx_find_buffer(idata)))
0514     {
0515         ndrx_TPset_error_fmt(TPEINVAL, "%s: Buffer %p not known to system!", 
0516                 __func__, idata);
0517         EXFAIL_OUT(ret);
0518     }
0519     
0520     
0521     /* Loop over the tpcallcaches, if `next' flag present, then perform next
0522      * if we get invalidate their, then delete target records by the key */
0523     buf_type = &G_buf_descr[buffer_info->type_id];
0524 
0525     DL_FOREACH(svcc->caches, cache)
0526     {
0527         is_matched = EXFALSE;
0528         
0529         if (cache->buf_type->type_id == buf_type->type_id)
0530         {   
0531             if (ndrx_G_tpcache_types[cache->buf_type->type_id].pf_rule_eval)
0532             {
0533                 ret = ndrx_G_tpcache_types[cache->buf_type->type_id].pf_rule_eval(
0534                         cache, idata, ilen, errdet, sizeof(errdet));
0535                 if (EXFAIL==ret)
0536                 {
0537                     NDRX_CACHE_TPERROR(TPEINVAL, "%s: Failed to evaluate buffer [%s]: %s", 
0538                             __func__, cache->rule, errdet);
0539                     
0540                     EXFAIL_OUT(ret);
0541                 }
0542                 else if (EXFALSE==ret)
0543                 {
0544 #ifdef NDRX_TPCACHE_DEBUG
0545                     NDRX_LOG(log_debug, "Buffer RULE FALSE [%s] - try next", 
0546                             cache->rule);
0547 #endif
0548                     continue;
0549                 }
0550                 
0551                 NDRX_LOG(log_debug, "rule [%s] matched", cache->rule);
0552                 is_matched = EXTRUE;
0553                 
0554                 
0555                 /* any way if matched any then we want next cache run.. */
0556                 
0557                 *should_cache=EXTRUE;
0558                 
0559                 ret = EXSUCCEED;
0560             }
0561             else
0562             {
0563                 /* We should not get here! */
0564                 NDRX_CACHE_TPERROR(TPEINVAL,"%s: Unsupported buffer type [%s] for cache", 
0565                                 __func__, cache->buf_type->type);
0566                 EXFAIL_OUT(ret);
0567             }
0568         }
0569         
0570         /* if we are here, the cache is matched */
0571         
0572         if (!(cache->flags & NDRX_TPCACHE_TPCF_INVAL))
0573         {
0574             /* ONLY IN CASE IF NOT INVAL - Check should we refresh? */
0575             if (NULL!=ndrx_G_tpcache_types[cache->buf_type->type_id].pf_refreshrule_eval &&
0576                     EXEOS!=cache->refreshrule[0])
0577             {
0578                 ret = ndrx_G_tpcache_types[cache->buf_type->type_id].pf_refreshrule_eval(cache, 
0579                         idata, ilen, errdet, sizeof(errdet));
0580                 if (EXFAIL==ret)
0581                 {
0582                     /* Failed to eval refresh rule */
0583                     NDRX_LOG(log_error, "Failed to eval refresh rule: %s", errdet);
0584 
0585                     ndrx_TPset_error_fmt(TPESYSTEM, "Failed to eval refresh rule: %s", 
0586                             errdet);
0587                     EXFAIL_OUT(ret);
0588                 }
0589                 else if (EXTRUE==ret)
0590                 {
0591                     NDRX_LOG(log_info, "Cache will be refreshed - rule matched "
0592                             "(do not continue cache lookup)");
0593                     *should_cache=EXTRUE;
0594                     ret = NDRX_TPCACHE_ENOCACHEDATA;
0595                     goto out;
0596                 }
0597             }
0598         }
0599 
0600         /* Test the rule, if and not found then stage to NDRX_TPCACHE_ENOTFOUNADD 
0601          * OK, we need to build a key
0602          */
0603 
0604         NDRX_STRCPY_SAFE(key, cache->keyfmt);
0605 
0606         /* Build the key... */
0607         if (EXSUCCEED!=(ret = ndrx_G_tpcache_types[buffer_info->type_id].pf_get_key(
0608                 cache, idata, ilen, key, sizeof(key), errdet, sizeof(errdet))))
0609         {
0610             if (NDRX_TPCACHE_ENOKEYDATA==ret)
0611             {
0612                 NDRX_LOG(log_debug, "Failed to build key (no data for key): %s", errdet);
0613                 goto out;
0614             }
0615             else
0616             {
0617                 NDRX_LOG(log_error, "Failed to build key: ", errdet);
0618 
0619                 /* generate TP error here! */
0620                 ndrx_TPset_error_fmt(TPESYSTEM, "%s: Failed to build cache key: %s", 
0621                         __func__, errdet);
0622                 goto out;
0623             }
0624         }
0625         
0626         if (cache->flags & NDRX_TPCACHE_TPCF_NEXT)
0627         {
0628 #ifdef NDRX_TPCACHE_DEBUG
0629             NDRX_LOG(log_debug, "Next flag present, go to next cache (if have one)");
0630 #endif
0631             is_matched=EXFALSE;
0632             continue;
0633         }
0634         else
0635         {
0636             break;
0637         }
0638         
0639     }
0640     
0641     /* cache not found */
0642     if (!is_matched)
0643     {
0644         
0645 #ifdef NDRX_TPCACHE_DEBUG
0646         NDRX_LOG(log_debug, "No cache defined for [%s], buffer type [%s] ", 
0647                 svc, buf_type->type);
0648 #endif
0649         ret = NDRX_TPCACHE_ENOCACHE;
0650         goto out;
0651     }
0652     
0653     /* LOOP END */
0654     
0655     *should_cache=EXTRUE;
0656     
0657     if (cache->flags & NDRX_TPCACHE_TPCF_INVAL)
0658     {
0659         NDRX_LOG(log_info, "Last was invalidate cache -> let save process to inval!");
0660         ret = NDRX_TPCACHE_ENOCACHEDATA;
0661         goto out;
0662     }
0663         
0664     if (flags & TPNOCACHEDDATA)
0665     {
0666         /* in this case we must */
0667         
0668         NDRX_LOG(log_info, "No cache data -> request lookup for key [%s]", key);
0669         
0670         ret = NDRX_TPCACHE_ENOCACHEDATA;
0671         goto out;
0672     }
0673     
0674     /* Check the cache group now (if defined for this cache) */
0675     if (cache->flags & NDRX_TPCACHE_TPCF_KEYITEMS)
0676     {
0677         if (EXSUCCEED!=(ret = ndrx_cache_keygrp_lookup(cache, idata, ilen, 
0678                 odata, olen, key, flags)))
0679         {
0680             /* lets see what error says us */
0681             
0682             switch (ret)
0683             {
0684                 case NDRX_TPCACHE_ENOCACHEDATA:
0685                     /* OK data not in cache return that not found */
0686                     goto out;
0687                     break;
0688                 case NDRX_TPCACHE_ENOTFOUNDLIM:
0689                     *saved_tperrno = cache->keygroupmtperrno;
0690                     *saved_tpurcode = cache->keygroupmtpurcode;
0691                     
0692                     
0693                     NDRX_LOG(log_debug, "MAX keygroup reject tperrno: %d "
0694                             "tpurcode: %ld", *saved_tperrno, *saved_tpurcode);
0695                     
0696                     ret=EXSUCCEED;
0697                     goto out;
0698                     
0699                     break;
0700                 default:
0701                     goto out;
0702                     break;
0703             }
0704         }
0705     }
0706     
0707     /* Lookup DB - check the flags if with update, requires update, then no read
0708      * only */
0709     
0710     /* TODO: For TIMESYNC we might move to RO and leave dupscan for tpcached! */
0711     if ( (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_TIMESYNC) ||
0712             (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_LRU) ||
0713             (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_HITS))
0714     {
0715         flagsdb = 0;
0716     }
0717     else
0718     {
0719         flagsdb = EDB_RDONLY;
0720     }
0721     
0722     if (EXSUCCEED!=(ret=ndrx_cache_edb_begin(cache->cachedb, &txn, flagsdb)))
0723     {
0724         NDRX_LOG(log_error, "%s: failed to start tran", __func__);
0725         goto out;
0726     }
0727     tran_started = EXTRUE;
0728     
0729     if (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_TIMESYNC)
0730     {
0731 #ifdef NDRX_TPCACHE_DEBUG
0732         NDRX_LOG(log_debug, "Performing timesync based complex lookup");
0733 #endif
0734 
0735         if (EXSUCCEED!=ndrx_cache_edb_cursor_open(cache->cachedb, txn, &cursor))
0736         {
0737             NDRX_LOG(log_error, "Failed to open cursor!");
0738             EXFAIL_OUT(ret);
0739         }
0740         
0741         /* OK fetch the first rec of cursor, next records we shall kill (if any) */
0742         /* first: EDB_FIRST_DUP - this we accept and process */
0743         
0744         if (EXSUCCEED!=(ret=ndrx_cache_edb_cursor_get(cache->cachedb, cursor,
0745                     key, &cachedata, EDB_SET_KEY, &align)))
0746         {
0747             if (EDB_NOTFOUND!=ret)
0748             {
0749                 NDRX_LOG(log_error, "Failed to scan for data!");
0750                 EXFAIL_OUT(ret);
0751             }
0752             /* no data found */
0753             ret = NDRX_TPCACHE_ENOCACHEDATA;
0754             goto out;
0755         }
0756         
0757     }
0758     else
0759     {
0760 #ifdef NDRX_TPCACHE_DEBUG
0761         NDRX_LOG(log_debug, "Performing simple lookup");
0762 #endif
0763         if (EXSUCCEED!=(ret=ndrx_cache_edb_get(cache->cachedb, txn, key, &cachedata,
0764                 seterror_not_found, &align)))
0765         {
0766             /* error already provided by wrapper */
0767             NDRX_LOG(log_debug, "%s: failed to get cache by [%s]", __func__, key);
0768             goto out;
0769         }
0770     }
0771     
0772     if (align)
0773     {
0774         defer_free = cachedata.mv_data;
0775     }
0776     
0777     exdata = (ndrx_tpcache_data_t *) cachedata.mv_data;
0778     
0779     /* validate record */
0780         
0781     NDRX_CACHE_CHECK_DBDATA((&cachedata), exdata, key, TPMINVAL);
0782 
0783     /* OK we have a raw data... lets dump something... */
0784 #ifdef NDRX_TPCACHE_DEBUG
0785     NDRX_LOG(log_debug, "Got cache record for key [%s] of service [%s]", key, svc);
0786     /* Dump more correctly with admin info */
0787     NDRX_DUMP(6, "Got cache data", (char *)cachedata.mv_data, 
0788             (int)cachedata.mv_size);
0789     NDRX_TPCACHETPCALL_DBDATA(log_debug, exdata);
0790 #endif
0791     
0792     /* Error shall be set by func */
0793     
0794     /* check that we are allowed to receive data */
0795     if (noenterr && !(cache->flags & NDRX_TPCACHE_TPCF_NOSVCOK))
0796     {
0797     ndrx_TPset_error_fmt(TPENOENT, "%s: Data found in cache but nosvcok no present", 
0798         __func__, svc);
0799         *should_cache = EXFALSE;
0800         EXFAIL_OUT(ret);
0801     }
0802     
0803     if (EXSUCCEED!=ndrx_G_tpcache_types[buffer_info->type_id].pf_cache_get(
0804             cache, exdata, buf_type, idata, ilen, odata, olen, flags))
0805     {
0806         NDRX_LOG(log_error, "%s: Failed to receive data: ", __func__);
0807         EXFAIL_OUT(ret);
0808     }
0809     
0810     *saved_tperrno = exdata->saved_tperrno;
0811     *saved_tpurcode = exdata->saved_tpurcode;
0812     
0813     NDRX_LOG(log_debug, "cache tperrno: %d tpurcode: %ld",
0814             *saved_tperrno, *saved_tpurcode);
0815     
0816     /* Update cache (if needed) */
0817     
0818     
0819     /* perform copy if needed for cache update */
0820     if ((cache->cachedb->flags & NDRX_TPCACHE_FLAGS_LRU) ||
0821             (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_HITS))
0822     {
0823         cachedata_update.mv_size = cachedata.mv_size;
0824         cachedata_update.mv_data = NDRX_MALLOC(cachedata.mv_size);
0825         
0826         if (NULL==cachedata_update.mv_data)
0827         {
0828             int err = errno;
0829             
0830             NDRX_CACHE_TPERROR(TPEOS, "Failed to allocate %ld bytes: %s",
0831                     (long)cachedata_update.mv_size, strerror(err));
0832         }
0833         
0834         memcpy(cachedata_update.mv_data, cachedata.mv_data, cachedata.mv_size);
0835         
0836         exdata_update = (ndrx_tpcache_data_t *)cachedata_update.mv_data;
0837         /* ok this might overflow, then it will be time for cache to reset...
0838          * but that will be long number of requests away...
0839          */
0840 
0841     /* if we reach max then keep max */
0842     
0843     
0844     if (exdata_update->hits < LONG_MAX - 1)
0845     {
0846             exdata_update->hits++;
0847     }
0848     else
0849     {
0850             /* set to max value (if any runs over) */
0851             exdata_update->hits  = LONG_MAX;
0852     }
0853     
0854         ndrx_utc_tstamp2(&exdata_update->hit_t, &exdata_update->hit_tusec);
0855 
0856 #ifdef NDRX_TPCACHE_DEBUG        
0857         NDRX_LOG(log_debug, "hits=%ld t=%ld t=%ld", exdata_update->hits,
0858                 exdata_update->hit_t, exdata_update->hit_tusec);
0859 #endif
0860         if (cursor_open)
0861         {
0862             edb_cursor_close(cursor);
0863         }
0864         cursor_open=EXFALSE;
0865         
0866         /* delete all records 
0867          * TODO: Maybe we can skip the delete step?
0868          */
0869         if (EXSUCCEED!=(ret=ndrx_cache_edb_del (cache->cachedb, txn, 
0870             key, NULL)))
0871         {
0872             if (EDB_NOTFOUND==ret)
0873             {
0874                 ret=EXSUCCEED;
0875             }
0876             else
0877             {
0878                 EXFAIL_OUT(ret);
0879             }
0880         }
0881         
0882         /* Add record */
0883         
0884         /* dup was mandatory... flag if using sorting, afaik, or not? */
0885 #if 0
0886         if (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_TIMESYNC)
0887         {
0888             dbflags = EDB_APPENDDUP;
0889         }
0890         else
0891         {
0892             dbflags = 0;
0893         }
0894 #endif
0895         if (EXSUCCEED!=ndrx_cache_edb_put (cache->cachedb, txn, 
0896             key, &cachedata_update, 0, EXTRUE))
0897         {
0898             NDRX_LOG(log_debug, "Failed to put/update DB record - ignore error");
0899             force_abort = EXTRUE;
0900             goto out;
0901         }
0902     }
0903     else if (cache->cachedb->flags & NDRX_TPCACHE_FLAGS_TIMESYNC)
0904     {
0905         /* fetch next for dups and remove them.. if any.. */
0906         /* next: MDB_NEXT_DUP  - we kill this! */
0907         align = 0;
0908         while (EXSUCCEED==(ret=ndrx_cache_edb_cursor_get(cache->cachedb, cursor,
0909                     key, &cachedata_delete, EDB_NEXT_DUP, &align)))
0910         {
0911             /* delete the record, not needed, some old cache rec */
0912             NDRX_DUMP(log_debug, "Deleting duplicate record...", 
0913                     cachedata_delete.mv_data, cachedata_delete.mv_size);
0914             
0915             if (EXSUCCEED!=(ret=ndrx_cache_edb_del (cache->cachedb, txn, 
0916                     key, &cachedata_delete)))
0917             {
0918                 if (ret!=EDB_NOTFOUND)
0919                 {
0920                     /* if not found maybe next key will be found */
0921                     break;
0922                 }
0923             }
0924             
0925             if (align)
0926             {
0927                 NDRX_FREE(cachedata_delete.mv_data);
0928                 cachedata_delete.mv_data = NULL;
0929             }
0930         }
0931         
0932         if (align && NULL!=cachedata_delete.mv_data)
0933         {
0934             NDRX_FREE(cachedata_delete.mv_data);
0935         }
0936         
0937         if (ret!=EDB_NOTFOUND)
0938         {
0939             EXFAIL_OUT(ret);
0940         }
0941         else
0942         {
0943             ret = EXSUCCEED;
0944         }
0945     }
0946     
0947 out:
0948 
0949     if (NULL!=cachedata_update.mv_data)
0950     {
0951         NDRX_FREE(cachedata_update.mv_data);
0952     }
0953 
0954     if (cursor_open)
0955     {
0956         edb_cursor_close(cursor);
0957     }
0958 
0959     if (tran_started)
0960     {
0961         if (EXSUCCEED==ret && !force_abort)
0962         {
0963             ndrx_cache_edb_commit(cache->cachedb, txn);
0964         }
0965         else
0966         {
0967             ndrx_cache_edb_abort(cache->cachedb, txn);
0968         }
0969     }
0970 
0971     if (defer_free)
0972     {
0973         NDRX_FREE(defer_free);
0974     }
0975 
0976     return ret;
0977 }
0978 
0979 /* vim: set ts=4 sw=4 et smartindent: */