LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_scenario.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 47 82 57.3 %
Date: 2024-12-20 21:24:02 Functions: 7 11 63.6 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * (author) M. Kersten
      15             :  * @+ Session Scenarios
      16             :  * In MonetDB multiple languages and execution engines can
      17             :  * be combined at run time to satisfy a wide user-community.
      18             :  * Such an assemblage of components is called a @emph{scenario}
      19             :  * and consists of a @emph{engine}. These hooks allow
      20             :  * for both linked-in and external components.
      21             :  *
      22             :  * The languages supported are SQL, the Monet Assembly Language (MAL), and profiler.
      23             :  * The default scenario handles MAL instructions, which is used
      24             :  * to illustrate the behavior of the scenario steps.
      25             :  *
      26             :  * The MAL reader component handles interaction with
      27             :  * a front-end to obtain a string for subsequent compilation and
      28             :  * execution. The reader uses the common stream package to read
      29             :  * data in large chunks, if possible. In interactive mode the lines
      30             :  * are processed one at a time.
      31             :  *
      32             :  * The final stage is to choose an execution paradigm,
      33             :  * i.e. interpretative (default), compilation of an ad-hoc user
      34             :  * defined function, dataflow driven interpretation,
      35             :  * or vectorized pipe-line execution by a dedicated engine.
      36             :  *
      37             :  * A failure encountered in any of the steps terminates the scenario
      38             :  * cycle. It returns to the user for a new command.
      39             :  *
      40             :  * @+ Scenario management
      41             :  * Scenarios are captured in modules; they can be dynamically loaded
      42             :  * and remain active until the system is brought to a halt.
      43             :  * Thereafter its components are set to those required by
      44             :  * the scenario and the client initialization takes place.
      45             :  *
      46             :  * A scenario is interpreted in a strictly linear fashion,
      47             :  * i.e. performing a symbolic optimization before scheduling decisions
      48             :  * are taken.
      49             :  * The routines associated with each state in
      50             :  * the scenario may patch the code so as to assure that subsequent
      51             :  * execution can use a different scenario, e.g., to handle dynamic
      52             :  * code fragments.
      53             :  *
      54             :  * The state of execution is maintained in the scenario record for
      55             :  * each individual client. Sharing this information between clients
      56             :  * should be dealt with in the implementation of the scenario managers.
      57             :  * Upon need, the client can postpone a session scenario by
      58             :  * pushing a new one(language, optimize,
      59             :  * processor).
      60             :  *
      61             :  * @+ Scenario administration
      62             :  * Administration of scenarios follows the access rules
      63             :  * defined for code modules in general.
      64             :  *
      65             :  */
      66             : #include "monetdb_config.h"
      67             : #include "mal_scenario.h"
      68             : #include "mal_client.h"
      69             : #include "mal_authorize.h"
      70             : #include "mal_exception.h"
      71             : #include "mal_profiler.h"
      72             : #include "mal_private.h"
      73             : #include "mal_session.h"
      74             : 
      75             : #ifdef HAVE_SYS_TIMES_H
      76             : # include <sys/times.h>
      77             : #endif
      78             : 
      79             : static struct SCENARIO scenarioRec[MAXSCEN] = {
      80             :         {
      81             :                 .name = "mal",
      82             :                 .language = "mal",
      83             :                 .initClient = "MALinitClient",
      84             :                 .initClientCmd = (init_client) MALinitClient,
      85             :                 .exitClient = "MALexitClient",
      86             :                 .exitClientCmd = (exit_client) MALexitClient,
      87             :                 .engine = "MALengine",
      88             :                 .engineCmd = (engine_fptr) MALengine,
      89             :         },
      90             :         {
      91             :                 .name = NULL,
      92             :         }
      93             : };
      94             : 
      95             : static str fillScenario(Client c, Scenario scen);
      96             : static MT_Lock scenarioLock = MT_LOCK_INITIALIZER(scenarioLock);
      97             : 
      98             : 
      99             : /*
     100             :  * Currently each user can define a new scenario, provided we have a free slot.
     101             :  * Scenarios not hardwired can always be dropped.
     102             :  */
     103             : Scenario
     104         704 : getFreeScenario(void)
     105             : {
     106         704 :         int i;
     107         704 :         Scenario scen = NULL;
     108             : 
     109         704 :         MT_lock_set(&scenarioLock);
     110        2464 :         for (i = 0; i < MAXSCEN && scenarioRec[i].name; i++)
     111             :                 ;
     112         704 :         if (i < MAXSCEN)
     113         704 :                 scen = scenarioRec + i;
     114         704 :         MT_lock_unset(&scenarioLock);
     115             : 
     116         704 :         return scen;
     117             : }
     118             : 
     119             : str
     120         352 : defaultScenario(Client c)
     121             : {
     122         352 :         return fillScenario(c, scenarioRec);
     123             : }
     124             : 
     125             : /*
     126             :  * The Monet debugger provides an option to inspect the scenarios currently
     127             :  * defined.
     128             :  *
     129             :  */
     130             : static void
     131           0 : print_scenarioCommand(stream *f, str cmd)
     132             : {
     133           0 :         mnstr_printf(f, " \"%s\",", cmd);
     134             : }
     135             : 
     136             : void
     137           0 : showScenario(stream *f, Scenario scen)
     138             : {
     139           0 :         mnstr_printf(f, "[ \"%s\",", scen->name);
     140           0 :         print_scenarioCommand(f, scen->initClient);
     141           0 :         print_scenarioCommand(f, scen->exitClient);
     142           0 :         print_scenarioCommand(f, scen->engine);
     143           0 :         mnstr_printf(f, "]\n");
     144           0 : }
     145             : 
     146             : Scenario
     147       38283 : findScenario(const char *nme)
     148             : {
     149       38283 :         int i;
     150       38283 :         Scenario scen = scenarioRec;
     151             : 
     152       76795 :         for (i = 0; i < MAXSCEN; i++, scen++)
     153       76796 :                 if (scen->name && strcmp(scen->name, nme) == 0)
     154       38284 :                         return scen;
     155             :         return NULL;
     156             : }
     157             : 
     158             : void
     159           0 : showScenarioByName(stream *f, const char *nme)
     160             : {
     161           0 :         Scenario scen = findScenario(nme);
     162             : 
     163           0 :         if (scen)
     164           0 :                 showScenario(f, scen);
     165           0 : }
     166             : 
     167             : void
     168           0 : showAllScenarios(stream *f)
     169             : {
     170           0 :         int i;
     171           0 :         Scenario scen = scenarioRec;
     172             : 
     173           0 :         for (i = 0; i < MAXSCEN && scen->name; i++, scen++)
     174           0 :                 showScenario(f, scen);
     175           0 : }
     176             : 
     177             : str
     178          69 : getScenarioLanguage(Client c)
     179             : {
     180          69 :         Scenario scen = findScenario(c->scenario);
     181          69 :         if (scen)
     182          69 :                 return scen->language;
     183             :         return "mal";
     184             : }
     185             : 
     186             : /*
     187             :  * Changing the scenario for a particular client invalidates the
     188             :  * state maintained for the previous scenario.
     189             :  * Before we initialize a scenario the client scenario is reset to
     190             :  * the MAL scenario. This implies that all scenarios are initialized
     191             :  * using the same scenario. After the scenario initialization file
     192             :  * has been processed, the scenario functions are replaced with the
     193             :  * proper ones.
     194             :  *
     195             :  * All client records should be initialized with a default
     196             :  * scenario, i.e. the first described in the scenario table.
     197             :  */
     198             : static str
     199       37867 : fillScenario(Client c, Scenario scen)
     200             : {
     201       37867 :         c->scenario = scen->name;
     202             : 
     203       37867 :         c->engine = scen->engineCmd;
     204       37867 :         c->initClient = scen->initClientCmd;
     205       37867 :         c->exitClient = scen->exitClientCmd;
     206       37867 :         return (MAL_SUCCEED);
     207             : }
     208             : 
     209             : /*
     210             :  * Setting a new scenario calls for saving the previous state
     211             :  * and execution of the initClientScenario routine.
     212             :  */
     213             : str
     214       37514 : setScenario(Client c, const char *nme)
     215             : {
     216       37514 :         str msg;
     217       37514 :         Scenario scen;
     218             : 
     219       37514 :         scen = findScenario(nme);
     220       37515 :         if (scen == NULL)
     221           0 :                 throw(MAL, "setScenario", SCENARIO_NOT_FOUND " '%s'", nme);
     222             : 
     223       37515 :         msg = fillScenario(c, scen);
     224       37515 :         if (msg) {
     225             :                 /* error occurred, reset the scenario , assume default always works */
     226             :                 c->scenario = NULL;
     227             :                 c->initClient = NULL;
     228             :                 c->exitClient = NULL;
     229             :                 c->engine = NULL;
     230             :                 return msg;
     231             :         }
     232       37515 :         return MAL_SUCCEED;
     233             : }
     234             : 
     235             : /*
     236             :  * After finishing a session in a scenario, we should reset the
     237             :  * state of the previous one. But also call the exitClient
     238             :  * to garbage collect any scenario specific structures.
     239             :  */
     240             : 
     241             : void
     242           0 : resetScenario(Client c)
     243             : {
     244           0 :         Scenario scen = scenarioRec;
     245             : 
     246           0 :         if (c->scenario == 0)
     247             :                 return;
     248             : 
     249           0 :         scen = findScenario(c->scenario);
     250           0 :         if (scen != NULL && scen->exitClientCmd) {
     251           0 :                 str msg = (*scen->exitClientCmd) (c);
     252           0 :                 freeException(msg);
     253             :         }
     254             : 
     255           0 :         c->scenario = NULL;
     256           0 :         c->initClient = NULL;
     257           0 :         c->exitClient = NULL;
     258           0 :         c->engine = NULL;
     259             : }
     260             : 
     261             : /*
     262             :  * The building blocks of scenarios are routines obeying a strict
     263             :  * name signature. They require exclusive access to the client
     264             :  * record. Any specific information should be accessible from
     265             :  * there, e.g., access to a scenario specific descriptor.
     266             :  * The client scenario initialization and finalization brackets
     267             :  * are  @sc{xyzinitClient()} and @sc{xyzexitClient()}.
     268             :  *
     269             :  * The @sc{xyzengine(Client c)} contains the applicable back-end engine.
     270             :  * The default is the MAL interpreter, which provides good balance
     271             :  * between speed and ability to analysis its behavior.
     272             :  *
     273             :  */
     274             : 
     275             : /*
     276             :  * Access control enforcement. Except for the server owner
     277             :  * running a scenario should be explicitly permitted.
     278             :  */
     279             : static str
     280       37495 : runScenarioBody(Client c)
     281             : {
     282       37495 :         MT_thread_setworking("engine");
     283      537674 :         while (c->mode > FINISHCLIENT && !GDKexiting()) {
     284      499952 :                 c->engine(c);
     285      500179 :                 assert(c->curprg->def->errors == NULL);
     286             :         }
     287       37502 :         if (!GDKexiting() && GDKerrbuf && GDKerrbuf[0])
     288           0 :                 mnstr_printf(c->fdout, "!GDKerror: %s\n", GDKerrbuf);
     289       37501 :         return c->exitClient(c);
     290             : }
     291             : 
     292             : str
     293       37495 : runScenario(Client c)
     294             : {
     295       37495 :         str msg = MAL_SUCCEED;
     296             : 
     297       37495 :         if (c == 0)
     298             :                 return msg;
     299       37495 :         msg = runScenarioBody(c);
     300       37503 :         if (msg != MAL_SUCCEED &&
     301           0 :                 strcmp(msg, "MALException:client.quit:Server stopped."))
     302           0 :                 mnstr_printf(c->fdout, "!%s\n", msg);
     303             :         return msg;
     304             : }

Generated by: LCOV version 1.14