Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief ATMI level cache - keygroup routines
0003  *   Invalidate their cache shall be done by buffer. And not by key. Thus for
0004  *   invalidate their, our key is irrelevant.
0005  *   Delete shall be performed last on keygrp
0006  *   The insert first shall be done in keygrp and then keyitems.
0007  *
0008  * @file atmi_cache_keygrp.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 #include <ubf_int.h>
0057 #include <ubfutil.h>
0058 /*---------------------------Externs------------------------------------*/
0059 /*---------------------------Macros-------------------------------------*/
0060 /*---------------------------Enums--------------------------------------*/
0061 /*---------------------------Typedefs-----------------------------------*/
0062 /*---------------------------Globals------------------------------------*/
0063 /*---------------------------Statics------------------------------------*/
0064 /*---------------------------Prototypes---------------------------------*/
0065 
0066 /**
0067  * Perform lookup in keygroup.
0068  * If keys counter is overreached and data is not found, then request shall be
0069  * rejected (basically we respond from cache with reject).
0070  * 
0071  * If key is not found in group, then lookup again (even if it might be in the
0072  * key item db (as these are two database and we might crash in the middle)...
0073  * 
0074  * @param cache
0075  * @param idata
0076  * @param ilen
0077  * @param cachekey
0078  * @return TPFAIL/NDRX_TPCACHE_ENOKEYDATA/NDRX_TPCACHE_ENOTFOUNDLIM - if limit
0079  * /EDB_NOTFOUND
0080  * reached.
0081  */
0082 expublic int ndrx_cache_keygrp_lookup(ndrx_tpcallcache_t *cache, 
0083             char *idata, long ilen, char **odata, long *olen, char *cachekey,
0084             long flags)
0085 {
0086     int ret = EXSUCCEED;
0087     char key[NDRX_CACHE_KEY_MAX+1];
0088     char errdet[MAX_TP_ERROR_LEN+1];
0089     EDB_txn *txn;
0090     int tran_started = EXFALSE;
0091     EDB_val cachedata;
0092     ndrx_tpcache_data_t *exdata;
0093     typed_buffer_descr_t *buf_type = &G_buf_descr[BUF_TYPE_UBF];
0094     UBFH *p_ub_keys = NULL;        /* list of keys in keygroup */
0095     long rsplen;
0096     Bnext_state_t state1;
0097     BFLDID bfldid1;
0098     long numkeys = 0;
0099     BFLDOCC occ;
0100     char *dptr;
0101     BFLDLEN dlen;
0102     int cachekey_found = EXFALSE;
0103     int got_dbname = EXFALSE;
0104     int align;
0105     char *defer_free = NULL;
0106     
0107     NDRX_LOG(log_debug, "%s enter", __func__);
0108     
0109     NDRX_STRCPY_SAFE(key, cache->keygrpfmt);
0110     
0111     if (EXSUCCEED!=(ret = ndrx_G_tpcache_types[cache->buf_type->type_id].pf_get_key(
0112                 cache, idata, ilen, key, sizeof(key), errdet, sizeof(errdet))))
0113     {
0114         if (NDRX_TPCACHE_ENOKEYDATA==ret)
0115         {
0116             NDRX_LOG(log_debug, "Failed to build key (no data for key): %s", errdet);
0117             goto out;
0118         }
0119         else
0120         {
0121             NDRX_CACHE_TPERRORNOU(TPESYSTEM, "%s: Failed to build cache key: %s", 
0122                     __func__, errdet);
0123             goto out;
0124         }
0125     }
0126     
0127     NDRX_LOG(log_debug, "Key group key [%s]", key);
0128     
0129     
0130     if (EXSUCCEED!=(ret=ndrx_cache_edb_begin(cache->keygrpdb, &txn, EDB_RDONLY)))
0131     {
0132         NDRX_LOG(log_error, "%s: failed to start tran", __func__);
0133         goto out;
0134     }
0135     
0136     tran_started = EXTRUE;
0137     
0138     
0139     if (EXSUCCEED!=(ret=ndrx_cache_edb_get(cache->keygrpdb, txn, key, &cachedata,
0140             EXFALSE, &align)))
0141     {
0142         /* error already provided by wrapper */
0143         NDRX_LOG(log_debug, "%s: failed to get cache by [%s]", __func__, key);
0144         goto out;
0145     }
0146     
0147     /* Check the record validity */
0148     if (align)
0149     {
0150         defer_free = cachedata.mv_data;
0151     }
0152     
0153     exdata = (ndrx_tpcache_data_t *)((char *)cachedata.mv_data);
0154     NDRX_CACHE_CHECK_DBDATA((&cachedata), exdata, key, TPESYSTEM);
0155     
0156     
0157     /* Receive data as UBF buffer, so that we can test it... 
0158      * this is just list 
0159      */
0160     
0161     if (EXSUCCEED!=ndrx_mbuf_prepare_incoming(exdata->atmi_buf, 
0162                 exdata->atmi_buf_len, (char **)&p_ub_keys, &rsplen, 0, 0))
0163     {
0164         /* the error shall be set already */
0165         NDRX_LOG(log_error, "Failed to read keygroup record for [%s]", key);
0166         EXFAIL_OUT(ret);
0167     }
0168     
0169     /* iterate the buffer to find they key, and check the total count of the
0170      * keys if limit is defined
0171      */
0172     
0173     bfldid1 = BFIRSTFLDID;
0174     
0175     while (!cachekey_found)
0176     {
0177         ret=ndrx_Bnext(&state1, p_ub_keys, &bfldid1, &occ, NULL, &dlen, &dptr);
0178         
0179         if (0==ret)
0180         {
0181             /* we are at EOF */
0182             break;
0183         }
0184         else if (0 > ret)
0185         {
0186             /* we got an error while scanning key storage */
0187             NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Failed to iterate key group items: %s", 
0188                     __func__, Bstrerror(Berror));
0189             EXFAIL_OUT(ret);
0190         }
0191         
0192         ret=0;
0193 
0194         switch (bfldid1)
0195         {
0196             /* in which db keys are stored? 
0197              * DB name will be always first as the field id is less than OPEXPR
0198              * and 
0199              */
0200             case EX_CACHE_DBNAME:
0201                 
0202                 got_dbname = EXTRUE;
0203                 if (0!=strcmp(dptr, cache->cachedbnm))
0204                 {
0205                     NDRX_CACHE_TPERROR(TPESYSTEM, "%s: consistency error, expected "
0206                             "db [%s] but got [%s] "
0207                             "for group record of cache item key [%s], groupkey [%s]",
0208                             __func__, cache->cachedbnm, dptr, cachekey, 
0209                             key);
0210                     EXFAIL_OUT(ret);
0211                 }
0212                 
0213                 break;
0214             
0215             /* keys ops */
0216             case EX_CACHE_OPEXPR:
0217                 
0218                 numkeys++;
0219                 
0220                 if (0==strcmp(dptr, cachekey))
0221                 {
0222                     cachekey_found=EXTRUE;
0223                     NDRX_LOG(log_debug, "Key found in group");
0224                 }
0225                 
0226                 break;
0227                 
0228             default:
0229                 /* raise error as key is not supported */
0230                 NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Invalid field [%s][%d] in "
0231                         "keygroup [%s] db [%s]",
0232                         __func__, Bfname(bfldid1), bfldid1, 
0233                         cachekey, cache->keygrpdb->cachedb);
0234                 EXFAIL_OUT(ret);
0235                 break;
0236         }
0237 
0238     }
0239     
0240     if (!got_dbname)
0241     {
0242         NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Invalid data saved in "
0243                         "keygroup [%s] db [%s] - missing EX_CACHE_DBNAME!",
0244                         __func__,  cachekey, cache->keygrpdb->cachedb);
0245         EXFAIL_OUT(ret);
0246     }
0247     
0248     NDRX_LOG(log_debug, "cachekey_found=%d, cache->keygroupmax=%ld numkeys=%ld",
0249             cachekey_found, cache->keygroupmax, numkeys);
0250     
0251     if (!cachekey_found && cache->keygroupmax > 0 )
0252     {
0253         /* Check the key count and see if reject is needed...? */
0254         
0255         if (numkeys >= cache->keygroupmax)
0256         {
0257             NDRX_LOG(log_error, "Number keys in group [%ld] max allowed in group [%ld]"
0258                     " - reject",
0259                     numkeys, cache->keygroupmax);
0260             
0261             ret = NDRX_TPCACHE_ENOTFOUNDLIM;
0262 
0263             /* generate response...  this shall be done via type selector */
0264             if (EXSUCCEED!=ndrx_G_tpcache_types[cache->buf_type->type_id].pf_cache_maxreject(
0265                     cache, idata, ilen, odata, olen, flags, buf_type))
0266             {
0267                 NDRX_LOG(log_error, "%s: Failed to reject user buffer!", __func__);
0268                 EXFAIL_OUT(ret);
0269             }
0270             
0271             goto out;
0272         }
0273     }
0274     
0275     if (!cachekey_found)
0276     {
0277         NDRX_LOG(log_debug, "Key not found in group");
0278         ret=NDRX_TPCACHE_ENOCACHEDATA;
0279     }
0280     else
0281     {
0282         NDRX_LOG(log_debug, "Key found in group, ret=%d", ret);
0283     }
0284     
0285 out:
0286 
0287     if (tran_started)
0288     {
0289         /* terminate transaction please */
0290         ndrx_cache_edb_abort(cache->keygrpdb, txn);
0291     }
0292 
0293     if (defer_free)
0294     {
0295         NDRX_FREE(defer_free);
0296     }
0297 
0298     return ret;
0299 }
0300 
0301 /**
0302  * Add update keygroup. Only interesting question is how about duplicate
0303  * keys? If it is duplicate, then key group does not change. So there shall be
0304  * no problems.
0305  * if single keyitem is deleted in non-inval mode, then keyitem must be removed
0306  * from the list. Only in inval trigger, we shall invalidate full group...
0307  * @param deleteop use EXTRUE if performing delete operation from the keygroup
0308  * @param have_keygrp we have a keygroup, do not use data for this purpose
0309  * @param cachekey key item key
0310  */
0311 expublic int ndrx_cache_keygrp_addupd(ndrx_tpcallcache_t *cache, 
0312         char *idata, long ilen, char *cachekey, char *have_keygrp, int deleteop,
0313         EDB_txn *txn)
0314 {
0315     int ret = EXSUCCEED;
0316     char key[NDRX_CACHE_KEY_MAX+1];
0317     char errdet[MAX_TP_ERROR_LEN+1];
0318     EDB_val cachedata;
0319     ndrx_tpcache_data_t *exdata=NULL;
0320     typed_buffer_descr_t *buf_type = &G_buf_descr[BUF_TYPE_UBF];
0321     UBFH *p_ub_keys = NULL;        /* list of keys in keygroup */
0322     long rsplen;
0323     Bnext_state_t state1;
0324     BFLDID bfldid1;
0325     long numkeys = 0;
0326     BFLDOCC occ, occ_found=EXFAIL;
0327     char *dptr;
0328     BFLDLEN dlen;
0329     int got_dbname = EXFALSE;
0330     int cachekey_found = EXFALSE;
0331     char *buf=NULL;
0332     size_t buf_len;
0333     char *kg_ptr;
0334     int align;
0335     char *defer_free = NULL;
0336     
0337     NDRX_SYSBUF_MALLOC_WERR_OUT(buf, buf_len, ret);
0338     
0339     if (NULL!=have_keygrp)
0340     {
0341         kg_ptr=have_keygrp;
0342     }
0343     else
0344     {
0345         NDRX_STRCPY_SAFE(key, cache->keygrpfmt);
0346 
0347         if (EXSUCCEED!=(ret = ndrx_G_tpcache_types[cache->buf_type->type_id].pf_get_key(
0348                     cache, idata, ilen, key, sizeof(key), errdet, sizeof(errdet))))
0349         {
0350             if (NDRX_TPCACHE_ENOKEYDATA==ret)
0351             {
0352                 NDRX_LOG(log_debug, "Failed to build key (no data for key): %s", errdet);
0353                 goto out;
0354             }
0355             else
0356             {
0357                 NDRX_CACHE_TPERRORNOU(TPESYSTEM, "%s: Failed to build cache key: %s", 
0358                         __func__, errdet);
0359                 goto out;
0360             }
0361         }
0362         kg_ptr = key;
0363     }
0364     
0365     NDRX_LOG(log_debug, "Key group key [%s]", kg_ptr);
0366     
0367     if (NULL==(p_ub_keys = (UBFH *)tpalloc("UBF", 0, 1024)))
0368     {
0369         NDRX_LOG(log_error, "Failed to allocate UBF buffer: %s", tpstrerror(tperrno));
0370     }
0371     
0372     if (EXSUCCEED!=(ret=ndrx_cache_edb_get(cache->keygrpdb, txn, kg_ptr, &cachedata,
0373             EXFALSE, &align)))
0374     {
0375         /* error already provided by wrapper */
0376         if (EDB_NOTFOUND==ret)
0377         {
0378             if (deleteop)
0379             {
0380                 NDRX_LOG(log_debug, "Key group record does not exists - "
0381                         "assume keyitem deleted ok");
0382                 ret=EXSUCCEED;
0383                 goto out;
0384             }
0385             
0386             /* prepare buffer where to write off the keys */
0387             NDRX_LOG(log_debug, "Key group is missing -> must be added");
0388             
0389             /* Add db name to buffer (of source cache) */
0390             if (EXSUCCEED!=Bchg(p_ub_keys, EX_CACHE_DBNAME, 0, cache->cachedbnm, 0L))
0391             {
0392                 NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Set install `EX_CACHE_DBNAME': %s", 
0393                     __func__, Bstrerror(Berror));
0394                 EXFAIL_OUT(ret);
0395             }
0396         }
0397         else
0398         {
0399             NDRX_LOG(log_debug, "%s: failed to get cache by [%s]", __func__, kg_ptr);
0400             goto out;
0401         }
0402     }
0403     else
0404     {
0405         /* Check the record validity */
0406         if (align)
0407         {
0408             defer_free = cachedata.mv_data;
0409         }
0410         exdata = (ndrx_tpcache_data_t *)((char *)cachedata.mv_data);
0411         NDRX_CACHE_CHECK_DBDATA((&cachedata), exdata, kg_ptr, TPESYSTEM);
0412 
0413 
0414         /* Receive data as UBF buffer, so that we can test it... 
0415          * this is just list 
0416          */
0417 
0418         if (EXSUCCEED!=ndrx_mbuf_prepare_incoming(exdata->atmi_buf, 
0419                     exdata->atmi_buf_len, (char **)&p_ub_keys, &rsplen, 0, 0))
0420         {
0421             /* the error shall be set already */
0422             NDRX_LOG(log_error, "Failed to read keygroup record for [%s]", kg_ptr);
0423             EXFAIL_OUT(ret);
0424         }
0425 
0426         /* iterate the buffer to find they key, and check the total count of the
0427          * keys if limit is defined
0428          */
0429 
0430         bfldid1 = BFIRSTFLDID;
0431 
0432         while (1)
0433         {
0434             ret=ndrx_Bnext(&state1, p_ub_keys, &bfldid1, &occ, NULL, &dlen, &dptr);
0435 
0436             if (0==ret)
0437             {
0438                 /* we are at EOF */
0439                 break;
0440             }
0441             else if (0 > ret)
0442             {
0443                 /* we got an error while scanning key storage */
0444                 NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Failed to iterate key group items: %s", 
0445                         __func__, Bstrerror(Berror));
0446                 EXFAIL_OUT(ret);
0447             }
0448 
0449             switch (bfldid1)
0450             {
0451                 /* in which db keys are stored? 
0452                  * DB name will be always first as the field id is less than OPEXPR
0453                  * and 
0454                  */
0455                 case EX_CACHE_DBNAME:
0456 
0457                     got_dbname = EXTRUE;
0458                     if (0!=strcmp(dptr, cache->cachedbnm))
0459                     {
0460                         NDRX_CACHE_TPERROR(TPESYSTEM, "%s: consistency error, expected "
0461                                 "db [%s] but got [%s] "
0462                                 "for group record of cache item key [%s], groupkey [%s]",
0463                                 __func__, cache->cachedbnm, dptr, cachekey, 
0464                                 kg_ptr);
0465                         EXFAIL_OUT(ret);
0466                     }
0467 
0468                     break;
0469 
0470                 /* keys ops */
0471                 case EX_CACHE_OPEXPR:
0472 
0473                     numkeys++;
0474 
0475                     if (0==strcmp(dptr, cachekey))
0476                     {
0477                         cachekey_found=EXTRUE;
0478                         occ_found = occ;
0479                         NDRX_LOG(log_debug, "Key found in group at occ [%d]", 
0480                                 occ_found);
0481                         break;
0482                     }
0483 
0484                     break;
0485 
0486                 default:
0487                     /* raise error as key is not supported */
0488                     NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Invalid field [%s][%d] in "
0489                             "keygroup [%s] db [%s]",
0490                             __func__, Bfname(bfldid1), bfldid1, 
0491                             cachekey, cache->keygrpdb->cachedb);
0492                     EXFAIL_OUT(ret);
0493                     break;
0494             }
0495 
0496         }
0497 
0498         if (!got_dbname)
0499         {
0500             NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Invalid data saved in "
0501                             "keygroup [%s] db [%s] - missing EX_CACHE_DBNAME!",
0502                             __func__,  cachekey, cache->keygrpdb->cachedb);
0503             EXFAIL_OUT(ret);
0504         }
0505 
0506         if (!cachekey_found)
0507         {
0508             if (deleteop)
0509             {
0510                 NDRX_LOG(log_debug, "Keyitem not found in group - assume deleted ok");
0511                 goto out;
0512             }
0513         }
0514         else
0515         {
0516             NDRX_LOG(log_debug, "Key found in group");
0517             
0518         }
0519     }
0520     
0521     if ((cachekey_found && deleteop) || (!cachekey_found && !deleteop))
0522     {
0523         if (deleteop)
0524         {
0525             NDRX_LOG(log_debug, "Removing key from the group");
0526             
0527             if (EXSUCCEED!=Bdel(p_ub_keys, EX_CACHE_OPEXPR, occ_found))
0528             {
0529                 NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Failed to delete "
0530                         "EX_CACHE_OPEXPR[%d]: %s",
0531                         occ_found, Bstrerror(Berror));
0532                 EXFAIL_OUT(ret);
0533             }
0534         }
0535         else
0536         {
0537             NDRX_LOG(log_debug, "Adding key to the group");
0538         
0539             if (NULL==(p_ub_keys = (UBFH *)tprealloc((char *)p_ub_keys, 
0540                     Bsizeof(p_ub_keys) + strlen(cachekey))))
0541             {
0542                 NDRX_LOG(log_error, "Failed to allocate UBF buffer: %s", 
0543                         tpstrerror(tperrno));
0544                 EXFAIL_OUT(ret);
0545             }
0546             
0547             if (EXSUCCEED!=Badd(p_ub_keys, EX_CACHE_OPEXPR, cachekey, 0L))
0548             {
0549                 NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Failed to add EX_CACHE_OPEXPR to UBF: %s",
0550                         Bstrerror(Berror));
0551                 EXFAIL_OUT(ret);
0552             }
0553         }
0554         /* write record off to DB... */
0555         
0556         ndrx_debug_dump_UBF(log_debug, "Saving to keygroup", (UBFH *)p_ub_keys);
0557     
0558         if (NULL==exdata)
0559         {
0560             exdata = (ndrx_tpcache_data_t *)buf;
0561             memset(exdata, 0, sizeof(ndrx_tpcache_data_t));
0562             
0563             exdata->magic = NDRX_CACHE_MAGIC;
0564             NDRX_STRCPY_SAFE(exdata->svcnm, cache->svcnm);
0565             exdata->nodeid = (short)tpgetnodeid();
0566 
0567             /* get current timestamp */
0568             ndrx_utc_tstamp2(&exdata->t, &exdata->tusec);
0569             
0570             exdata->cache_idx = cache->idx;
0571         }
0572         else
0573         {
0574             /* update existing data.. */
0575             memcpy(buf, exdata, sizeof(ndrx_tpcache_data_t));
0576             exdata = (ndrx_tpcache_data_t *)buf;
0577         }
0578         
0579         
0580         exdata->atmi_type_id = buf_type->type_id;
0581         exdata->atmi_buf_len = NDRX_MSGSIZEMAX - sizeof(ndrx_tpcache_data_t);
0582     
0583         if (EXSUCCEED!=ndrx_mbuf_prepare_outgoing((char *)p_ub_keys, 
0584                     0, exdata->atmi_buf, &exdata->atmi_buf_len, 0L, NDRX_MBUF_FLAG_NOCALLINFO))
0585         {
0586             userlog("Failed to prepare buffer for saving in keygroup: %s", 
0587                     tpstrerror(tperrno));
0588             NDRX_LOG(log_error, "Failed to prepare buffer for saving in keygroup");
0589             EXFAIL_OUT(ret);
0590         }
0591         
0592         cachedata.mv_data = (void *)exdata;
0593         cachedata.mv_size = exdata->atmi_buf_len + sizeof(ndrx_tpcache_data_t);
0594         
0595         if (EXSUCCEED!=(ret=ndrx_cache_edb_put (cache->keygrpdb, txn, 
0596                 kg_ptr, &cachedata, 0, EXFALSE)))
0597         {
0598             NDRX_LOG(log_debug, "Failed to put DB for keygroup...!");
0599             goto out;
0600         }
0601     }
0602     
0603 out:
0604                     
0605     if (NULL!=defer_free)
0606     {
0607         NDRX_FREE(defer_free);
0608     }
0609 
0610     if (NULL!=buf)
0611     {
0612         NDRX_SYSBUF_FREE(buf);
0613     }
0614 
0615     return ret;
0616 }
0617 
0618 
0619 /**
0620  * Delete keygroup keyitems. The group by it self should be removed by outer 
0621  * caller.
0622  * @param dbkeygroup This is keygroup database
0623  * @param p_ub
0624  * @param keyitem_dbname test dbname against (optional, to test if buffer compares)
0625  * @return 
0626  */
0627 exprivate int ndrx_cache_invalgroup(ndrx_tpcache_db_t* dbkeygroup, 
0628         UBFH *p_ub, char *keyitem_dbname, EDB_txn *txn)
0629 {
0630     int ret = EXSUCCEED;
0631     Bnext_state_t state1;
0632     BFLDID bfldid1;
0633     BFLDOCC occ;
0634     char *dptr;
0635     BFLDLEN dlen;
0636     long numkeys = 0;
0637     ndrx_tpcache_db_t* db = NULL;
0638     
0639     bfldid1 = BFIRSTFLDID;
0640 
0641     while (1)
0642     {
0643          ret=ndrx_Bnext(&state1, p_ub, &bfldid1, &occ, NULL, &dlen, &dptr);
0644 
0645          if (0==ret)
0646          {
0647              /* we are at EOF */
0648              break;
0649          }
0650          else if (0 > ret)
0651          {
0652              /* we got an error while scanning key storage */
0653              NDRX_CACHE_TPERROR(TPESYSTEM, "%s: Failed to iterate key group items: %s", 
0654                      __func__, Bstrerror(Berror));
0655              EXFAIL_OUT(ret);
0656          }
0657          
0658          switch (bfldid1)
0659          {
0660              case EX_CACHE_DBNAME:
0661                 /* Resolve DB name... */
0662                 NDRX_LOG(log_debug, "Key item DB Lookup: [%s]", dptr);
0663                 
0664                 /* Check DB name if have one... */
0665                 if (NULL!=keyitem_dbname)
0666                 {
0667                     if (0!=strcmp(keyitem_dbname, dptr))
0668                     {
0669                         NDRX_CACHE_TPERRORNOU(TPESYSTEM, "Expected db name of keyitems "
0670                                 "[%s] does not match actual in UBF [%s]",
0671                                 keyitem_dbname, dptr);
0672                         EXFAIL_OUT(ret);
0673                     }
0674                 }
0675                 
0676                 if (NULL==(db = ndrx_cache_dbresolve(dptr, NDRX_TPCACH_INIT_NORMAL)))
0677                 {
0678                     NDRX_CACHE_TPERRORNOU(TPENOENT, "Failed to get db record for [%s]: %s", 
0679                            dptr, tpstrerror(tperrno));
0680                     EXFAIL_OUT(ret);
0681                 }
0682 
0683                 break;
0684                  
0685              /* keys ops */
0686              case EX_CACHE_OPEXPR:
0687 
0688                 numkeys++;
0689                 
0690                 if (NULL==db)
0691                 {
0692                     NDRX_CACHE_TPERROR(TPESYSTEM, "Missing EX_CACHE_DBNAME in keygroup!");
0693                     EXFAIL_OUT(ret);
0694                 }
0695                 
0696                 NDRX_LOG(log_debug, "About to erase: [%s] from [%s] db", 
0697                         dptr, db->cachedb);
0698                 
0699                 if (EXSUCCEED!=(ret=ndrx_cache_edb_del (db, txn, dptr, NULL)))
0700                 {
0701                     if (EDB_NOTFOUND==ret)
0702                     {
0703                         ret=EXSUCCEED;
0704                     }
0705                     else
0706                     {
0707                         EXFAIL_OUT(ret);
0708                     }
0709                 }
0710 
0711                 break;
0712          }
0713      }
0714     
0715     
0716     /* TODO: Delete group by it self */
0717     
0718     
0719 out:
0720 
0721     return ret;
0722 }
0723 
0724 /**
0725  * return a keygroup.
0726  * This will start read only transactions
0727  * @param db database
0728  * @param txn transaction in progress
0729  * @param key key to search for (it is a group key)
0730  * @param pp_ub UBF buffer with keys
0731  * @return EXSUCCEED/EXFAIL
0732  */
0733 exprivate int ndrx_cache_keygrp_getgroup(ndrx_tpcache_db_t* db, EDB_txn *txn, 
0734         char *key, UBFH **pp_ub)
0735 {
0736     int ret = EXSUCCEED;
0737     EDB_val cachedata;
0738     ndrx_tpcache_data_t *exdata;
0739     long rsplen;
0740     int align;
0741     char *defer_free = NULL;
0742     NDRX_LOG(log_debug, "%s: Key group key [%s]", __func__, key);
0743     
0744     if (EXSUCCEED!=(ret=ndrx_cache_edb_get(db, txn, key, &cachedata,
0745             EXFALSE, &align)))
0746     {
0747         /* error already provided by wrapper */
0748         NDRX_LOG(log_debug, "%s: failed to get cache by [%s]", __func__, key);
0749         goto out;
0750     }
0751     
0752     /* Check the record validity */
0753     if (align)
0754     {
0755         defer_free = cachedata.mv_data;
0756     }
0757     exdata = (ndrx_tpcache_data_t *)((char *)cachedata.mv_data);
0758     NDRX_CACHE_CHECK_DBDATA((&cachedata), exdata, key, TPESYSTEM);
0759     
0760     
0761     /* Receive data as UBF buffer, so that we can test it... 
0762      * this is just list 
0763      */
0764     if (EXSUCCEED!=ndrx_mbuf_prepare_incoming(exdata->atmi_buf, 
0765                 exdata->atmi_buf_len, (char **)pp_ub, &rsplen, 0, 0))
0766     {
0767         /* the error shall be set already */
0768         NDRX_LOG(log_error, "Failed to read keygroup record for [%s]", key);
0769         EXFAIL_OUT(ret);
0770     }
0771     
0772 out:
0773                     
0774     if (defer_free)
0775     {
0776         NDRX_FREE(defer_free);
0777     }
0778 
0779     NDRX_LOG(log_debug, "%s returns %d", __func__, ret);
0780 
0781     return ret;
0782 }
0783 
0784 /**
0785  * Delete by key, group values...
0786  * use this func in ndrx_cache_inval_by_key()
0787  * This shall be done only if we delete 
0788  * 
0789  * Supported modes:
0790  * - delete keyitem by data - remove all group
0791  * - delete keygrp by key - remove full group
0792  * - all other modes works by single db record.
0793  * - if we delete from keyitems, then keygroup record shall be updated accordingly... (after delete happended)
0794  * @param db this is db of keygroup
0795  * @param txn this is keygroup transaction, data transaction will be made internally
0796  * @param keyitem_dbname
0797  */
0798 expublic int ndrx_cache_keygrp_inval_by_key(ndrx_tpcache_db_t* db, 
0799         char *key, EDB_txn *txn, char *keyitem_dbname)
0800 {
0801     int ret = EXSUCCEED;
0802     UBFH *p_ub = NULL;
0803     
0804     NDRX_LOG(log_debug, "%s enter", __func__);
0805     
0806     if (EXSUCCEED!=(ret=ndrx_cache_keygrp_getgroup(db, txn, key, &p_ub)))
0807     {
0808         NDRX_LOG(log_info, "Failed to get keygroup: %s", tpstrerror(tperrno));
0809         goto out;
0810     }
0811     
0812     if (EXSUCCEED!=(ret=ndrx_cache_invalgroup(db, p_ub, keyitem_dbname, txn)))
0813     {
0814         NDRX_LOG(log_info, "Failed to get keygroup: %s", tpstrerror(tperrno));
0815         goto out;
0816     }
0817     
0818     /* Remove group record by it self */
0819     if (EXSUCCEED!=(ret=ndrx_cache_edb_del (db, txn, key, NULL)))
0820     {
0821         if (EDB_NOTFOUND==ret)
0822         {
0823             ret=EXSUCCEED;
0824         }
0825         else
0826         {
0827             EXFAIL_OUT(ret);
0828         }
0829     }
0830     
0831 out:
0832 
0833     if (NULL!=p_ub)
0834     {
0835         NDRX_FREE((char *)p_ub);
0836     }
0837 
0838     NDRX_LOG(log_debug, "%s return %d", __func__, ret);
0839     return ret;
0840 }
0841 
0842 /**
0843  * Extract key by cache data
0844  * @param cache cache definition
0845  * @param exdata 
0846  * @param keyout
0847  * @param keyout_bufsz
0848  * @return 
0849  */
0850 expublic int ndrx_cache_keygrp_getkey_from_data(ndrx_tpcallcache_t* cache, 
0851         ndrx_tpcache_data_t *exdata, char *keyout, long keyout_bufsz)
0852 {
0853     int ret = EXSUCCEED;
0854     char *buf = NULL;
0855     long rsplen = 0;
0856     char errdet[MAX_TP_ERROR_LEN+1];
0857     
0858     typed_buffer_descr_t *buf_type = &G_buf_descr[exdata->atmi_type_id];
0859     
0860     if (EXSUCCEED!=ndrx_G_tpcache_types[exdata->atmi_type_id].pf_cache_get(
0861             cache, exdata, buf_type, buf, 0, &buf, &rsplen, 0))
0862     {
0863         NDRX_LOG(log_error, "%s: Failed to process ", __func__);
0864         EXFAIL_OUT(ret);
0865     }
0866     
0867     /* get the key */
0868     
0869     NDRX_STRCPY_SAFE_DST(keyout, cache->keygrpfmt, keyout_bufsz);
0870     
0871     if (EXSUCCEED!=(ret = ndrx_G_tpcache_types[cache->buf_type->type_id].pf_get_key(
0872                 cache, buf, rsplen, keyout, keyout_bufsz, errdet, sizeof(errdet))))
0873     {
0874         if (NDRX_TPCACHE_ENOKEYDATA==ret)
0875         {
0876             NDRX_LOG(log_debug, "Failed to build key (no data for key): %s", errdet);
0877             goto out;
0878         }
0879         else
0880         {
0881             NDRX_CACHE_TPERRORNOU(TPESYSTEM, "%s: Failed to build cache key: %s", 
0882                     __func__, errdet);
0883             goto out;
0884         }
0885     }
0886     
0887 out:
0888 
0889     /* free up the data buffer */
0890     if (NULL!=buf)
0891     {
0892         tpfree(buf);
0893     }
0894 
0895     return ret;
0896 }
0897 
0898 /**
0899  * Delete keygroup record by data.
0900  * Can reuse transaction...
0901  * use this func in ndrx_cache_inval_by_data
0902  * So if we delete key item, that will key the keygroup fully...
0903  * We shall return the status that full group is removed 
0904  * @param txn this is keygroup transaction, data transaction will be made internally
0905  * @param cache tpcall cache which being invalidated
0906  */
0907 expublic int ndrx_cache_keygrp_inval_by_data(ndrx_tpcallcache_t *cache, 
0908         char *idata, long ilen, EDB_txn *txn)
0909 {
0910     char key[NDRX_CACHE_KEY_MAX+1];
0911     char errdet[MAX_TP_ERROR_LEN+1];
0912     int ret = EXSUCCEED;
0913     
0914     NDRX_LOG(log_debug, "%s enter", __func__);
0915     
0916     
0917     NDRX_STRCPY_SAFE(key, cache->keygrpfmt);
0918     
0919     if (EXSUCCEED!=(ret = ndrx_G_tpcache_types[cache->buf_type->type_id].pf_get_key(
0920                 cache, idata, ilen, key, sizeof(key), errdet, sizeof(errdet))))
0921     {
0922         if (NDRX_TPCACHE_ENOKEYDATA==ret)
0923         {
0924             NDRX_LOG(log_debug, "Failed to build key (no data for key): %s", errdet);
0925             goto out;
0926         }
0927         else
0928         {
0929             NDRX_CACHE_TPERRORNOU(TPESYSTEM, "%s: Failed to build cache key: %s", 
0930                     __func__, errdet);
0931             goto out;
0932         }
0933     }
0934     
0935     NDRX_LOG(log_debug, "%s: Key group key built [%s]", __func__, key);
0936     
0937     
0938     if (EXSUCCEED!=(ret = ndrx_cache_keygrp_inval_by_key(cache->keygrpdb, key, 
0939             txn, cache->cachedbnm)))
0940     {
0941         NDRX_LOG(log_error, "Failed to remove key group [%s] of db [%s]",
0942                 key, cache->keygrpdb->cachedb);
0943         EXFAIL_OUT(ret);
0944     }
0945     
0946     /* Remove group record by it self 
0947      * Already done..
0948     
0949     if (EXSUCCEED!=(ret=ndrx_cache_edb_del (cache->keygrpdb, txn, key, NULL)))
0950     {
0951         if (EDB_NOTFOUND==ret)
0952         {
0953             ret=EXSUCCEED;
0954         }
0955         else
0956         {
0957             EXFAIL_OUT(ret);
0958         }
0959     }
0960      * */
0961     
0962 out:
0963    
0964     NDRX_LOG(log_debug, "%s return %d", __func__, ret);
0965     return ret;
0966 }
0967 /* vim: set ts=4 sw=4 et smartindent: */