Changeset: 26ee66ffb88a for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=26ee66ffb88a Modified Files: monetdb5/extras/jaql/jaqlscenario.c monetdb5/mal/mal.c monetdb5/mal/mal.h monetdb5/mal/mal_client.c monetdb5/mal/mal_client.h monetdb5/mal/mal_dataflow.c monetdb5/mal/mal_debugger.c monetdb5/mal/mal_interpreter.c monetdb5/mal/mal_recycle.c monetdb5/mal/mal_scenario.c monetdb5/mal/mal_session.c monetdb5/modules/mal/clients.c monetdb5/modules/mal/clients.mal monetdb5/modules/mal/mdb.c sql/backends/monet5/sql_scenario.c Branch: Feb2013 Log Message:
More defensive shutdown A server receives a TERMSIG when it is requested to stop. The old version simply stopped in the middle of the process. Now, first all active clients receive a notice to stop at the next MAL instruction, which would lead to an EXCEPTION message that will trigger transaction aborts. Then we wait a few seconds (currently 5) before the system actually terminates forcefully. Client state names has been renamed and BLOCKCLIENT is introduced to avoid that new clients appear on the scene while shutting down. diffs (truncated from 606 to 300 lines): diff --git a/monetdb5/extras/jaql/jaqlscenario.c b/monetdb5/extras/jaql/jaqlscenario.c --- a/monetdb5/extras/jaql/jaqlscenario.c +++ b/monetdb5/extras/jaql/jaqlscenario.c @@ -155,7 +155,7 @@ JAQLreader(Client c) /* "activate" the stream by sending a prompt (client sync) */ if (c->fdin->eof != 0) { if (mnstr_flush(c->fdout) < 0) { - c->mode = FINISHING; + c->mode = FINISHCLIENT; } else { c->fdin->eof = 0; } @@ -180,7 +180,7 @@ JAQLparser(Client c) fprintf(stderr, "%s, cannot handle client!\n", errmsg); /* stop here, instead of printing the exception below to the * client in an endless loop */ - c->mode = FINISHING; + c->mode = FINISHCLIENT; return errmsg; } @@ -204,7 +204,7 @@ JAQLparser(Client c) /* stop if it seems nothing is going to come any more */ if (j->scanstreameof == 1) { - c->mode = FINISHING; + c->mode = FINISHCLIENT; freetree(j->p); j->p = NULL; return MAL_SUCCEED; diff --git a/monetdb5/mal/mal.c b/monetdb5/mal/mal.c --- a/monetdb5/mal/mal.c +++ b/monetdb5/mal/mal.c @@ -18,9 +18,6 @@ */ /* - * @f mal - * @- - * @node Design Considerations, Architecture Overview, Design Overview, Design Overview * @+ Design Considerations * Redesign of the MonetDB software stack was driven by the need to * reduce the effort to extend the system into novel directions @@ -73,7 +70,7 @@ * Moreover, a textual interface reduces the programming * effort otherwise needed to develop test and application programs. * The XML trend as the language for tool interaction supports our decision. - * @- + * * @node Architecture Overview, MAL Synopsis, Design Considerations, Design Overview * @+ Architecture Overview * The architecture is built around a few independent components: @@ -255,55 +252,75 @@ int mal_init(void){ return 0; } /* - * @- * Upon exit we should attempt to remove all allocated memory explicitly. * This seemingly superflous action is necessary to simplify analyis of * memory leakage problems later on. */ + +/* stopping clients should be done with care, as they may be in the mids of + * transactions. One safe place is between MAL instructions, which would + * abort the transaction by raising an exception. All non-console sessions are + * terminate this way. + * We should also ensure that no new client enters the scene while shutting down. + * For this we mark the client records as BLOCKCLIENT. + * + * Beware, mal_exit is also called during a SIGTERM from the monetdb tool + */ +static void stopClients(void) +{ + Client cntxt = mal_clients; + + MT_lock_set(&mal_contextLock,"stopClients"); + for(cntxt= mal_clients +1; cntxt < mal_clients+MAL_MAXCLIENTS; cntxt++) + if ( cntxt->mode == RUNCLIENT) + cntxt->mode = FINISHCLIENT; + else if (cntxt->mode == FREECLIENT) + cntxt->mode = BLOCKCLIENT; + MT_lock_unset(&mal_contextLock,"stopClients"); +} + int moreClients(int reruns) { - int freeclient=0, finishing=0, claimed=0; + int freeclient=0, finishing=0, running=0, blocked = 0; Client cntxt = mal_clients; - freeclient=0; finishing=0; claimed=0; for(cntxt= mal_clients+1; cntxt<mal_clients+MAL_MAXCLIENTS; cntxt++){ freeclient += (cntxt->mode == FREECLIENT); - finishing += (cntxt->mode == FINISHING); - claimed += (cntxt->mode == CLAIMED); - if( cntxt->mode & FINISHING) - printf("#Client %d %d\n",(int)(cntxt - mal_clients), cntxt->idx); + finishing += (cntxt->mode == FINISHCLIENT); + running += (cntxt->mode == RUNCLIENT); + blocked += (cntxt->mode == BLOCKCLIENT); } - if( reruns == 3){ - mnstr_printf(mal_clients->fdout,"#MALexit: server forced exit" - " %d finishing %d claimed\n", - finishing,claimed); + if( reruns > 3){ + printf("MALexit: server forced exit %d free %d finishing %d running %d blocked\n", + freeclient, finishing,running, blocked); return 0; } - return finishing+claimed; + return finishing+running; } + void mal_exit(void){ str err; /* - * @- * Before continuing we should make sure that all clients * (except the console) have left the scene. */ - RECYCLEshutdown(mal_clients); /* remove any left over intermediates */ - stopProfiling(); - stopMALdataflow(); + stopClients(); #if 0 { - int reruns=0, goon; + int reruns=0, go_on; do{ - if ( (goon=moreClients(reruns)) ) + if ( (go_on = moreClients(reruns)) ) MT_sleep_ms(1000); if(reruns) mnstr_printf(mal_clients->fdout,"#MALexit: clients still active\n"); - } while (++reruns<3 && goon); + } while (++reruns < SERVERSHUTDOWNDELAY && go_on); } #endif + stopMALdataflow(); + stopProfiling(); + RECYCLEshutdown(mal_clients); /* remove any left over intermediates */ unloadLibraries(); #if 0 /* skip this to solve random crashes, needs work */ diff --git a/monetdb5/mal/mal.h b/monetdb5/mal/mal.h --- a/monetdb5/mal/mal.h +++ b/monetdb5/mal/mal.h @@ -18,6 +18,7 @@ */ /* + * (c) Martin Kersten * @+ Monet Basic Definitions * Definitions that need to included in every file of the Monet system, * as well as in user defined module implementations. @@ -42,7 +43,6 @@ * The number of invocation arguments is kept to a minimum. * See `man mserver5` or tools/mserver/mserver5.1 * for additional system variable settings. - * @ */ #define MAXSCRIPT 64 #define MEMORY_THRESHOLD 0.8 @@ -70,8 +70,6 @@ mal_export int memoryclaims; /* num #define GRPoptimizers (OPTMASK) #define GRPforcemito (FORCEMITOMASK) /* - * @- - * @node Execution Engine, Session Scenarios, MAL Synopsis , Design Overview * @+ Execution Engine * The execution engine comes in several flavors. The default is a * simple, sequential MAL interpreter. For each MAL function call it creates @@ -156,4 +154,5 @@ mal_export int moreClients(int reruns); #define MAXPATHLEN 1024 #endif +#define SERVERSHUTDOWNDELAY 5 /* seconds */ #endif /* _MAL_H*/ diff --git a/monetdb5/mal/mal_client.c b/monetdb5/mal/mal_client.c --- a/monetdb5/mal/mal_client.c +++ b/monetdb5/mal/mal_client.c @@ -38,7 +38,7 @@ * * A client record is initialized upon acceptance of a connection. The * client runs in his own thread of control until it finds a - * soft-termination request mode (FINISHING) or its IO file descriptors + * soft-termination request mode (FINISHCLIENT) or its IO file descriptors * are closed. The latter generates an IO error, which leads to a safe * termination. * @@ -135,14 +135,14 @@ MCnewClient(void) { Client c; MT_lock_set(&mal_contextLock, "newClient"); - if (mal_clients[CONSOLE].user && mal_clients[CONSOLE].mode == FINISHING) { + if (mal_clients[CONSOLE].user && mal_clients[CONSOLE].mode == FINISHCLIENT) { /*system shutdown in progress */ MT_lock_unset(&mal_contextLock, "newClient"); return NULL; } for (c = mal_clients; c < mal_clients + MAL_MAXCLIENTS; c++) { if (c->mode == FREECLIENT) { - c->mode = CLAIMED; + c->mode = RUNCLIENT; break; } } @@ -346,7 +346,7 @@ void freeClient(Client c) { Thread t = c->mythread; - c->mode = FINISHING; + c->mode = FINISHCLIENT; #ifdef MAL_CLIENT_DEBUG printf("# Free client %d\n", c->idx); @@ -409,7 +409,7 @@ MCcloseClient(Client c) } /* adm is set to disallow new clients entering */ - mal_clients[CONSOLE].mode = FINISHING; + mal_clients[CONSOLE].mode = FINISHCLIENT; mal_exit(); } diff --git a/monetdb5/mal/mal_client.h b/monetdb5/mal/mal_client.h --- a/monetdb5/mal/mal_client.h +++ b/monetdb5/mal/mal_client.h @@ -30,9 +30,10 @@ #define CONSOLE 0 #define isAdministrator(X) (X==mal_clients) -#define FREECLIENT 0 -#define FINISHING 1 -#define CLAIMED 2 +#define FREECLIENT 0 +#define FINISHCLIENT 1 +#define RUNCLIENT 2 +#define BLOCKCLIENT 3 #define PROCESSTIMEOUT 2 /* seconds */ diff --git a/monetdb5/mal/mal_dataflow.c b/monetdb5/mal/mal_dataflow.c --- a/monetdb5/mal/mal_dataflow.c +++ b/monetdb5/mal/mal_dataflow.c @@ -430,7 +430,7 @@ DFLOWinitBlk(DataFlow flow, MalBlkPtr mb throw(MAL, "dataflow", "DFLOWinitBlk(): Called with flow == NULL"); if (mb == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Called with mb == NULL"); - PARDEBUG fprintf(stderr, "Initialize dflow block\n"); + PARDEBUG fprintf(stderr, "#Initialize dflow block\n"); assign = (int *) GDKzalloc(mb->vtop * sizeof(int)); if (assign == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Failed to allocate assign"); @@ -481,7 +481,7 @@ DFLOWinitBlk(DataFlow flow, MalBlkPtr mb l = getEndOfLife(mb, getArg(p, j)); if (l != pc && l < flow->stop && l > flow->start) { /* add edge to the target instruction for wakeup call */ - PARDEBUG fprintf(stderr, "endoflife for %s is %d -> %d\n", getVarName(mb, getArg(p, j)), n + flow->start, l); + PARDEBUG fprintf(stderr, "#endoflife for %s is %d -> %d\n", getVarName(mb, getArg(p, j)), n + flow->start, l); assert(pc < l); /* only dependencies on earlier instructions */ l -= flow->start; if (flow->nodes[n]) { @@ -635,7 +635,7 @@ runMALdataflow(Client cntxt, MalBlkPtr m int i; #ifdef DEBUG_FLOW - fprintf(stderr, "runMALdataflow for block %d - %d\n", startpc, stoppc); + fprintf(stderr, "#runMALdataflow for block %d - %d\n", startpc, stoppc); printFunction(GDKstdout, mb, 0, LIST_MAL_STMT | LIST_MAPI); #endif diff --git a/monetdb5/mal/mal_debugger.c b/monetdb5/mal/mal_debugger.c --- a/monetdb5/mal/mal_debugger.c +++ b/monetdb5/mal/mal_debugger.c @@ -426,7 +426,7 @@ retryRead: b = (char *) (*cntxt->phase[MAL_SCENARIO_READER])(cntxt); if (b != 0) break; - if (cntxt->mode == FINISHING) + if (cntxt->mode == FINISHCLIENT) break; /* SQL patch, it should only react to Smessages, Xclose requests to be ignored */ if (strncmp(cntxt->fdin->buf, "Xclose", 6) == 0) { diff --git a/monetdb5/mal/mal_interpreter.c b/monetdb5/mal/mal_interpreter.c --- a/monetdb5/mal/mal_interpreter.c +++ b/monetdb5/mal/mal_interpreter.c @@ -540,6 +540,11 @@ str runMALsequence(Client cntxt, MalBlkP while (stkpc < mb->stop && stkpc != stoppc) { pci = getInstrPtr(mb, stkpc); + if (cntxt->mode == FINISHCLIENT){ + stkpc = stoppc; + ret= createException(MAL, "mal.interpreter", "premature stopped client"); + break; + } if (cntxt->itrace || mb->trap) { _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list