LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_factory.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 118 186 63.4 %
Date: 2021-09-14 22:17:06 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * (author) M. Kersten
      11             :  * For documentation see website
      12             :  */
      13             : #include "monetdb_config.h"
      14             : #include "mal_factory.h"
      15             : #include "mal_instruction.h"
      16             : #include "mal_interpreter.h"
      17             : #include "mal_function.h"
      18             : #include "mal_exception.h"
      19             : #include "mal_session.h"
      20             : #include "mal_namespace.h"
      21             : #include "mal_private.h"
      22             : 
      23             : typedef struct {
      24             :         int id;                 /* unique plant number */
      25             :         MalBlkPtr factory;
      26             :         MalStkPtr stk;          /* private state */
      27             :         int pc;                 /* where we are */
      28             :         int inuse;              /* able to handle it */
      29             :         int next;               /* next plant of same factory */
      30             :         int policy;             /* flags to control behavior */
      31             : 
      32             :         Client client;          /* who called it */
      33             :         MalBlkPtr caller;       /* from routine */
      34             :         MalStkPtr env;          /* with the stack  */
      35             :         InstrPtr pci;           /* with the instruction */
      36             : } PlantRecord, *Plant;
      37             : 
      38             : #define MAXPLANTS 256
      39             : static PlantRecord plants[MAXPLANTS];
      40             : static int lastPlant= 0;
      41             : static int plantId = 1;
      42             : 
      43             : mal_export Plant newPlant(MalBlkPtr mb);
      44             : 
      45             : 
      46             : static int
      47             : findPlant(MalBlkPtr mb){
      48             :         int i;
      49           0 :         for(i=0; i<lastPlant; i++)
      50           0 :         if( plants[i].factory == mb)
      51             :                 return i;
      52             :         return -1;
      53             : }
      54             : 
      55             : str
      56     1000025 : runFactory(Client cntxt, MalBlkPtr mb, MalBlkPtr mbcaller, MalStkPtr stk, InstrPtr pci)
      57             : {
      58             :         Plant pl=0;
      59             :         int firstcall= TRUE, i, k;
      60     1000025 :         InstrPtr psig = getInstrPtr(mb, 0);
      61             :         ValPtr lhs, rhs;
      62             :         char cmd;
      63             :         str msg;
      64             : 
      65             : 
      66             :         /* the lookup can be largely avoided by handing out the index
      67             :            upon factory definition. todo
      68             :                 Alternative is to move them to the front
      69             :          */
      70     1000047 :         for(i=0; i< lastPlant; i++)
      71     1000035 :         if( plants[i].factory == mb){
      72     1000013 :                 if(i > 0 && i< lastPlant ){
      73           4 :                         PlantRecord prec= plants[i-1];
      74           4 :                         plants[i-1] = plants[i];
      75           4 :                         plants[i]= prec;
      76             :                         i--;
      77             :                 }
      78     1000013 :                 pl= plants+i;
      79             :                 firstcall= FALSE;
      80     1000013 :                 break;
      81             :         }
      82     1000025 :         if (pl == 0) {
      83             :                 /* compress the plant table*/
      84          39 :                 for(k=i=0;i<=lastPlant; i++)
      85          27 :                 if( plants[i].inuse)
      86           8 :                         plants[k++]= plants[i];
      87          12 :                 lastPlant = k;
      88             :                 /* initialize a new plant using the owner policy */
      89          12 :                 pl = newPlant(mb);
      90          12 :                 if (pl == NULL)
      91           0 :                         throw(MAL, "factory.new", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      92             :         }
      93             :         /*
      94             :          * We have found a factory to process the request.
      95             :          * Let's call it as a synchronous action, without concern on parallelism.
      96             :          */
      97             :         /* remember context */
      98     1000025 :         pl->client = cntxt;
      99     1000025 :         pl->caller = mbcaller;
     100     1000025 :         pl->env = stk;
     101     1000025 :         pl->pci = pci;
     102     1000025 :         pl->inuse = 1;
     103             :         /* inherit debugging */
     104     1000025 :         cmd = stk->cmd;
     105     1000025 :         if ( pl->stk == NULL)
     106           0 :                 throw(MAL, "factory.new", "internal error, stack frame missing");
     107             : 
     108             :         /* copy the calling arguments onto the stack
     109             :            of the factory */
     110     1000025 :         i = psig->retc;
     111     2000045 :         for (k = pci->retc; i < pci->argc; i++, k++) {
     112     1000020 :                 lhs = &pl->stk->stk[psig->argv[k]];
     113             :                 /* variable arguments ? */
     114     1000020 :                 if (k == psig->argc - 1)
     115     1000020 :                         k--;
     116             : 
     117     1000020 :                 rhs = &pl->env->stk[getArg(pci, i)];
     118     1000020 :                 if (VALcopy(lhs, rhs) == NULL)
     119           0 :                         throw(MAL, "factory.call", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     120     1000020 :                 if( lhs->vtype == TYPE_bat )
     121           0 :                         BBPretain(lhs->val.bval);
     122             :         }
     123     1000025 :         if (mb->errors)
     124           0 :                 throw(MAL, "factory.call", PROGRAM_GENERAL);
     125     1000025 :         if (firstcall ){
     126             :                 /* initialize the stack */
     127          87 :                 for(i= psig->argc; i< mb->vtop; i++) {
     128          75 :                         lhs = &pl->stk->stk[i];
     129          75 :                         if( isVarConstant(mb,i) > 0 ){
     130          49 :                                 if( !isVarDisabled(mb,i)){
     131          49 :                                         rhs = &getVarConstant(mb,i);
     132          49 :                                         if (VALcopy(lhs,rhs) == NULL)
     133           0 :                                                 throw(MAL, "factory.call", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     134             :                                 }
     135             :                         } else{
     136          26 :                                 lhs->vtype = getVarGDKType(mb,i);
     137          26 :                                 lhs->val.pval = 0;
     138          26 :                                 lhs->len = 0;
     139             :                         }
     140             :                 }
     141          12 :                 pl->stk->stktop = mb->vtop;
     142          12 :                 pl->stk->stkbot= mb->vtop;     /* stack already initialized */
     143          12 :                 msg = runMAL(cntxt, mb, 0, pl->stk);
     144             :          } else {
     145     1000013 :                 msg = reenterMAL(cntxt, mb, pl->pc, -1, pl->stk);
     146             :         }
     147             :         /* propagate change in debugging status */
     148     1000025 :         if (cmd && pl->stk && pl->stk->cmd != cmd && cmd != 'x')
     149           0 :                 for (; stk; stk = stk->up)
     150           0 :                         stk->cmd = pl->stk->cmd;
     151             :         return msg;
     152             : }
     153             : /*
     154             :  * The shortcut operator for factory calls assumes that the user is
     155             :  * not interested in the results produced.
     156             :  */
     157             : str
     158           0 : callFactory(Client cntxt, MalBlkPtr mb, ValPtr argv[], char flag){
     159             :         Plant pl;
     160           0 :         InstrPtr psig = getInstrPtr(mb, 0);
     161             :         int i;
     162             :         ValPtr lhs,rhs;
     163             :         MalStkPtr stk;
     164             :         str ret;
     165             : 
     166             :         i= findPlant(mb);
     167           0 :         if( i< 0) {
     168             :                 /* first call? prepare the factory */
     169           0 :                 pl = newPlant(mb);
     170           0 :                 if (pl == NULL)
     171           0 :                         throw(MAL, "factory.call", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     172             :                 /* remember context, which does not exist. */
     173           0 :                 pl->client = cntxt;
     174           0 :                 pl->caller = 0;
     175           0 :                 pl->env = 0;
     176           0 :                 pl->pci = 0;
     177           0 :                 pl->inuse = 1;
     178           0 :                 stk = pl->stk;
     179             :                 /* initialize the stack */
     180           0 :                 stk->stktop= mb->vtop;
     181           0 :                 stk->stksize= mb->vsize;
     182           0 :                 stk->blk= mb;
     183           0 :                 stk->up = 0;
     184           0 :                 stk->cmd= flag;
     185             :                 /* initialize the stack */
     186           0 :                 for(i= psig->argc; i< mb->vtop; i++)
     187           0 :                 if( isVarConstant(mb,i) > 0 ){
     188           0 :                         lhs = &stk->stk[i];
     189           0 :                         rhs = &getVarConstant(mb,i);
     190           0 :                         if (VALcopy(lhs,rhs) == NULL)
     191           0 :                                 throw(MAL, "factory.call", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     192             :                 } else {
     193             :                         lhs = &stk->stk[i];
     194           0 :                         lhs->vtype = getVarGDKType(mb,i);
     195             :                 }
     196           0 :                 pl->stk= stk;
     197             :         } else  {
     198           0 :                 pl= plants+i;
     199             :                 /*
     200             :                  * When you re-enter the factory the old arguments should be
     201             :                  * released to make room for the new ones.
     202             :                  */
     203           0 :                 for (i = psig->retc; i < psig->argc; i++) {
     204           0 :                         lhs = &pl->stk->stk[psig->argv[i]];
     205           0 :                         if( lhs->vtype == TYPE_bat )
     206           0 :                                 BBPrelease(lhs->val.bval);
     207             :                 }
     208             :         }
     209             :         /* copy the calling arguments onto the stack of the factory */
     210           0 :         i = psig->retc;
     211           0 :         for (i = psig->retc; i < psig->argc; i++) {
     212           0 :                 lhs = &pl->stk->stk[psig->argv[i]];
     213           0 :                 if (VALcopy(lhs, argv[i]) == NULL)
     214           0 :                         throw(MAL, "factory.call", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     215           0 :                 if( lhs->vtype == TYPE_bat )
     216           0 :                         BBPretain(lhs->val.bval);
     217             :         }
     218           0 :         ret=  reenterMAL(cntxt, mb, pl->pc, -1, pl->stk);
     219             :         /* garbage collect the string arguments, these positions
     220             :            will simply be overwritten the next time.
     221             :         for (i = psig->retc; i < psig->argc; i++)
     222             :                 garbageElement(lhs = &pl->stk->stk[psig->argv[i]]);
     223             :         */
     224           0 :         return ret;
     225             : }
     226             : /*
     227             :  * A new plant is constructed. The properties of the factory
     228             :  * should be known upon compile time. They are retrieved from
     229             :  * the signature of the factory definition.
     230             :  */
     231             : Plant
     232          12 : newPlant(MalBlkPtr mb)
     233             : {
     234             :         Plant p, plim;
     235             :         MalStkPtr stk;
     236             : 
     237          12 :         plim = plants + lastPlant;
     238          20 :         for (p = plants; p < plim && p->factory; p++)
     239             :                 ;
     240          12 :         stk = newGlobalStack(mb->vsize);
     241          12 :         if (lastPlant == MAXPLANTS || stk == NULL){
     242           0 :                 if( stk) GDKfree(stk);
     243           0 :                 return 0;
     244             :         }
     245          12 :         if (p == plim)
     246          12 :                 lastPlant++;
     247          12 :         p->factory = mb;
     248          12 :         p->id = plantId++;
     249             : 
     250          12 :         p->pc = 1;           /* where we start */
     251          12 :         p->stk = stk;
     252          12 :         p->stk->blk = mb;
     253          12 :         p->stk->keepAlive = TRUE;
     254          12 :         return p;
     255             : }
     256             : 
     257             : /*
     258             :  * Upon reaching the yield operator, the factory is
     259             :  * suspended until the next request arrives.
     260             :  * The information in the target list should be delivered
     261             :  * to the caller stack frame.
     262             :  */
     263             : int
     264     1000025 : yieldResult(MalBlkPtr mb, InstrPtr p, int pc)
     265             : {
     266     1000025 :         Plant pl, plim = plants + lastPlant;
     267             :         ValPtr lhs, rhs;
     268             :         int i;
     269             : 
     270             :         (void) p;
     271             :         (void) pc;
     272     1000036 :         for (pl = plants; pl < plim; pl++)
     273     1000036 :                 if (pl->factory == mb ) {
     274     1000025 :                         if( pl->env == NULL)
     275           0 :                                 return(int) (pl-plants);
     276     2000050 :                         for (i = 0; i < p->retc; i++) {
     277     1000025 :                                 rhs = &pl->stk->stk[getArg(p, i)];
     278     1000025 :                                 lhs = &pl->env->stk[getArg(pl->pci, i)];
     279     1000025 :                                 if (VALcopy(lhs, rhs) == NULL)
     280             :                                         return -1;
     281             :                         }
     282     1000025 :                         return (int) (pl-plants);
     283             :                 }
     284             :         return -1;
     285             : }
     286             : 
     287             : str
     288     1000022 : yieldFactory(MalBlkPtr mb, InstrPtr p, int pc)
     289             : {
     290             :         Plant pl;
     291             :         int i;
     292             : 
     293     1000022 :         i = yieldResult(mb, p, pc);
     294             : 
     295     1000022 :         if (i>=0) {
     296     1000022 :                 pl = plants+i;
     297     1000022 :                 pl->pc = pc + 1;
     298     1000022 :                 pl->client = NULL;
     299     1000022 :                 pl->caller = NULL;
     300     1000022 :                 pl->pci = NULL;
     301     1000022 :                 pl->env = NULL;
     302     1000022 :                 return MAL_SUCCEED;
     303             :         }
     304           0 :         throw(MAL, "factory.yield", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     305             : }
     306             : 
     307             : /*
     308             :  * A return from a factory body implies removal of
     309             :  * all state information.
     310             :  * This code should also prepare for handling factories
     311             :  * that are still running threads in parallel.
     312             :  */
     313             : 
     314             : str
     315           9 : shutdownFactory(Client cntxt, MalBlkPtr mb)
     316             : {
     317             :         Plant pl, plim;
     318             : 
     319           9 :         plim = plants + lastPlant;
     320          23 :         for (pl = plants; pl < plim; pl++)
     321          14 :                 if (pl->factory == mb) {
     322             :                         /* MSresetStack(mb, pl->stk);*/
     323             :                         /* freeStack(pl->stk); there may be a reference?*/
     324             :                         /* we are inside the body of the factory and about to return */
     325           9 :                         pl->factory = 0;
     326           9 :                         if (pl->stk)
     327           9 :                                 pl->stk->keepAlive = FALSE;
     328           9 :                         if ( pl->stk) {
     329           9 :                                 garbageCollector(cntxt, mb, pl->stk,TRUE);
     330           9 :                                 GDKfree(pl->stk);
     331             :                         }
     332           9 :                         pl->stk=0;
     333           9 :                         pl->pc = 0;
     334           9 :                         pl->inuse = 0;
     335           9 :                         pl->client = NULL;
     336           9 :                         pl->caller = NULL;
     337           9 :                         pl->pci = NULL;
     338           9 :                         pl->env = NULL;
     339             :                         pl->client = NULL;
     340             :                         pl->caller = NULL;
     341             :                         pl->env= NULL;
     342             :                         pl->pci = NULL;
     343             :                 }
     344           9 :         return MAL_SUCCEED;
     345             : }
     346             : 
     347             : str
     348           0 : shutdownFactoryByName(Client cntxt, Module m, str nme){
     349             :         Plant pl, plim;
     350             :         InstrPtr p;
     351             :         Symbol s;
     352             : 
     353           0 :         plim = plants + lastPlant;
     354           0 :         for (pl = plants; pl < plim; pl++)
     355           0 :                 if (pl->factory ) {
     356             :                         MalStkPtr stk;
     357             : 
     358           0 :                         p= getInstrPtr(pl->factory,0);
     359           0 :                         if( strcmp(nme, getFunctionId(p)) != 0) continue;
     360           0 :                         s = findSymbolInModule(m, nme );
     361           0 :                         if (s == NULL){
     362           0 :                                 throw(MAL, "factory.remove",
     363             :                                         OPERATION_FAILED " SQL entry '%s' not found",
     364             :                                         putName(nme));
     365             :                         }
     366           0 :                         stk = pl->stk;
     367           0 :                         MSresetStack(cntxt, pl->factory, stk);
     368           0 :                         shutdownFactory(cntxt, pl->factory);
     369           0 :                         freeStack(stk);
     370           0 :                         deleteSymbol(m,s);
     371           0 :                         return MAL_SUCCEED;
     372             :                 }
     373             :         return MAL_SUCCEED;
     374             : }
     375             : 
     376         264 : void mal_factory_reset(void)
     377             : {
     378             :         Plant pl, plim;
     379             : 
     380         264 :         plim = plants + lastPlant;
     381         269 :         for (pl = plants; pl < plim; pl++){
     382             :                         /* MSresetStack(mb, pl->stk);*/
     383             :                         /* freeStack(pl->stk); there may be a reference?*/
     384             :                         /* we are inside the body of the factory and about to return */
     385           5 :                         if (pl->stk) {
     386           3 :                                 pl->stk->keepAlive = FALSE;
     387           3 :                                 garbageCollector(NULL, pl->factory, pl->stk, TRUE);
     388           3 :                                 GDKfree(pl->stk);
     389             :                         }
     390           5 :                         pl->factory = 0;
     391           5 :                         pl->stk=0;
     392           5 :                         pl->pc = 0;
     393           5 :                         pl->inuse = 0;
     394           5 :                         pl->client = NULL;
     395           5 :                         pl->caller = NULL;
     396           5 :                         pl->pci = NULL;
     397           5 :                         pl->env = NULL;
     398             :                         pl->client = NULL;
     399             :                         pl->caller = NULL;
     400             :                         pl->env= NULL;
     401             :                         pl->pci = NULL;
     402             :         }
     403         264 :         plantId = 1;
     404         264 :         lastPlant = 0;
     405         264 : }

Generated by: LCOV version 1.14