⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 network-mysqld.c

📁 Mysql Proxy本身是个很好的mysql负载均衡工具,但是其本身有bug:当多个mysql 做slave的时候,如果一个slave死掉,会影响别的slave也死掉!这个文件修复了这个bug!
💻 C
📖 第 1 页 / 共 4 页
字号:
		network_queue_append_chunk(send_sock->send_queue, packet);		recv_sock->packet_len = PACKET_LEN_UNSET;		g_queue_delete_link(recv_sock->recv_queue->chunks, chunk);		/**		 * send it out to the client 		 */		con->state = CON_STATE_SEND_AUTH_OLD_PASSWORD;		break; }	case CON_STATE_SEND_AUTH_OLD_PASSWORD:		/**		 * data is at the server, read the response next 		 */		con->state = CON_STATE_READ_AUTH_RESULT;		break;	case CON_STATE_READ_QUERY:		func = con->plugins.con_read_query;		break;	case CON_STATE_READ_QUERY_RESULT:		func = con->plugins.con_read_query_result;		break;	case CON_STATE_SEND_QUERY_RESULT:		func = con->plugins.con_send_query_result;		if (!func) { /* default implementation */			con->state = CON_STATE_READ_QUERY;		}		break;	default:		g_error("%s.%d: unhandled state: %d", 				__FILE__, __LINE__,				state);	}	if (!func) return RET_SUCCESS;	return (*func)(srv, con);}/** * handle the different states of the MySQL protocol * * @param event_fd     fd on which the event was fired * @param events       the event that was fired * @param user_data    the connection handle */void network_mysqld_con_handle(int event_fd, short events, void *user_data) {	guint ostate;	network_mysqld_con *con = user_data;	network_mysqld *srv = con->srv;	g_assert(srv);	g_assert(con);	if (events == EV_READ) {		int b = -1;		if (ioctl(event_fd, FIONREAD, &b)) {			g_critical("ioctl(%d, FIONREAD, ...) failed: %s", event_fd, strerror(errno));			con->state = CON_STATE_ERROR;		} else if (b != 0) {			if (con->client && event_fd == con->client->fd) {				con->client->to_read = b;			} else if (con->server && event_fd == con->server->fd) {				con->server->to_read = b;			} else {				g_error("%s.%d: neither nor", __FILE__, __LINE__);			}		} else {			if (con->client && event_fd == con->client->fd) {				/* the client closed the connection, let's keep the server side open */				con->state = CON_STATE_CLOSE_CLIENT;			} else {				/* server side closed on use, oops, close both sides */				con->state = CON_STATE_ERROR;			}		}	}#define WAIT_FOR_EVENT(ev_struct, ev_type, timeout) \	event_set(&(ev_struct->event), ev_struct->fd, ev_type, network_mysqld_con_handle, user_data); \	event_base_set(srv->event_base, &(ev_struct->event));\	event_add(&(ev_struct->event), timeout);	/**	 * loop on the same connection as long as we don't end up in a stable state	 */	do {		ostate = con->state;		switch (con->state) {		case CON_STATE_ERROR:			/* we can't go on, close the connection */			plugin_call_cleanup(srv, con);			network_mysqld_con_free(con);			con = NULL;			return;		case CON_STATE_CLOSE_CLIENT:			/* the server connection is still fine, 			 * let's keep it open for reuse */			plugin_call_cleanup(srv, con);			network_mysqld_con_free(con);			con = NULL;			return;		case CON_STATE_INIT:			/* if we are a proxy ask the remote server for the hand-shake packet 			 * if not, we generate one */			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				/**				 * no luck, let's close the connection				 */				g_critical("%s.%d: plugin_call(CON_STATE_INIT) != RET_SUCCESS", __FILE__, __LINE__);				con->state = CON_STATE_ERROR;								break;			}			break;		case CON_STATE_CONNECT_SERVER:			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				/**				 * hmm, if this is success and we have something in the clients send-queue				 * we just send it out ... who needs a server ? */				if (con->client->send_queue->chunks->length > 0 && con->server == NULL) {					/* we want to send something to the client */					con->state = CON_STATE_SEND_HANDSHAKE;				} else {					g_assert(con->server);				}				break;			case RET_ERROR_RETRY:				if (con->server) {					/**					 * we have a server connection waiting to begin writable					 */					WAIT_FOR_EVENT(con->server, EV_WRITE, NULL);					return;				} else {					/* try to get a connection to another backend,					 *					 * setting ostate = CON_STATE_INIT is a hack to make sure					 * the loop is coming back to this function again */					ostate = CON_STATE_INIT;				}				break;			case RET_ERROR:				/**				 * connecting failed and no option to retry				 *				 * close the connection				 */				con->state = CON_STATE_SEND_ERROR;				break;			default:				g_error("%s.%d: ...", __FILE__, __LINE__);								break;			}			break;		case CON_STATE_READ_HANDSHAKE: {			/**			 * read auth data from the remote mysql-server 			 */			network_socket *recv_sock;			recv_sock = con->server;			g_assert(events == 0 || event_fd == recv_sock->fd);			switch (network_mysqld_read(srv, recv_sock)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				/* call us again when you have a event */				WAIT_FOR_EVENT(con->server, EV_READ, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				g_error("%s.%d: plugin_call(CON_STATE_CONNECT_SERVER) returned an error", __FILE__, __LINE__);				break;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			case RET_ERROR:				/**				 * we couldn't understand the pack from the server 				 * 				 * we have something in the queue and will send it to the client				 * and close the connection afterwards				 */								con->state = CON_STATE_SEND_ERROR;				break;			default:				g_error("%s.%d: ...", __FILE__, __LINE__);				break;			}				break; }		case CON_STATE_SEND_HANDSHAKE: 			/* send the hand-shake to the client and wait for a response */						switch (network_mysqld_write(srv, con->client)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->client, EV_WRITE, NULL);								return;			case RET_ERROR_RETRY:			case RET_ERROR:				/**				 * writing failed, closing connection				 */				con->state = CON_STATE_ERROR;				break;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_error("%s.%d: plugin_call(CON_STATE_SEND_HANDSHAKE) != RET_SUCCESS", __FILE__, __LINE__);				break;			}			break;		case CON_STATE_READ_AUTH: {			/* read auth from client */			network_socket *recv_sock;			recv_sock = con->client;			g_assert(events == 0 || event_fd == recv_sock->fd);			switch (network_mysqld_read(srv, recv_sock)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->client, EV_READ, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				g_error("%s.%d: network_mysqld_read(CON_STATE_READ_AUTH) returned an error", __FILE__, __LINE__);				return;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_error("%s.%d: plugin_call(CON_STATE_READ_AUTH) != RET_SUCCESS", __FILE__, __LINE__);				break;			}			break; }		case CON_STATE_SEND_AUTH:			/* send the auth-response to the server */			switch (network_mysqld_write(srv, con->server)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->server, EV_WRITE, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				/* might be a connection close, we should just close the connection and be happy */				con->state = CON_STATE_ERROR;				break;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_error("%s.%d: plugin_call(CON_STATE_SEND_AUTH) != RET_SUCCESS", __FILE__, __LINE__);				break;			}			break;		case CON_STATE_READ_AUTH_RESULT: {			/* read the auth result from the server */			network_socket *recv_sock;			GList *chunk;			GString *packet;			recv_sock = con->server;			g_assert(events == 0 || event_fd == recv_sock->fd);			switch (network_mysqld_read(srv, recv_sock)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->server, EV_READ, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				g_error("%s.%d: network_mysqld_read(CON_STATE_READ_AUTH_RESULT) returned an error", __FILE__, __LINE__);				return;			}			/**			 * depending on the result-set we have different exit-points			 * - OK  -> READ_QUERY			 * - EOF -> (read old password hash) 			 * - ERR -> ERROR			 */			chunk = recv_sock->recv_queue->chunks->head;			packet = chunk->data;			g_assert(packet);			g_assert(packet->len > NET_HEADER_SIZE);			con->parse.state.auth_result.state = packet->str[NET_HEADER_SIZE];			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_critical("%s.%d: plugin_call(CON_STATE_READ_AUTH_RESULT) != RET_SUCCESS", __FILE__, __LINE__);				con->state = CON_STATE_ERROR;				break;			}			break; }		case CON_STATE_SEND_AUTH_RESULT: {			/* send the hand-shake to the client and wait for a response */			switch (network_mysqld_write(srv, con->client)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->client, EV_WRITE, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				g_debug("%s.%d: network_mysqld_write(CON_STATE_SEND_AUTH_RESULT) returned an error", __FILE__, __LINE__);				con->state = CON_STATE_ERROR;				break;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_error("%s.%d: ...", __FILE__, __LINE__);				break;			}							break; }		case CON_STATE_READ_AUTH_OLD_PASSWORD: 			/* read auth from client */			switch (network_mysqld_read(srv, con->client)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->client, EV_READ, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				g_error("%s.%d: network_mysqld_read(CON_STATE_READ_AUTH_OLD_PASSWORD) returned an error", __FILE__, __LINE__);				return;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_error("%s.%d: plugin_call(CON_STATE_READ_AUTH_OLD_PASSWORD) != RET_SUCCESS", __FILE__, __LINE__);				break;			}			break; 		case CON_STATE_SEND_AUTH_OLD_PASSWORD:			/* send the auth-response to the server */			switch (network_mysqld_write(srv, con->server)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->server, EV_WRITE, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				/* might be a connection close, we should just close the connection and be happy */				g_debug("%s.%d: network_mysqld_write(CON_STATE_SEND_AUTH_OLD_PASSWORD) returned an error", __FILE__, __LINE__);				con->state = CON_STATE_ERROR;				break;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_error("%s.%d: plugin_call(CON_STATE_SEND_AUTH_OLD_PASSWORD) != RET_SUCCESS", __FILE__, __LINE__);				break;			}			break;		case CON_STATE_READ_QUERY: {			network_socket *recv_sock;			recv_sock = con->client;			g_assert(events == 0 || event_fd == recv_sock->fd);			switch (network_mysqld_read(srv, recv_sock)) {			case RET_SUCCESS:				break;			case RET_WAIT_FOR_EVENT:				WAIT_FOR_EVENT(con->client, EV_READ, NULL);				return;			case RET_ERROR_RETRY:			case RET_ERROR:				g_error("%s.%d: network_mysqld_read(CON_STATE_READ_QUERY) returned an error", __FILE__, __LINE__);				return;			}			switch (plugin_call(srv, con, con->state)) {			case RET_SUCCESS:				break;			default:				g_critical("%s.%d: plugin_call(CON_STATE_READ_QUERY) failed", __FILE__, __LINE__);				con->state = CON_STATE_ERROR;				break;			}			break; }		case CON_STATE_SEND_QUERY: 			/* send the query to the server */			if (con->server->send_queue->offset == 0) {				/* only parse the packets once */				GString *s;				GList *chunk;				chunk = con->server->send_queue->chunks->head;				s = chunk->data;				/* only parse once and don't care about the blocking read */				if (con->parse.command == COM_QUERY &&				    con->parse.state.query == PARSE_COM_QUERY_LOAD_DATA) {					/* is this a LOAD DATA INFILE ... extra round ? */					/* this isn't a command packet, but a LOAD DATA INFILE data-packet */					if (s->str[0] == 0 && s->str[1] == 0 && s->str[2] == 0) {						con->parse.state.query = PARSE_COM_QUERY_LOAD_DATA_END_DATA;					}				} else if (con->is_overlong_packet) {					/* the last packet was a over-long packet					 * this is the same command, just more data */						if (con->parse.len != PACKET_LEN_MAX) {						con->is_overlong_packet = 0;					}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -