In dcb.c:dcb_close DCB is removed either before or after the call dcb->func.close. Since mysql backend protocol sends COM_QUIT and thus, writes to backend DCB, it is kept in DCB_STATE_POLLING until the write is completed.

dcb.h: define ERRHAND temporarily since changes are still behind that macro
Defined two error handling actions in router.h: ERRACT_NEW_COMMECTION and ERRACT_REPLY_CLIENT.
Failed database is logged at expanding frequence to error and to message log due changes in mysql_mon.c. Added two new members in MONITOR_SERVERS: mon_err_count, and mon_prev_status so that each backend can be treated individually.

Error handling: if mysql_backend.c:dcb_read fails, router's handleError is called instead of closing session.
	If mysql_client.c:SESSION_ROUTE_QUERY fails router's handleError is called instead of sending error to client.

	readwritesplit.c:select_connect_backend_servers is modified so that in can be called during active router session. When called, it attempts to find one master and maximum number of configured slaves in correct state if necessary.
	When handleError needs to replace failed unit it now calls select_connect_backend_servers.
This commit is contained in:
VilhoRaatikka
2014-06-08 19:36:12 +03:00
parent 916b763685
commit 889bdd4f8c
8 changed files with 298 additions and 121 deletions

View File

@ -65,7 +65,9 @@ static int gw_backend_hangup(DCB *dcb);
static int backend_write_delayqueue(DCB *dcb);
static void backend_set_delayqueue(DCB *dcb, GWBUF *queue);
static int gw_change_user(DCB *backend_dcb, SERVER *server, SESSION *in_session, GWBUF *queue);
static int gw_session(DCB *backend_dcb, void *data);
#if defined(NOT_USED)
static int gw_session(DCB *backend_dcb, void *data);
#endif
static MYSQL_session* gw_get_shared_session_auth_info(DCB* dcb);
static GWPROTOCOL MyObject = {
@ -401,8 +403,12 @@ static int gw_read_backend_event(DCB *dcb) {
SESSION *session = dcb->session;
CHK_SESSION(session);
/* read available backend data */
rc = dcb_read(dcb, &writebuf);
router = session->service->router;
router_instance = session->service->router_instance;
rsession = session->router_session;
/* read available backend data */
rc = dcb_read(dcb, &writebuf);
if (rc < 0) {
/*< vraa : errorHandle */
@ -412,7 +418,24 @@ static int gw_read_backend_event(DCB *dcb) {
* dcb from getting hanged.
*/
#if defined(ERRHANDLE)
dcb_close(dcb);
bool succp;
/**
* - send error for client
* - mark failed backend BREF_NOT_USED
* - go through all servers and select one according to
* the criteria that user specified in the beginning.
*/
router->handleError(router_instance,
rsession,
"Read from backend failed.",
dcb,
ERRACT_NEW_CONNECTION,
&succp);
if (!succp)
{
dcb_close(dcb);
}
#else
(dcb->func).close(dcb);
#endif
@ -424,9 +447,6 @@ static int gw_read_backend_event(DCB *dcb) {
rc = 0;
goto return_rc;
}
router = session->service->router;
router_instance = session->service->router_instance;
rsession = session->router_session;
/* Note the gwbuf doesn't have here a valid queue->command
* descriptions as it is a fresh new one!
@ -671,6 +691,9 @@ static int gw_error_backend_event(DCB *dcb) {
router = session->service->router;
router_instance = session->service->router_instance;
#if defined(ERRHANDLE2)
router->handleError();
#else
if (dcb->state != DCB_STATE_POLLING) {
/*< vraa : errorHandle */
/*<
@ -720,6 +743,7 @@ static int gw_error_backend_event(DCB *dcb) {
router->closeSession(router_instance, rsession);
}
#endif
return rc;
}