LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_module.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 151 179 84.4 %
Date: 2021-09-14 22:17:06 Functions: 18 19 94.7 %

          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. L. Kersten
      11             :  * All symbols are collected in modules. Modules are either global
      12             :  * or private for the user. The latter are known as 'user' module functions
      13             :  * and reside within the Client record.
      14             :  */
      15             : 
      16             : #include "monetdb_config.h"
      17             : #include "mal_module.h"
      18             : #include "mal_function.h"   /* for printFunction() */
      19             : #include "mal_namespace.h"
      20             : #include "mal_client.h"
      21             : #include "mal_interpreter.h"
      22             : #include "mal_listing.h"
      23             : #include "mal_private.h"
      24             : 
      25             : /*
      26             :  * Definition of a new module may interfere with concurrent actions.
      27             :  * A jump table is mainted to provide a quick start in the module
      28             :  * table to find the correct one.
      29             :  *
      30             :  * All modules are persistent during a server session
      31             :  */
      32             : 
      33             : #define MODULE_HASH_SIZE 1024
      34             : static Module moduleIndex[MODULE_HASH_SIZE] = { NULL };
      35             : 
      36             : MALfcn
      37          31 : findFunctionImplementation(const char *cname)
      38             : {
      39       24734 :         for (int i = 0; i < MODULE_HASH_SIZE; i++) {
      40       24722 :                 if (moduleIndex[i] != NULL && moduleIndex[i]->space != NULL) {
      41      437584 :                         for (int j = 0; j < MAXSCOPE; j++) {
      42             :                                 Symbol s;
      43      435887 :                                 if ((s = moduleIndex[i]->space[j]) != NULL) {
      44             :                                         do {
      45      290486 :                                                 if (s->def &&
      46      290486 :                                                         strcmp(s->def->binding, cname) == 0 &&
      47          39 :                                                         s->def->stmt &&
      48          39 :                                                         s->def->stmt[0] &&
      49          39 :                                                         s->def->stmt[0]->fcn) {
      50          19 :                                                         return s->def->stmt[0]->fcn;
      51             :                                                 }
      52      290467 :                                         } while ((s = s->peer) != NULL);
      53             :                                 }
      54             :                         }
      55             :                 }
      56             :         }
      57             :         return NULL;
      58             : }
      59             : 
      60             : BAT *
      61           6 : getModules(void)
      62             : {
      63           6 :         BAT *b = COLnew(0, TYPE_str, 100, TRANSIENT);
      64             :         int i;
      65             :         Module s,n;
      66             : 
      67        6150 :         for( i = 0; i< MODULE_HASH_SIZE; i++){
      68        6144 :                 s = moduleIndex[i];
      69        6558 :                 while(s){
      70         414 :                         if (BUNappend(b, s->name, FALSE) != GDK_SUCCEED) {
      71           0 :                                 BBPreclaim(b);
      72           0 :                                 return NULL;
      73             :                         }
      74         414 :                         n = s->link;
      75         414 :                         while(n)
      76           0 :                                 n = n->link;
      77             :                         s = s->link;
      78             :                 }
      79             :         }
      80             :         return b;
      81             : }
      82             : 
      83             : // perform sanity check on duplicate occurrences as well
      84             : void
      85           0 : dumpModules(stream *out)
      86             : {
      87             :         int i;
      88             :         Module s,n;
      89           0 :         for( i = 0; i< MODULE_HASH_SIZE; i++){
      90           0 :                 s= moduleIndex[i];
      91           0 :                 while(s){
      92           0 :                         mnstr_printf(out,"[%d] module %s\n", i, s->name);
      93           0 :                         n = s->link;
      94           0 :                         while(n){
      95           0 :                                 if( n == s)
      96           0 :                                         mnstr_printf(out,"ASSERTION error, double occurrence of symbol in symbol table\n");
      97           0 :                                 n= n->link;
      98             :                         }
      99           0 :                         s= s->link;
     100             :                 }
     101             :         }
     102           0 : }
     103             : 
     104             : /* Remove all globally known functions */
     105             : void
     106         264 : mal_module_reset(void)
     107             : {
     108             :         int i;
     109             :         Module m;
     110             : 
     111      270600 :         for(i = 0; i < MODULE_HASH_SIZE; i++) {
     112      270336 :                 m= moduleIndex[i];
     113      270336 :                 moduleIndex[i] = 0;
     114      288630 :                 while(m) {
     115       18294 :                         Module next = m->link;
     116       18294 :                         freeModule(m);
     117             :                         m = next;
     118             :                 }
     119             :         }
     120         264 : }
     121             : 
     122             : static int getModuleIndex(const char *name) {
     123    82884027 :         return (int) (strHash(name) % MODULE_HASH_SIZE);
     124             : }
     125             : 
     126       18294 : static void clrModuleIndex(Module cur){
     127       18294 :         int index = getModuleIndex(cur->name);
     128             :         Module prev = NULL;
     129       18294 :         Module m = moduleIndex[index];
     130       18294 :         while(m) {
     131           0 :                 if (m == cur) {
     132           0 :                         if (!prev) {
     133           0 :                                 moduleIndex[index] = m->link;
     134             :                         } else {
     135           0 :                                 prev->link = m->link;
     136             :                         }
     137           0 :                         return;
     138             :                 }
     139             :                 prev = m;
     140           0 :                 m = m->link;
     141             :         }
     142             : }
     143             : 
     144       18426 : static void addModuleToIndex(Module cur){
     145       18426 :         int index = getModuleIndex(cur->name);
     146       18426 :         cur->link = moduleIndex[index];
     147       18426 :         moduleIndex[index] = cur;
     148       18426 : }
     149             : 
     150    82847307 : Module getModule(const char *name) {
     151             :         int index = getModuleIndex(name);
     152    82847307 :         Module m = moduleIndex[index];
     153    84377618 :         while(m) {
     154    82815348 :                 if (name == m->name)
     155    81285037 :                         return m;
     156     1530311 :                 m = m->link;
     157             :         }
     158             :         return NULL;
     159             : }
     160             : 
     161          10 : void getModuleList(Module** out, int* length) {
     162             :         int i;
     163             :         int moduleCount = 0;
     164             :         int currentIndex = 0;
     165       10250 :         for(i = 0; i < MODULE_HASH_SIZE; i++) {
     166       10240 :                 Module m = moduleIndex[i];
     167       10956 :                 while(m) {
     168         716 :                         moduleCount++;
     169         716 :                         m = m->link;
     170             :                 }
     171             :         }
     172          10 :         *out = GDKzalloc(moduleCount * sizeof(Module));
     173          10 :         if (*out == NULL) {
     174             :                 return;
     175             :         }
     176          10 :         *length = moduleCount;
     177             : 
     178       10250 :         for(i = 0; i < MODULE_HASH_SIZE; i++) {
     179       10240 :                 Module m = moduleIndex[i];
     180       10956 :                 while(m) {
     181         716 :                         (*out)[currentIndex++] = m;
     182         716 :                         m = m->link;
     183             :                 }
     184             :         }
     185             : }
     186             : 
     187          10 : void freeModuleList(Module* list) {
     188          10 :         GDKfree(list);
     189          10 : }
     190             : 
     191             : /*
     192             :  * Module scope management
     193             :  * It will contain the symbol table of all globally accessible functions.
     194             :  */
     195       18426 : Module globalModule(const char *nme)
     196             : {       Module cur;
     197             : 
     198             :         // Global modules are not named 'user'
     199       18426 :         assert (strcmp(nme, "user"));
     200       18426 :         nme = putName(nme);
     201       18426 :         cur = (Module) GDKzalloc(sizeof(ModuleRecord));
     202       18426 :         if (cur == NULL)
     203             :                 return NULL;
     204       18426 :         cur->name = nme;
     205       18426 :         cur->link = NULL;
     206       18426 :         cur->space = (Symbol *) GDKzalloc(MAXSCOPE * sizeof(Symbol));
     207       18426 :         if (cur->space == NULL) {
     208           0 :                 GDKfree(cur);
     209           0 :                 return NULL;
     210             :         }
     211       18426 :         addModuleToIndex(cur);
     212       18426 :         return cur;
     213             : }
     214             : 
     215             : /* Every client record has a private module name 'user'
     216             :  * for keeping around non-shared functions */
     217        4582 : Module userModule(void){
     218             :         Module cur;
     219             : 
     220        4582 :         cur = (Module) GDKzalloc(sizeof(ModuleRecord));
     221        4582 :         if (cur == NULL)
     222             :                 return NULL;
     223        4582 :         cur->name = putName("user");
     224        4582 :         cur->link = NULL;
     225        4582 :         cur->space = NULL;
     226        4582 :         cur->space = (Symbol *) GDKzalloc(MAXSCOPE * sizeof(Symbol));
     227        4582 :         if (cur->space == NULL) {
     228           0 :                 GDKfree(cur);
     229           0 :                 return NULL;
     230             :         }
     231             :         return cur;
     232             : }
     233             : /*
     234             :  * The scope can be fixed. This is used by the parser.
     235             :  * Reading a module often calls for creation first.
     236             :  */
     237         524 : Module fixModule(const char *nme) {
     238             :         Module m;
     239             : 
     240         524 :         m = getModule(nme);
     241         524 :         if (m) return m;
     242           4 :         return globalModule(nme);
     243             : }
     244             : /*
     245             :  * The freeModule operation throws away a symbol without
     246             :  * concerns on it whereabouts in the scope structure.
     247             :  */
     248       22875 : static void freeSubScope(Module scope)
     249             : {
     250             :         int i;
     251             :         Symbol s;
     252             : 
     253       22875 :         if (scope->space == NULL)
     254             :                 return;
     255     5878875 :         for(i = 0; i < MAXSCOPE; i++) {
     256     5856000 :                 if( scope->space[i]){
     257             :                         s= scope->space[i];
     258      142320 :                         scope->space[i] = NULL;
     259      142320 :                         freeSymbolList(s);
     260             :                 }
     261             :         }
     262       22875 :         GDKfree(scope->space);
     263       22875 :         scope->space = 0;
     264             : }
     265             : 
     266       22875 : void freeModule(Module m)
     267             : {
     268             :         Symbol s;
     269             : 
     270       22875 :         if (m == NULL)
     271             :                 return;
     272       22875 :         if ((s = findSymbolInModule(m, "epilogue")) != NULL) {
     273        1837 :                 InstrPtr pci = getInstrPtr(s->def,0);
     274        1837 :                 if (pci && pci->token == COMMANDsymbol && pci->argc == 1) {
     275        1837 :                         int ret = 0;
     276             : 
     277        1837 :                         assert(pci->fcn != NULL);
     278        1837 :                         (*pci->fcn)(&ret);
     279             :                         (void)ret;
     280             :                 }
     281             :         }
     282       22875 :         freeSubScope(m);
     283       22875 :         if (strcmp(m->name, "user")) {
     284       18294 :                 clrModuleIndex(m);
     285             :         }
     286       22875 :         if (m->help)
     287           0 :                 GDKfree(m->help);
     288       22875 :         GDKfree(m);
     289             : }
     290             : 
     291             : /*
     292             :  * After filling in a structure it is added to the multi-level symbol
     293             :  * table.  We keep a skip list of similarly named function symbols.
     294             :  * This speeds up searching provided the modules adhere to the
     295             :  * structure and group the functions as well.
     296             :  */
     297     3493419 : void insertSymbol(Module scope, Symbol prg){
     298             :         InstrPtr sig;
     299             :         int t;
     300             :         Module c;
     301             : 
     302     3493419 :         assert(scope);
     303     3493419 :         sig = getSignature(prg);
     304     3493419 :         if(getModuleId(sig) && getModuleId(sig)!= scope->name){
     305             :                 /* move the definition to the proper place */
     306             :                 /* default scope is the last resort */
     307     1530591 :                 c= findModule(scope,getModuleId(sig));
     308     1530591 :                 if ( c )
     309             :                         scope = c;
     310             :         }
     311     3493419 :         t = getSymbolIndex(getFunctionId(sig));
     312     3493419 :         if( scope->space == NULL) {
     313           0 :                 scope->space = (Symbol *) GDKzalloc(MAXSCOPE * sizeof(Symbol));
     314           0 :                 if (scope->space == NULL)
     315             :                         return;
     316             :         }
     317     3493419 :         assert(scope->space);
     318     3493419 :         if (scope->space[t] == prg){
     319             :                 /* already known, last inserted */
     320             :         } else {
     321     3493409 :                 prg->peer= scope->space[t];
     322     3493409 :                 scope->space[t] = prg;
     323     3493409 :                 if( prg->peer &&
     324     3349853 :                         idcmp(prg->name,prg->peer->name) == 0)
     325     2963935 :                         prg->skip = prg->peer->skip;
     326             :                 else
     327      529474 :                         prg->skip = prg->peer;
     328             :         }
     329     3493419 :         assert(prg != prg->peer);
     330             : }
     331             : /*
     332             :  * Removal of elements from the symbol table should be
     333             :  * done with care. For, it should be assured that
     334             :  * there are no references to the definition at the
     335             :  * moment of removal. This situation can not easily
     336             :  * checked at runtime, without tremendous overhead.
     337             :  */
     338         303 : void deleteSymbol(Module scope, Symbol prg){
     339             :         InstrPtr sig;
     340             :         int t;
     341             : 
     342         303 :         sig = getSignature(prg);
     343         303 :         if (getModuleId(sig) && getModuleId(sig)!= scope->name ){
     344             :                 /* move the definition to the proper place */
     345             :                 /* default scope is the last resort */
     346           2 :                 Module c= findModule(scope, getModuleId(sig));
     347           2 :                 if(c )
     348             :                         scope = c;
     349             :         }
     350         303 :         t = getSymbolIndex(getFunctionId(sig));
     351         303 :         if (scope->space[t] == prg) {
     352         302 :                 scope->space[t] = scope->space[t]->peer;
     353         302 :                 freeSymbol(prg);
     354             :         } else {
     355             :                 Symbol nxt = scope->space[t];
     356           1 :                 while (nxt->peer != NULL) {
     357           1 :                         if (nxt->peer == prg) {
     358           1 :                                 nxt->peer = prg->peer;
     359           1 :                                 nxt->skip = prg->peer;
     360           1 :                                 freeSymbol(prg);
     361           1 :                                 return;
     362             :                         }
     363             :                         nxt = nxt->peer;
     364             :                 }
     365             :         }
     366             : }
     367             : 
     368             : /*
     369             :  * Searching the scope structure.
     370             :  * Finding a scope is unrestricted. For modules we explicitly look for
     371             :  * the start of a new module scope.
     372             :  * All core modules are accessed through the jumptable.
     373             :  * The 'user' module is an alias for the scope attached
     374             :  * to the current user.
     375             :  */
     376    79055736 : Module findModule(Module scope, const char *name){
     377             :         Module def = scope;
     378             :         Module m;
     379    79055736 :         if (name == NULL) return scope;
     380    79055736 :         m = getModule(name);
     381    79055743 :         if (m) return m;
     382             : 
     383             :         /* default is always matched with current */
     384     1543003 :         if (def->name == NULL) return NULL;
     385             :         return def;
     386             : }
     387             : 
     388             : /*
     389             :  * The routine findSymbolInModule starts at a MAL scope level and searches
     390             :  * an element amongst the peers.
     391             :  *
     392             :  * In principal, external variables are subject to synchronization actions
     393             :  * to avoid concurrency conflicts. This also implies, that any parallel
     394             :  * block introduces a temporary scope.
     395             :  *
     396             :  * The variation on this routine is to dump the definition of
     397             :  * all matching definitions.
     398             :  */
     399      967969 : Symbol findSymbolInModule(Module v, const char *fcn) {
     400             :         Symbol s;
     401      967969 :         if (v == NULL || fcn == NULL) return NULL;
     402      967935 :         s = v->space[(int)(*fcn)];
     403     2679425 :         while (s != NULL) {
     404     2648043 :                 if (idcmp(s->name,fcn)==0) return s;
     405     1711490 :                 s = s->skip;
     406             :         }
     407             :         return NULL;
     408             : }
     409             : 
     410        2245 : Symbol findSymbol(Module usermodule, const char *mod, const char *fcn) {
     411        2245 :         Module m = findModule(usermodule, mod);
     412        2245 :         return findSymbolInModule(m, fcn);
     413             : }

Generated by: LCOV version 1.14