diff --git a/Documentation/routers/schemarouter/SchemaRouter.md b/Documentation/routers/schemarouter/SchemaRouter.md index f583ab357..7823bd817 100644 --- a/Documentation/routers/schemarouter/SchemaRouter.md +++ b/Documentation/routers/schemarouter/SchemaRouter.md @@ -42,6 +42,12 @@ GRANT SELECT,USAGE ON shard.* TO 'john'@'%'; This would in effect allow the user 'john' to only see the database 'shard' on this server. Take notice that these grants are matched against MaxScale's hostname instead of the client's hostname. Only user authentication uses the client's hostname and all other grants use MaxScale's hostname. +The schemarouter supports the following router options: + +|option |parameter |description| +--------------------------------------------- +|max_sescmd_hitory | |Set a limit on the number of session modifying commands a session can execute. This sets an effective cap on the memory consupmtion of the session.| + ## Limitations The schemarouter router currently has some limitations due to the nature of the sharding implementation and the way the session variables are detected and routed. Here is a list of the current limitations. diff --git a/server/modules/include/schemarouter.h b/server/modules/include/schemarouter.h index 805bbf544..2d39722c7 100644 --- a/server/modules/include/schemarouter.h +++ b/server/modules/include/schemarouter.h @@ -235,7 +235,8 @@ typedef struct backend_ref_st { typedef struct schemarouter_config_st { int rw_max_slave_conn_percent; int rw_max_slave_conn_count; - target_t rw_use_sql_variables_in; + target_t rw_use_sql_variables_in; + int max_sescmd_hist; } schemarouter_config_t; @@ -268,6 +269,7 @@ struct router_client_session { GWBUF* queue; /*< Query that was received before the session was ready */ DCB* dcb_route; /*< Internal DCB used to trigger re-routing of buffers */ DCB* dcb_reply; /*< Internal DCB used to send replies to the client */ + int n_sescmd; #if defined(SS_DEBUG) skygw_chk_t rses_chk_tail; #endif diff --git a/server/modules/routing/schemarouter/schemarouter.c b/server/modules/routing/schemarouter/schemarouter.c index 6852f9d14..8e0724bef 100644 --- a/server/modules/routing/schemarouter/schemarouter.c +++ b/server/modules/routing/schemarouter/schemarouter.c @@ -720,6 +720,7 @@ createInstance(SERVICE *service, char **options) return NULL; } router->service = service; + router->schemarouter_config.max_sescmd_hist = 0; spinlock_init(&router->lock); /** Calculate number of servers */ @@ -734,6 +735,37 @@ createInstance(SERVICE *service, char **options) service->users_from_all = true; } + bool failure = false; + + for(i=0;options && options[i];i++) + { + char* value; + if((value = strchr(options[i],'=')) == NULL) + { + skygw_log_write(LOGFILE_ERROR,"Error: Unknown router options for Schemarouter: %s",options[i]); + failure = true; + break; + } + *value = '\0'; + value++; + if(strcmp(options[i],"max_sescmd_history") == 0) + { + router->schemarouter_config.max_sescmd_hist = atoi(value); + } + else + { + skygw_log_write(LOGFILE_ERROR,"Error: Unknown router options for Schemarouter: %s",options[i]); + failure = true; + break; + } + } + + if(failure) + { + free(router); + return NULL; + } + while (server != NULL) { nservers++; @@ -891,7 +923,8 @@ static void* newSession( client_rses->dcb_reply->func.read = internalReply; client_rses->dcb_reply->state = DCB_STATE_POLLING; client_rses->dcb_reply->session = session; - + memcpy(&client_rses->rses_config,&router->schemarouter_config,sizeof(schemarouter_config_t)); + client_rses->n_sescmd = 0; client_rses->dcb_route = dcb_alloc(DCB_ROLE_REQUEST_HANDLER); client_rses->dcb_route->func.read = internalRoute; client_rses->dcb_route->state = DCB_STATE_POLLING; @@ -3733,17 +3766,33 @@ static bool route_session_write( succp = false; goto return_succp; } - /** + + if(router_cli_ses->rses_config.max_sescmd_hist > 0 && + router_cli_ses->n_sescmd >= router_cli_ses->rses_config.max_sescmd_hist) + { + LOGIF(LE, (skygw_log_write( + LOGFILE_ERROR|LOGFILE_TRACE, + "Router session exceeded session command history limit of %d. " + "Closing router session.", + router_cli_ses->rses_config.max_sescmd_hist))); + gwbuf_free(querybuf); + rses_end_locked_router_action(router_cli_ses); + router_cli_ses->rses_client_dcb->func.hangup(router_cli_ses->rses_client_dcb); + + goto return_succp; + } + /** + * * Additional reference is created to querybuf to * prevent it from being released before properties - * are cleaned up as a part of router sessionclean-up. + * are cleaned up as a part of router session clean-up. */ prop = rses_property_init(RSES_PROP_TYPE_SESCMD); mysql_sescmd_init(prop, querybuf, packet_type, router_cli_ses); /** Add sescmd property to router client session */ rses_property_add(router_cli_ses, prop); - + router_cli_ses->n_sescmd++; for (i=0; irses_nbackends; i++) { if (BREF_IS_IN_USE((&backend_ref[i])))