Fix to #473, http://bugs.skysql.com/show_bug.cgi?id=473 Several memory issues. Read the code. In general one-off hint is only added to gwbuf and freed in gwbuf_free. Stacked hint is copied to stack and to gwbuf. gwbuf is freed after routing but stacked hint is freed either in stop or when session is closed. All this applies to named hint as well except that in addition, it has one more copy in named hint struct which is emptied when session is closed.
This commit is contained in:
parent
183428c48b
commit
86a4c3ba90
@ -116,6 +116,7 @@ BUF_PROPERTY *prop;
|
||||
free(prop->value);
|
||||
free(prop);
|
||||
}
|
||||
/** Release the hint */
|
||||
while (buf->hint)
|
||||
{
|
||||
HINT* h = buf->hint;
|
||||
|
@ -144,9 +144,23 @@ static void
|
||||
closeSession(FILTER *instance, void *session)
|
||||
{
|
||||
HINT_SESSION *my_session = (HINT_SESSION *)session;
|
||||
NAMEDHINTS* named_hints;
|
||||
HINTSTACK* hint_stack;
|
||||
|
||||
if (my_session->request)
|
||||
gwbuf_free(my_session->request);
|
||||
|
||||
|
||||
/** Free named hints */
|
||||
named_hints = my_session->named_hints;
|
||||
|
||||
while ((named_hints = free_named_hint(named_hints)) != NULL)
|
||||
;
|
||||
/** Free stacked hints */
|
||||
hint_stack = my_session->stack;
|
||||
|
||||
while ((hint_stack = free_hint_stack(hint_stack)) != NULL)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -233,10 +233,15 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
|
||||
if (tok->token != TOK_MAXSCALE)
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Invalid hint string '%s'. Hint should start "
|
||||
"with keyword 'maxscale'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Invalid hint string '%s'. Hint should start "
|
||||
"with keyword 'maxscale'",
|
||||
"with keyword 'maxscale'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
@ -267,12 +272,39 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
break;
|
||||
default:
|
||||
/* Error: expected hint, name or STOP */
|
||||
;
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'route', 'stop' or hint name instead of "
|
||||
"'%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'route', 'stop' or hint name instead of "
|
||||
"'%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
}
|
||||
break;
|
||||
case HS_ROUTE:
|
||||
if (tok->token != TOK_TO)
|
||||
/* Error, expect TO */;
|
||||
{
|
||||
/* Error, expect TO */;
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'to' instead of '%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'to' instead of '%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
}
|
||||
state = HS_ROUTE1;
|
||||
break;
|
||||
case HS_ROUTE1:
|
||||
@ -290,8 +322,22 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
state = HS_ROUTE_SERVER;
|
||||
break;
|
||||
default:
|
||||
/* Error expected MASTER, SLAVE or SERVER */
|
||||
;
|
||||
/* Error expected MASTER, SLAVE or SERVER */
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'master', 'slave', or 'server' instead "
|
||||
"of '%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'master', 'slave', or 'server' instead "
|
||||
"of '%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
}
|
||||
break;
|
||||
case HS_ROUTE_SERVER:
|
||||
@ -302,8 +348,23 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error: Expected server name */
|
||||
/* Error: Expected server name */
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"server name instead of '%s'. Hint "
|
||||
"ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"server name instead of '%s'. Hint "
|
||||
"ignored.",
|
||||
token_get_keyword(tok))));
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
}
|
||||
break;
|
||||
case HS_NAME:
|
||||
switch (tok->token)
|
||||
{
|
||||
@ -323,7 +384,20 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
break;
|
||||
default:
|
||||
/* Error, token tok->value not expected */
|
||||
;
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'=', 'prepare', or 'start' instead of "
|
||||
"'%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'=', 'prepare', or 'start' instead of "
|
||||
"'%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
}
|
||||
break;
|
||||
case HS_PVALUE:
|
||||
@ -345,7 +419,20 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
break;
|
||||
default:
|
||||
/* Error, token tok->value not expected */
|
||||
;
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'route' or hint name instead of "
|
||||
"'%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Syntax error in hint. Expected "
|
||||
"'route' or hint name instead of "
|
||||
"'%s'. Hint ignored.",
|
||||
token_get_keyword(tok))));
|
||||
token_free(tok);
|
||||
goto retblock;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -387,6 +474,7 @@ HINT_MODE mode = HM_EXECUTE;
|
||||
/* We starting an already define set of named hints */
|
||||
rval = lookup_named_hint(session, hintname);
|
||||
hint_push(session, hint_dup(rval));
|
||||
free(hintname);
|
||||
rval = NULL;
|
||||
} else if (hintname == NULL && rval == NULL)
|
||||
{
|
||||
@ -426,7 +514,7 @@ retblock:
|
||||
* top of stack if there is one.
|
||||
*/
|
||||
if (session->stack)
|
||||
rval = hint_dup(session->stack->hint);
|
||||
rval = hint_dup(session->stack->hint);
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
@ -598,12 +686,76 @@ NAMEDHINTS *block;
|
||||
|
||||
if ((block = (NAMEDHINTS *)malloc(sizeof(NAMEDHINTS))) == NULL)
|
||||
return;
|
||||
if ((block->name = strdup(name)) == NULL)
|
||||
{
|
||||
free(block);
|
||||
return;
|
||||
}
|
||||
block->hints = hint;
|
||||
|
||||
block->name = name;
|
||||
block->hints = hint_dup(hint);
|
||||
block->next = session->named_hints;
|
||||
session->named_hints = block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the given NAMEDHINTS struct and all included hints.
|
||||
*
|
||||
* @param named_hint NAMEDHINTS struct to be released
|
||||
*
|
||||
* @return pointer to next NAMEDHINTS struct.
|
||||
*/
|
||||
NAMEDHINTS* free_named_hint(
|
||||
NAMEDHINTS* named_hint)
|
||||
{
|
||||
NAMEDHINTS* next;
|
||||
|
||||
if (named_hint != NULL)
|
||||
{
|
||||
HINT* hint;
|
||||
|
||||
next = named_hint->next;
|
||||
|
||||
while (named_hint->hints != NULL)
|
||||
{
|
||||
hint = named_hint->hints->next;
|
||||
hint_free(named_hint->hints);
|
||||
named_hint->hints = hint;
|
||||
}
|
||||
free(named_hint->name);
|
||||
free(named_hint);
|
||||
return next;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the given HINTSTACK struct and all included hints.
|
||||
*
|
||||
* @param hint_stack HINTSTACK struct to be released
|
||||
*
|
||||
* @return pointer to next HINTSTACK struct.
|
||||
*/
|
||||
HINTSTACK* free_hint_stack(
|
||||
HINTSTACK* hint_stack)
|
||||
{
|
||||
HINTSTACK* next;
|
||||
|
||||
if (hint_stack != NULL)
|
||||
{
|
||||
HINT* hint;
|
||||
|
||||
next = hint_stack->next;
|
||||
|
||||
while (hint_stack->hint != NULL)
|
||||
{
|
||||
hint = hint_stack->hint->next;
|
||||
hint_free(hint_stack->hint);
|
||||
hint_stack->hint = hint;
|
||||
}
|
||||
free(hint_stack);
|
||||
return next;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
@ -106,5 +106,9 @@ typedef struct {
|
||||
|
||||
|
||||
extern HINT *hint_parser(HINT_SESSION *session, GWBUF *request);
|
||||
NAMEDHINTS* free_named_hint(NAMEDHINTS* named_hint);
|
||||
HINTSTACK* free_hint_stack(HINTSTACK* hint_stack);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -422,7 +422,6 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
GWBUF *read_buffer = NULL;
|
||||
ROUTER_OBJECT *router = NULL;
|
||||
ROUTER *router_instance = NULL;
|
||||
void *rsession = NULL;
|
||||
SESSION *session = dcb->session;
|
||||
int nbytes_read = 0;
|
||||
|
||||
@ -787,7 +786,7 @@ static int gw_error_backend_event(DCB *dcb)
|
||||
* closed by router and COM_QUIT sent or there was an error which
|
||||
* have already been handled.
|
||||
*/
|
||||
if (dcb->session != DCB_STATE_POLLING)
|
||||
if (dcb->state != DCB_STATE_POLLING)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -1404,7 +1404,6 @@ static int route_by_statement(SESSION *session, GWBUF *readbuf)
|
||||
int rc = -1;
|
||||
GWBUF* packetbuf;
|
||||
#if defined(SS_DEBUG)
|
||||
gwbuf_type_t prevtype;
|
||||
GWBUF* tmpbuf;
|
||||
|
||||
tmpbuf = readbuf;
|
||||
|
@ -1122,10 +1122,18 @@ static route_target_t get_route_target (
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Error : Unknown hint parameter "
|
||||
"'%s' when 'max_slave_replication_lag' "
|
||||
"was expected.",
|
||||
(char *)hint->data)));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Warning : Unknown routing parameter hint : %s",
|
||||
(char *)hint->data)));
|
||||
"Error : Unknown hint parameter "
|
||||
"'%s' when 'max_slave_replication_lag' "
|
||||
"was expected.",
|
||||
(char *)hint->data)));
|
||||
}
|
||||
}
|
||||
hint = hint->next;
|
||||
@ -1705,7 +1713,6 @@ static void clientReply (
|
||||
if (LOG_IS_ENABLED(LOGFILE_ERROR) &&
|
||||
MYSQL_IS_ERROR_PACKET(((uint8_t *)GWBUF_DATA(writebuf))))
|
||||
{
|
||||
SESSION* ses = backend_dcb->session;
|
||||
uint8_t* buf =
|
||||
(uint8_t *)GWBUF_DATA((scur->scmd_cur_cmd->my_sescmd_buf));
|
||||
size_t len = MYSQL_GET_PACKET_LEN(buf);
|
||||
@ -2302,9 +2309,7 @@ static bool select_connect_backend_servers(
|
||||
BACKEND* b = backend_ref[i].bref_backend;
|
||||
|
||||
if (BREF_IS_IN_USE((&backend_ref[i])))
|
||||
{
|
||||
backend_type_t btype = BACKEND_TYPE(b);
|
||||
|
||||
{
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"Selected %s in \t%s:%d",
|
||||
@ -3373,6 +3378,11 @@ static bool handle_error_reply_client(
|
||||
CHK_DCB(client_dcb);
|
||||
client_dcb->func.write(client_dcb, errmsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((errmsg=gwbuf_consume(errmsg, GWBUF_LENGTH(errmsg))) != NULL)
|
||||
;
|
||||
}
|
||||
succp = false; /** false because new servers aren's selected. */
|
||||
|
||||
return succp;
|
||||
@ -3427,6 +3437,11 @@ static bool handle_error_new_connection(
|
||||
client_dcb->func.write(client_dcb, errmsg);
|
||||
bref_clear_state(bref, BREF_WAITING_RESULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((errmsg=gwbuf_consume(errmsg, GWBUF_LENGTH(errmsg))) != NULL)
|
||||
;
|
||||
}
|
||||
bref_clear_state(bref, BREF_IN_USE);
|
||||
bref_set_state(bref, BREF_CLOSED);
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user