From 06b59ffe2e9a56a379baca03d18398d19fcb8aa4 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Sun, 22 Feb 2015 04:10:57 +0200 Subject: [PATCH 001/275] Testing of plain routing with MongoDB. --- server/modules/protocol/CMakeLists.txt | 9 + server/modules/protocol/mongo_backend.c | 1204 +++++++++++++++++++++++ server/modules/protocol/mongo_client.c | 1004 +++++++++++++++++++ server/modules/routing/CMakeLists.txt | 4 + server/modules/routing/plainroute.c | 923 +++++++++++++++++ 5 files changed, 3144 insertions(+) create mode 100644 server/modules/protocol/mongo_backend.c create mode 100644 server/modules/protocol/mongo_client.c create mode 100644 server/modules/routing/plainroute.c diff --git a/server/modules/protocol/CMakeLists.txt b/server/modules/protocol/CMakeLists.txt index fa1c2ab34..0bea95832 100644 --- a/server/modules/protocol/CMakeLists.txt +++ b/server/modules/protocol/CMakeLists.txt @@ -6,6 +6,15 @@ add_library(MySQLBackend SHARED mysql_backend.c mysql_common.c) target_link_libraries(MySQLBackend log_manager utils) install(TARGETS MySQLBackend DESTINATION modules) +add_library(mongoclient SHARED mongo_client.c mysql_common.c) +target_link_libraries(mongoclient log_manager utils) +install(TARGETS mongoclient DESTINATION modules) + +add_library(mongobackend SHARED mongo_backend.c mysql_common.c) +target_link_libraries(mongobackend log_manager utils) +install(TARGETS mongobackend DESTINATION modules) + + add_library(telnetd SHARED telnetd.c) target_link_libraries(telnetd log_manager utils) install(TARGETS telnetd DESTINATION modules) diff --git a/server/modules/protocol/mongo_backend.c b/server/modules/protocol/mongo_backend.c new file mode 100644 index 000000000..4fe1ff0b8 --- /dev/null +++ b/server/modules/protocol/mongo_backend.c @@ -0,0 +1,1204 @@ +/* + * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright MariaDB Corporation Ab 2013-2014 + */ + +#include "mysql_client_server_protocol.h" +#include +#include +#include +#include + +/* + * MySQL Protocol module for handling the protocol between the gateway + * and the backend MySQL database. + * + * Revision History + * Date Who Description + * 14/06/2013 Mark Riddoch Initial version + * 17/06/2013 Massimiliano Pinto Added MaxScale To Backends routines + * 01/07/2013 Massimiliano Pinto Put Log Manager example code behind SS_DEBUG macros. + * 03/07/2013 Massimiliano Pinto Added delayq for incoming data before mysql connection + * 04/07/2013 Massimiliano Pinto Added asyncrhronous MySQL protocol connection to backend + * 05/07/2013 Massimiliano Pinto Added closeSession if backend auth fails + * 12/07/2013 Massimiliano Pinto Added Mysql Change User via dcb->func.auth() + * 15/07/2013 Massimiliano Pinto Added Mysql session change via dcb->func.session() + * 17/07/2013 Massimiliano Pinto Added dcb->command update from gwbuf->command for proper routing + server replies to client via router->clientReply + * 04/09/2013 Massimiliano Pinto Added dcb->session and dcb->session->client checks for NULL + * 12/09/2013 Massimiliano Pinto Added checks in gw_read_backend_event() for gw_read_backend_handshake + * 27/09/2013 Massimiliano Pinto Changed in gw_read_backend_event the check for dcb_read(), now is if rc < 0 + * 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support + * 10/11/2014 Massimiliano Pinto Client charset is passed to backend + * + */ +#include + +MODULE_INFO info = { + MODULE_API_PROTOCOL, + MODULE_GA, + GWPROTOCOL_VERSION, + "The MySQL to backend server protocol" +}; + +/** Defined in log_manager.cc */ +extern int lm_enabled_logfiles_bitmask; +extern size_t log_ses_count[]; +extern __thread log_info_t tls_log_info; + +static char *version_str = "V2.0.0"; +static int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *in_session); +static int gw_read_backend_event(DCB* dcb); +static int gw_write_backend_event(DCB *dcb); +static int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue); +static int gw_error_backend_event(DCB *dcb); +static int gw_backend_close(DCB *dcb); +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 GWBUF* process_response_data (DCB* dcb, GWBUF* readbuf, int nbytes_to_process); +extern char* create_auth_failed_msg( GWBUF* readbuf, char* hostaddr, uint8_t* sha1); +extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db); +static bool sescmd_response_complete(DCB* dcb); + + +#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 = { + gw_read_backend_event, /* Read - EPOLLIN handler */ + gw_MySQLWrite_backend, /* Write - data from gateway */ + gw_write_backend_event, /* WriteReady - EPOLLOUT handler */ + gw_error_backend_event, /* Error - EPOLLERR handler */ + gw_backend_hangup, /* HangUp - EPOLLHUP handler */ + NULL, /* Accept */ + gw_create_backend_connection, /* Connect */ + gw_backend_close, /* Close */ + NULL, /* Listen */ + gw_change_user, /* Authentication */ + NULL /* Session */ +}; + +/* + * Implementation of the mandatory version entry point + * + * @return version string of the module + */ +char * +version() +{ + return version_str; +} + +/* + * The module initialisation routine, called when the module + * is first loaded. + */ +void +ModuleInit() +{ +} + +/* + * The module entry point routine. It is this routine that + * must populate the structure that is referred to as the + * "module object", this is a structure with the set of + * external entry points for this module. + * + * @return The module object + */ +GWPROTOCOL * +GetModuleObject() +{ + return &MyObject; +} + + +static MYSQL_session* gw_get_shared_session_auth_info( + DCB* dcb) +{ + MYSQL_session* auth_info = NULL; + CHK_DCB(dcb); + CHK_SESSION(dcb->session); + + spinlock_acquire(&dcb->session->ses_lock); + + if (dcb->session->state != SESSION_STATE_ALLOC) { + auth_info = dcb->session->data; + } else { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [gw_get_shared_session_auth_info] Couldn't get " + "session authentication info. Session in a wrong state %d.", + pthread_self(), + dcb->session->state))); + } + spinlock_release(&dcb->session->ses_lock); + + return auth_info; +} + +/** + * Backend Read Event for EPOLLIN on the MySQL backend protocol module + * @param dcb The backend Descriptor Control Block + * @return 1 on operation, 0 for no action + */ +static int gw_read_backend_event(DCB *dcb) { + MySQLProtocol *client_protocol = NULL; + MySQLProtocol *backend_protocol = NULL; + MYSQL_session *current_session = NULL; + int rc = 0; + + + backend_protocol = (MySQLProtocol *) dcb->protocol; + CHK_PROTOCOL(backend_protocol); + + + /* reading MySQL command output from backend and writing to the client */ + { + GWBUF *read_buffer = NULL; + ROUTER_OBJECT *router = NULL; + ROUTER *router_instance = NULL; + SESSION *session = dcb->session; + int nbytes_read = 0; + + CHK_SESSION(session); + router = session->service->router; + router_instance = session->service->router_instance; + + /* read available backend data */ + rc = dcb_read(dcb, &read_buffer); + + if (rc < 0) + { + GWBUF* errbuf; + bool succp; + + errbuf = mysql_create_custom_error( + 1, + 0, + "Read from backend failed"); + + router->handleError( + router_instance, + session->router_session, + errbuf, + dcb, + ERRACT_NEW_CONNECTION, + &succp); + gwbuf_free(errbuf); + + if (!succp) + { + spinlock_acquire(&session->ses_lock); + session->state = SESSION_STATE_STOPPING; + spinlock_release(&session->ses_lock); + } + ss_dassert(dcb->dcb_errhandle_called); + dcb_close(dcb); + rc = 0; + goto return_rc; + } + nbytes_read = gwbuf_length(read_buffer); + + if (nbytes_read == 0 && dcb->dcb_readqueue == NULL) + { + goto return_rc; + } + else + { + ss_dassert(read_buffer != NULL || dcb->dcb_readqueue != NULL); + } + + /** Packet prefix was read earlier */ + if (dcb->dcb_readqueue) + { + if (read_buffer != NULL) + { + read_buffer = gwbuf_append(dcb->dcb_readqueue, read_buffer); + } + else + { + read_buffer = dcb->dcb_readqueue; + } + nbytes_read = gwbuf_length(read_buffer); + + if (nbytes_read < 5) /*< read at least command type */ + { + rc = 0; + LOGIF(LD, (skygw_log_write_flush( + LOGFILE_DEBUG, + "%p [gw_read_backend_event] Read %d bytes " + "from DCB %p, fd %d, session %s. " + "Returning to poll wait.\n", + pthread_self(), + nbytes_read, + dcb, + dcb->fd, + dcb->session))); + goto return_rc; + } + /** There is at least length and command type. */ + else + { + dcb->dcb_readqueue = NULL; + } + } + /** This may be either short prefix of a packet, or the tail of it. */ + else + { + if (nbytes_read < 5) + { + dcb->dcb_readqueue = gwbuf_append(dcb->dcb_readqueue, read_buffer); + rc = 0; + goto return_rc; + } + } + + + if (dcb->session->state == SESSION_STATE_ROUTER_READY && + dcb->session->client != NULL && + dcb->session->client->state == DCB_STATE_POLLING) + { + client_protocol = SESSION_PROTOCOL(dcb->session, + MySQLProtocol); + + { + gwbuf_set_type(read_buffer, GWBUF_TYPE_MYSQL); + router->clientReply(router_instance, session->router_session, read_buffer, dcb); + rc = 1; + } + } + else /*< session is closing; replying to client isn't possible */ + { + gwbuf_free(read_buffer); + } + } + +return_rc: + return rc; + +return_with_lock: + + goto return_rc; +} + +/* + * EPOLLOUT handler for the MySQL Backend protocol module. + * + * @param dcb The descriptor control block + * @return 1 in success, 0 in case of failure, + */ +static int gw_write_backend_event(DCB *dcb) { + int rc = 0; + MySQLProtocol *backend_protocol = dcb->protocol; + + /*< + * Don't write to backend if backend_dcb is not in poll set anymore. + */ + if (dcb->state != DCB_STATE_POLLING) { + uint8_t* data; + + if (dcb->writeq != NULL) + { + data = (uint8_t *)GWBUF_DATA(dcb->writeq); + + + } + else + { + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [gw_write_backend_event] Dcb %p in state %s " + "but there's nothing to write either.", + pthread_self(), + dcb, + STRDCBSTATE(dcb->state)))); + rc = 1; + } + goto return_rc; + } + + dcb_drain_writeq(dcb); + rc = 1; +return_rc: + + + return rc; +} + +/* + * Write function for backend DCB. Store command to protocol. + * + * @param dcb The DCB of the backend + * @param queue Queue of buffers to write + * @return 0 on failure, 1 on success + */ +static int +gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue) +{ + MySQLProtocol *backend_protocol = dcb->protocol; + int rc = 0; + + rc = dcb_write(dcb, queue); + + +return_rc: + return rc; +} + +/** + * Error event handler. + * Create error message, pass it to router's error handler and if error + * handler fails in providing enough backend servers, mark session being + * closed and call DCB close function which triggers closing router session + * and related backends (if any exists. + */ +static int gw_error_backend_event(DCB *dcb) +{ + SESSION* session; + void* rsession; + ROUTER_OBJECT* router; + ROUTER* router_instance; + GWBUF* errbuf; + bool succp; + session_state_t ses_state; + + CHK_DCB(dcb); + session = dcb->session; + CHK_SESSION(session); + rsession = session->router_session; + router = session->service->router; + router_instance = session->service->router_instance; + + /** + * Avoid running redundant error handling procedure. + * dcb_close is already called for the DCB. Thus, either connection is + * closed by router and COM_QUIT sent or there was an error which + * have already been handled. + */ + if (dcb->state != DCB_STATE_POLLING) + { + int error, len; + char buf[100]; + + len = sizeof(error); + + if (getsockopt(dcb->fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) == 0) + { + if (error != 0) + { + strerror_r(error, buf, 100); + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "DCB in state %s got error '%s'.", + STRDCBSTATE(dcb->state), + buf))); + } + } + return 1; + } + errbuf = mysql_create_custom_error( + 1, + 0, + "Lost connection to backend server."); + + spinlock_acquire(&session->ses_lock); + ses_state = session->state; + spinlock_release(&session->ses_lock); + + /** + * Session might be initialized when DCB already is in the poll set. + * Thus hangup can occur in the middle of session initialization. + * Only complete and successfully initialized sessions allow for + * calling error handler. + */ + while (ses_state == SESSION_STATE_READY) + { + spinlock_acquire(&session->ses_lock); + ses_state = session->state; + spinlock_release(&session->ses_lock); + } + + if (ses_state != SESSION_STATE_ROUTER_READY) + { + int error, len; + char buf[100]; + + len = sizeof(error); + if (getsockopt(dcb->fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) == 0) + { + if (error != 0) + { + strerror_r(error, buf, 100); + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error '%s' in session that is not ready for routing.", + buf))); + } + } + gwbuf_free(errbuf); + goto retblock; + } + +#if defined(SS_DEBUG) + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Backend error event handling."))); +#endif + router->handleError(router_instance, + rsession, + errbuf, + dcb, + ERRACT_NEW_CONNECTION, + &succp); + gwbuf_free(errbuf); + + /** + * If error handler fails it means that routing session can't continue + * and it must be closed. In success, only this DCB is closed. + */ + if (!succp) + { + spinlock_acquire(&session->ses_lock); + session->state = SESSION_STATE_STOPPING; + spinlock_release(&session->ses_lock); + } + ss_dassert(dcb->dcb_errhandle_called); + dcb_close(dcb); + +retblock: + return 1; +} + +/* + * Create a new backend connection. + * + * This routine will connect to a backend server and it is called by dbc_connect + * in router->newSession + * + * @param backend_dcb, in, out, use - backend DCB allocated from dcb_connect + * @param server, in, use - server to connect to + * @param session, in use - current session from client DCB + * @return 0/1 on Success and -1 on Failure. + * If succesful, returns positive fd to socket which is connected to + * backend server. Positive fd is copied to protocol and to dcb. + * If fails, fd == -1 and socket is closed. + */ +static int gw_create_backend_connection( + DCB *backend_dcb, + SERVER *server, + SESSION *session) +{ + MySQLProtocol *protocol = NULL; + int rv = -1; + int fd = -1; + + protocol = mysql_protocol_init(backend_dcb, -1); + ss_dassert(protocol != NULL); + + if (protocol == NULL) { + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [gw_create_backend_connection] Failed to create " + "protocol object for backend connection.", + pthread_self()))); + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to create " + "protocol object for backend connection."))); + goto return_fd; + } + + /*< if succeed, fd > 0, -1 otherwise */ + rv = gw_do_connect_to_backend(server->name, server->port, &fd); + /*< Assign protocol with backend_dcb */ + backend_dcb->protocol = protocol; + + /*< Set protocol state */ + switch (rv) { + case 0: + ss_dassert(fd > 0); + protocol->fd = fd; + protocol->protocol_auth_state = MYSQL_CONNECTED; + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [gw_create_backend_connection] Established " + "connection to %s:%i, protocol fd %d client " + "fd %d.", + pthread_self(), + server->name, + server->port, + protocol->fd, + session->client->fd))); + break; + + case 1: + ss_dassert(fd > 0); + protocol->protocol_auth_state = MYSQL_PENDING_CONNECT; + protocol->fd = fd; + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [gw_create_backend_connection] Connection " + "pending to %s:%i, protocol fd %d client fd %d.", + pthread_self(), + server->name, + server->port, + protocol->fd, + session->client->fd))); + break; + + default: + ss_dassert(fd == -1); + ss_dassert(protocol->protocol_auth_state == MYSQL_ALLOC); + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [gw_create_backend_connection] Connection " + "failed to %s:%i, protocol fd %d client fd %d.", + pthread_self(), + server->name, + server->port, + protocol->fd, + session->client->fd))); + break; + } /*< switch */ + +return_fd: + return fd; +} + + +/** + * Error event handler. + * Create error message, pass it to router's error handler and if error + * handler fails in providing enough backend servers, mark session being + * closed and call DCB close function which triggers closing router session + * and related backends (if any exists. + * + * @param dcb The current Backend DCB + * @return 1 always + */ +static int +gw_backend_hangup(DCB *dcb) +{ + SESSION* session; + void* rsession; + ROUTER_OBJECT* router; + ROUTER* router_instance; + bool succp; + GWBUF* errbuf; + session_state_t ses_state; + + CHK_DCB(dcb); + session = dcb->session; + CHK_SESSION(session); + + rsession = session->router_session; + router = session->service->router; + router_instance = session->service->router_instance; + + errbuf = mysql_create_custom_error( + 1, + 0, + "Lost connection to backend server."); + + spinlock_acquire(&session->ses_lock); + ses_state = session->state; + spinlock_release(&session->ses_lock); + + /** + * Session might be initialized when DCB already is in the poll set. + * Thus hangup can occur in the middle of session initialization. + * Only complete and successfully initialized sessions allow for + * calling error handler. + */ + while (ses_state == SESSION_STATE_READY) + { + spinlock_acquire(&session->ses_lock); + ses_state = session->state; + spinlock_release(&session->ses_lock); + } + + if (ses_state != SESSION_STATE_ROUTER_READY) + { + int error, len; + char buf[100]; + + len = sizeof(error); + if (getsockopt(dcb->fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) == 0) + { + if (error != 0) + { + strerror_r(error, buf, 100); + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Hangup in session that is not ready for routing, " + "Error reported is '%s'.", + buf))); + } + } + gwbuf_free(errbuf); + goto retblock; + } +#if defined(SS_DEBUG) + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Backend hangup error handling."))); +#endif + + router->handleError(router_instance, + rsession, + errbuf, + dcb, + ERRACT_NEW_CONNECTION, + &succp); + + gwbuf_free(errbuf); + /** There are no required backends available, close session. */ + if (!succp) + { +#if defined(SS_DEBUG) + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Backend hangup -> closing session."))); +#endif + spinlock_acquire(&session->ses_lock); + session->state = SESSION_STATE_STOPPING; + spinlock_release(&session->ses_lock); + } + ss_dassert(dcb->dcb_errhandle_called); + dcb_close(dcb); + +retblock: + return 1; +} + +/** + * Send COM_QUIT to backend so that it can be closed. + * @param dcb The current Backend DCB + * @return 1 always + */ +static int +gw_backend_close(DCB *dcb) +{ + DCB* client_dcb; + SESSION* session; + GWBUF* quitbuf; + + CHK_DCB(dcb); + session = dcb->session; + CHK_SESSION(session); + + LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG, + "%lu [gw_backend_close]", + pthread_self()))); + + quitbuf = mysql_create_com_quit(NULL, 0); + gwbuf_set_type(quitbuf, GWBUF_TYPE_MYSQL); + + /** Send COM_QUIT to the backend being closed */ + mysql_send_com_quit(dcb, 0, quitbuf); + + mysql_protocol_done(dcb); + /** + * The lock is needed only to protect the read of session->state and + * session->client values. Client's state may change by other thread + * but client's close and adding client's DCB to zombies list is executed + * only if client's DCB's state does _not_ change in parallel. + */ + spinlock_acquire(&session->ses_lock); + /** + * If session->state is STOPPING, start closing client session. + * Otherwise only this backend connection is closed. + */ + if (session != NULL && + session->state == SESSION_STATE_STOPPING && + session->client != NULL) + { + if (session->client->state == DCB_STATE_POLLING) + { + spinlock_release(&session->ses_lock); + + /** Close client DCB */ + dcb_close(session->client); + } + else + { + spinlock_release(&session->ses_lock); + } + } + else + { + spinlock_release(&session->ses_lock); + } + return 1; +} + +/** + * This routine put into the delay queue the input queue + * The input is what backend DCB is receiving + * The routine is called from func.write() when mysql backend connection + * is not yet complete buu there are inout data from client + * + * @param dcb The current backend DCB + * @param queue Input data in the GWBUF struct + */ +static void backend_set_delayqueue(DCB *dcb, GWBUF *queue) { + spinlock_acquire(&dcb->delayqlock); + + if (dcb->delayq) { + /* Append data */ + dcb->delayq = gwbuf_append(dcb->delayq, queue); + } else { + if (queue != NULL) { + /* create the delay queue */ + dcb->delayq = queue; + } + } + spinlock_release(&dcb->delayqlock); +} + +/** + * This routine writes the delayq via dcb_write + * The dcb->delayq contains data received from the client before + * mysql backend authentication succeded + * + * @param dcb The current backend DCB + * @return The dcb_write status + */ +static int backend_write_delayqueue(DCB *dcb) +{ + GWBUF *localq = NULL; + int rc; + + spinlock_acquire(&dcb->delayqlock); + + if (dcb->delayq == NULL) + { + spinlock_release(&dcb->delayqlock); + rc = 1; + } + else + { + localq = dcb->delayq; + dcb->delayq = NULL; + spinlock_release(&dcb->delayqlock); + + if (MYSQL_IS_CHANGE_USER(((uint8_t *)GWBUF_DATA(localq)))) + { + MYSQL_session* mses; + GWBUF* new_packet; + + mses = (MYSQL_session *)dcb->session->client->data; + new_packet = gw_create_change_user_packet( + mses, + (MySQLProtocol *)dcb->protocol); + /** + * Remove previous packet which lacks scramble + * and append the new. + */ + localq = gwbuf_consume(localq, GWBUF_LENGTH(localq)); + localq = gwbuf_append(localq, new_packet); + } + rc = dcb_write(dcb, localq); + } + + if (rc == 0) + { + GWBUF* errbuf; + bool succp; + ROUTER_OBJECT *router = NULL; + ROUTER *router_instance = NULL; + void *rsession = NULL; + SESSION *session = dcb->session; + + CHK_SESSION(session); + + if (session != NULL) + { + router = session->service->router; + router_instance = session->service->router_instance; + rsession = session->router_session; +#if defined(SS_DEBUG) + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Backend write delayqueue error handling."))); +#endif + errbuf = mysql_create_custom_error( + 1, + 0, + "Failed to write buffered data to back-end server. " + "Buffer was empty or back-end was disconnected during " + "operation. Attempting to find a new backend."); + + router->handleError(router_instance, + rsession, + errbuf, + dcb, + ERRACT_NEW_CONNECTION, + &succp); + gwbuf_free(errbuf); + + if (!succp) + { + spinlock_acquire(&session->ses_lock); + session->state = SESSION_STATE_STOPPING; + spinlock_release(&session->ses_lock); + ss_dassert(dcb->dcb_errhandle_called); + dcb_close(dcb); + } + } + } + return rc; +} + +/** + * This routine handles the COM_CHANGE_USER command + * + * @param dcb The current backend DCB + * @param server The backend server pointer + * @param in_session The current session data (MYSQL_session) + * @param queue The GWBUF containing the COM_CHANGE_USER receveid + * @return 1 on success and 0 on failure + */ +static int gw_change_user( + DCB *backend, + SERVER *server, + SESSION *in_session, + GWBUF *queue) +{ + MYSQL_session *current_session = NULL; + MySQLProtocol *backend_protocol = NULL; + MySQLProtocol *client_protocol = NULL; + char username[MYSQL_USER_MAXLEN+1]=""; + char database[MYSQL_DATABASE_MAXLEN+1]=""; + char current_database[MYSQL_DATABASE_MAXLEN+1]=""; + uint8_t client_sha1[MYSQL_SCRAMBLE_LEN]=""; + uint8_t *client_auth_packet = GWBUF_DATA(queue); + unsigned int auth_token_len = 0; + uint8_t *auth_token = NULL; + int rv = -1; + int auth_ret = 1; + + current_session = (MYSQL_session *)in_session->client->data; + backend_protocol = backend->protocol; + client_protocol = in_session->client->protocol; + + /* now get the user, after 4 bytes header and 1 byte command */ + client_auth_packet += 5; + strncpy(username, (char *)client_auth_packet,MYSQL_USER_MAXLEN); + client_auth_packet += strlen(username) + 1; + + /* get the auth token len */ + memcpy(&auth_token_len, client_auth_packet, 1); + + client_auth_packet++; + + /* allocate memory for token only if auth_token_len > 0 */ + if (auth_token_len > 0) { + auth_token = (uint8_t *)malloc(auth_token_len); + ss_dassert(auth_token != NULL); + + if (auth_token == NULL) + return rv; + memcpy(auth_token, client_auth_packet, auth_token_len); + client_auth_packet += auth_token_len; + } + + /* get new database name */ + strncpy(database, (char *)client_auth_packet,MYSQL_DATABASE_MAXLEN); + + /* get character set */ + if (strlen(database)) { + client_auth_packet += strlen(database) + 1; + } else { + client_auth_packet++; + } + + if (client_auth_packet && *client_auth_packet) + memcpy(&backend_protocol->charset, client_auth_packet, sizeof(int)); + + /* save current_database name */ + strncpy(current_database, current_session->db,MYSQL_DATABASE_MAXLEN); + + /* + * Now clear database name in dcb as we don't do local authentication on db name for change user. + * Local authentication only for user@host and if successful the database name change is sent to backend. + */ + strcpy(current_session->db, ""); + + /* + * decode the token and check the password. + * Note: if auth_token_len == 0 && auth_token == NULL, user is without password + */ + auth_ret = gw_check_mysql_scramble_data(backend->session->client, + auth_token, + auth_token_len, + client_protocol->scramble, + sizeof(client_protocol->scramble), + username, + client_sha1); + + if (auth_ret != 0) { + if (!service_refresh_users(backend->session->client->service)) { + /* Try authentication again with new repository data */ + /* Note: if no auth client authentication will fail */ + auth_ret = gw_check_mysql_scramble_data( + backend->session->client, + auth_token, auth_token_len, + client_protocol->scramble, + sizeof(client_protocol->scramble), + username, + client_sha1); + } + } + + /* copy back current datbase to client session */ + strcpy(current_session->db, current_database); + + /* let's free the auth_token now */ + if (auth_token) + free(auth_token); + + if (auth_ret != 0) { + char *password_set = NULL; + char *message = NULL; + GWBUF* buf; + + if (auth_token_len > 0) + password_set = (char *)client_sha1; + else + password_set = ""; + + /** + * Create an error message and make it look like legit reply + * from backend server. Then make it look like an incoming event + * so that thread gets new task of it, calls clientReply + * which filters out duplicate errors from same cause and forward + * reply to the client. + */ + message = create_auth_fail_str(username, + backend->session->client->remote, + password_set, + ""); + if (message == NULL) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Creating error message failed."))); + rv = 0; + goto retblock; + } + /** + * Add command to backend's protocol, create artificial reply + * packet and add it to client's read buffer. + */ + protocol_add_srv_command((MySQLProtocol*)backend->protocol, + MYSQL_COM_CHANGE_USER); + modutil_reply_auth_error(backend, message, 0); + rv = 1; + } else { + rv = gw_send_change_user_to_backend(database, username, client_sha1, backend_protocol); + /* + * Now copy new data into user session + */ + strcpy(current_session->user, username); + strcpy(current_session->db, database); + memcpy(current_session->client_sha1, client_sha1, sizeof(current_session->client_sha1)); + } + +retblock: + gwbuf_free(queue); + + return rv; +} + + +/** + * Move packets or parts of packets from readbuf to outbuf as the packet headers + * and lengths have been noticed and counted. + * Session commands need to be marked so that they can be handled properly in + * the router's clientReply. + * + * @param dcb Backend's DCB where data was read from + * @param readbuf GWBUF where data was read to + * @param nbytes_to_process Number of bytes that has been read and need to be processed + * + * @return GWBUF which includes complete MySQL packet + */ +static GWBUF* process_response_data ( + DCB* dcb, + GWBUF* readbuf, + int nbytes_to_process) +{ + int npackets_left = 0; /*< response's packet count */ + ssize_t nbytes_left = 0; /*< nbytes to be read for the packet */ + MySQLProtocol* p; + GWBUF* outbuf = NULL; + + /** Get command which was stored in gw_MySQLWrite_backend */ + p = DCB_PROTOCOL(dcb, MySQLProtocol); + if (!DCB_IS_CLONE(dcb)) CHK_PROTOCOL(p); + + /** All buffers processed here are sescmd responses */ + gwbuf_set_type(readbuf, GWBUF_TYPE_SESCMD_RESPONSE); + + /** + * Now it is known how many packets there should be and how much + * is read earlier. + */ + while (nbytes_to_process != 0) + { + mysql_server_cmd_t srvcmd; + bool succp; + + srvcmd = protocol_get_srv_command(p, false); + + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [process_response_data] Read command %s for DCB %p fd %d.", + pthread_self(), + STRPACKETTYPE(srvcmd), + dcb, + dcb->fd))); + /** + * Read values from protocol structure, fails if values are + * uninitialized. + */ + if (npackets_left == 0) + { + succp = protocol_get_response_status(p, &npackets_left, &nbytes_left); + + if (!succp || npackets_left == 0) + { + /** + * Examine command type and the readbuf. Conclude response + * packet count from the command type or from the first + * packet content. Fails if read buffer doesn't include + * enough data to read the packet length. + */ + init_response_status(readbuf, srvcmd, &npackets_left, &nbytes_left); + } + } + /** Only session commands with responses should be processed */ + ss_dassert(npackets_left > 0); + + /** Read incomplete packet. */ + if (nbytes_left > nbytes_to_process) + { + /** Includes length info so it can be processed */ + if (nbytes_to_process >= 5) + { + /** discard source buffer */ + readbuf = gwbuf_consume(readbuf, GWBUF_LENGTH(readbuf)); + nbytes_left -= nbytes_to_process; + } + nbytes_to_process = 0; + } + /** Packet was read. All bytes belonged to the last packet. */ + else if (nbytes_left == nbytes_to_process) + { + nbytes_left = 0; + nbytes_to_process = 0; + ss_dassert(npackets_left > 0); + npackets_left -= 1; + outbuf = gwbuf_append(outbuf, readbuf); + readbuf = NULL; + } + /** + * Packet was read. There should be more since bytes were + * left over. + * Move the next packet to its own buffer and add that next + * to the prev packet's buffer. + */ + else /*< nbytes_left < nbytes_to_process */ + { + ss_dassert(nbytes_left >= 0); + nbytes_to_process -= nbytes_left; + + /** Move the prefix of the buffer to outbuf from redbuf */ + outbuf = gwbuf_append(outbuf, + gwbuf_clone_portion(readbuf, 0, (size_t)nbytes_left)); + readbuf = gwbuf_consume(readbuf, (size_t)nbytes_left); + ss_dassert(npackets_left > 0); + npackets_left -= 1; + nbytes_left = 0; + } + + /** Store new status to protocol structure */ + protocol_set_response_status(p, npackets_left, nbytes_left); + + /** A complete packet was read */ + if (nbytes_left == 0) + { + /** No more packets in this response */ + if (npackets_left == 0 && outbuf != NULL) + { + GWBUF* b = outbuf; + + while (b->next != NULL) + { + b = b->next; + } + /** Mark last as end of response */ + gwbuf_set_type(b, GWBUF_TYPE_RESPONSE_END); + + /** Archive the command */ + protocol_archive_srv_command(p); + } + /** Read next packet */ + else + { + uint8_t* data; + + /** Read next packet length */ + data = GWBUF_DATA(readbuf); + nbytes_left = MYSQL_GET_PACKET_LEN(data)+MYSQL_HEADER_LEN; + /** Store new status to protocol structure */ + protocol_set_response_status(p, npackets_left, nbytes_left); + } + } + } + return outbuf; +} + + +static bool sescmd_response_complete( + DCB* dcb) +{ + int npackets_left; + ssize_t nbytes_left; + MySQLProtocol* p; + bool succp; + + p = DCB_PROTOCOL(dcb, MySQLProtocol); + if (!DCB_IS_CLONE(dcb)) CHK_PROTOCOL(p); + + protocol_get_response_status(p, &npackets_left, &nbytes_left); + + if (npackets_left == 0) + { + succp = true; + } + else + { + succp = false; + } + return succp; +} diff --git a/server/modules/protocol/mongo_client.c b/server/modules/protocol/mongo_client.c new file mode 100644 index 000000000..1de7d237d --- /dev/null +++ b/server/modules/protocol/mongo_client.c @@ -0,0 +1,1004 @@ +/* + * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright MariaDB Corporation Ab 2013-2015 + */ + +/** + * @file mongo_client.c + * + * Revision History + * Date Who Description + + * + */ +#include +#include +#include +#include +#include +#include + +#include + +MODULE_INFO info = { + MODULE_API_PROTOCOL, + MODULE_GA, + GWPROTOCOL_VERSION, + "The client to plain protocol implementation" +}; + +/** Defined in log_manager.cc */ +extern int lm_enabled_logfiles_bitmask; +extern size_t log_ses_count[]; +extern __thread log_info_t tls_log_info; + +static char *version_str = "V1.0.0"; + +static int plain_accept(DCB *listener); +static int plain_listen(DCB *listener, char *config_bind); +static int plain_read(DCB* dcb); +static int plain_write_ready(DCB *dcb); +static int plain_write(DCB *dcb, GWBUF *queue); +static int plain_client_error(DCB *dcb); +static int plain_client_close(DCB *dcb); +static int plain_client_hangup_event(DCB *dcb); + +/* + * The "module object" for the mysqld client protocol module. + */ +static GWPROTOCOL MyObject = { + plain_read, /* Read - EPOLLIN handler */ + plain_write, /* Write - data from gateway */ + plain_write_ready, /* WriteReady - EPOLLOUT handler */ + plain_client_error, /* Error - EPOLLERR handler */ + plain_client_hangup_event, /* HangUp - EPOLLHUP handler */ + plain_accept, /* Accept */ + NULL, /* Connect */ + plain_client_close, /* Close */ + plain_listen, /* Listen */ + NULL, /* Authentication */ + NULL /* Session */ +}; + +/** + * Implementation of the mandatory version entry point + * + * @return version string of the module + */ +char * +version() +{ + return version_str; +} + +/** + * The module initialisation routine, called when the module + * is first loaded. + */ +void +ModuleInit() +{ +} + +/** + * The module entry point routine. It is this routine that + * must populate the structure that is referred to as the + * "module object", this is a structure with the set of + * external entry points for this module. + * + * @return The module object + */ +GWPROTOCOL * +GetModuleObject() +{ + return &MyObject; +} + +/** + * mysql_send_ok + * + * Send a MySQL protocol OK message to the dcb (client) + * + * @param dcb Descriptor Control Block for the connection to which the OK is sent + * @param packet_number + * @param in_affected_rows + * @param mysql_message + * @return packet length + * + */ +int +mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) { + return 1; +} + +/** + * MySQLSendHandshake + * + * @param dcb The descriptor control block to use for sending the handshake request + * @return The packet length sent + */ +int +MySQLSendHandshake(DCB* dcb) +{ + return 1; +} + +/** + * gw_mysql_do_authentication + * + * Performs the MySQL protocol 4.1 authentication, using data in GWBUF *queue + * + * (MYSQL_session*)client_data including: user, db, client_sha1 are copied into + * the dcb->data and later to dcb->session->data. + * + * client_capabilitiesa are copied into the dcb->protocol + * + * @param dcb Descriptor Control Block of the client + * @param queue The GWBUF with data from client + * @return 0 If succeed, otherwise non-zero value + * + * @note in case of failure, dcb->data is freed before returning. If succeed, + * dcb->data is freed in session.c:session_free. + */ +static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { + MySQLProtocol *protocol = NULL; + /* int compress = -1; */ + int connect_with_db = -1; + uint8_t *client_auth_packet = GWBUF_DATA(queue); + int client_auth_packet_size = 0; + char *username = NULL; + char *database = NULL; + unsigned int auth_token_len = 0; + uint8_t *auth_token = NULL; + uint8_t *stage1_hash = NULL; + int auth_ret = -1; + MYSQL_session *client_data = NULL; + + CHK_DCB(dcb); + + protocol = DCB_PROTOCOL(dcb, MySQLProtocol); + CHK_PROTOCOL(protocol); + client_data = (MYSQL_session *)calloc(1, sizeof(MYSQL_session)); +#if defined(SS_DEBUG) + client_data->myses_chk_top = CHK_NUM_MYSQLSES; + client_data->myses_chk_tail = CHK_NUM_MYSQLSES; +#endif + /** + * Assign authentication structure with client DCB. + */ + dcb->data = client_data; + + stage1_hash = client_data->client_sha1; + username = client_data->user; + + client_auth_packet_size = gwbuf_length(queue); + + /* For clients supporting CLIENT_PROTOCOL_41 + * the Handshake Response Packet is: + * + * 4 bytes mysql protocol heade + * 4 bytes capability flags + * 4 max-packet size + * 1 byte character set + * string[23] reserved (all [0]) + * ... + * ... + */ + + /* Detect now if there are enough bytes to continue */ + if (client_auth_packet_size < (4 + 4 + 4 + 1 + 23)) + { + return 1; + } + + memcpy(&protocol->client_capabilities, client_auth_packet + 4, 4); + + connect_with_db = + GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB & gw_mysql_get_byte4( + (uint32_t *)&protocol->client_capabilities); + /* + compress = + GW_MYSQL_CAPABILITIES_COMPRESS & gw_mysql_get_byte4( + &protocol->client_capabilities); + */ + + username = get_username_from_auth(username, client_auth_packet); + + if (username == NULL) + { + return 1; + } + + /* get charset */ + memcpy(&protocol->charset, client_auth_packet + 4 + 4 + 4, sizeof (int)); + + /* get the auth token len */ + memcpy(&auth_token_len, + client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1, + 1); + + /* + * Note: some clients may pass empty database, connect_with_db !=0 but database ="" + */ + if (connect_with_db) { + database = client_data->db; + strncpy(database, + (char *)(client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + + 1 + 1 + auth_token_len), MYSQL_DATABASE_MAXLEN); + } + + /* allocate memory for token only if auth_token_len > 0 */ + if (auth_token_len) { + auth_token = (uint8_t *)malloc(auth_token_len); + memcpy(auth_token, + client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1 + 1, + auth_token_len); + } + + /* + * Decode the token and check the password + * Note: if auth_token_len == 0 && auth_token == NULL, user is without password + */ + + auth_ret = gw_check_mysql_scramble_data(dcb, + auth_token, + auth_token_len, + protocol->scramble, + sizeof(protocol->scramble), + username, + stage1_hash); + + /* check for database name match in resource hashtable */ + auth_ret = check_db_name_after_auth(dcb, database, auth_ret); + + /* On failed auth try to load users' table from backend database */ + if (auth_ret != 0) { + if (!service_refresh_users(dcb->service)) { + /* Try authentication again with new repository data */ + /* Note: if no auth client authentication will fail */ + auth_ret = gw_check_mysql_scramble_data( + dcb, + auth_token, + auth_token_len, + protocol->scramble, + sizeof(protocol->scramble), + username, + stage1_hash); + } + else + { + LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE, + "%s: login attempt for user %s, user not " + "found.", + dcb->service->name, username))); + } + } + + /* Do again the database check */ + auth_ret = check_db_name_after_auth(dcb, database, auth_ret); + + /* on succesful auth set user into dcb field */ + if (auth_ret == 0) { + dcb->user = strdup(client_data->user); + } + + /* let's free the auth_token now */ + if (auth_token) { + free(auth_token); + } + + return auth_ret; +} + +/** + * Write function for client DCB: writes data from MaxScale to Client + * + * @param dcb The DCB of the client + * @param queue Queue of buffers to write + */ +int +plain_write(DCB *dcb, GWBUF *queue) +{ + return dcb_write(dcb, queue); +} + +/** + * Client read event triggered by EPOLLIN + * + * @param dcb Descriptor control block + * @return 0 if succeed, 1 otherwise + */ +int plain_read( + DCB* dcb) +{ + SESSION *session = NULL; + ROUTER_OBJECT *router = NULL; + ROUTER *router_instance = NULL; + void *rsession = NULL; + MySQLProtocol *protocol = NULL; + GWBUF *read_buffer = NULL; + int rc = 0; + int nbytes_read = 0; + uint8_t cap = 0; + bool stmt_input = false; /*< router input type */ + + CHK_DCB(dcb); + protocol = DCB_PROTOCOL(dcb, MySQLProtocol); + CHK_PROTOCOL(protocol); + rc = dcb_read(dcb, &read_buffer); + + if (rc < 0) + { + dcb_close(dcb); + } + nbytes_read = gwbuf_length(read_buffer); + + if (nbytes_read == 0) + { + goto return_rc; + } + + if(dcb->session == NULL) + { + dcb->session = session_alloc(dcb->service,dcb); + } + + rc = SESSION_ROUTE_QUERY(dcb->session, read_buffer); + + +return_rc: + + return rc; +} + +/////////////////////////////////////////////// +// client write event to Client triggered by EPOLLOUT +////////////////////////////////////////////// +/** + * @node Client's fd became writable, and EPOLLOUT event + * arrived. As a consequence, client input buffer (writeq) is flushed. + * + * Parameters: + * @param dcb - in, use + * client dcb + * + * @return constantly 1 + * + * + * @details (write detailed description here) + * + */ +int plain_write_ready(DCB *dcb) +{ + MySQLProtocol *protocol = NULL; + + CHK_DCB(dcb); + + ss_dassert(dcb->state != DCB_STATE_DISCONNECTED); + + if (dcb == NULL) { + goto return_1; + } + + if (dcb->state == DCB_STATE_DISCONNECTED) { + goto return_1; + } + + if (dcb->protocol == NULL) { + goto return_1; + } + protocol = (MySQLProtocol *)dcb->protocol; + + + dcb_drain_writeq(dcb); + goto return_1; + +return_1: + + return 1; +} + +/** + * set listener for mysql protocol, retur 1 on success and 0 in failure + */ +int plain_listen( + DCB *listen_dcb, + char *config_bind) +{ + int l_so; + int syseno = 0; + struct sockaddr_in serv_addr; + struct sockaddr_un local_addr; + struct sockaddr *current_addr; + int one = 1; + int rc; + + if (strchr(config_bind, '/')) { + char *tmp = strrchr(config_bind, ':'); + if (tmp) + *tmp = '\0'; + + // UNIX socket create + if ((l_so = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, + "\n* Error: can't create UNIX socket due " + "error %i, %s.\n\n\t", + errno, + strerror(errno)); + return 0; + } + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sun_family = AF_UNIX; + strncpy(local_addr.sun_path, config_bind, sizeof(local_addr.sun_path) - 1); + + current_addr = (struct sockaddr *) &local_addr; + + } else { + /* MaxScale, as default, will bind on port 4406 */ + if (!parse_bindconfig(config_bind, 4406, &serv_addr)) { + fprintf(stderr, "Error in parse_bindconfig for [%s]\n", config_bind); + return 0; + } + // TCP socket create + if ((l_so = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, + "\n* Error: can't create socket due " + "error %i, %s.\n\n\t", + errno, + strerror(errno)); + return 0; + } + + current_addr = (struct sockaddr *) &serv_addr; + } + + listen_dcb->fd = -1; + + // socket options + if((syseno = setsockopt(l_so, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one))) != 0){ + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,"Error: Failed to set socket options. Error %d: %s",errno,strerror(errno)))); + } + + + // set NONBLOCKING mode + setnonblocking(l_so); + + /* get the right socket family for bind */ + switch (current_addr->sa_family) { + case AF_UNIX: + rc = unlink(config_bind); + if ( (rc == -1) && (errno!=ENOENT) ) { + fprintf(stderr, "Error unlink Unix Socket %s\n", config_bind); + } + + if (bind(l_so, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) { + fprintf(stderr, + "\n* Bind failed due error %i, %s.\n", + errno, + strerror(errno)); + fprintf(stderr, "* Can't bind to %s\n\n", config_bind); + close(l_so); + return 0; + } + + /* set permission for all users */ + if (chmod(config_bind, 0777) < 0) { + fprintf(stderr, + "\n* chmod failed for %s due error %i, %s.\n\n", + config_bind, + errno, + strerror(errno)); + } + + break; + + case AF_INET: + if (bind(l_so, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + fprintf(stderr, + "\n* Bind failed due error %i, %s.\n", + errno, + strerror(errno)); + fprintf(stderr, "* Can't bind to %s\n\n", config_bind); + close(l_so); + return 0; + } + break; + + default: + fprintf(stderr, "* Socket Family %i not supported\n", current_addr->sa_family); + close(l_so); + return 0; + } + + rc = listen(l_so, 10 * SOMAXCONN); + + if (rc == 0) { + LOGIF(LM, (skygw_log_write_flush(LOGFILE_MESSAGE,"Listening MySQL connections at %s", config_bind))); + } else { + int eno = errno; + errno = 0; + fprintf(stderr, + "\n* Failed to start listening MySQL due error %d, %s\n\n", + eno, + strerror(eno)); + close(l_so); + return 0; + } + // assign l_so to dcb + listen_dcb->fd = l_so; + + // add listening socket to poll structure + if (poll_add_dcb(listen_dcb) == -1) { + fprintf(stderr, + "\n* Failed to start polling the socket due error " + "%i, %s.\n\n", + errno, + strerror(errno)); + return 0; + } +#if defined(FAKE_CODE) + conn_open[l_so] = true; +#endif /* FAKE_CODE */ + listen_dcb->func.accept = plain_accept; + + return 1; +} + + +/** + * @node (write brief function description here) + * + * Parameters: + * @param listener - + * + * + * @return 0 in success, 1 in failure + * + * + * @details (write detailed description here) + * + */ +int plain_accept(DCB *listener) +{ + int rc = 0; + DCB *client_dcb; + MySQLProtocol *protocol; + int c_sock; + struct sockaddr client_conn; + socklen_t client_len = sizeof(struct sockaddr_storage); + int sendbuf = GW_BACKEND_SO_SNDBUF; + socklen_t optlen = sizeof(sendbuf); + int eno = 0; + int syseno = 0; + int i = 0; + + CHK_DCB(listener); + + while (1) { + + retry_accept: + +#if defined(FAKE_CODE) + if (fail_next_accept > 0) + { + c_sock = -1; + eno = fail_accept_errno; + fail_next_accept -= 1; + } else { + fail_accept_errno = 0; +#endif /* FAKE_CODE */ + // new connection from client + c_sock = accept(listener->fd, + (struct sockaddr *) &client_conn, + &client_len); + eno = errno; + errno = 0; +#if defined(FAKE_CODE) + } +#endif /* FAKE_CODE */ + + if (c_sock == -1) { + + if (eno == EAGAIN || eno == EWOULDBLOCK) + { + /** + * We have processed all incoming connections. + */ + rc = 1; + goto return_rc; + } + else if (eno == ENFILE || eno == EMFILE) + { + struct timespec ts1; + ts1.tv_sec = 0; + /** + * Exceeded system's (ENFILE) or processes + * (EMFILE) max. number of files limit. + */ + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [plain_accept] Error %d, %s. ", + pthread_self(), + eno, + strerror(eno)))); + + if (i == 0) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error %d, %s. " + "Failed to accept new client " + "connection.", + eno, + strerror(eno)))); + } + i++; + ts1.tv_nsec = 100*i*i*1000000; + nanosleep(&ts1, NULL); + + if (i<10) { + goto retry_accept; + } + rc = 1; + goto return_rc; + } + else + { + /** + * Other error. + */ + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [plain_accept] Error %d, %s.", + pthread_self(), + eno, + strerror(eno)))); + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Failed to accept new client " + "connection due to %d, %s.", + eno, + strerror(eno)))); + rc = 1; + goto return_rc; + } /* if (eno == ..) */ + } /* if (c_sock == -1) */ + /* reset counter */ + i = 0; + + listener->stats.n_accepts++; +#if defined(SS_DEBUG) + LOGIF(LD, (skygw_log_write_flush( + LOGFILE_DEBUG, + "%lu [plain_accept] Accepted fd %d.", + pthread_self(), + c_sock))); +#endif /* SS_DEBUG */ +#if defined(FAKE_CODE) + conn_open[c_sock] = true; +#endif /* FAKE_CODE */ + /* set nonblocking */ + sendbuf = GW_CLIENT_SO_SNDBUF; + + if((syseno = setsockopt(c_sock, SOL_SOCKET, SO_SNDBUF, &sendbuf, optlen)) != 0){ + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,"Error: Failed to set socket options. Error %d: %s",errno,strerror(errno)))); + } + + sendbuf = GW_CLIENT_SO_RCVBUF; + + if((syseno = setsockopt(c_sock, SOL_SOCKET, SO_RCVBUF, &sendbuf, optlen)) != 0){ + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,"Error: Failed to set socket options. Error %d: %s",errno,strerror(errno)))); + } + setnonblocking(c_sock); + + client_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER); + + if (client_dcb == NULL) { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Failed to create " + "DCB object for client connection."))); + close(c_sock); + rc = 1; + goto return_rc; + } + + client_dcb->service = listener->session->service; + client_dcb->fd = c_sock; + + // get client address + if ( client_conn.sa_family == AF_UNIX) + { + // client address + client_dcb->remote = strdup("localhost_from_socket"); + // set localhost IP for user authentication + (client_dcb->ipv4).sin_addr.s_addr = 0x0100007F; + } + else + { + /* client IPv4 in raw data*/ + memcpy(&client_dcb->ipv4, + (struct sockaddr_in *)&client_conn, + sizeof(struct sockaddr_in)); + /* client IPv4 in string representation */ + client_dcb->remote = (char *)calloc(INET_ADDRSTRLEN+1, sizeof(char)); + + if (client_dcb->remote != NULL) + { + inet_ntop(AF_INET, + &(client_dcb->ipv4).sin_addr, + client_dcb->remote, + INET_ADDRSTRLEN); + } + } + protocol = mysql_protocol_init(client_dcb, c_sock); + ss_dassert(protocol != NULL); + + if (protocol == NULL) { + /** delete client_dcb */ + dcb_close(client_dcb); + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [plain_accept] Failed to create " + "protocol object for client connection.", + pthread_self()))); + rc = 1; + goto return_rc; + } + client_dcb->protocol = protocol; + // assign function poiters to "func" field + memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); + + // client protocol state change + protocol->protocol_auth_state = MYSQL_IDLE; + + /** + * Set new descriptor to event set. At the same time, + * change state to DCB_STATE_POLLING so that + * thread which wakes up sees correct state. + */ + if (poll_add_dcb(client_dcb) == -1) + { + /* Send a custom error as MySQL command reply */ + mysql_send_custom_error( + client_dcb, + 1, + 0, + "MaxScale internal error."); + + /** close client_dcb */ + dcb_close(client_dcb); + + /** Previous state is recovered in poll_add_dcb. */ + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [plain_accept] Failed to add dcb %p for " + "fd %d to epoll set.", + pthread_self(), + client_dcb, + client_dcb->fd))); + rc = 1; + goto return_rc; + } + else + { + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [plain_accept] Added dcb %p for fd " + "%d to epoll set.", + pthread_self(), + client_dcb, + client_dcb->fd))); + } + } /**< while 1 */ +#if defined(SS_DEBUG) + if (rc == 0) { + CHK_DCB(client_dcb); + CHK_PROTOCOL(((MySQLProtocol *)client_dcb->protocol)); + } +#endif +return_rc: + + return rc; +} + +static int plain_client_error( + DCB* dcb) +{ + SESSION* session; + + CHK_DCB(dcb); + + session = dcb->session; + + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [plain_client_error] Error event handling for DCB %p " + "in state %s, session %p.", + pthread_self(), + dcb, + STRDCBSTATE(dcb->state), + (session != NULL ? session : NULL)))); + + if (session != NULL && session->state == SESSION_STATE_STOPPING) + { + goto retblock; + } + + dcb_close(dcb); + +retblock: + return 1; +} + +static int +plain_client_close(DCB *dcb) +{ + SESSION* session; + ROUTER_OBJECT* router; + void* router_instance; +#if defined(SS_DEBUG) + MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol; + if (dcb->state == DCB_STATE_POLLING || + dcb->state == DCB_STATE_NOPOLLING || + dcb->state == DCB_STATE_ZOMBIE) + { + if (!DCB_IS_CLONE(dcb)) CHK_PROTOCOL(protocol); + } +#endif + LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG, + "%lu [plain_client_close]", + pthread_self()))); + mysql_protocol_done(dcb); + session = dcb->session; + /** + * session may be NULL if session_alloc failed. + * In that case, router session wasn't created. + */ + if (session != NULL) + { + CHK_SESSION(session); + spinlock_acquire(&session->ses_lock); + + if (session->state != SESSION_STATE_STOPPING) + { + session->state = SESSION_STATE_STOPPING; + } + router_instance = session->service->router_instance; + router = session->service->router; + /** + * If router session is being created concurrently router + * session might be NULL and it shouldn't be closed. + */ + if (session->router_session != NULL) + { + spinlock_release(&session->ses_lock); + /** Close router session and all its connections */ + router->closeSession(router_instance, session->router_session); + } + else + { + spinlock_release(&session->ses_lock); + } + } + return 1; +} + +/** + * Handle a hangup event on the client side descriptor. + * + * We simply close the DCB, this will propogate the closure to any + * backend descriptors and perform the session cleanup. + * + * @param dcb The DCB of the connection + */ +static int +plain_client_hangup_event(DCB *dcb) +{ + SESSION* session; + + CHK_DCB(dcb); + session = dcb->session; + + if (session != NULL && session->state == SESSION_STATE_ROUTER_READY) + { + CHK_SESSION(session); + } + + if (session != NULL && session->state == SESSION_STATE_STOPPING) + { + goto retblock; + } + + dcb_close(dcb); + +retblock: + return 1; +} + + +/** + * Detect if buffer includes partial mysql packet or multiple packets. + * Store partial packet to dcb_readqueue. Send complete packets one by one + * to router. + * + * It is assumed readbuf includes at least one complete packet. + * Return 1 in success. If the last packet is incomplete return success but + * leave incomplete packet to readbuf. + * + * @param session Session pointer + * @param p_readbuf Pointer to the address of GWBUF including the query + * + * @return 1 if succeed, + */ +static int route_by_statement( + SESSION* session, + GWBUF** p_readbuf) +{ + int rc; + GWBUF* packetbuf; +#if defined(SS_DEBUG) + GWBUF* tmpbuf; + + tmpbuf = *p_readbuf; + while (tmpbuf != NULL) + { + ss_dassert(GWBUF_IS_TYPE_MYSQL(tmpbuf)); + tmpbuf=tmpbuf->next; + } +#endif + do + { + ss_dassert(GWBUF_IS_TYPE_MYSQL((*p_readbuf))); + + /** + * Collect incoming bytes to a buffer until complete packet has + * arrived and then return the buffer. + */ + packetbuf = gw_MySQL_get_next_packet(p_readbuf); + + if (packetbuf != NULL) + { + CHK_GWBUF(packetbuf); + ss_dassert(GWBUF_IS_TYPE_MYSQL(packetbuf)); + /** + * This means that buffer includes exactly one MySQL + * statement. + * backend func.write uses the information. MySQL backend + * protocol, for example, stores the command identifier + * to protocol structure. When some other thread reads + * the corresponding response the command tells how to + * handle response. + * + * Set it here instead of plain_read to make + * sure it is set to each (MySQL) packet. + */ + gwbuf_set_type(packetbuf, GWBUF_TYPE_SINGLE_STMT); + /** Route query */ + rc = SESSION_ROUTE_QUERY(session, packetbuf); + } + else + { + rc = 1; + goto return_rc; + } + } + while (rc == 1 && *p_readbuf != NULL); + +return_rc: + return rc; +} + diff --git a/server/modules/routing/CMakeLists.txt b/server/modules/routing/CMakeLists.txt index 4cf341d83..a14ca00ad 100644 --- a/server/modules/routing/CMakeLists.txt +++ b/server/modules/routing/CMakeLists.txt @@ -9,6 +9,10 @@ add_library(readconnroute SHARED readconnroute.c) target_link_libraries(readconnroute log_manager utils) install(TARGETS readconnroute DESTINATION modules) +add_library(plainroute SHARED plainroute.c) +target_link_libraries(plainroute log_manager utils) +install(TARGETS plainroute DESTINATION modules) + add_library(debugcli SHARED debugcli.c debugcmd.c) target_link_libraries(debugcli log_manager utils) install(TARGETS debugcli DESTINATION modules) diff --git a/server/modules/routing/plainroute.c b/server/modules/routing/plainroute.c new file mode 100644 index 000000000..245a3427a --- /dev/null +++ b/server/modules/routing/plainroute.c @@ -0,0 +1,923 @@ +/* + * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright MariaDB Corporation Ab 2013-2014 + */ + +/** + * @file readconnroute.c - Read Connection Load Balancing Query Router + * + * This is the implementation of a simple query router that balances + * read connections. It assumes the service is configured with a set + * of slaves and that the application clients already split read and write + * queries. It offers a service to balance the client read connections + * over this set of slave servers. It does this once only, at the time + * the connection is made. It chooses the server that currently has the least + * number of connections by keeping a count for each server of how + * many connections the query router has made to the server. + * + * When two servers have the same number of current connections the one with + * the least number of connections since startup will be used. + * + * The router may also have options associated to it that will limit the + * choice of backend server. Currently two options are supported, the "master" + * option will cause the router to only connect to servers marked as masters + * and the "slave" option will limit connections to routers that are marked + * as slaves. If neither option is specified the router will connect to either + * masters or slaves. + * + * @verbatim + * Revision History + * + * Date Who Description + * 14/06/2013 Mark Riddoch Initial implementation + * 25/06/2013 Mark Riddoch Addition of checks for current server state + * 26/06/2013 Mark Riddoch Use server with least connections since + * startup if the number of current + * connections is the same for two servers + * Addition of master and slave options + * 27/06/2013 Vilho Raatikka Added skygw_log_write command as an example + * and necessary headers. + * 17/07/2013 Massimiliano Pinto Added clientReply routine: + * called by backend server to send data to client + * Included mysql_client_server_protocol.h + * with macros and MySQL commands with MYSQL_ prefix + * avoiding any conflict with the standard ones + * in mysql.h + * 22/07/2013 Mark Riddoch Addition of joined router option for Galera + * clusters + * 31/07/2013 Massimiliano Pinto Added a check for candidate server, if NULL return + * 12/08/2013 Mark Riddoch Log unsupported router options + * 04/09/2013 Massimiliano Pinto Added client NULL check in clientReply + * 22/10/2013 Massimiliano Pinto errorReply called from backend, for client error reply + * or take different actions such as open a new backend connection + * 20/02/2014 Massimiliano Pinto If router_options=slave, route traffic to master if no slaves available + * 06/03/2014 Massimiliano Pinto Server connection counter is now updated in closeSession + * 24/06/2014 Massimiliano Pinto New rules for selecting the Master server + * 27/06/2014 Mark Riddoch Addition of server weighting + * + * @endverbatim + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/** Defined in log_manager.cc */ +extern int lm_enabled_logfiles_bitmask; +extern size_t log_ses_count[]; +extern __thread log_info_t tls_log_info; + +MODULE_INFO info = { + MODULE_API_ROUTER, + MODULE_GA, + ROUTER_VERSION, + "A connection based router to load balance based on connections" +}; + +static char *version_str = "V1.1.0"; + +/* The router entry points */ +static ROUTER *createInstance(SERVICE *service, char **options); +static void *newSession(ROUTER *instance, SESSION *session); +static void closeSession(ROUTER *instance, void *router_session); +static void freeSession(ROUTER *instance, void *router_session); +static int routeQuery(ROUTER *instance, void *router_session, GWBUF *queue); +static void diagnostics(ROUTER *instance, DCB *dcb); +static void clientReply( + ROUTER *instance, + void *router_session, + GWBUF *queue, + DCB *backend_dcb); +static void handleError( + ROUTER *instance, + void *router_session, + GWBUF *errbuf, + DCB *backend_dcb, + error_action_t action, + bool *succp); +static uint8_t getCapabilities (ROUTER* inst, void* router_session); + + +/** The module object definition */ +static ROUTER_OBJECT MyObject = { + createInstance, + newSession, + closeSession, + freeSession, + routeQuery, + diagnostics, + clientReply, + handleError, + getCapabilities +}; + +static bool rses_begin_locked_router_action( + ROUTER_CLIENT_SES* rses); + +static void rses_end_locked_router_action( + ROUTER_CLIENT_SES* rses); + +static BACKEND *get_root_master( + BACKEND **servers); +static int handle_state_switch( + DCB* dcb,DCB_REASON reason, void * routersession); +static SPINLOCK instlock; +static ROUTER_INSTANCE *instances; + +/** + * Implementation of the mandatory version entry point + * + * @return version string of the module + */ +char * +version() +{ + return version_str; +} + +/** + * The module initialisation routine, called when the module + * is first loaded. + */ +void +ModuleInit() +{ + LOGIF(LM, (skygw_log_write( + LOGFILE_MESSAGE, + "Initialise readconnroute router module %s.\n", version_str))); + spinlock_init(&instlock); + instances = NULL; +} + +/** + * The module entry point routine. It is this routine that + * must populate the structure that is referred to as the + * "module object", this is a structure with the set of + * external entry points for this module. + * + * @return The module object + */ +ROUTER_OBJECT * +GetModuleObject() +{ + return &MyObject; +} + +/** + * Create an instance of the router for a particular service + * within the gateway. + * + * @param service The service this router is being create for + * @param options An array of options for this query router + * + * @return The instance data for this new instance + */ +static ROUTER * +createInstance(SERVICE *service, char **options) +{ +ROUTER_INSTANCE *inst; +SERVER *server; +SERVER_REF *sref; +int i, n; +BACKEND *backend; +char *weightby; + + if ((inst = calloc(1, sizeof(ROUTER_INSTANCE))) == NULL) { + return NULL; + } + + inst->service = service; + spinlock_init(&inst->lock); + + /* + * We need an array of the backend servers in the instance structure so + * that we can maintain a count of the number of connections to each + * backend server. + */ + for (sref = service->dbref, n = 0; sref; sref = sref->next) + n++; + + inst->servers = (BACKEND **)calloc(n + 1, sizeof(BACKEND *)); + if (!inst->servers) + { + free(inst); + return NULL; + } + + for (sref = service->dbref, n = 0; sref; sref = sref->next) + { + if ((inst->servers[n] = malloc(sizeof(BACKEND))) == NULL) + { + for (i = 0; i < n; i++) + free(inst->servers[i]); + free(inst->servers); + free(inst); + return NULL; + } + inst->servers[n]->server = sref->server; + inst->servers[n]->current_connection_count = 0; + inst->servers[n]->weight = 1000; + n++; + } + inst->servers[n] = NULL; + + if ((weightby = serviceGetWeightingParameter(service)) != NULL) + { + int total = 0; + for (n = 0; inst->servers[n]; n++) + { + backend = inst->servers[n]; + total += atoi(serverGetParameter(backend->server, + weightby)); + } + if (total == 0) + { + LOGIF(LE, (skygw_log_write(LOGFILE_ERROR, + "WARNING: Weighting Parameter for service '%s' " + "will be ignored as no servers have values " + "for the parameter '%s'.\n", + service->name, weightby))); + } + else + { + for (n = 0; inst->servers[n]; n++) + { + int perc, wght; + backend = inst->servers[n]; + perc = ((wght = atoi(serverGetParameter(backend->server, + weightby))) * 1000) / total; + if (perc == 0 && wght != 0) + perc = 1; + backend->weight = perc; + if (perc == 0) + { + LOGIF(LE, (skygw_log_write( + LOGFILE_ERROR, + "Server '%s' has no value " + "for weighting parameter '%s', " + "no queries will be routed to " + "this server.\n", + inst->servers[n]->server->unique_name, + weightby))); + } + + } + } + } + + /* + * Process the options + */ + inst->bitmask = 0; + inst->bitvalue = 0; + if (options) + { + for (i = 0; options[i]; i++) + { + if (!strcasecmp(options[i], "master")) + { + inst->bitmask |= (SERVER_MASTER|SERVER_SLAVE); + inst->bitvalue |= SERVER_MASTER; + } + else if (!strcasecmp(options[i], "slave")) + { + inst->bitmask |= (SERVER_MASTER|SERVER_SLAVE); + inst->bitvalue |= SERVER_SLAVE; + } + else if (!strcasecmp(options[i], "synced")) + { + inst->bitmask |= (SERVER_JOINED); + inst->bitvalue |= SERVER_JOINED; + } + else if (!strcasecmp(options[i], "ndb")) + { + inst->bitmask |= (SERVER_NDB); + inst->bitvalue |= SERVER_NDB; + } + else + { + LOGIF(LM, (skygw_log_write( + LOGFILE_MESSAGE, + "* Warning : Unsupported router " + "option \'%s\' for readconnroute. " + "Expected router options are " + "[slave|master|synced|ndb]", + options[i]))); + } + } + } + + /* + * We have completed the creation of the instance data, so now + * insert this router instance into the linked list of routers + * that have been created with this module. + */ + spinlock_acquire(&instlock); + inst->next = instances; + instances = inst; + spinlock_release(&instlock); + + return (ROUTER *)inst; +} + +/** + * Associate a new session with this instance of the router. + * + * @param instance The router instance data + * @param session The session itself + * @return Session specific data for this session + */ +static void * +newSession(ROUTER *instance, SESSION *session) +{ +ROUTER_INSTANCE *inst = (ROUTER_INSTANCE *)instance; +ROUTER_CLIENT_SES *client_rses; +BACKEND *candidate = NULL; +int i; + + LOGIF(LD, (skygw_log_write_flush( + LOGFILE_DEBUG, + "%lu [newSession] new router session with session " + "%p, and inst %p.", + pthread_self(), + session, + inst))); + + + client_rses = (ROUTER_CLIENT_SES *)calloc(1, sizeof(ROUTER_CLIENT_SES)); + + if (client_rses == NULL) { + return NULL; + } + +#if defined(SS_DEBUG) + client_rses->rses_chk_top = CHK_NUM_ROUTER_SES; + client_rses->rses_chk_tail = CHK_NUM_ROUTER_SES; +#endif + + + /** + * Find a backend server to connect to. This is the extent of the + * load balancing algorithm we need to implement for this simple + * connection router. + */ + + /* + * Loop over all the servers and find any that have fewer connections + * than the candidate server. + * + * If a server has less connections than the current candidate we mark this + * as the new candidate to connect to. + * + * If a server has the same number of connections currently as the candidate + * and has had less connections over time than the candidate it will also + * become the new candidate. This has the effect of spreading the + * connections over different servers during periods of very low load. + */ + for (i = 0; inst->servers[i]; i++) { + + + if (SERVER_IN_MAINT(inst->servers[i]->server)) + continue; + + if (inst->servers[i]->weight == 0) + continue; + + + + /* If no candidate set, set first running server as + our initial candidate server */ + if(candidate == NULL) + { + candidate = inst->servers[i]; + } + else if((inst->servers[i]->current_connection_count + * 1000) / inst->servers[i]->weight < + (candidate->current_connection_count * + 1000) / candidate->weight) + { + /* This running server has fewer + connections, set it as a new candidate */ + candidate = inst->servers[i]; + } + else if((inst->servers[i]->current_connection_count + * 1000) / inst->servers[i]->weight == + (candidate->current_connection_count * + 1000) / candidate->weight && + inst->servers[i]->server->stats.n_connections < + candidate->server->stats.n_connections) + { + /* This running server has the same number + of connections currently as the candidate + but has had fewer connections over time + than candidate, set this server to candidate*/ + candidate = inst->servers[i]; + } + } + + + + client_rses->rses_capabilities = RCAP_TYPE_PACKET_INPUT; + + /* + * We now have the server with the least connections. + * Bump the connection count for this server + */ + atomic_add(&candidate->current_connection_count, 1); + client_rses->backend = candidate; + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "%lu [newSession] Selected server in port %d. " + "Connections : %d\n", + pthread_self(), + candidate->server->port, + candidate->current_connection_count))); + /* + * Open a backend connection, putting the DCB for this + * connection in the client_rses->backend_dcb + */ + client_rses->backend_dcb = dcb_connect(candidate->server, + session, + candidate->server->protocol); + if (client_rses->backend_dcb == NULL) + { + atomic_add(&candidate->current_connection_count, -1); + free(client_rses); + return NULL; + } + dcb_add_callback( + client_rses->backend_dcb, + DCB_REASON_NOT_RESPONDING, + &handle_state_switch, + client_rses); + inst->stats.n_sessions++; + + /** + * Add this session to the list of active sessions. + */ + spinlock_acquire(&inst->lock); + client_rses->next = inst->connections; + inst->connections = client_rses; + spinlock_release(&inst->lock); + + + return (void *)client_rses; +} + +/** + * @node Unlink from backend server, unlink from router's connection list, + * and free memory of a router client session. + * + * Parameters: + * @param router - + * + * + * @param router_cli_ses - + * + * + * @return void + * + * + * @details (write detailed description here) + * + */ +static void freeSession( + ROUTER* router_instance, + void* router_client_ses) +{ + ROUTER_INSTANCE* router = (ROUTER_INSTANCE *)router_instance; + ROUTER_CLIENT_SES* router_cli_ses = + (ROUTER_CLIENT_SES *)router_client_ses; + int prev_val; + + prev_val = atomic_add(&router_cli_ses->backend->current_connection_count, -1); + ss_dassert(prev_val > 0); + + spinlock_acquire(&router->lock); + + if (router->connections == router_cli_ses) { + router->connections = router_cli_ses->next; + } else { + ROUTER_CLIENT_SES *ptr = router->connections; + + while (ptr != NULL && ptr->next != router_cli_ses) { + ptr = ptr->next; + } + + if (ptr != NULL) { + ptr->next = router_cli_ses->next; + } + } + spinlock_release(&router->lock); + + LOGIF(LD, (skygw_log_write_flush( + LOGFILE_DEBUG, + "%lu [freeSession] Unlinked router_client_session %p from " + "router %p and from server on port %d. Connections : %d. ", + pthread_self(), + router_cli_ses, + router, + router_cli_ses->backend->server->port, + prev_val-1))); + + free(router_cli_ses); +} + + +/** + * Close a session with the router, this is the mechanism + * by which a router may cleanup data structure etc. + * + * @param instance The router instance data + * @param router_session The session being closed + */ +static void +closeSession(ROUTER *instance, void *router_session) +{ +ROUTER_CLIENT_SES *router_cli_ses = (ROUTER_CLIENT_SES *)router_session; +DCB* backend_dcb; + + CHK_CLIENT_RSES(router_cli_ses); + /** + * Lock router client session for secure read and update. + */ + if (rses_begin_locked_router_action(router_cli_ses)) + { + /* decrease server current connection counter */ + atomic_add(&router_cli_ses->backend->server->stats.n_current, -1); + + backend_dcb = router_cli_ses->backend_dcb; + router_cli_ses->backend_dcb = NULL; + router_cli_ses->rses_closed = true; + /** Unlock */ + rses_end_locked_router_action(router_cli_ses); + + /** + * Close the backend server connection + */ + if (backend_dcb != NULL) { + CHK_DCB(backend_dcb); + dcb_close(backend_dcb); + } + } +} + +/** + * We have data from the client, we must route it to the backend. + * This is simply a case of sending it to the connection that was + * chosen when we started the client session. + * + * @param instance The router instance + * @param router_session The router session returned from the newSession call + * @param queue The queue of data buffers to route + * @return if succeed 1, otherwise 0 + */ +static int +routeQuery(ROUTER *instance, void *router_session, GWBUF *queue) +{ + ROUTER_INSTANCE *inst = (ROUTER_INSTANCE *)instance; + ROUTER_CLIENT_SES *router_cli_ses = (ROUTER_CLIENT_SES *)router_session; + uint8_t *payload = GWBUF_DATA(queue); + int mysql_command; + int rc; + DCB* backend_dcb; + bool rses_is_closed; + + inst->stats.n_queries++; + + /** Dirty read for quick check if router is closed. */ + if (router_cli_ses->rses_closed) + { + rses_is_closed = true; + } + else + { + /** + * Lock router client session for secure read of DCBs + */ + rses_is_closed = !(rses_begin_locked_router_action(router_cli_ses)); + } + + if (!rses_is_closed) + { + backend_dcb = router_cli_ses->backend_dcb; + /** unlock */ + rses_end_locked_router_action(router_cli_ses); + } + + if (rses_is_closed || backend_dcb == NULL) + { + LOGIF(LT, (skygw_log_write( + LOGFILE_TRACE, + "Error : Failed to route MySQL command %d to backend " + "server.", + mysql_command))); + rc = 0; + goto return_rc; + } + + + rc = backend_dcb->func.write(backend_dcb, queue); + +return_rc: + return rc; +} + +/** + * Display router diagnostics + * + * @param instance Instance of the router + * @param dcb DCB to send diagnostics to + */ +static void +diagnostics(ROUTER *router, DCB *dcb) +{ +ROUTER_INSTANCE *router_inst = (ROUTER_INSTANCE *)router; +ROUTER_CLIENT_SES *session; +int i = 0; +BACKEND *backend; +char *weightby; + + spinlock_acquire(&router_inst->lock); + session = router_inst->connections; + while (session) + { + i++; + session = session->next; + } + spinlock_release(&router_inst->lock); + + dcb_printf(dcb, "\tNumber of router sessions: %d\n", + router_inst->stats.n_sessions); + dcb_printf(dcb, "\tCurrent no. of router sessions: %d\n", i); + dcb_printf(dcb, "\tNumber of queries forwarded: %d\n", + router_inst->stats.n_queries); + if ((weightby = serviceGetWeightingParameter(router_inst->service)) + != NULL) + { + dcb_printf(dcb, "\tConnection distribution based on %s " + "server parameter.\n", + weightby); + dcb_printf(dcb, + "\t\tServer Target %% Connections\n"); + for (i = 0; router_inst->servers[i]; i++) + { + backend = router_inst->servers[i]; + dcb_printf(dcb, "\t\t%-20s %3.1f%% %d\n", + backend->server->unique_name, + (float)backend->weight / 10, + backend->current_connection_count); + } + + } +} + +/** + * Client Reply routine + * + * The routine will reply to client data from backend server + * + * @param instance The router instance + * @param router_session The router session + * @param backend_dcb The backend DCB + * @param queue The GWBUF with reply data + */ +static void +clientReply( + ROUTER *instance, + void *router_session, + GWBUF *queue, + DCB *backend_dcb) +{ + DCB *client ; + + client = backend_dcb->session->client; + + ss_dassert(client != NULL); + + SESSION_ROUTE_REPLY(backend_dcb->session, queue); +} + +/** + * Error Handler routine + * + * The routine will handle errors that occurred in backend writes. + * + * @param instance The router instance + * @param router_session The router session + * @param message The error message to reply + * @param backend_dcb The backend DCB + * @param action The action: REPLY, REPLY_AND_CLOSE, NEW_CONNECTION + * + */ +static void handleError( + ROUTER *instance, + void *router_session, + GWBUF *errbuf, + DCB *backend_dcb, + error_action_t action, + bool *succp) + +{ + DCB *client_dcb; + SESSION *session = backend_dcb->session; + session_state_t sesstate; + + /** Reset error handle flag from a given DCB */ + if (action == ERRACT_RESET) + { + backend_dcb->dcb_errhandle_called = false; + return; + } + + /** Don't handle same error twice on same DCB */ + if (backend_dcb->dcb_errhandle_called) + { + /** we optimistically assume that previous call succeed */ + *succp = true; + return; + } + else + { + backend_dcb->dcb_errhandle_called = true; + } + spinlock_acquire(&session->ses_lock); + sesstate = session->state; + client_dcb = session->client; + + if (sesstate == SESSION_STATE_ROUTER_READY) + { + CHK_DCB(client_dcb); + spinlock_release(&session->ses_lock); + client_dcb->func.write(client_dcb, gwbuf_clone(errbuf)); + } + else + { + spinlock_release(&session->ses_lock); + } + + /** false because connection is not available anymore */ + *succp = false; +} + +/** to be inline'd */ +/** + * @node Acquires lock to router client session if it is not closed. + * + * Parameters: + * @param rses - in, use + * + * + * @return true if router session was not closed. If return value is true + * it means that router is locked, and must be unlocked later. False, if + * router was closed before lock was acquired. + * + * + * @details (write detailed description here) + * + */ +static bool rses_begin_locked_router_action( + ROUTER_CLIENT_SES* rses) +{ + bool succp = false; + + CHK_CLIENT_RSES(rses); + + if (rses->rses_closed) { + goto return_succp; + } + spinlock_acquire(&rses->rses_lock); + if (rses->rses_closed) { + spinlock_release(&rses->rses_lock); + goto return_succp; + } + succp = true; + +return_succp: + return succp; +} + +/** to be inline'd */ +/** + * @node Releases router client session lock. + * + * Parameters: + * @param rses - + * + * + * @return void + * + * + * @details (write detailed description here) + * + */ +static void rses_end_locked_router_action( + ROUTER_CLIENT_SES* rses) +{ + CHK_CLIENT_RSES(rses); + spinlock_release(&rses->rses_lock); +} + + +static uint8_t getCapabilities( + ROUTER* inst, + void* router_session) +{ + return 0; +} + +/******************************** + * This routine returns the root master server from MySQL replication tree + * Get the root Master rule: + * + * find server with the lowest replication depth level + * and the SERVER_MASTER bitval + * Servers are checked even if they are in 'maintenance' + * + * @param servers The list of servers + * @return The Master found + * + */ + +static BACKEND *get_root_master(BACKEND **servers) { + int i = 0; + BACKEND *master_host = NULL; + + for (i = 0; servers[i]; i++) { + if (servers[i] && (servers[i]->server->status & (SERVER_MASTER|SERVER_MAINT)) == SERVER_MASTER) { + if (master_host && servers[i]->server->depth < master_host->server->depth) { + master_host = servers[i]; + } else { + if (master_host == NULL) { + master_host = servers[i]; + } + } + } + } + return master_host; +} + +static int handle_state_switch(DCB* dcb,DCB_REASON reason, void * routersession) +{ + ss_dassert(dcb != NULL); + SESSION* session = dcb->session; + ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES*)routersession; + SERVICE* service = session->service; + ROUTER* router = (ROUTER *)service->router; + + switch(reason) + { + case DCB_REASON_CLOSE: + dcb->func.close(dcb); + break; + case DCB_REASON_DRAINED: + /** Do we need to do anything? */ + break; + case DCB_REASON_HIGH_WATER: + /** Do we need to do anything? */ + break; + case DCB_REASON_LOW_WATER: + /** Do we need to do anything? */ + break; + case DCB_REASON_ERROR: + dcb->func.error(dcb); + break; + case DCB_REASON_HUP: + dcb->func.hangup(dcb); + break; + case DCB_REASON_NOT_RESPONDING: + dcb->func.hangup(dcb); + break; + default: + break; + } + + return 0; +} From b11d66148a23f588254e5da40ed8a566831c18bd Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 24 Mar 2015 19:23:37 +0200 Subject: [PATCH 002/275] Updated plain protocol. --- server/modules/include/plainprotocol.h | 260 +++++++++ server/modules/protocol/mongo_backend.c | 736 +++++++----------------- server/modules/protocol/mongo_client.c | 314 +--------- 3 files changed, 485 insertions(+), 825 deletions(-) create mode 100644 server/modules/include/plainprotocol.h diff --git a/server/modules/include/plainprotocol.h b/server/modules/include/plainprotocol.h new file mode 100644 index 000000000..35ecd1cd0 --- /dev/null +++ b/server/modules/include/plainprotocol.h @@ -0,0 +1,260 @@ +#ifndef _MYSQL_PROTOCOL_H +#define _MYSQL_PROTOCOL_H +/* + * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright MariaDB Corporation Ab 2013-2015 + */ + +/* + * Revision History + * + * Date Who Description + * 24-03-2015 Markus Makela Initial implementation + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define GW_MYSQL_VERSION "MaxScale " MAXSCALE_VERSION +#define GW_MYSQL_LOOP_TIMEOUT 300000000 +#define GW_MYSQL_READ 0 +#define GW_MYSQL_WRITE 1 +#define MYSQL_HEADER_LEN 4L + +#define GW_MYSQL_PROTOCOL_VERSION 10 // version is 10 +#define GW_MYSQL_HANDSHAKE_FILLER 0x00 +#define GW_MYSQL_SERVER_CAPABILITIES_BYTE1 0xff +#define GW_MYSQL_SERVER_CAPABILITIES_BYTE2 0xf7 +#define GW_MYSQL_SERVER_LANGUAGE 0x08 +#define GW_MYSQL_MAX_PACKET_LEN 0xffffffL; +#define GW_MYSQL_SCRAMBLE_SIZE 20 +#define GW_SCRAMBLE_LENGTH_323 8 + +#ifndef MYSQL_SCRAMBLE_LEN +# define MYSQL_SCRAMBLE_LEN GW_MYSQL_SCRAMBLE_SIZE +#endif + +#define GW_NOINTR_CALL(A) do { errno = 0; A; } while (errno == EINTR) +#define SMALL_CHUNK 1024 +#define MAX_CHUNK SMALL_CHUNK * 8 * 4 +#define ToHex(Y) (Y>='0'&&Y<='9'?Y-'0':Y-'A'+10) +struct dcb; + +/** Protocol packing macros. */ +#define gw_mysql_set_byte2(__buffer, __int) do { \ + (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ + (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); } while (0) +#define gw_mysql_set_byte3(__buffer, __int) do { \ + (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ + (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); \ + (__buffer)[2]= (uint8_t)(((__int) >> 16) & 0xFF); } while (0) +#define gw_mysql_set_byte4(__buffer, __int) do { \ + (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ + (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); \ + (__buffer)[2]= (uint8_t)(((__int) >> 16) & 0xFF); \ + (__buffer)[3]= (uint8_t)(((__int) >> 24) & 0xFF); } while (0) + +/** Protocol unpacking macros. */ +#define gw_mysql_get_byte2(__buffer) \ + (uint16_t)((__buffer)[0] | \ + ((__buffer)[1] << 8)) +#define gw_mysql_get_byte3(__buffer) \ + (uint32_t)((__buffer)[0] | \ + ((__buffer)[1] << 8) | \ + ((__buffer)[2] << 16)) +#define gw_mysql_get_byte4(__buffer) \ + (uint32_t)((__buffer)[0] | \ + ((__buffer)[1] << 8) | \ + ((__buffer)[2] << 16) | \ + ((__buffer)[3] << 24)) +#define gw_mysql_get_byte8(__buffer) \ + ((uint64_t)(__buffer)[0] | \ + ((uint64_t)(__buffer)[1] << 8) | \ + ((uint64_t)(__buffer)[2] << 16) | \ + ((uint64_t)(__buffer)[3] << 24) | \ + ((uint64_t)(__buffer)[4] << 32) | \ + ((uint64_t)(__buffer)[5] << 40) | \ + ((uint64_t)(__buffer)[6] << 48) | \ + ((uint64_t)(__buffer)[7] << 56)) + +/** MySQL protocol constants */ +typedef enum +{ + GW_MYSQL_CAPABILITIES_NONE= 0, + GW_MYSQL_CAPABILITIES_LONG_PASSWORD= (1 << 0), + GW_MYSQL_CAPABILITIES_FOUND_ROWS= (1 << 1), + GW_MYSQL_CAPABILITIES_LONG_FLAG= (1 << 2), + GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB= (1 << 3), + GW_MYSQL_CAPABILITIES_NO_SCHEMA= (1 << 4), + GW_MYSQL_CAPABILITIES_COMPRESS= (1 << 5), + GW_MYSQL_CAPABILITIES_ODBC= (1 << 6), + GW_MYSQL_CAPABILITIES_LOCAL_FILES= (1 << 7), + GW_MYSQL_CAPABILITIES_IGNORE_SPACE= (1 << 8), + GW_MYSQL_CAPABILITIES_PROTOCOL_41= (1 << 9), + GW_MYSQL_CAPABILITIES_INTERACTIVE= (1 << 10), + GW_MYSQL_CAPABILITIES_SSL= (1 << 11), + GW_MYSQL_CAPABILITIES_IGNORE_SIGPIPE= (1 << 12), + GW_MYSQL_CAPABILITIES_TRANSACTIONS= (1 << 13), + GW_MYSQL_CAPABILITIES_RESERVED= (1 << 14), + GW_MYSQL_CAPABILITIES_SECURE_CONNECTION= (1 << 15), + GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS= (1 << 16), + GW_MYSQL_CAPABILITIES_MULTI_RESULTS= (1 << 17), + GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS= (1 << 18), + GW_MYSQL_CAPABILITIES_PLUGIN_AUTH= (1 << 19), + GW_MYSQL_CAPABILITIES_SSL_VERIFY_SERVER_CERT= (1 << 30), + GW_MYSQL_CAPABILITIES_REMEMBER_OPTIONS= (1 << 31), + GW_MYSQL_CAPABILITIES_CLIENT= (GW_MYSQL_CAPABILITIES_LONG_PASSWORD | + GW_MYSQL_CAPABILITIES_FOUND_ROWS | + GW_MYSQL_CAPABILITIES_LONG_FLAG | + GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB | + GW_MYSQL_CAPABILITIES_LOCAL_FILES | + GW_MYSQL_CAPABILITIES_PLUGIN_AUTH | + GW_MYSQL_CAPABILITIES_TRANSACTIONS | + GW_MYSQL_CAPABILITIES_PROTOCOL_41 | + GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS | + GW_MYSQL_CAPABILITIES_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_SECURE_CONNECTION), + GW_MYSQL_CAPABILITIES_CLIENT_COMPRESS= (GW_MYSQL_CAPABILITIES_LONG_PASSWORD | + GW_MYSQL_CAPABILITIES_FOUND_ROWS | + GW_MYSQL_CAPABILITIES_LONG_FLAG | + GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB | + GW_MYSQL_CAPABILITIES_LOCAL_FILES | + GW_MYSQL_CAPABILITIES_PLUGIN_AUTH | + GW_MYSQL_CAPABILITIES_TRANSACTIONS | + GW_MYSQL_CAPABILITIES_PROTOCOL_41 | + GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS | + GW_MYSQL_CAPABILITIES_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_COMPRESS + ), +} gw_mysql_capabilities_t; + +/** Copy from enum in mariadb-5.5 mysql_com.h */ +typedef enum mysql_server_cmd { + MYSQL_COM_UNDEFINED = -1, + MYSQL_COM_SLEEP = 0, + MYSQL_COM_QUIT, + MYSQL_COM_INIT_DB, + MYSQL_COM_QUERY, + MYSQL_COM_FIELD_LIST, + MYSQL_COM_CREATE_DB, + MYSQL_COM_DROP_DB, + MYSQL_COM_REFRESH, + MYSQL_COM_SHUTDOWN, + MYSQL_COM_STATISTICS, + MYSQL_COM_PROCESS_INFO, + MYSQL_COM_CONNECT, + MYSQL_COM_PROCESS_KILL, + MYSQL_COM_DEBUG, + MYSQL_COM_PING, + MYSQL_COM_TIME, + MYSQL_COM_DELAYED_INSERT, + MYSQL_COM_CHANGE_USER, + MYSQL_COM_BINLOG_DUMP, + MYSQL_COM_TABLE_DUMP, + MYSQL_COM_CONNECT_OUT, + MYSQL_COM_REGISTER_SLAVE, + MYSQL_COM_STMT_PREPARE, + MYSQL_COM_STMT_EXECUTE, + MYSQL_COM_STMT_SEND_LONG_DATA, + MYSQL_COM_STMT_CLOSE, + MYSQL_COM_STMT_RESET, + MYSQL_COM_SET_OPTION, + MYSQL_COM_STMT_FETCH, + MYSQL_COM_DAEMON, + MYSQL_COM_END /*< Must be the last */ +} mysql_server_cmd_t; + +/** + * MySQL Protocol specific state data. + * + * Protocol carries information from client side to backend side, such as + * MySQL session command information and history of earlier session commands. + */ +typedef struct { +#if defined(SS_DEBUG) + skygw_chk_t protocol_chk_top; +#endif + int fd; /*< The socket descriptor */ + struct dcb *owner_dcb; /*< The DCB of the socket + * we are running on */ + SPINLOCK protocol_lock; + uint8_t scramble[MYSQL_SCRAMBLE_LEN]; /*< server scramble, + * created or received */ + uint32_t server_capabilities; /*< server capabilities, + * created or received */ + uint32_t client_capabilities; /*< client capabilities, + * created or received */ + unsigned long tid; /*< MySQL Thread ID, in + * handshake */ + unsigned int charset; /*< MySQL character set at connect time */ +#if defined(SS_DEBUG) + skygw_chk_t protocol_chk_tail; +#endif +} PlainProtocol; + + + +#define MYSQL_GET_COMMAND(payload) (payload[4]) +#define MYSQL_GET_PACKET_NO(payload) (payload[3]) +#define MYSQL_GET_PACKET_LEN(payload) (gw_mysql_get_byte3(payload)) +#define MYSQL_GET_ERRCODE(payload) (gw_mysql_get_byte2(&payload[5])) +#define MYSQL_GET_STMTOK_NPARAM(payload) (gw_mysql_get_byte2(&payload[9])) +#define MYSQL_GET_STMTOK_NATTR(payload) (gw_mysql_get_byte2(&payload[11])) +#define MYSQL_IS_ERROR_PACKET(payload) (MYSQL_GET_COMMAND(payload)==0xff) +#define MYSQL_IS_COM_QUIT(payload) (MYSQL_GET_COMMAND(payload)==0x01) +#define MYSQL_IS_COM_INIT_DB(payload) (MYSQL_GET_COMMAND(payload)==0x02) +#define MYSQL_IS_CHANGE_USER(payload) (MYSQL_GET_COMMAND(payload)==0x11) +#define MYSQL_GET_NATTR(payload) ((int)payload[4]) + +#endif /** _MYSQL_PROTOCOL_H */ + +PlainProtocol* mysql_protocol_init(DCB* dcb, int fd); +void mysql_protocol_done (DCB* dcb); +PlainProtocol *gw_mysql_init(PlainProtocol *data); +int gw_receive_backend_auth(PlainProtocol *protocol); +int gw_decode_mysql_server_handshake(PlainProtocol *protocol, uint8_t *payload); +int gw_read_backend_handshake(PlainProtocol *protocol); +int gw_send_authentication_to_backend( + char *dbname, + char *user, + uint8_t *passwd, + PlainProtocol *protocol); + +int plain_do_connect_to_backend(char *host, int port, int* fd); diff --git a/server/modules/protocol/mongo_backend.c b/server/modules/protocol/mongo_backend.c index 4fe1ff0b8..b52663b6a 100644 --- a/server/modules/protocol/mongo_backend.c +++ b/server/modules/protocol/mongo_backend.c @@ -16,12 +16,14 @@ * Copyright MariaDB Corporation Ab 2013-2014 */ -#include "mysql_client_server_protocol.h" +#include #include #include #include #include +#define PLAIN_BACKEND_SO_SNDBUF (128 * 1024) +#define PLAIN_BACKEND_SO_RCVBUF (128 * 1024) /* * MySQL Protocol module for handling the protocol between the gateway * and the backend MySQL database. @@ -51,7 +53,7 @@ MODULE_INFO info = { MODULE_API_PROTOCOL, MODULE_GA, GWPROTOCOL_VERSION, - "The MySQL to backend server protocol" + "The plain protocol" }; /** Defined in log_manager.cc */ @@ -60,38 +62,32 @@ extern size_t log_ses_count[]; extern __thread log_info_t tls_log_info; static char *version_str = "V2.0.0"; -static int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *in_session); -static int gw_read_backend_event(DCB* dcb); -static int gw_write_backend_event(DCB *dcb); -static int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue); -static int gw_error_backend_event(DCB *dcb); -static int gw_backend_close(DCB *dcb); -static int gw_backend_hangup(DCB *dcb); +static int plain_create_backend_connection(DCB *backend, SERVER *server, SESSION *in_session); +static int plain_read_backend_event(DCB* dcb); +static int plain_write_ready_backend_event(DCB *dcb); +static int plain_write_backend(DCB *dcb, GWBUF *queue); +static int plain_error_backend_event(DCB *dcb); +static int plain_backend_close(DCB *dcb); +static int plain_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 plain_change_user(DCB *backend_dcb, SERVER *server, SESSION *in_session, GWBUF *queue); static GWBUF* process_response_data (DCB* dcb, GWBUF* readbuf, int nbytes_to_process); extern char* create_auth_failed_msg( GWBUF* readbuf, char* hostaddr, uint8_t* sha1); extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db); static bool sescmd_response_complete(DCB* dcb); - -#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 = { - gw_read_backend_event, /* Read - EPOLLIN handler */ - gw_MySQLWrite_backend, /* Write - data from gateway */ - gw_write_backend_event, /* WriteReady - EPOLLOUT handler */ - gw_error_backend_event, /* Error - EPOLLERR handler */ - gw_backend_hangup, /* HangUp - EPOLLHUP handler */ + plain_read_backend_event, /* Read - EPOLLIN handler */ + plain_write_backend, /* Write - data from gateway */ + plain_write_ready_backend_event, /* WriteReady - EPOLLOUT handler */ + plain_error_backend_event, /* Error - EPOLLERR handler */ + plain_backend_hangup, /* HangUp - EPOLLHUP handler */ NULL, /* Accept */ - gw_create_backend_connection, /* Connect */ - gw_backend_close, /* Close */ + plain_create_backend_connection, /* Connect */ + plain_backend_close, /* Close */ NULL, /* Listen */ - gw_change_user, /* Authentication */ + NULL, /* Authentication */ NULL /* Session */ }; @@ -130,43 +126,63 @@ GetModuleObject() } -static MYSQL_session* gw_get_shared_session_auth_info( - DCB* dcb) +/** + * Creates MySQL protocol structure + * + * @param dcb * Must be non-NULL. + * @param fd + * + * @return + * + * + * @details Protocol structure does not have fd because dcb is not + * connected yet. + * + */ +PlainProtocol* plain_protocol_init( + DCB* dcb, + int fd) { - MYSQL_session* auth_info = NULL; - CHK_DCB(dcb); - CHK_SESSION(dcb->session); + PlainProtocol* p; - spinlock_acquire(&dcb->session->ses_lock); + p = (PlainProtocol *) calloc(1, sizeof(PlainProtocol)); + ss_dassert(p != NULL); - if (dcb->session->state != SESSION_STATE_ALLOC) { - auth_info = dcb->session->data; - } else { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "%lu [gw_get_shared_session_auth_info] Couldn't get " - "session authentication info. Session in a wrong state %d.", - pthread_self(), - dcb->session->state))); + if (p == NULL) { + int eno = errno; + errno = 0; + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [mysql_init_protocol] MySQL protocol init failed : " + "memory allocation due error %d, %s.", + pthread_self(), + eno, + strerror(eno)))); + goto return_p; } - spinlock_release(&dcb->session->ses_lock); - return auth_info; + /*< Assign fd with protocol */ + p->fd = fd; + p->owner_dcb = dcb; + +return_p: + return p; } + /** * Backend Read Event for EPOLLIN on the MySQL backend protocol module * @param dcb The backend Descriptor Control Block * @return 1 on operation, 0 for no action */ -static int gw_read_backend_event(DCB *dcb) { - MySQLProtocol *client_protocol = NULL; - MySQLProtocol *backend_protocol = NULL; - MYSQL_session *current_session = NULL; +static int plain_read_backend_event(DCB *dcb) { + PlainProtocol *client_protocol = NULL; + PlainProtocol *backend_protocol = NULL; + int rc = 0; - backend_protocol = (MySQLProtocol *) dcb->protocol; + backend_protocol = (PlainProtocol *) dcb->protocol; CHK_PROTOCOL(backend_protocol); @@ -226,58 +242,12 @@ static int gw_read_backend_event(DCB *dcb) { ss_dassert(read_buffer != NULL || dcb->dcb_readqueue != NULL); } - /** Packet prefix was read earlier */ - if (dcb->dcb_readqueue) - { - if (read_buffer != NULL) - { - read_buffer = gwbuf_append(dcb->dcb_readqueue, read_buffer); - } - else - { - read_buffer = dcb->dcb_readqueue; - } - nbytes_read = gwbuf_length(read_buffer); - - if (nbytes_read < 5) /*< read at least command type */ - { - rc = 0; - LOGIF(LD, (skygw_log_write_flush( - LOGFILE_DEBUG, - "%p [gw_read_backend_event] Read %d bytes " - "from DCB %p, fd %d, session %s. " - "Returning to poll wait.\n", - pthread_self(), - nbytes_read, - dcb, - dcb->fd, - dcb->session))); - goto return_rc; - } - /** There is at least length and command type. */ - else - { - dcb->dcb_readqueue = NULL; - } - } - /** This may be either short prefix of a packet, or the tail of it. */ - else - { - if (nbytes_read < 5) - { - dcb->dcb_readqueue = gwbuf_append(dcb->dcb_readqueue, read_buffer); - rc = 0; - goto return_rc; - } - } - - if (dcb->session->state == SESSION_STATE_ROUTER_READY && dcb->session->client != NULL && dcb->session->client->state == DCB_STATE_POLLING) { client_protocol = SESSION_PROTOCOL(dcb->session, - MySQLProtocol); + PlainProtocol); { gwbuf_set_type(read_buffer, GWBUF_TYPE_MYSQL); @@ -305,9 +275,9 @@ return_with_lock: * @param dcb The descriptor control block * @return 1 in success, 0 in case of failure, */ -static int gw_write_backend_event(DCB *dcb) { +static int plain_write_ready_backend_event(DCB *dcb) { int rc = 0; - MySQLProtocol *backend_protocol = dcb->protocol; + PlainProtocol *backend_protocol = dcb->protocol; /*< * Don't write to backend if backend_dcb is not in poll set anymore. @@ -343,6 +313,138 @@ return_rc: return rc; } + +/** + * plain_do_connect_to_backend + * + * This routine creates socket and connects to a backend server. + * Connect it non-blocking operation. If connect fails, socket is closed. + * + * @param host The host to connect to + * @param port The host TCP/IP port + * @param *fd where connected fd is copied + * @return 0/1 on success and -1 on failure + * If successful, fd has file descriptor to socket which is connected to + * backend server. In failure, fd == -1 and socket is closed. + * + */ +int plain_do_connect_to_backend( + char *host, + int port, + int *fd) +{ + struct sockaddr_in serv_addr; + int rv; + int so = 0; + int bufsize; + + memset(&serv_addr, 0, sizeof serv_addr); + serv_addr.sin_family = AF_INET; + so = socket(AF_INET,SOCK_STREAM,0); + + if (so < 0) { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Establishing connection to backend server " + "%s:%d failed.\n\t\t Socket creation failed " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + rv = -1; + goto return_rv; + } + /* prepare for connect */ + setipaddress(&serv_addr.sin_addr, host); + serv_addr.sin_port = htons(port); + bufsize = PLAIN_BACKEND_SO_SNDBUF; + + if(setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) != 0) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to set socket options " + "%s:%d failed.\n\t\t Socket configuration failed " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + rv = -1; + /** Close socket */ + goto close_so; + } + bufsize = PLAIN_BACKEND_SO_RCVBUF; + + if(setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) != 0) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to set socket options " + "%s:%d failed.\n\t\t Socket configuration failed " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + rv = -1; + /** Close socket */ + goto close_so; + } + + /* set socket to as non-blocking here */ + setnonblocking(so); + rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + + if (rv != 0) + { + if (errno == EINPROGRESS) + { + rv = 1; + } + else + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to connect backend server %s:%d, " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + /** Close socket */ + goto close_so; + } + } + *fd = so; + LOGIF(LD, (skygw_log_write_flush( + LOGFILE_DEBUG, + "%lu [plain_do_connect_to_backend] Connected to backend server " + "%s:%d, fd %d.", + pthread_self(), + host, + port, + so))); + +return_rv: + return rv; + +close_so: + /*< Close newly created socket. */ + if (close(so) != 0) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to " + "close socket %d due %d, %s.", + so, + errno, + strerror(errno)))); + } + goto return_rv; +} + /* * Write function for backend DCB. Store command to protocol. * @@ -351,15 +453,13 @@ return_rc: * @return 0 on failure, 1 on success */ static int -gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue) +plain_write_backend(DCB *dcb, GWBUF *queue) { - MySQLProtocol *backend_protocol = dcb->protocol; + PlainProtocol *backend_protocol = dcb->protocol; int rc = 0; rc = dcb_write(dcb, queue); - -return_rc: return rc; } @@ -370,7 +470,7 @@ return_rc: * closed and call DCB close function which triggers closing router session * and related backends (if any exists. */ -static int gw_error_backend_event(DCB *dcb) +static int plain_error_backend_event(DCB *dcb) { SESSION* session; void* rsession; @@ -414,11 +514,7 @@ static int gw_error_backend_event(DCB *dcb) } return 1; } - errbuf = mysql_create_custom_error( - 1, - 0, - "Lost connection to backend server."); - + spinlock_acquire(&session->ses_lock); ses_state = session->state; spinlock_release(&session->ses_lock); @@ -501,12 +597,12 @@ retblock: * backend server. Positive fd is copied to protocol and to dcb. * If fails, fd == -1 and socket is closed. */ -static int gw_create_backend_connection( +static int plain_create_backend_connection( DCB *backend_dcb, SERVER *server, SESSION *session) { - MySQLProtocol *protocol = NULL; + PlainProtocol *protocol = NULL; int rv = -1; int fd = -1; @@ -527,7 +623,8 @@ static int gw_create_backend_connection( } /*< if succeed, fd > 0, -1 otherwise */ - rv = gw_do_connect_to_backend(server->name, server->port, &fd); + + rv = plain_do_connect_to_backend(server->name, server->port, &fd); /*< Assign protocol with backend_dcb */ backend_dcb->protocol = protocol; @@ -536,7 +633,7 @@ static int gw_create_backend_connection( case 0: ss_dassert(fd > 0); protocol->fd = fd; - protocol->protocol_auth_state = MYSQL_CONNECTED; + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_create_backend_connection] Established " @@ -551,7 +648,7 @@ static int gw_create_backend_connection( case 1: ss_dassert(fd > 0); - protocol->protocol_auth_state = MYSQL_PENDING_CONNECT; + protocol->fd = fd; LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, @@ -566,7 +663,7 @@ static int gw_create_backend_connection( default: ss_dassert(fd == -1); - ss_dassert(protocol->protocol_auth_state == MYSQL_ALLOC); + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_create_backend_connection] Connection " @@ -595,7 +692,7 @@ return_fd: * @return 1 always */ static int -gw_backend_hangup(DCB *dcb) +plain_backend_hangup(DCB *dcb) { SESSION* session; void* rsession; @@ -612,12 +709,7 @@ gw_backend_hangup(DCB *dcb) rsession = session->router_session; router = session->service->router; router_instance = session->service->router_instance; - - errbuf = mysql_create_custom_error( - 1, - 0, - "Lost connection to backend server."); - + spinlock_acquire(&session->ses_lock); ses_state = session->state; spinlock_release(&session->ses_lock); @@ -695,7 +787,7 @@ retblock: * @return 1 always */ static int -gw_backend_close(DCB *dcb) +plain_backend_close(DCB *dcb) { DCB* client_dcb; SESSION* session; @@ -705,17 +797,6 @@ gw_backend_close(DCB *dcb) session = dcb->session; CHK_SESSION(session); - LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG, - "%lu [gw_backend_close]", - pthread_self()))); - - quitbuf = mysql_create_com_quit(NULL, 0); - gwbuf_set_type(quitbuf, GWBUF_TYPE_MYSQL); - - /** Send COM_QUIT to the backend being closed */ - mysql_send_com_quit(dcb, 0, quitbuf); - - mysql_protocol_done(dcb); /** * The lock is needed only to protect the read of session->state and * session->client values. Client's state may change by other thread @@ -796,409 +877,18 @@ static int backend_write_delayqueue(DCB *dcb) } else { - localq = dcb->delayq; - dcb->delayq = NULL; - spinlock_release(&dcb->delayqlock); - - if (MYSQL_IS_CHANGE_USER(((uint8_t *)GWBUF_DATA(localq)))) - { - MYSQL_session* mses; - GWBUF* new_packet; - - mses = (MYSQL_session *)dcb->session->client->data; - new_packet = gw_create_change_user_packet( - mses, - (MySQLProtocol *)dcb->protocol); - /** - * Remove previous packet which lacks scramble - * and append the new. - */ - localq = gwbuf_consume(localq, GWBUF_LENGTH(localq)); - localq = gwbuf_append(localq, new_packet); - } + rc = dcb_write(dcb, localq); } if (rc == 0) { - GWBUF* errbuf; - bool succp; - ROUTER_OBJECT *router = NULL; - ROUTER *router_instance = NULL; - void *rsession = NULL; - SESSION *session = dcb->session; - - CHK_SESSION(session); - - if (session != NULL) - { - router = session->service->router; - router_instance = session->service->router_instance; - rsession = session->router_session; #if defined(SS_DEBUG) LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Backend write delayqueue error handling."))); #endif - errbuf = mysql_create_custom_error( - 1, - 0, - "Failed to write buffered data to back-end server. " - "Buffer was empty or back-end was disconnected during " - "operation. Attempting to find a new backend."); - - router->handleError(router_instance, - rsession, - errbuf, - dcb, - ERRACT_NEW_CONNECTION, - &succp); - gwbuf_free(errbuf); - - if (!succp) - { - spinlock_acquire(&session->ses_lock); - session->state = SESSION_STATE_STOPPING; - spinlock_release(&session->ses_lock); - ss_dassert(dcb->dcb_errhandle_called); - dcb_close(dcb); - } - } + } return rc; } - -/** - * This routine handles the COM_CHANGE_USER command - * - * @param dcb The current backend DCB - * @param server The backend server pointer - * @param in_session The current session data (MYSQL_session) - * @param queue The GWBUF containing the COM_CHANGE_USER receveid - * @return 1 on success and 0 on failure - */ -static int gw_change_user( - DCB *backend, - SERVER *server, - SESSION *in_session, - GWBUF *queue) -{ - MYSQL_session *current_session = NULL; - MySQLProtocol *backend_protocol = NULL; - MySQLProtocol *client_protocol = NULL; - char username[MYSQL_USER_MAXLEN+1]=""; - char database[MYSQL_DATABASE_MAXLEN+1]=""; - char current_database[MYSQL_DATABASE_MAXLEN+1]=""; - uint8_t client_sha1[MYSQL_SCRAMBLE_LEN]=""; - uint8_t *client_auth_packet = GWBUF_DATA(queue); - unsigned int auth_token_len = 0; - uint8_t *auth_token = NULL; - int rv = -1; - int auth_ret = 1; - - current_session = (MYSQL_session *)in_session->client->data; - backend_protocol = backend->protocol; - client_protocol = in_session->client->protocol; - - /* now get the user, after 4 bytes header and 1 byte command */ - client_auth_packet += 5; - strncpy(username, (char *)client_auth_packet,MYSQL_USER_MAXLEN); - client_auth_packet += strlen(username) + 1; - - /* get the auth token len */ - memcpy(&auth_token_len, client_auth_packet, 1); - - client_auth_packet++; - - /* allocate memory for token only if auth_token_len > 0 */ - if (auth_token_len > 0) { - auth_token = (uint8_t *)malloc(auth_token_len); - ss_dassert(auth_token != NULL); - - if (auth_token == NULL) - return rv; - memcpy(auth_token, client_auth_packet, auth_token_len); - client_auth_packet += auth_token_len; - } - - /* get new database name */ - strncpy(database, (char *)client_auth_packet,MYSQL_DATABASE_MAXLEN); - - /* get character set */ - if (strlen(database)) { - client_auth_packet += strlen(database) + 1; - } else { - client_auth_packet++; - } - - if (client_auth_packet && *client_auth_packet) - memcpy(&backend_protocol->charset, client_auth_packet, sizeof(int)); - - /* save current_database name */ - strncpy(current_database, current_session->db,MYSQL_DATABASE_MAXLEN); - - /* - * Now clear database name in dcb as we don't do local authentication on db name for change user. - * Local authentication only for user@host and if successful the database name change is sent to backend. - */ - strcpy(current_session->db, ""); - - /* - * decode the token and check the password. - * Note: if auth_token_len == 0 && auth_token == NULL, user is without password - */ - auth_ret = gw_check_mysql_scramble_data(backend->session->client, - auth_token, - auth_token_len, - client_protocol->scramble, - sizeof(client_protocol->scramble), - username, - client_sha1); - - if (auth_ret != 0) { - if (!service_refresh_users(backend->session->client->service)) { - /* Try authentication again with new repository data */ - /* Note: if no auth client authentication will fail */ - auth_ret = gw_check_mysql_scramble_data( - backend->session->client, - auth_token, auth_token_len, - client_protocol->scramble, - sizeof(client_protocol->scramble), - username, - client_sha1); - } - } - - /* copy back current datbase to client session */ - strcpy(current_session->db, current_database); - - /* let's free the auth_token now */ - if (auth_token) - free(auth_token); - - if (auth_ret != 0) { - char *password_set = NULL; - char *message = NULL; - GWBUF* buf; - - if (auth_token_len > 0) - password_set = (char *)client_sha1; - else - password_set = ""; - - /** - * Create an error message and make it look like legit reply - * from backend server. Then make it look like an incoming event - * so that thread gets new task of it, calls clientReply - * which filters out duplicate errors from same cause and forward - * reply to the client. - */ - message = create_auth_fail_str(username, - backend->session->client->remote, - password_set, - ""); - if (message == NULL) - { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Creating error message failed."))); - rv = 0; - goto retblock; - } - /** - * Add command to backend's protocol, create artificial reply - * packet and add it to client's read buffer. - */ - protocol_add_srv_command((MySQLProtocol*)backend->protocol, - MYSQL_COM_CHANGE_USER); - modutil_reply_auth_error(backend, message, 0); - rv = 1; - } else { - rv = gw_send_change_user_to_backend(database, username, client_sha1, backend_protocol); - /* - * Now copy new data into user session - */ - strcpy(current_session->user, username); - strcpy(current_session->db, database); - memcpy(current_session->client_sha1, client_sha1, sizeof(current_session->client_sha1)); - } - -retblock: - gwbuf_free(queue); - - return rv; -} - - -/** - * Move packets or parts of packets from readbuf to outbuf as the packet headers - * and lengths have been noticed and counted. - * Session commands need to be marked so that they can be handled properly in - * the router's clientReply. - * - * @param dcb Backend's DCB where data was read from - * @param readbuf GWBUF where data was read to - * @param nbytes_to_process Number of bytes that has been read and need to be processed - * - * @return GWBUF which includes complete MySQL packet - */ -static GWBUF* process_response_data ( - DCB* dcb, - GWBUF* readbuf, - int nbytes_to_process) -{ - int npackets_left = 0; /*< response's packet count */ - ssize_t nbytes_left = 0; /*< nbytes to be read for the packet */ - MySQLProtocol* p; - GWBUF* outbuf = NULL; - - /** Get command which was stored in gw_MySQLWrite_backend */ - p = DCB_PROTOCOL(dcb, MySQLProtocol); - if (!DCB_IS_CLONE(dcb)) CHK_PROTOCOL(p); - - /** All buffers processed here are sescmd responses */ - gwbuf_set_type(readbuf, GWBUF_TYPE_SESCMD_RESPONSE); - - /** - * Now it is known how many packets there should be and how much - * is read earlier. - */ - while (nbytes_to_process != 0) - { - mysql_server_cmd_t srvcmd; - bool succp; - - srvcmd = protocol_get_srv_command(p, false); - - LOGIF(LD, (skygw_log_write( - LOGFILE_DEBUG, - "%lu [process_response_data] Read command %s for DCB %p fd %d.", - pthread_self(), - STRPACKETTYPE(srvcmd), - dcb, - dcb->fd))); - /** - * Read values from protocol structure, fails if values are - * uninitialized. - */ - if (npackets_left == 0) - { - succp = protocol_get_response_status(p, &npackets_left, &nbytes_left); - - if (!succp || npackets_left == 0) - { - /** - * Examine command type and the readbuf. Conclude response - * packet count from the command type or from the first - * packet content. Fails if read buffer doesn't include - * enough data to read the packet length. - */ - init_response_status(readbuf, srvcmd, &npackets_left, &nbytes_left); - } - } - /** Only session commands with responses should be processed */ - ss_dassert(npackets_left > 0); - - /** Read incomplete packet. */ - if (nbytes_left > nbytes_to_process) - { - /** Includes length info so it can be processed */ - if (nbytes_to_process >= 5) - { - /** discard source buffer */ - readbuf = gwbuf_consume(readbuf, GWBUF_LENGTH(readbuf)); - nbytes_left -= nbytes_to_process; - } - nbytes_to_process = 0; - } - /** Packet was read. All bytes belonged to the last packet. */ - else if (nbytes_left == nbytes_to_process) - { - nbytes_left = 0; - nbytes_to_process = 0; - ss_dassert(npackets_left > 0); - npackets_left -= 1; - outbuf = gwbuf_append(outbuf, readbuf); - readbuf = NULL; - } - /** - * Packet was read. There should be more since bytes were - * left over. - * Move the next packet to its own buffer and add that next - * to the prev packet's buffer. - */ - else /*< nbytes_left < nbytes_to_process */ - { - ss_dassert(nbytes_left >= 0); - nbytes_to_process -= nbytes_left; - - /** Move the prefix of the buffer to outbuf from redbuf */ - outbuf = gwbuf_append(outbuf, - gwbuf_clone_portion(readbuf, 0, (size_t)nbytes_left)); - readbuf = gwbuf_consume(readbuf, (size_t)nbytes_left); - ss_dassert(npackets_left > 0); - npackets_left -= 1; - nbytes_left = 0; - } - - /** Store new status to protocol structure */ - protocol_set_response_status(p, npackets_left, nbytes_left); - - /** A complete packet was read */ - if (nbytes_left == 0) - { - /** No more packets in this response */ - if (npackets_left == 0 && outbuf != NULL) - { - GWBUF* b = outbuf; - - while (b->next != NULL) - { - b = b->next; - } - /** Mark last as end of response */ - gwbuf_set_type(b, GWBUF_TYPE_RESPONSE_END); - - /** Archive the command */ - protocol_archive_srv_command(p); - } - /** Read next packet */ - else - { - uint8_t* data; - - /** Read next packet length */ - data = GWBUF_DATA(readbuf); - nbytes_left = MYSQL_GET_PACKET_LEN(data)+MYSQL_HEADER_LEN; - /** Store new status to protocol structure */ - protocol_set_response_status(p, npackets_left, nbytes_left); - } - } - } - return outbuf; -} - - -static bool sescmd_response_complete( - DCB* dcb) -{ - int npackets_left; - ssize_t nbytes_left; - MySQLProtocol* p; - bool succp; - - p = DCB_PROTOCOL(dcb, MySQLProtocol); - if (!DCB_IS_CLONE(dcb)) CHK_PROTOCOL(p); - - protocol_get_response_status(p, &npackets_left, &nbytes_left); - - if (npackets_left == 0) - { - succp = true; - } - else - { - succp = false; - } - return succp; -} diff --git a/server/modules/protocol/mongo_client.c b/server/modules/protocol/mongo_client.c index 1de7d237d..450634e12 100644 --- a/server/modules/protocol/mongo_client.c +++ b/server/modules/protocol/mongo_client.c @@ -30,14 +30,13 @@ #include #include #include - -#include +#include MODULE_INFO info = { MODULE_API_PROTOCOL, MODULE_GA, GWPROTOCOL_VERSION, - "The client to plain protocol implementation" + "The plain client protocol" }; /** Defined in log_manager.cc */ @@ -107,201 +106,6 @@ GetModuleObject() return &MyObject; } -/** - * mysql_send_ok - * - * Send a MySQL protocol OK message to the dcb (client) - * - * @param dcb Descriptor Control Block for the connection to which the OK is sent - * @param packet_number - * @param in_affected_rows - * @param mysql_message - * @return packet length - * - */ -int -mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) { - return 1; -} - -/** - * MySQLSendHandshake - * - * @param dcb The descriptor control block to use for sending the handshake request - * @return The packet length sent - */ -int -MySQLSendHandshake(DCB* dcb) -{ - return 1; -} - -/** - * gw_mysql_do_authentication - * - * Performs the MySQL protocol 4.1 authentication, using data in GWBUF *queue - * - * (MYSQL_session*)client_data including: user, db, client_sha1 are copied into - * the dcb->data and later to dcb->session->data. - * - * client_capabilitiesa are copied into the dcb->protocol - * - * @param dcb Descriptor Control Block of the client - * @param queue The GWBUF with data from client - * @return 0 If succeed, otherwise non-zero value - * - * @note in case of failure, dcb->data is freed before returning. If succeed, - * dcb->data is freed in session.c:session_free. - */ -static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { - MySQLProtocol *protocol = NULL; - /* int compress = -1; */ - int connect_with_db = -1; - uint8_t *client_auth_packet = GWBUF_DATA(queue); - int client_auth_packet_size = 0; - char *username = NULL; - char *database = NULL; - unsigned int auth_token_len = 0; - uint8_t *auth_token = NULL; - uint8_t *stage1_hash = NULL; - int auth_ret = -1; - MYSQL_session *client_data = NULL; - - CHK_DCB(dcb); - - protocol = DCB_PROTOCOL(dcb, MySQLProtocol); - CHK_PROTOCOL(protocol); - client_data = (MYSQL_session *)calloc(1, sizeof(MYSQL_session)); -#if defined(SS_DEBUG) - client_data->myses_chk_top = CHK_NUM_MYSQLSES; - client_data->myses_chk_tail = CHK_NUM_MYSQLSES; -#endif - /** - * Assign authentication structure with client DCB. - */ - dcb->data = client_data; - - stage1_hash = client_data->client_sha1; - username = client_data->user; - - client_auth_packet_size = gwbuf_length(queue); - - /* For clients supporting CLIENT_PROTOCOL_41 - * the Handshake Response Packet is: - * - * 4 bytes mysql protocol heade - * 4 bytes capability flags - * 4 max-packet size - * 1 byte character set - * string[23] reserved (all [0]) - * ... - * ... - */ - - /* Detect now if there are enough bytes to continue */ - if (client_auth_packet_size < (4 + 4 + 4 + 1 + 23)) - { - return 1; - } - - memcpy(&protocol->client_capabilities, client_auth_packet + 4, 4); - - connect_with_db = - GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB & gw_mysql_get_byte4( - (uint32_t *)&protocol->client_capabilities); - /* - compress = - GW_MYSQL_CAPABILITIES_COMPRESS & gw_mysql_get_byte4( - &protocol->client_capabilities); - */ - - username = get_username_from_auth(username, client_auth_packet); - - if (username == NULL) - { - return 1; - } - - /* get charset */ - memcpy(&protocol->charset, client_auth_packet + 4 + 4 + 4, sizeof (int)); - - /* get the auth token len */ - memcpy(&auth_token_len, - client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1, - 1); - - /* - * Note: some clients may pass empty database, connect_with_db !=0 but database ="" - */ - if (connect_with_db) { - database = client_data->db; - strncpy(database, - (char *)(client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + - 1 + 1 + auth_token_len), MYSQL_DATABASE_MAXLEN); - } - - /* allocate memory for token only if auth_token_len > 0 */ - if (auth_token_len) { - auth_token = (uint8_t *)malloc(auth_token_len); - memcpy(auth_token, - client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1 + 1, - auth_token_len); - } - - /* - * Decode the token and check the password - * Note: if auth_token_len == 0 && auth_token == NULL, user is without password - */ - - auth_ret = gw_check_mysql_scramble_data(dcb, - auth_token, - auth_token_len, - protocol->scramble, - sizeof(protocol->scramble), - username, - stage1_hash); - - /* check for database name match in resource hashtable */ - auth_ret = check_db_name_after_auth(dcb, database, auth_ret); - - /* On failed auth try to load users' table from backend database */ - if (auth_ret != 0) { - if (!service_refresh_users(dcb->service)) { - /* Try authentication again with new repository data */ - /* Note: if no auth client authentication will fail */ - auth_ret = gw_check_mysql_scramble_data( - dcb, - auth_token, - auth_token_len, - protocol->scramble, - sizeof(protocol->scramble), - username, - stage1_hash); - } - else - { - LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE, - "%s: login attempt for user %s, user not " - "found.", - dcb->service->name, username))); - } - } - - /* Do again the database check */ - auth_ret = check_db_name_after_auth(dcb, database, auth_ret); - - /* on succesful auth set user into dcb field */ - if (auth_ret == 0) { - dcb->user = strdup(client_data->user); - } - - /* let's free the auth_token now */ - if (auth_token) { - free(auth_token); - } - - return auth_ret; -} /** * Write function for client DCB: writes data from MaxScale to Client @@ -328,7 +132,7 @@ int plain_read( ROUTER_OBJECT *router = NULL; ROUTER *router_instance = NULL; void *rsession = NULL; - MySQLProtocol *protocol = NULL; + PlainProtocol *protocol = NULL; GWBUF *read_buffer = NULL; int rc = 0; int nbytes_read = 0; @@ -336,7 +140,7 @@ int plain_read( bool stmt_input = false; /*< router input type */ CHK_DCB(dcb); - protocol = DCB_PROTOCOL(dcb, MySQLProtocol); + protocol = DCB_PROTOCOL(dcb, PlainProtocol); CHK_PROTOCOL(protocol); rc = dcb_read(dcb, &read_buffer); @@ -383,7 +187,7 @@ return_rc: */ int plain_write_ready(DCB *dcb) { - MySQLProtocol *protocol = NULL; + PlainProtocol *protocol = NULL; CHK_DCB(dcb); @@ -400,7 +204,7 @@ int plain_write_ready(DCB *dcb) if (dcb->protocol == NULL) { goto return_1; } - protocol = (MySQLProtocol *)dcb->protocol; + protocol = (PlainProtocol *)dcb->protocol; dcb_drain_writeq(dcb); @@ -575,7 +379,7 @@ int plain_accept(DCB *listener) { int rc = 0; DCB *client_dcb; - MySQLProtocol *protocol; + PlainProtocol *protocol; int c_sock; struct sockaddr client_conn; socklen_t client_len = sizeof(struct sockaddr_storage); @@ -591,24 +395,12 @@ int plain_accept(DCB *listener) retry_accept: -#if defined(FAKE_CODE) - if (fail_next_accept > 0) - { - c_sock = -1; - eno = fail_accept_errno; - fail_next_accept -= 1; - } else { - fail_accept_errno = 0; -#endif /* FAKE_CODE */ // new connection from client c_sock = accept(listener->fd, (struct sockaddr *) &client_conn, &client_len); eno = errno; errno = 0; -#if defined(FAKE_CODE) - } -#endif /* FAKE_CODE */ if (c_sock == -1) { @@ -687,9 +479,7 @@ int plain_accept(DCB *listener) pthread_self(), c_sock))); #endif /* SS_DEBUG */ -#if defined(FAKE_CODE) - conn_open[c_sock] = true; -#endif /* FAKE_CODE */ + /* set nonblocking */ sendbuf = GW_CLIENT_SO_SNDBUF; @@ -762,9 +552,7 @@ int plain_accept(DCB *listener) // assign function poiters to "func" field memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); - // client protocol state change - protocol->protocol_auth_state = MYSQL_IDLE; - + /** * Set new descriptor to event set. At the same time, * change state to DCB_STATE_POLLING so that @@ -773,12 +561,7 @@ int plain_accept(DCB *listener) if (poll_add_dcb(client_dcb) == -1) { /* Send a custom error as MySQL command reply */ - mysql_send_custom_error( - client_dcb, - 1, - 0, - "MaxScale internal error."); - + /** close client_dcb */ dcb_close(client_dcb); @@ -807,7 +590,7 @@ int plain_accept(DCB *listener) #if defined(SS_DEBUG) if (rc == 0) { CHK_DCB(client_dcb); - CHK_PROTOCOL(((MySQLProtocol *)client_dcb->protocol)); + CHK_PROTOCOL(((PlainProtocol *)client_dcb->protocol)); } #endif return_rc: @@ -851,7 +634,7 @@ plain_client_close(DCB *dcb) ROUTER_OBJECT* router; void* router_instance; #if defined(SS_DEBUG) - MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol; + PlainProtocol* protocol = (PlainProtocol *)dcb->protocol; if (dcb->state == DCB_STATE_POLLING || dcb->state == DCB_STATE_NOPOLLING || dcb->state == DCB_STATE_ZOMBIE) @@ -929,76 +712,3 @@ retblock: return 1; } - -/** - * Detect if buffer includes partial mysql packet or multiple packets. - * Store partial packet to dcb_readqueue. Send complete packets one by one - * to router. - * - * It is assumed readbuf includes at least one complete packet. - * Return 1 in success. If the last packet is incomplete return success but - * leave incomplete packet to readbuf. - * - * @param session Session pointer - * @param p_readbuf Pointer to the address of GWBUF including the query - * - * @return 1 if succeed, - */ -static int route_by_statement( - SESSION* session, - GWBUF** p_readbuf) -{ - int rc; - GWBUF* packetbuf; -#if defined(SS_DEBUG) - GWBUF* tmpbuf; - - tmpbuf = *p_readbuf; - while (tmpbuf != NULL) - { - ss_dassert(GWBUF_IS_TYPE_MYSQL(tmpbuf)); - tmpbuf=tmpbuf->next; - } -#endif - do - { - ss_dassert(GWBUF_IS_TYPE_MYSQL((*p_readbuf))); - - /** - * Collect incoming bytes to a buffer until complete packet has - * arrived and then return the buffer. - */ - packetbuf = gw_MySQL_get_next_packet(p_readbuf); - - if (packetbuf != NULL) - { - CHK_GWBUF(packetbuf); - ss_dassert(GWBUF_IS_TYPE_MYSQL(packetbuf)); - /** - * This means that buffer includes exactly one MySQL - * statement. - * backend func.write uses the information. MySQL backend - * protocol, for example, stores the command identifier - * to protocol structure. When some other thread reads - * the corresponding response the command tells how to - * handle response. - * - * Set it here instead of plain_read to make - * sure it is set to each (MySQL) packet. - */ - gwbuf_set_type(packetbuf, GWBUF_TYPE_SINGLE_STMT); - /** Route query */ - rc = SESSION_ROUTE_QUERY(session, packetbuf); - } - else - { - rc = 1; - goto return_rc; - } - } - while (rc == 1 && *p_readbuf != NULL); - -return_rc: - return rc; -} - From c3cb8df8a03705477dd8f31d20a7db161fe4951c Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 31 Mar 2015 15:12:50 +0300 Subject: [PATCH 003/275] Renamed mongo protocol to plain protocol. --- server/modules/protocol/{mongo_backend.c => plainbackend.c} | 0 server/modules/protocol/{mongo_client.c => plainclient.c} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename server/modules/protocol/{mongo_backend.c => plainbackend.c} (100%) rename server/modules/protocol/{mongo_client.c => plainclient.c} (100%) diff --git a/server/modules/protocol/mongo_backend.c b/server/modules/protocol/plainbackend.c similarity index 100% rename from server/modules/protocol/mongo_backend.c rename to server/modules/protocol/plainbackend.c diff --git a/server/modules/protocol/mongo_client.c b/server/modules/protocol/plainclient.c similarity index 100% rename from server/modules/protocol/mongo_client.c rename to server/modules/protocol/plainclient.c From 341c04aa483a6d2bd92558f161cd8a5857bfcc98 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 31 Mar 2015 17:27:25 +0300 Subject: [PATCH 004/275] First tests. --- server/modules/monitor/CMakeLists.txt | 2 +- server/modules/monitor/mon_exec.c | 38 ++++++++++++++++++++++++++ server/modules/monitor/mon_exec.h | 13 +++++++++ server/modules/monitor/mysql_mon.c | 14 +++++++++- server/modules/monitor/mysqlmon.h | 1 + server/modules/protocol/CMakeLists.txt | 12 ++++---- 6 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 server/modules/monitor/mon_exec.c create mode 100644 server/modules/monitor/mon_exec.h diff --git a/server/modules/monitor/CMakeLists.txt b/server/modules/monitor/CMakeLists.txt index a99a66142..3d3f83580 100644 --- a/server/modules/monitor/CMakeLists.txt +++ b/server/modules/monitor/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(mysqlmon SHARED mysql_mon.c) +add_library(mysqlmon SHARED mysql_mon.c mon_exec.c) target_link_libraries(mysqlmon log_manager utils) install(TARGETS mysqlmon DESTINATION modules) diff --git a/server/modules/monitor/mon_exec.c b/server/modules/monitor/mon_exec.c new file mode 100644 index 000000000..122390da9 --- /dev/null +++ b/server/modules/monitor/mon_exec.c @@ -0,0 +1,38 @@ +#include + +/** Defined in log_manager.cc */ +extern int lm_enabled_logfiles_bitmask; +extern size_t log_ses_count[]; +extern __thread log_info_t tls_log_info; + +/** + *Execute a command in a separate process. + *@param cmd Command to execute + *@return 0 on success, -1 on error. + */ +int monitor_exec_cmd(char* cmd) +{ + int rval = 0; + pid_t pid; + + pid = fork(); + + if(pid < 0) + { + skygw_log_write(LOGFILE_ERROR,"Error: Failed to execute command '%s', fork failed: [%d] %s", + cmd,errno,strerror(errno)); + rval = -1; + } + else if(pid == 0) + { + /** Child process, execute command */ + execl(cmd,cmd,NULL); + } + else + { + LOGIF(LD,skygw_log_write(LD,"[monitor_exec_cmd] Forked child process %d : %s.",pid,cmd)); + } + + return rval; + +} diff --git a/server/modules/monitor/mon_exec.h b/server/modules/monitor/mon_exec.h new file mode 100644 index 000000000..ed277ab3e --- /dev/null +++ b/server/modules/monitor/mon_exec.h @@ -0,0 +1,13 @@ +#ifndef MON_EXEC_HG +#define MON_EXEC_HG + +#include +#include +#include +#include +#include +#include + +int monitor_exec_cmd(char* cmd); + +#endif diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 9945086fb..51720c225 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -64,6 +64,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -184,6 +185,7 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt; handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT; handle->read_timeout=DEFAULT_READ_TIMEOUT; handle->write_timeout=DEFAULT_WRITE_TIMEOUT; + handle->script = NULL; spinlock_init(&handle->lock); } @@ -193,6 +195,8 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt; handle->detectStaleMaster = config_truth_value(params->value); else if(!strcmp(params->name,"detect_replication_lag")) handle->replicationHeartbeat = config_truth_value(params->value); + else if(!strcmp(params->name,"script")) + handle->script = strdup(params->value); params = params->next; } @@ -696,7 +700,15 @@ int log_no_master = 1; !(SERVER_IS_IN_CLUSTER(ptr->server))) { dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING); - } + } + +/* + if(handle->script) + { + if(monitor_exec_cmd(handle->script)) + skygw_log_write(LOGFILE_ERROR,"Error: Failed to execute command '%s' on server state change.",handle->script); + } +*/ } if (mon_status_changed(ptr)) diff --git a/server/modules/monitor/mysqlmon.h b/server/modules/monitor/mysqlmon.h index a7d7fb419..3b5658a5a 100644 --- a/server/modules/monitor/mysqlmon.h +++ b/server/modules/monitor/mysqlmon.h @@ -77,6 +77,7 @@ typedef struct { int write_timeout; /**< Timeout in seconds for each attempt to write to the server. * There are retries and the total effective timeout value is two times the option value. */ + char *script;0 } MYSQL_MONITOR; #define MONITOR_RUNNING 1 diff --git a/server/modules/protocol/CMakeLists.txt b/server/modules/protocol/CMakeLists.txt index 0bea95832..7d118c3ec 100644 --- a/server/modules/protocol/CMakeLists.txt +++ b/server/modules/protocol/CMakeLists.txt @@ -6,13 +6,13 @@ add_library(MySQLBackend SHARED mysql_backend.c mysql_common.c) target_link_libraries(MySQLBackend log_manager utils) install(TARGETS MySQLBackend DESTINATION modules) -add_library(mongoclient SHARED mongo_client.c mysql_common.c) -target_link_libraries(mongoclient log_manager utils) -install(TARGETS mongoclient DESTINATION modules) +add_library(plainclient SHARED plainclient.c mysql_common.c) +target_link_libraries(plainclient log_manager utils) +install(TARGETS plainclient DESTINATION modules) -add_library(mongobackend SHARED mongo_backend.c mysql_common.c) -target_link_libraries(mongobackend log_manager utils) -install(TARGETS mongobackend DESTINATION modules) +add_library(plainbackend SHARED plainbackend.c mysql_common.c) +target_link_libraries(plainbackend log_manager utils) +install(TARGETS plainbackend DESTINATION modules) add_library(telnetd SHARED telnetd.c) From 15164224587231a27afadb0f26441fc32581f864 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 7 Apr 2015 04:35:32 +0300 Subject: [PATCH 005/275] A script can now be called in mysql_mon when a master server loses master status. --- server/modules/monitor/mysql_mon.c | 34 ++++++++++++++++++++---------- server/modules/monitor/mysqlmon.h | 3 ++- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 51720c225..0e035d98e 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -22,7 +22,7 @@ * @verbatim * Revision History * - * Date Who Description + * Date Who Demaster_down_scription * 08/07/13 Mark Riddoch Initial implementation * 11/07/13 Mark Riddoch Addition of code to check replication * status @@ -185,7 +185,7 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt; handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT; handle->read_timeout=DEFAULT_READ_TIMEOUT; handle->write_timeout=DEFAULT_WRITE_TIMEOUT; - handle->script = NULL; + handle->master_down_script = NULL; spinlock_init(&handle->lock); } @@ -195,8 +195,18 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt; handle->detectStaleMaster = config_truth_value(params->value); else if(!strcmp(params->name,"detect_replication_lag")) handle->replicationHeartbeat = config_truth_value(params->value); - else if(!strcmp(params->name,"script")) - handle->script = strdup(params->value); + else if(!strcmp(params->name,"master_down_script")) + { + if(access(params->value,F_OK) == 0) + { + handle->master_down_script = strdup(params->value); + handle->master_down_script_called = 0; + } + else + { + skygw_log_write(LOGFILE_ERROR,"Error: could not find master_down_script file: %s",params->value); + } + } params = params->next; } @@ -688,6 +698,11 @@ int log_no_master = 1; "Server %s:%d lost the master status.", ptr->server->name, ptr->server->port))); + if(handle->master_down_script) + { + if(monitor_exec_cmd(handle->master_down_script)) + skygw_log_write(LOGFILE_ERROR,"Error: Failed to execute command '%s' on server state change.",handle->master_down_script); + } } /** * Here we say: If the server's state changed @@ -700,15 +715,12 @@ int log_no_master = 1; !(SERVER_IS_IN_CLUSTER(ptr->server))) { dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING); + } -/* - if(handle->script) - { - if(monitor_exec_cmd(handle->script)) - skygw_log_write(LOGFILE_ERROR,"Error: Failed to execute command '%s' on server state change.",handle->script); - } -*/ + + + } if (mon_status_changed(ptr)) diff --git a/server/modules/monitor/mysqlmon.h b/server/modules/monitor/mysqlmon.h index 3b5658a5a..969334b3b 100644 --- a/server/modules/monitor/mysqlmon.h +++ b/server/modules/monitor/mysqlmon.h @@ -77,7 +77,8 @@ typedef struct { int write_timeout; /**< Timeout in seconds for each attempt to write to the server. * There are retries and the total effective timeout value is two times the option value. */ - char *script;0 + char *master_down_script; + int master_down_script_called; } MYSQL_MONITOR; #define MONITOR_RUNNING 1 From 03badb9b7bd1caf97fb4cc1621f6ed22a5a91305 Mon Sep 17 00:00:00 2001 From: counterpoint Date: Fri, 24 Apr 2015 15:35:10 +0100 Subject: [PATCH 006/275] Modifications to galera monitor to control whether selection of master is wanted. --- .gitignore | 1 + .../Getting-Started/Configuration-Guide.md | 12 +++++-- server/core/config.c | 2 ++ server/modules/monitor/galera_mon.c | 31 +++++++++++++------ server/modules/monitor/mysqlmon.h | 4 ++- .../routing/schemarouter/schemarouter.c | 20 +++++------- .../routing/schemarouter/shardrouter.c | 21 +++++-------- 7 files changed, 53 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index c761d00c4..7fe302bd3 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ depend.mk # Vi swap files .*.swp +/build/ \ No newline at end of file diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 8b3fdc301..9bf75aa2f 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -440,6 +440,7 @@ backend_write_timeout=2 # galeramon specific options disable_master_failback=0 available_when_donor=0 +disable_master_role_setting=0 ``` #### `module` @@ -510,6 +511,13 @@ This option if set to 1 will allow Galera monitor to keep a node in `Donor` stat As xtrabackup is a non-locking SST method, a node in `Donor` status can still be considered in sync. This option is not enabled by default and should be used as the administrator's discretion. +#### `disable_master_role_setting` + +This option if set to 1 will stop the Galera monitor from setting the status of +backend servers to master or slave. It is applicable when the Galera router is +being used to spread writes across multiple nodes, so that no server is to be +nominated as the master. + #### `backend_connect_timeout` This option, with default value of `3` sets the monitor connect timeout to backends. @@ -1367,11 +1375,11 @@ Example: ``` [Galera Listener] type=listener -address=192.1681.3.33 +address=192.168.3.33 port=4408 socket=/servers/maxscale/galera.sock ``` -TCP/IP Traffic must be permitted to 192.1681.3.33 port 4408 +TCP/IP Traffic must be permitted to 192.168.3.33 port 4408 For Unix socket, the socket file path (example: `/servers/maxscale/galera.sock`) must be writable by the Unix user MaxScale runs as. diff --git a/server/core/config.c b/server/core/config.c index aef540e9c..c063958da 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -43,6 +43,7 @@ * 20/02/15 Markus Mäkelä Added connection_timeout parameter for services * 05/03/15 Massimiliano Pinto Added notification_feedback support * 20/04/15 Guillaume Lefranc Added available_when_donor parameter + * 22/04/15 Martin Brampton Added disable_master_role_setting parameter * * @endverbatim */ @@ -1895,6 +1896,7 @@ static char *monitor_params[] = "backend_read_timeout", "backend_write_timeout", "available_when_donor", + "disable_master_role_setting", NULL }; /** diff --git a/server/modules/monitor/galera_mon.c b/server/modules/monitor/galera_mon.c index ee93eb3bf..b5309d9fb 100644 --- a/server/modules/monitor/galera_mon.c +++ b/server/modules/monitor/galera_mon.c @@ -160,6 +160,7 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt; handle->interval = MONITOR_INTERVAL; handle->disableMasterFailback = 0; handle->availableWhenDonor = 0; + handle->disableMasterRoleSetting = 0; handle->master = NULL; handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT; handle->read_timeout=DEFAULT_READ_TIMEOUT; @@ -172,8 +173,10 @@ CONFIG_PARAMETER* params = (CONFIG_PARAMETER*)opt; { if(!strcmp(params->name,"disable_master_failback")) handle->disableMasterFailback = config_truth_value(params->value); - if(!strcmp(params->name,"available_when_donor")) + else if(!strcmp(params->name,"available_when_donor")) handle->availableWhenDonor = config_truth_value(params->value); + else if(!strcmp(params->name,"disable_master_role_setting")) + handle->disableMasterRoleSetting = config_truth_value(params->value); params = params->next; } @@ -294,6 +297,7 @@ char *sep; dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval); dcb_printf(dcb,"\tMaster Failback:\t%s\n", (handle->disableMasterFailback == 1) ? "off" : "on"); dcb_printf(dcb,"\tAvailable when Donor:\t%s\n", (handle->availableWhenDonor == 1) ? "on" : "off"); + dcb_printf(dcb,"\tMaster Role Setting Disabled:\t%s\n", (handle->disableMasterRoleSetting == 1) ? "on" : "off"); dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", handle->connect_timeout); dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", handle->read_timeout); dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", handle->write_timeout); @@ -596,40 +600,47 @@ int log_no_members = 1; * Decision depends on master_stickiness value set in configuration */ - /* get the candidate master, followinf MIN(node_id) rule */ + /* get the candidate master, following MIN(node_id) rule */ candidate_master = get_candidate_master(handle->databases); /* Select the master, based on master_stickiness */ - handle->master = set_cluster_master(handle->master, candidate_master, master_stickiness); + if (1 == handle->disableMasterRoleSetting) { + handle->master = NULL; + } + else { + handle->master = set_cluster_master(handle->master, candidate_master, master_stickiness); + } ptr = handle->databases; - while (ptr && handle->master) { + while (ptr) { if (!SERVER_IS_JOINED(ptr->server) || SERVER_IN_MAINT(ptr->server)) { ptr = ptr->next; continue; } - if (ptr != handle->master) { + if (handle->master) { + if (ptr != handle->master) { /* set the Slave role */ server_set_status(ptr->server, SERVER_SLAVE); server_clear_status(ptr->server, SERVER_MASTER); - /* clear master stickyness */ + /* clear master stickiness */ server_clear_status(ptr->server, SERVER_MASTER_STICKINESS); - } else { + } else { /* set the Master role */ server_set_status(handle->master->server, SERVER_MASTER); server_clear_status(handle->master->server, SERVER_SLAVE); if (candidate_master && handle->master->server->node_id != candidate_master->server->node_id) { - /* set master stickyness */ + /* set master stickiness */ server_set_status(handle->master->server, SERVER_MASTER_STICKINESS); } else { - /* clear master stickyness */ + /* clear master stickiness */ server_clear_status(ptr->server, SERVER_MASTER_STICKINESS); } - } + } + } is_cluster++; diff --git a/server/modules/monitor/mysqlmon.h b/server/modules/monitor/mysqlmon.h index f3deb56f8..11de7e0f4 100644 --- a/server/modules/monitor/mysqlmon.h +++ b/server/modules/monitor/mysqlmon.h @@ -35,7 +35,8 @@ * 28/08/14 Massimiliano Pinto Addition of detectStaleMaster * 30/10/14 Massimiliano Pinto Addition of disableMasterFailback * 07/11/14 Massimiliano Pinto Addition of NetworkTimeout: connect, read, write - * 20/05/15 Guillaume Lefranc Addition of availableWhenDonor + * 20/04/15 Guillaume Lefranc Addition of availableWhenDonor + * 22/04/15 Martin Brampton Addition of disableMasterRoleSetting * * @endverbatim */ @@ -70,6 +71,7 @@ typedef struct { int detectStaleMaster; /**< Monitor flag for MySQL replication Stale Master detection */ int disableMasterFailback; /**< Monitor flag for Galera Cluster Master failback */ int availableWhenDonor; /**< Monitor flag for Galera Cluster Donor availability */ + int disableMasterRoleSetting; /**< Monitor flag to disable setting master role */ MONITOR_SERVERS *master; /**< Master server for MySQL Master/Slave replication */ MONITOR_SERVERS *databases; /**< Linked list of servers to monitor */ int connect_timeout; /**< Connect timeout in seconds for mysql_real_connect */ diff --git a/server/modules/routing/schemarouter/schemarouter.c b/server/modules/routing/schemarouter/schemarouter.c index 6852f9d14..f9c44ac4e 100644 --- a/server/modules/routing/schemarouter/schemarouter.c +++ b/server/modules/routing/schemarouter/schemarouter.c @@ -243,24 +243,23 @@ static int hashcmpfun( /** * Convert a length encoded string into a C string. * @param data Pointer to the first byte of the string - * @param len Pointer to an integer where the length of the string will be stored. On errors this will be set to -1. * @return Pointer to the newly allocated string or NULL if the value is NULL or an error occurred */ -char* get_lenenc_str(void* data, int* len) +char* get_lenenc_str(void* data) { unsigned char* ptr = (unsigned char*)data; char* rval; - long size, offset; + uintptr_t size; + long offset; - if(data == NULL || len == NULL) + if(data == NULL) { - *len = -1; return NULL; } if(*ptr < 251) { - size = *ptr; + size = (uintptr_t)*ptr; offset = 1; } else @@ -268,7 +267,6 @@ char* get_lenenc_str(void* data, int* len) switch(*(ptr)) { case 0xfb: - *len = 1; return NULL; case 0xfc: size = *(ptr + 1) + (*(ptr + 2) << 8); @@ -280,8 +278,8 @@ char* get_lenenc_str(void* data, int* len) break; case 0xfe: size = *ptr + ((*(ptr + 2) << 8)) + (*(ptr + 3) << 16) + - (*(ptr + 4) << 24) + (*(ptr + 5) << 32) + (*(ptr + 6) << 40) + - (*(ptr + 7) << 48) + (*(ptr + 8) << 56); + (*(ptr + 4) << 24) + ((uintptr_t)*(ptr + 5) << 32) + ((uintptr_t)*(ptr + 6) << 40) + + ((uintptr_t)*(ptr + 7) << 48) + ((uintptr_t)*(ptr + 8) << 56); offset = 8; break; default: @@ -297,7 +295,6 @@ char* get_lenenc_str(void* data, int* len) memset(rval + size,0,1); } - *len = size + offset; return rval; } @@ -360,8 +357,7 @@ bool parse_showdb_response(ROUTER_CLIENT_SES* rses, backend_ref_t* bref, GWBUF** { int payloadlen = gw_mysql_get_byte3(ptr); int packetlen = payloadlen + 4; - int len = 0; - char* data = get_lenenc_str(ptr+4,&len); + char* data = get_lenenc_str(ptr+4); if(data) { diff --git a/server/modules/routing/schemarouter/shardrouter.c b/server/modules/routing/schemarouter/shardrouter.c index a3c9da3c4..b9e480c67 100644 --- a/server/modules/routing/schemarouter/shardrouter.c +++ b/server/modules/routing/schemarouter/shardrouter.c @@ -262,25 +262,23 @@ hashcmpfun( /** * Convert a length encoded string into a C string. * @param data Pointer to the first byte of the string - * @param len Pointer to an integer where the length of the string will be stored. On errors this will be set to -1. * @return Pointer to the newly allocated string or NULL if the value is NULL or an error occurred */ -char* get_lenenc_str(void* data, int* len) +char* get_lenenc_str(void* data) { unsigned char* ptr = (unsigned char*)data; char* rval; - long size, offset; + uintptr_t size; + long offset; - if(data == NULL || len == NULL) + if(data == NULL) { - if(len) - *len = -1; return NULL; } if(*ptr < 251) { - size = *ptr; + size = (uintptr_t)*ptr; offset = 1; } else @@ -288,7 +286,6 @@ char* get_lenenc_str(void* data, int* len) switch(*(ptr)) { case 0xfb: - *len = 1; return NULL; case 0xfc: size = *(ptr + 1) + (*(ptr + 2) << 8); @@ -300,8 +297,8 @@ char* get_lenenc_str(void* data, int* len) break; case 0xfe: size = *ptr + ((*(ptr + 2) << 8)) + (*(ptr + 3) << 16) + - (*(ptr + 4) << 24) + ((long)*(ptr + 5) << 32) + ((long)*(ptr + 6) << 40) + - ((long)*(ptr + 7) << 48) + ((long)*(ptr + 8) << 56); + (*(ptr + 4) << 24) + ((uintptr_t)*(ptr + 5) << 32) + ((uintptr_t)*(ptr + 6) << 40) + + ((uintptr_t)*(ptr + 7) << 48) + ((uintptr_t)*(ptr + 8) << 56); offset = 8; break; default: @@ -317,7 +314,6 @@ char* get_lenenc_str(void* data, int* len) memset(rval + size,0,1); } - *len = size + offset; return rval; } @@ -360,8 +356,7 @@ parse_mapping_response(ROUTER_CLIENT_SES* rses, char* target, GWBUF* buf) { int payloadlen = gw_mysql_get_byte3(ptr); int packetlen = payloadlen + 4; - int len = 0; - char* data = get_lenenc_str(ptr+4,&len); + char* data = get_lenenc_str(ptr+4); if(data) { From eec053924c0fd1085023458ade00098c7110fb39 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Fri, 24 Apr 2015 22:11:49 +0300 Subject: [PATCH 007/275] Updated various MaxScale command line and configuration options to allow custom log, module, data, cache and language directories. --- CMakeLists.txt | 30 ++++-- server/core/gateway.c | 226 +++++++++++++++++++++++++++------------ server/core/load_utils.c | 9 +- server/include/gw.h | 1 + 4 files changed, 185 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 94842ebaa..e654e766e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,19 +137,29 @@ ${CMAKE_SOURCE_DIR}/Documentation/Release-Notes/MaxScale-1.1-Release-Notes.md execute_process(COMMAND perl ${CMAKE_SOURCE_DIR}/Documentation/format.pl ${CMAKE_SOURCE_DIR}/Documentation/Upgrading-To-MaxScale-1.1.0.md ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt) -install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION .) -install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION .) -install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION .) message(STATUS "Installing MaxScale to: ${CMAKE_INSTALL_PREFIX}/") -install(FILES server/MaxScale_template.cnf DESTINATION etc) -install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION etc) -install(FILES ${ERRMSG} DESTINATION mysql) -install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION .) -install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION .) -install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .) - +if(PACKAGE) + install(FILES server/MaxScale_template.cnf DESTINATION /etc) + install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION /etc) + install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION /usr/share/maxscale) + install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION /usr/share/maxscale) + install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/maxscale) + install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION /usr/share/maxscale) + install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION /usr/share/maxscale) + install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION /usr/share/maxscale) +else() + install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION .) + install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION .) + install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION .) + install(FILES server/MaxScale_template.cnf DESTINATION etc) + install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION etc) + install(FILES ${ERRMSG} DESTINATION mysql) + install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION .) + install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION .) + install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .) +endif() # Install startup scripts and ldconfig files if(WITH_SCRIPTS) configure_file(${CMAKE_SOURCE_DIR}/maxscale.conf.in ${CMAKE_BINARY_DIR}/maxscale.conf @ONLY) diff --git a/server/core/gateway.c b/server/core/gateway.c index ed69d3e3e..c06b9f309 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -113,12 +113,15 @@ static char* server_options[] = { const int num_elements = (sizeof(server_options) / sizeof(char *)) - 1; -const char* default_cnf_fname = "etc/MaxScale.cnf"; +const char* default_cnf_fname = "MaxScale.cnf"; const char* default_configdir = "/etc/"; const char* default_logdir = "/var/log/maxscale/"; -const char* default_libdir = "/lib64/maxscale/lib/"; -const char* default_moddir = "/lib64/maxscale/modules/"; +const char* default_datadir = "/var/lib/maxscale/"; +const char* default_moduledir = "/lib64/maxscale/modules/"; +const char* default_cachedir = "/var/cache/maxscale/"; +const char* default_langdir = "/usr/share/mysql/english/"; +const char* default_piddir = "/var/run/maxscale/"; static char* server_groups[] = { "embedded", @@ -132,14 +135,15 @@ static char* server_groups[] = { /* The data directory we created for this gateway instance */ static char datadir[PATH_MAX+1] = ""; - +static bool datadir_defined = false; /*< If the datadir was already set */ /* The data directory we created for this gateway instance */ static char pidfile[PATH_MAX+1] = ""; static char* configdir = NULL; static char* logdir = NULL; -static char* libdir = NULL; -static char* moddir = NULL; +static char* moduledir = NULL; +static char* cachedir = NULL; +static char* langdir = NULL; /** * exit flag for log flusher. */ @@ -161,9 +165,14 @@ static struct option long_options[] = { {"config", required_argument, 0, 'f'}, {"nodaemon", no_argument, 0, 'd'}, {"log", required_argument, 0, 'l'}, - {"logdir", required_argument, 0, 'L'}, + {"logdir", required_argument, 0, 'L'}, + {"datadir", required_argument, 0, 'D'}, + {"configdir",required_argument, 0, 'C'}, + {"moduledir",required_argument, 0, 'B'}, + {"cachedir",required_argument, 0, 'A'}, + {"language",required_argument, 0, 'N'}, {"syslog", required_argument, 0, 's'}, - {"maxscalelog", required_argument, 0, 'S'}, + {"maxscalelog",required_argument,0,'S'}, {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, '?'}, {0, 0, 0, 0} @@ -201,6 +210,14 @@ static bool resolve_maxscale_homedir( static char* check_dir_access(char* dirname,bool,bool); +/** + * Get the directory with all the modules. + * @return The module directory + */ +char* get_moduledir() +{ + return moduledir; +} /** * Handler for SIGHUP signal. Reload the configuration for the * gateway. @@ -369,11 +386,10 @@ void datadir_cleanup() { int depth = 1; int flags = FTW_CHDIR|FTW_DEPTH|FTW_MOUNT; - int rc; if (datadir[0] != 0 && access(datadir, F_OK) == 0) { - rc = nftw(datadir, ntfw_cb, depth, flags); + nftw(datadir, ntfw_cb, depth, flags); } } @@ -394,14 +410,13 @@ static bool file_write_footer( FILE* outfile) { bool succp = false; - size_t wbytes1; size_t len1; const char* header_buf1; header_buf1 = "------------------------------------------------------" "\n\n"; len1 = strlen(header_buf1); - wbytes1=fwrite((void*)header_buf1, len1, 1, outfile); + fwrite((void*)header_buf1, len1, 1, outfile); succp = true; @@ -412,9 +427,6 @@ static bool file_write_header( FILE* outfile) { bool succp = false; - size_t wbytes1; - size_t wbytes2; - size_t wbytes3; size_t len1; size_t len2; size_t len3; @@ -458,9 +470,9 @@ static bool file_write_header( #if defined(LAPTOP_TEST) nanosleep(&ts1, NULL); #else - wbytes1=fwrite((void*)header_buf1, len1, 1, outfile); - wbytes2=fwrite((void*)header_buf2, len2, 1, outfile); - wbytes3=fwrite((void*)header_buf3, len3, 1, outfile); + fwrite((void*)header_buf1, len1, 1, outfile); + fwrite((void*)header_buf2, len2, 1, outfile); + fwrite((void*)header_buf3, len3, 1, outfile); #endif succp = true; @@ -1015,20 +1027,28 @@ static void usage(void) { fprintf(stderr, "\nUsage : %s [-h] | [-d] [-c ] [-f ]\n\n" - " -d|--nodaemon enable running in terminal process (default:disabled)\n" - " -c|--homedir=... relative|absolute MaxScale home directory\n" - " -f|--config=... relative|absolute pathname of MaxScale configuration file\n" - " (default: $MAXSCALE_HOME/etc/MaxScale.cnf)\n" - " -l|--log=... log to file or shared memory\n" - " -lfile or -lshm - defaults to shared memory\n" - " -L|--logdir=... path to log file directory\n" - " (default: /var/log/maxscale)\n" - " -s|--syslog= log messages to syslog." - " True or false - defaults to true\n" - " -S|--maxscalelog= log messages to MaxScale log." - " True or false - defaults to true\n" - " -v|--version print version info and exit\n" - " -?|--help show this help\n" + " -d|--nodaemon enable running in terminal process (default:disabled)\n" + " -c|--homedir=... relative|absolute MaxScale home directory\n" + " -f|--config=... relative|absolute pathname of MaxScale configuration file\n" + " (default: $MAXSCALE_HOME/etc/MaxScale.cnf)\n" + " -l|--log=... log to file or shared memory\n" + " -lfile or -lshm - defaults to shared memory\n" + " -L|--logdir=... path to log file directory\n" + " (default: /var/log/maxscale)\n" + " -D|--datadir=... path to data directory\n" + " (default: /var/lib/maxscale)\n" + " -C|--configdir=... path to configuration file directory\n" + " (default: /etc/)\n" + " -B|--moduledir=... path to module directory\n" + " (default: /var/lib/maxscale)\n" + " -A|--cachedir=... path to cache directory\n" + " (default: /var/cache/maxscale)\n" + " -s|--syslog= log messages to syslog.\n" + " True or false - defaults to true\n" + " -S|--maxscalelog= log messages to MaxScale log.\n" + " True or false - defaults to true\n" + " -v|--version print version info and exit\n" + " -?|--help show this help\n" , progname); } @@ -1103,9 +1123,8 @@ int main(int argc, char **argv) NULL}; sigemptyset(&sigpipe_mask); sigaddset(&sigpipe_mask, SIGPIPE); - progname = *argv; - + sprintf(datadir, "%s", default_datadir); #if defined(FAKE_CODE) memset(conn_open, 0, sizeof(bool)*10240); memset(dcb_fake_write_errno, 0, sizeof(unsigned char)*10240); @@ -1133,7 +1152,7 @@ int main(int argc, char **argv) } } - while ((opt = getopt_long(argc, argv, "dc:f:l:vs:S:?L:", + while ((opt = getopt_long(argc, argv, "dc:f:l:vs:S:?L:D:C:B:", long_options, &option_index)) != -1) { bool succp = true; @@ -1245,6 +1264,33 @@ int main(int argc, char **argv) logdir = tmp_path; } + break; + case 'N': + if(handle_path_arg(&tmp_path,optarg,NULL,true,false)) + { + langdir = tmp_path; + } + break; + case 'D': + sprintf(datadir,"%s",optarg); + datadir_defined = true; + break; + case 'C': + if(handle_path_arg(&tmp_path,optarg,NULL,true,false)) + { + configdir = tmp_path; + } + break; + case 'B': + if(handle_path_arg(&tmp_path,optarg,NULL,true,false)) + { + moduledir = tmp_path; + } + case 'A': + if(handle_path_arg(&tmp_path,optarg,NULL,true,true)) + { + cachedir = tmp_path; + } break; case 'S': if(strstr(optarg,"=")) @@ -1547,11 +1593,17 @@ int main(int argc, char **argv) goto return_main; } - /*< + /** Use the cache dir for the mysql folder of the embedded library */ + sprintf(mysql_home, "%s/mysql", cachedir); + setenv("MYSQL_HOME", mysql_home, 1); + + /*< * If MaxScale home directory wasn't set by command-line argument. * Next, resolve it from environment variable and further on, * try to use default. */ +/* + if (home_dir == NULL) { if (!resolve_maxscale_homedir(&home_dir)) @@ -1560,8 +1612,7 @@ int main(int argc, char **argv) rc = MAXSCALE_HOMELESS; goto return_main; } - sprintf(mysql_home, "%s/mysql", home_dir); - setenv("MYSQL_HOME", mysql_home, 1); + } else { @@ -1601,13 +1652,28 @@ int main(int argc, char **argv) } free(log_context); } +*/ - char pbuf[PATH_MAX]; + /** + * Resolve the full pathname for configuration file and check for + * read accessibility. + */ + char pathbuf[PATH_MAX+1]; + snprintf(pathbuf,PATH_MAX,"%s",configdir ? configdir:default_configdir); + if(pathbuf[strlen(pathbuf)-1] != '/') + strcat(pathbuf,"/"); - sprintf(pbuf,"%s/etc/MaxScale.cnf",home_dir); + if (!resolve_maxscale_conf_fname(&cnf_file_path, pathbuf, cnf_file_arg)) + { + ss_dassert(cnf_file_path == NULL); + rc = MAXSCALE_BADCONFIG; + goto return_main; + } - ini_parse(pbuf,cnf_preparser,NULL); + ini_parse(cnf_file_path,cnf_preparser,NULL); + if(!datadir_defined) + sprintf(datadir,"%s",default_datadir); /** * Init Log Manager for MaxScale. * If $MAXSCALE_HOME is set then write the logs into $MAXSCALE_HOME/log. @@ -1678,25 +1744,25 @@ int main(int argc, char **argv) goto return_main; } } - /** - * Resolve the full pathname for configuration file and check for - * read accessibility. - */ - if (!resolve_maxscale_conf_fname(&cnf_file_path, home_dir, cnf_file_arg)) - { - ss_dassert(cnf_file_path == NULL); - rc = MAXSCALE_BADCONFIG; - goto return_main; - } - /*< + + + if(cachedir == NULL) + cachedir = strdup(default_cachedir); + + if(langdir == NULL) + langdir = strdup(default_langdir); + + /** * Set a data directory for the mysqld library, we use * a unique directory name to avoid clauses if multiple * instances of the gateway are beign run on the same * machine. */ - sprintf(datadir, "%s/data", home_dir); + if(datadir[strlen(datadir)-1] != '/') + strcat(datadir,"/"); + strcat(datadir,"data"); if(mkdir(datadir, 0777) != 0){ if(errno != EEXIST){ @@ -1706,7 +1772,7 @@ int main(int argc, char **argv) } } - sprintf(datadir, "%s/data/data%d", home_dir, getpid()); + sprintf(datadir, "%s/data%d", datadir, getpid()); if(mkdir(datadir, 0777) != 0){ @@ -1720,27 +1786,29 @@ int main(int argc, char **argv) if (!daemon_mode) { fprintf(stderr, - "Home directory : %s" - "\nConfiguration file : %s" + //"Home directory : %s" + "Configuration file : %s" "\nLog directory : %s" "\nData directory : %s\n\n", - home_dir, + //home_dir, cnf_file_path, logdir, datadir); } +/* LOGIF(LM, (skygw_log_write_flush( LOGFILE_MESSAGE, "Home directory : %s", home_dir))); +*/ LOGIF(LM, (skygw_log_write_flush( LOGFILE_MESSAGE, "Data directory : %s", datadir))); LOGIF(LM, (skygw_log_write_flush( LOGFILE_MESSAGE, - "Log directory : %s/log", - home_dir))); + "Log directory : %s/", + logdir))); LOGIF(LM, (skygw_log_write_flush( LOGFILE_MESSAGE, "Configuration file : %s", @@ -1758,8 +1826,8 @@ int main(int argc, char **argv) { snprintf(language_arg, 11+PATH_MAX+1, - "--language=%s/mysql", - home_dir); + "--language=%s", + langdir); server_options[i] = language_arg; } } @@ -1815,6 +1883,9 @@ int main(int argc, char **argv) } libmysqld_started = TRUE; + if(moduledir == NULL) + moduledir = strdup(default_moduledir); + if (!config_load(cnf_file_path)) { char* fprerr = "Failed to load MaxScale configuration " @@ -2015,7 +2086,7 @@ static int write_pid_file(char *home_dir) { int fd = -1; - snprintf(pidfile, PATH_MAX, "%s/data/maxscale.pid", home_dir); + snprintf(pidfile, PATH_MAX, "%smaxscale.pid",default_piddir); fd = open(pidfile, O_WRONLY | O_CREAT | O_TRUNC, 0777); if (fd == -1) { @@ -2100,21 +2171,42 @@ static int cnf_preparser(void* data, const char* section, const char* name, cons char pathbuffer[PATH_MAX]; char* errstr; + /** These are read from the configuration file. These will not override + * command line parameters but will override default values. */ if(strcasecmp(section,"maxscale") == 0) { if(strcmp(name, "logdir") == 0) { - /** logdir is only NULL if no command line parameter was given */ if(logdir == NULL) handle_path_arg(&logdir,(char*)value,NULL,true,true); } - else if(strcmp(name, "moddir") == 0) + else if(strcmp(name, "moduledir") == 0) { - handle_path_arg(&moddir,(char*)value,NULL,true,false); + if(moduledir == NULL) + handle_path_arg(&moduledir,(char*)value,NULL,true,false); } - else if(strcmp(name, "libdir") == 0) + else if(strcmp(name, "datadir") == 0) { - handle_path_arg(&libdir,(char*)value,NULL,true,false); + if(!datadir_defined) + { + char* tmp; + if(handle_path_arg(&tmp,(char*)value,NULL,true,false)) + { + sprintf(datadir,"%s",tmp); + datadir_defined = true; + free(tmp); + } + } + } + else if(strcmp(name, "cachedir") == 0) + { + if(cachedir == NULL) + handle_path_arg((char**)&datadir,(char*)value,NULL,true,false); + } + else if(strcmp(name, "language") == 0) + { + if(langdir == NULL) + handle_path_arg((char**)&langdir,(char*)value,NULL,true,false); } } diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 172f24ad0..c2716befa 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -48,6 +48,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -146,16 +147,16 @@ MODULE_INFO *mod_info = NULL; if (access(fname, F_OK) == -1) { - home = get_maxscale_home (); - snprintf(fname, MAXPATHLEN+1,"%s/modules/lib%s.so", home, module); + //home = get_maxscale_home (); + snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_moduledir(), module); if (access(fname, F_OK) == -1) { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Error : Unable to find library for " - "module: %s.", - module))); + "module: %s. Module dir: %s", + module, get_moduledir()))); return NULL; } } diff --git a/server/include/gw.h b/server/include/gw.h index 9c8507210..e2c69aa7c 100644 --- a/server/include/gw.h +++ b/server/include/gw.h @@ -65,3 +65,4 @@ int gw_write(DCB *dcb, const void *buf, size_t nbytes); int gw_getsockerrno(int fd); int parse_bindconfig(char *, unsigned short, struct sockaddr_in *); int setipaddress(struct in_addr *, char *); +char* get_moduledir(); \ No newline at end of file From df9bc65430c8f786fd71b52dbd0f22dcba911cc1 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Sat, 25 Apr 2015 06:53:59 +0300 Subject: [PATCH 008/275] Added variables that are used when installing instead of relative paths. --- CMakeLists.txt | 35 ++++------ client/CMakeLists.txt | 2 +- log_manager/CMakeLists.txt | 4 +- macros.cmake | 28 ++++++++ query_classifier/CMakeLists.txt | 2 +- server/core/CMakeLists.txt | 6 +- server/core/gateway.c | 65 +++++++++---------- server/core/load_utils.c | 1 - server/include/gw.h | 17 ++++- server/modules/filter/CMakeLists.txt | 18 ++--- server/modules/filter/hint/CMakeLists.txt | 2 +- server/modules/monitor/CMakeLists.txt | 8 +-- server/modules/protocol/CMakeLists.txt | 12 ++-- server/modules/routing/CMakeLists.txt | 12 ++-- server/modules/routing/binlog/CMakeLists.txt | 4 +- server/modules/routing/maxinfo/CMakeLists.txt | 4 +- .../routing/readwritesplit/CMakeLists.txt | 2 +- 17 files changed, 122 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e654e766e..48bf38e8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ if(NOT CURL_FOUND) message(FATAL_ERROR "Failed to locate dependency: libcurl") endif() -set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/modules) # Make sure the release notes for this release are present if it is a stable one if(${MAXSCALE_VERSION} MATCHES "-stable") @@ -47,6 +46,7 @@ if(${MAXSCALE_VERSION} MATCHES "-stable") message(FATAL_ERROR "Could not find the release notes for this stable release: ${MAXSCALE_VERSION_NUMERIC}") endif() endif() +set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/${MAXSCALE_MODULE_INSTALL}:${CMAKE_INSTALL_PREFIX}/${MAXSCALE_LIBRARY_INSTALL}) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/server/include) configure_file(${CMAKE_SOURCE_DIR}/server/include/version.h.in ${CMAKE_BINARY_DIR}/server/include/version.h) @@ -127,7 +127,7 @@ if(NOT WITHOUT_MAXADMIN) add_subdirectory(client) endif() - +# Generate text versions of some documents execute_process(COMMAND perl ${CMAKE_SOURCE_DIR}/Documentation/format.pl ${CMAKE_SOURCE_DIR}/Documentation/Changelog.md ${CMAKE_BINARY_DIR}/Changelog.txt) @@ -138,28 +138,17 @@ execute_process(COMMAND perl ${CMAKE_SOURCE_DIR}/Documentation/format.pl ${CMAKE_SOURCE_DIR}/Documentation/Upgrading-To-MaxScale-1.1.0.md ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt) -message(STATUS "Installing MaxScale to: ${CMAKE_INSTALL_PREFIX}/") -if(PACKAGE) - install(FILES server/MaxScale_template.cnf DESTINATION /etc) - install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION /etc) - install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION /usr/share/maxscale) - install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION /usr/share/maxscale) - install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/maxscale) - install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION /usr/share/maxscale) - install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION /usr/share/maxscale) - install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION /usr/share/maxscale) -else() - install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION .) - install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION .) - install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION .) - install(FILES server/MaxScale_template.cnf DESTINATION etc) - install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION etc) - install(FILES ${ERRMSG} DESTINATION mysql) - install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION .) - install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION .) - install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .) -endif() +install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION ${MAXSCALE_SHARE_DIR}) +install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION ${MAXSCALE_SHARE_DIR}) +install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION ${MAXSCALE_SHARE_DIR}) +install(FILES server/MaxScale_template.cnf DESTINATION ${MAXSCALE_CONFIG_DIR}) +install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION ${MAXSCALE_CONFIG_DIR}) +install(FILES ${ERRMSG} DESTINATION ${MAXSCALE_LANG_DIR}) +install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION ${MAXSCALE_SHARE_DIR}) +install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION ${MAXSCALE_SHARE_DIR}) +install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${MAXSCALE_SHARE_DIR}) + # Install startup scripts and ldconfig files if(WITH_SCRIPTS) configure_file(${CMAKE_SOURCE_DIR}/maxscale.conf.in ${CMAKE_BINARY_DIR}/maxscale.conf @ONLY) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 755f2eac8..9b679aae0 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -7,4 +7,4 @@ if(HIST) else() message(STATUS "Could not find editline library. MaxAdmin will be built without it.") endif() -install(TARGETS maxadmin DESTINATION bin) +install(TARGETS maxadmin DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) diff --git a/log_manager/CMakeLists.txt b/log_manager/CMakeLists.txt index fdef33f6c..607341d9a 100644 --- a/log_manager/CMakeLists.txt +++ b/log_manager/CMakeLists.txt @@ -3,7 +3,7 @@ if(LOG_DEBUG) endif() add_library(log_manager SHARED log_manager.cc) target_link_libraries(log_manager pthread aio stdc++) -install(TARGETS log_manager DESTINATION lib) +install(TARGETS log_manager DESTINATION ${MAXSCALE_LIBRARY_INSTALL}) if(BUILD_TESTS) add_subdirectory(test) -endif() \ No newline at end of file +endif() diff --git a/macros.cmake b/macros.cmake index 440c3fed5..d80202534 100644 --- a/macros.cmake +++ b/macros.cmake @@ -74,6 +74,34 @@ macro(set_variables) # Build extra tools set(BUILD_TOOLS FALSE CACHE BOOL "Build extra utility tools") + # Change installation directories to standard locations for packages + if(PACKAGE) + set(MAXSCALE_MODULE_INSTALL /lib64/maxscale CACHE PATH "Module installation path") + set(MAXSCALE_LIBRARY_INSTALL /lib64/maxscale CACHE PATH "Library installation path") + message(STATUS "Installing MaxScale modules to: ${MAXSCALE_MODULE_INSTALL}/") + set(MAXSCALE_EXECUTABLE_INSTALL /bin CACHE PATH "Executable installation path") + message(STATUS "Installing MaxScale binaries to: ${MAXSCALE_EXECUTABLE_INSTALL}/") + set(MAXSCALE_CONFIG_DIR /etc CACHE PATH "Configuration file installation path") + set(MAXSCALE_DOC_DIR /usr/share/maxscale/doc CACHE PATH "Documentation installation path") + set(MAXSCALE_LOG_DIR /var/log/maxscale CACHE PATH "Log file directory") + message(STATUS "MaxScale log directory: ${MAXSCALE_LOG_DIR}/") + set(MAXSCALE_CACHE_DIR /var/cache/maxscale CACHE PATH "Service cache file directory") + set(MAXSCALE_LANG_DIR /var/cache/maxscale CACHE PATH "Language file directory(errmsg.sys)") + set(MAXSCALE_SHARE_DIR /usr/share/maxscale CACHE PATH "Share file installation path") + set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_DIR}:${MAXSCALE_LIBRARY_DIR}) + else() + message(STATUS "Installing MaxScale to: ${CMAKE_INSTALL_PREFIX}/") + set(MAXSCALE_MODULE_INSTALL lib64/maxscale CACHE PATH "Module installation path") + set(MAXSCALE_LIBRARY_INSTALL lib64/maxscale CACHE PATH "Library installation path") + set(MAXSCALE_EXECUTABLE_INSTALL bin CACHE PATH "Executable installation path") + set(MAXSCALE_CONFIG_DIR etc CACHE PATH "Configuration file installation path") + set(MAXSCALE_DOC_DIR doc CACHE PATH "Documentation installation path") + set(MAXSCALE_LOG_DIR log CACHE PATH "Log file directory") + set(MAXSCALE_CACHE_DIR cache CACHE PATH "Service cache file directory") + set(MAXSCALE_LANG_DIR cache CACHE PATH "Log file directory") + set(MAXSCALE_SHARE_DIR . CACHE PATH "Share file installation path") + endif() + endmacro() macro(check_deps) diff --git a/query_classifier/CMakeLists.txt b/query_classifier/CMakeLists.txt index 42270cd2c..7fb36d6c6 100644 --- a/query_classifier/CMakeLists.txt +++ b/query_classifier/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(query_classifier SHARED query_classifier.cc) -install(TARGETS query_classifier DESTINATION lib) +install(TARGETS query_classifier COMPONENT lib DESTINATION ${MAXSCALE_LIBRARY_INSTALL}) if(BUILD_TESTS) add_subdirectory(test) endif() diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 630d4c034..ee01396d8 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -18,15 +18,15 @@ if(WITH_TCMALLOC) endif() target_link_libraries(maxscale ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++) -install(TARGETS maxscale DESTINATION bin) +install(TARGETS maxscale DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) add_executable(maxkeys maxkeys.c secrets.c utils.c) target_link_libraries(maxkeys log_manager utils pthread crypt crypto) -install(TARGETS maxkeys DESTINATION bin) +install(TARGETS maxkeys DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) add_executable(maxpasswd maxpasswd.c secrets.c utils.c) target_link_libraries(maxpasswd log_manager utils pthread crypt crypto) -install(TARGETS maxpasswd DESTINATION bin) +install(TARGETS maxpasswd DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) if(BUILD_TESTS) add_subdirectory(test) diff --git a/server/core/gateway.c b/server/core/gateway.c index c06b9f309..d2bcd13a9 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -113,16 +113,6 @@ static char* server_options[] = { const int num_elements = (sizeof(server_options) / sizeof(char *)) - 1; -const char* default_cnf_fname = "MaxScale.cnf"; - -const char* default_configdir = "/etc/"; -const char* default_logdir = "/var/log/maxscale/"; -const char* default_datadir = "/var/lib/maxscale/"; -const char* default_moduledir = "/lib64/maxscale/modules/"; -const char* default_cachedir = "/var/cache/maxscale/"; -const char* default_langdir = "/usr/share/mysql/english/"; -const char* default_piddir = "/var/run/maxscale/"; - static char* server_groups[] = { "embedded", "server", @@ -1752,7 +1742,8 @@ int main(int argc, char **argv) if(langdir == NULL) langdir = strdup(default_langdir); - + if(moduledir == NULL) + moduledir = strdup(default_moduledir); /** * Set a data directory for the mysqld library, we use * a unique directory name to avoid clauses if multiple @@ -1786,33 +1777,35 @@ int main(int argc, char **argv) if (!daemon_mode) { fprintf(stderr, - //"Home directory : %s" - "Configuration file : %s" - "\nLog directory : %s" - "\nData directory : %s\n\n", - //home_dir, + "Configuration file : %s\n" + "Log directory : %s\n" + "Data directory : %s\n" + "Module directory : %s\n\n", cnf_file_path, logdir, - datadir); + datadir, + moduledir); } -/* - LOGIF(LM, (skygw_log_write_flush( - LOGFILE_MESSAGE, - "Home directory : %s", - home_dir))); -*/ - LOGIF(LM, (skygw_log_write_flush( - LOGFILE_MESSAGE, - "Data directory : %s", - datadir))); - LOGIF(LM, (skygw_log_write_flush( - LOGFILE_MESSAGE, - "Log directory : %s/", - logdir))); - LOGIF(LM, (skygw_log_write_flush( - LOGFILE_MESSAGE, - "Configuration file : %s", - cnf_file_path))); + + LOGIF(LM, + (skygw_log_write_flush( + LOGFILE_MESSAGE, + "Configuration file: %s", + cnf_file_path))); + LOGIF(LM, + (skygw_log_write_flush( + LOGFILE_MESSAGE, + "Log directory: %s/", + logdir))); + LOGIF(LM, + (skygw_log_write_flush( + LOGFILE_MESSAGE, + "Data directory: %s", + datadir))); + LOGIF(LM, + (skygw_log_write_flush(LOGFILE_MESSAGE, + "Module directory: %s", + moduledir))); /*< Update the server options */ for (i = 0; server_options[i]; i++) @@ -2211,4 +2204,4 @@ static int cnf_preparser(void* data, const char* section, const char* name, cons } return 1; -} \ No newline at end of file +} diff --git a/server/core/load_utils.c b/server/core/load_utils.c index c2716befa..c1ae57a3e 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -147,7 +147,6 @@ MODULE_INFO *mod_info = NULL; if (access(fname, F_OK) == -1) { - //home = get_maxscale_home (); snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_moduledir(), module); if (access(fname, F_OK) == -1) diff --git a/server/include/gw.h b/server/include/gw.h index e2c69aa7c..64db00204 100644 --- a/server/include/gw.h +++ b/server/include/gw.h @@ -1,3 +1,5 @@ +#ifndef _GW_HG +#define _GW_HG #include #include #include @@ -16,9 +18,19 @@ #include #include #include - #include +/** Default file locations */ +static const char* default_cnf_fname = "MaxScale.cnf"; +static const char* default_configdir = "/etc/"; +static const char* default_logdir = "/var/log/maxscale/"; +static const char* default_datadir = "/var/cache/maxscale/"; +static const char* default_moduledir = "/lib64/maxscale/"; +static const char* default_cachedir = "/var/cache/maxscale/"; +static const char* default_langdir = "/usr/share/mysql/english/"; /*< This is where the MariaDB + * server installs errmsg.sys */ +static const char* default_piddir = "/var/run/maxscale/"; + #define EXIT_FAILURE 1 // network buffer is 32K @@ -65,4 +77,5 @@ int gw_write(DCB *dcb, const void *buf, size_t nbytes); int gw_getsockerrno(int fd); int parse_bindconfig(char *, unsigned short, struct sockaddr_in *); int setipaddress(struct in_addr *, char *); -char* get_moduledir(); \ No newline at end of file +char* get_moduledir(); +#endif diff --git a/server/modules/filter/CMakeLists.txt b/server/modules/filter/CMakeLists.txt index 0af1ea566..77ebc7d0c 100644 --- a/server/modules/filter/CMakeLists.txt +++ b/server/modules/filter/CMakeLists.txt @@ -3,41 +3,41 @@ if(BUILD_RABBITMQ) include_directories(${RABBITMQ_HEADERS}) add_library(mqfilter SHARED mqfilter.c) target_link_libraries(mqfilter query_classifier log_manager utils ${RABBITMQ_LIBRARIES}) - install(TARGETS mqfilter DESTINATION modules) + install(TARGETS mqfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) endif() add_library(regexfilter SHARED regexfilter.c) target_link_libraries(regexfilter log_manager utils) -install(TARGETS regexfilter DESTINATION modules) +install(TARGETS regexfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(testfilter SHARED testfilter.c) target_link_libraries(testfilter log_manager utils) -install(TARGETS testfilter DESTINATION modules) +install(TARGETS testfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(qlafilter SHARED qlafilter.c) target_link_libraries(qlafilter log_manager utils) -install(TARGETS qlafilter DESTINATION modules) +install(TARGETS qlafilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(tee SHARED tee.c) target_link_libraries(tee log_manager utils) -install(TARGETS tee DESTINATION modules) +install(TARGETS tee DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(topfilter SHARED topfilter.c) target_link_libraries(topfilter log_manager utils) -install(TARGETS topfilter DESTINATION modules) +install(TARGETS topfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(dbfwfilter SHARED dbfwfilter.c) target_link_libraries(dbfwfilter log_manager utils query_classifier) -install(TARGETS dbfwfilter DESTINATION modules) +install(TARGETS dbfwfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(namedserverfilter SHARED namedserverfilter.c) target_link_libraries(namedserverfilter log_manager utils) -install(TARGETS namedserverfilter DESTINATION modules) +install(TARGETS namedserverfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) if(BUILD_SLAVELAG) add_library(slavelag SHARED slavelag.c) target_link_libraries(slavelag log_manager utils query_classifier) - install(TARGETS slavelag DESTINATION modules) + install(TARGETS slavelag DESTINATION ${MAXSCALE_MODULE_INSTALL}) endif() if(BUILD_TOOLS) diff --git a/server/modules/filter/hint/CMakeLists.txt b/server/modules/filter/hint/CMakeLists.txt index f47cb637e..ecc3cbb85 100644 --- a/server/modules/filter/hint/CMakeLists.txt +++ b/server/modules/filter/hint/CMakeLists.txt @@ -1,4 +1,4 @@ add_library(hintfilter SHARED hintfilter.c hintparser.c) set_target_properties(hintfilter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib) target_link_libraries(hintfilter ssl log_manager utils) -install(TARGETS hintfilter DESTINATION modules) \ No newline at end of file +install(TARGETS hintfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) diff --git a/server/modules/monitor/CMakeLists.txt b/server/modules/monitor/CMakeLists.txt index a99a66142..74a6f2870 100644 --- a/server/modules/monitor/CMakeLists.txt +++ b/server/modules/monitor/CMakeLists.txt @@ -1,16 +1,16 @@ add_library(mysqlmon SHARED mysql_mon.c) target_link_libraries(mysqlmon log_manager utils) -install(TARGETS mysqlmon DESTINATION modules) +install(TARGETS mysqlmon DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(galeramon SHARED galera_mon.c) target_link_libraries(galeramon log_manager utils) -install(TARGETS galeramon DESTINATION modules) +install(TARGETS galeramon DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(ndbclustermon SHARED ndbcluster_mon.c) target_link_libraries(ndbclustermon log_manager utils) -install(TARGETS ndbclustermon DESTINATION modules) +install(TARGETS ndbclustermon DESTINATION ${MAXSCALE_MODULE_INSTALL}) if(BUILD_MMMON) add_library(mmmon SHARED mm_mon.c) target_link_libraries(mmmon log_manager utils) - install(TARGETS mmmon DESTINATION modules) + install(TARGETS mmmon DESTINATION ${MAXSCALE_MODULE_INSTALL}) endif() diff --git a/server/modules/protocol/CMakeLists.txt b/server/modules/protocol/CMakeLists.txt index fa1c2ab34..488f2e4b6 100644 --- a/server/modules/protocol/CMakeLists.txt +++ b/server/modules/protocol/CMakeLists.txt @@ -1,27 +1,27 @@ add_library(MySQLClient SHARED mysql_client.c mysql_common.c) target_link_libraries(MySQLClient log_manager utils) -install(TARGETS MySQLClient DESTINATION modules) +install(TARGETS MySQLClient DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(MySQLBackend SHARED mysql_backend.c mysql_common.c) target_link_libraries(MySQLBackend log_manager utils) -install(TARGETS MySQLBackend DESTINATION modules) +install(TARGETS MySQLBackend DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(telnetd SHARED telnetd.c) target_link_libraries(telnetd log_manager utils) -install(TARGETS telnetd DESTINATION modules) +install(TARGETS telnetd DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(HTTPD SHARED httpd.c) target_link_libraries(HTTPD log_manager utils) -install(TARGETS HTTPD DESTINATION modules) +install(TARGETS HTTPD DESTINATION ${MAXSCALE_MODULE_INSTALL}) if(BUILD_TESTS) add_library(testprotocol SHARED testprotocol.c) - install(TARGETS testprotocol DESTINATION modules) + install(TARGETS testprotocol DESTINATION ${MAXSCALE_MODULE_INSTALL}) endif() add_library(maxscaled SHARED maxscaled.c) target_link_libraries(maxscaled log_manager utils) -install(TARGETS maxscaled DESTINATION modules) +install(TARGETS maxscaled DESTINATION ${MAXSCALE_MODULE_INSTALL}) diff --git a/server/modules/routing/CMakeLists.txt b/server/modules/routing/CMakeLists.txt index 77abe6cd1..b73edfa8c 100644 --- a/server/modules/routing/CMakeLists.txt +++ b/server/modules/routing/CMakeLists.txt @@ -2,28 +2,28 @@ if(BUILD_TESTS) add_subdirectory(test) add_library(testroute SHARED testroute.c) target_link_libraries(testroute log_manager utils) - install(TARGETS testroute DESTINATION modules) + install(TARGETS testroute DESTINATION ${MAXSCALE_MODULE_INSTALL}) endif() add_library(schemarouter SHARED schemarouter/schemarouter.c) target_link_libraries(schemarouter log_manager utils query_classifier) -install(TARGETS schemarouter DESTINATION modules) +install(TARGETS schemarouter DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(shardrouter SHARED schemarouter/shardrouter.c) target_link_libraries(shardrouter log_manager utils query_classifier) -install(TARGETS shardrouter DESTINATION modules) +install(TARGETS shardrouter DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(readconnroute SHARED readconnroute.c) target_link_libraries(readconnroute log_manager utils) -install(TARGETS readconnroute DESTINATION modules) +install(TARGETS readconnroute DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(debugcli SHARED debugcli.c debugcmd.c) target_link_libraries(debugcli log_manager utils) -install(TARGETS debugcli DESTINATION modules) +install(TARGETS debugcli DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_library(cli SHARED cli.c debugcmd.c) target_link_libraries(cli log_manager utils) -install(TARGETS cli DESTINATION modules) +install(TARGETS cli DESTINATION ${MAXSCALE_MODULE_INSTALL}) add_subdirectory(readwritesplit) add_subdirectory(schemarouter/test) diff --git a/server/modules/routing/binlog/CMakeLists.txt b/server/modules/routing/binlog/CMakeLists.txt index 4de2a35b4..9fcd8536e 100644 --- a/server/modules/routing/binlog/CMakeLists.txt +++ b/server/modules/routing/binlog/CMakeLists.txt @@ -1,4 +1,4 @@ add_library(binlogrouter SHARED blr.c blr_master.c blr_cache.c blr_slave.c blr_file.c) -set_target_properties(binlogrouter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib) +set_target_properties(binlogrouter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_INSTALL}:${MAXSCALE_LIBRARY_INSTALL}) target_link_libraries(binlogrouter ssl pthread log_manager) -install(TARGETS binlogrouter DESTINATION modules) +install(TARGETS binlogrouter DESTINATION ${MAXSCALE_MODULE_INSTALL}) diff --git a/server/modules/routing/maxinfo/CMakeLists.txt b/server/modules/routing/maxinfo/CMakeLists.txt index 898df9b73..2585f2a2a 100644 --- a/server/modules/routing/maxinfo/CMakeLists.txt +++ b/server/modules/routing/maxinfo/CMakeLists.txt @@ -1,4 +1,4 @@ add_library(maxinfo SHARED maxinfo.c maxinfo_parse.c maxinfo_error.c maxinfo_exec.c) -set_target_properties(maxinfo PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib) +set_target_properties(maxinfo PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_INSTALL}:MAXSCALE_LIBRARY_INSTALL) target_link_libraries(maxinfo pthread log_manager) -install(TARGETS maxinfo DESTINATION modules) +install(TARGETS maxinfo DESTINATION ${MAXSCALE_MODULE_INSTALL}) diff --git a/server/modules/routing/readwritesplit/CMakeLists.txt b/server/modules/routing/readwritesplit/CMakeLists.txt index 6960d4c8d..fe56582dc 100644 --- a/server/modules/routing/readwritesplit/CMakeLists.txt +++ b/server/modules/routing/readwritesplit/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(readwritesplit SHARED readwritesplit.c) target_link_libraries(readwritesplit ssl pthread log_manager utils query_classifier) -install(TARGETS readwritesplit DESTINATION modules) +install(TARGETS readwritesplit DESTINATION ${MAXSCALE_MODULE_INSTALL}) if(BUILD_TESTS) add_subdirectory(test) endif() From ed426ca30da5c61b9aaf7805bdd5c0166c2d0cd1 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Sun, 26 Apr 2015 06:21:28 +0300 Subject: [PATCH 009/275] Updated packaging install layout, moved some cmake files around. --- CMakeLists.txt | 14 +++++++++----- cmake/install_layout.cmake | 29 +++++++++++++++++++++++++++++ macros.cmake => cmake/macros.cmake | 28 ---------------------------- etc/postinst.in | 3 +++ plugins/CMakeLists.txt | 10 +++++----- server/core/gateway.c | 14 ++++++++++---- server/core/service.c | 8 +++++--- 7 files changed, 61 insertions(+), 45 deletions(-) create mode 100644 cmake/install_layout.cmake rename macros.cmake => cmake/macros.cmake (83%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48bf38e8e..bf7e135e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,13 +6,16 @@ endif() message(STATUS "CMake version: ${CMAKE_VERSION}") -include(macros.cmake) - +include(${CMAKE_SOURCE_DIR}/cmake/macros.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/install_layout.cmake) enable_testing() set_variables() set_maxscale_version() -set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") + +set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, RPM, DEB") +set_install_layout(${INSTALL_LAYOUT}) + set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") @@ -37,6 +40,7 @@ if(NOT CURL_FOUND) message(FATAL_ERROR "Failed to locate dependency: libcurl") endif() +set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_DIR}:${MAXSCALE_LIBRARY_DIR}) # Make sure the release notes for this release are present if it is a stable one if(${MAXSCALE_VERSION} MATCHES "-stable") @@ -144,7 +148,7 @@ install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION ${MAXSCALE_SHARE_ install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION ${MAXSCALE_SHARE_DIR}) install(FILES server/MaxScale_template.cnf DESTINATION ${MAXSCALE_CONFIG_DIR}) install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION ${MAXSCALE_CONFIG_DIR}) -install(FILES ${ERRMSG} DESTINATION ${MAXSCALE_LANG_DIR}) +install(FILES ${ERRMSG} DESTINATION ${MAXSCALE_SHARE_DIR}) install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION ${MAXSCALE_SHARE_DIR}) install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION ${MAXSCALE_SHARE_DIR}) install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${MAXSCALE_SHARE_DIR}) @@ -225,7 +229,7 @@ if(PACKAGE) endif() endif() -add_custom_target(buildtests +add_custom_target(buildtestsx COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR} -DWITH_SCRIPTS=N ${CMAKE_SOURCE_DIR} COMMAND make COMMENT "Building test suite..." VERBATIM diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake new file mode 100644 index 000000000..0d594188f --- /dev/null +++ b/cmake/install_layout.cmake @@ -0,0 +1,29 @@ +# Set the install layout +# Possible values: +# STANDALONE - Installs to /usr/local/mariadb-maxscale +# RPM - Installs to /usr +# DEB - Installs to /usr +function(set_install_layout TYPE) + + if(${TYPE} MATCHES "STANDALONE") + + set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") + +# RPM and DEB are the same until differences are found + elseif(${TYPE} MATCHES "RPM") + + set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") + + elseif(${TYPE} MATCHES "DEB") + + set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") + + endif() + + set(MAXSCALE_MODULE_INSTALL lib64/maxscale CACHE PATH "Module installation path") + set(MAXSCALE_LIBRARY_INSTALL lib64/maxscale CACHE PATH "Library installation path") + set(MAXSCALE_EXECUTABLE_INSTALL bin CACHE PATH "Executable installation path") + set(MAXSCALE_SHARE_DIR share/maxscale CACHE PATH "Share file installation path, includes licence and readme files") + set(MAXSCALE_DOC_DIR ${MAXSCALE_SHARE_DIR}/doc CACHE PATH "Documentation installation path, text versions only") + set(MAXSCALE_CONFIG_DIR ${MAXSCALE_SHARE_DIR}/etc CACHE PATH "Configuration file installation path, example configurations will be placed here") +endfunction() diff --git a/macros.cmake b/cmake/macros.cmake similarity index 83% rename from macros.cmake rename to cmake/macros.cmake index d80202534..440c3fed5 100644 --- a/macros.cmake +++ b/cmake/macros.cmake @@ -74,34 +74,6 @@ macro(set_variables) # Build extra tools set(BUILD_TOOLS FALSE CACHE BOOL "Build extra utility tools") - # Change installation directories to standard locations for packages - if(PACKAGE) - set(MAXSCALE_MODULE_INSTALL /lib64/maxscale CACHE PATH "Module installation path") - set(MAXSCALE_LIBRARY_INSTALL /lib64/maxscale CACHE PATH "Library installation path") - message(STATUS "Installing MaxScale modules to: ${MAXSCALE_MODULE_INSTALL}/") - set(MAXSCALE_EXECUTABLE_INSTALL /bin CACHE PATH "Executable installation path") - message(STATUS "Installing MaxScale binaries to: ${MAXSCALE_EXECUTABLE_INSTALL}/") - set(MAXSCALE_CONFIG_DIR /etc CACHE PATH "Configuration file installation path") - set(MAXSCALE_DOC_DIR /usr/share/maxscale/doc CACHE PATH "Documentation installation path") - set(MAXSCALE_LOG_DIR /var/log/maxscale CACHE PATH "Log file directory") - message(STATUS "MaxScale log directory: ${MAXSCALE_LOG_DIR}/") - set(MAXSCALE_CACHE_DIR /var/cache/maxscale CACHE PATH "Service cache file directory") - set(MAXSCALE_LANG_DIR /var/cache/maxscale CACHE PATH "Language file directory(errmsg.sys)") - set(MAXSCALE_SHARE_DIR /usr/share/maxscale CACHE PATH "Share file installation path") - set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_DIR}:${MAXSCALE_LIBRARY_DIR}) - else() - message(STATUS "Installing MaxScale to: ${CMAKE_INSTALL_PREFIX}/") - set(MAXSCALE_MODULE_INSTALL lib64/maxscale CACHE PATH "Module installation path") - set(MAXSCALE_LIBRARY_INSTALL lib64/maxscale CACHE PATH "Library installation path") - set(MAXSCALE_EXECUTABLE_INSTALL bin CACHE PATH "Executable installation path") - set(MAXSCALE_CONFIG_DIR etc CACHE PATH "Configuration file installation path") - set(MAXSCALE_DOC_DIR doc CACHE PATH "Documentation installation path") - set(MAXSCALE_LOG_DIR log CACHE PATH "Log file directory") - set(MAXSCALE_CACHE_DIR cache CACHE PATH "Service cache file directory") - set(MAXSCALE_LANG_DIR cache CACHE PATH "Log file directory") - set(MAXSCALE_SHARE_DIR . CACHE PATH "Share file installation path") - endif() - endmacro() macro(check_deps) diff --git a/etc/postinst.in b/etc/postinst.in index 4bd193958..46772ca16 100755 --- a/etc/postinst.in +++ b/etc/postinst.in @@ -1,5 +1,8 @@ #!/bin/sh +mkdir -p /var/log/maxscale +mkdir -p /var/cache/maxscale +mkdir -p /var/run/maxscale cp @CMAKE_INSTALL_PREFIX@/maxscale /etc/init.d/ cp @CMAKE_INSTALL_PREFIX@/maxscale.conf /etc/ld.so.conf.d/ /sbin/ldconfig diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 3ea1eb028..1936ebe84 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,5 +1,5 @@ -install(FILES nagios/check_maxscale_monitors.pl DESTINATION plugins/nagios) -install(FILES nagios/check_maxscale_resources.pl DESTINATION plugins/nagios) -install(FILES nagios/check_maxscale_threads.pl DESTINATION plugins/nagios) -install(FILES nagios/maxscale_commands.cfg DESTINATION plugins/nagios) -install(FILES nagios/server1.cfg DESTINATION plugins/nagios) +install(FILES nagios/check_maxscale_monitors.pl DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) +install(FILES nagios/check_maxscale_resources.pl DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) +install(FILES nagios/check_maxscale_threads.pl DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) +install(FILES nagios/maxscale_commands.cfg DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) +install(FILES nagios/server1.cfg DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) diff --git a/server/core/gateway.c b/server/core/gateway.c index d2bcd13a9..6b55b2661 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -1276,6 +1276,7 @@ int main(int argc, char **argv) { moduledir = tmp_path; } + break; case 'A': if(handle_path_arg(&tmp_path,optarg,NULL,true,true)) { @@ -1739,7 +1740,6 @@ int main(int argc, char **argv) if(cachedir == NULL) cachedir = strdup(default_cachedir); - if(langdir == NULL) langdir = strdup(default_langdir); if(moduledir == NULL) @@ -1780,11 +1780,13 @@ int main(int argc, char **argv) "Configuration file : %s\n" "Log directory : %s\n" "Data directory : %s\n" - "Module directory : %s\n\n", + "Module directory : %s\n" + "Service cache : %s\n\n", cnf_file_path, logdir, datadir, - moduledir); + moduledir, + cachedir); } LOGIF(LM, @@ -1806,6 +1808,10 @@ int main(int argc, char **argv) (skygw_log_write_flush(LOGFILE_MESSAGE, "Module directory: %s", moduledir))); + LOGIF(LM, + (skygw_log_write_flush(LOGFILE_MESSAGE, + "Service cache: %s", + cachedir))); /*< Update the server options */ for (i = 0; server_options[i]; i++) @@ -1882,7 +1888,7 @@ int main(int argc, char **argv) if (!config_load(cnf_file_path)) { char* fprerr = "Failed to load MaxScale configuration " - "file. Exiting."; + "file. Exiting. See the error log for details."; print_log_n_stderr(false, !daemon_mode, fprerr, fprerr, 0); LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, diff --git a/server/core/service.c b/server/core/service.c index 4584ded24..9455921b7 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -61,6 +61,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -112,7 +113,7 @@ SERVICE *service; return NULL; if ((service->router = load_module(router, MODULE_ROUTER)) == NULL) { - char* home = get_maxscale_home(); + char* home = get_moduledir(); char* ldpath = getenv("LD_LIBRARY_PATH"); LOGIF(LE, (skygw_log_write_flush( @@ -120,12 +121,13 @@ SERVICE *service; "Error : Unable to load %s module \"%s\".\n\t\t\t" " Ensure that lib%s.so exists in one of the " "following directories :\n\t\t\t " - "- %s/modules\n\t\t\t - %s", + "- %s/modules\n%s%s", MODULE_ROUTER, router, router, home, - ldpath))); + ldpath?"\t\t\t - ":"", + ldpath?ldpath:""))); free(service); return NULL; } From 10e9203b5be2cc2cb7d5bfade09259fb6a12e667 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Sun, 26 Apr 2015 11:39:00 +0300 Subject: [PATCH 010/275] Updated postinst script --- CMakeLists.txt | 9 +++++---- etc/postinst.in | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bf7e135e7..78d205936 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,13 +175,14 @@ if(WITH_SCRIPTS) endif() if(PACKAGE) - install(FILES ${CMAKE_BINARY_DIR}/maxscale DESTINATION . + # Install the files copied by the postinst script into the share folder + install(FILES ${CMAKE_BINARY_DIR}/maxscale DESTINATION ${MAXSCALE_SHARE_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(FILES ${CMAKE_BINARY_DIR}/maxscale.conf DESTINATION . + install(FILES ${CMAKE_BINARY_DIR}/maxscale.conf DESTINATION ${MAXSCALE_SHARE_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(FILES ${CMAKE_BINARY_DIR}/postinst DESTINATION . + install(FILES ${CMAKE_BINARY_DIR}/postinst DESTINATION ${MAXSCALE_SHARE_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(FILES ${CMAKE_BINARY_DIR}/postrm DESTINATION . + install(FILES ${CMAKE_BINARY_DIR}/postrm DESTINATION ${MAXSCALE_SHARE_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) if(${CMAKE_VERSION} VERSION_LESS 2.8.12) message(WARNING "CMake version is ${CMAKE_VERSION}. Building of packages requires version 2.8.12 or greater.") diff --git a/etc/postinst.in b/etc/postinst.in index 46772ca16..c04850019 100755 --- a/etc/postinst.in +++ b/etc/postinst.in @@ -3,6 +3,6 @@ mkdir -p /var/log/maxscale mkdir -p /var/cache/maxscale mkdir -p /var/run/maxscale -cp @CMAKE_INSTALL_PREFIX@/maxscale /etc/init.d/ -cp @CMAKE_INSTALL_PREFIX@/maxscale.conf /etc/ld.so.conf.d/ +cp @CMAKE_INSTALL_PREFIX@/@MAXSCALE_SHARE_DIR@/maxscale /etc/init.d/ +cp @CMAKE_INSTALL_PREFIX@/@MAXSCALE_SHARE_DIR@/maxscale.conf /etc/ld.so.conf.d/ /sbin/ldconfig From 17a7b2addbebc2ac8d19b897e195014830b87431 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Sun, 26 Apr 2015 20:08:27 +0300 Subject: [PATCH 011/275] Updated more variables. --- CMakeLists.txt | 39 ++++++++++--------- client/CMakeLists.txt | 2 +- cmake/install_layout.cmake | 31 ++++++--------- log_manager/CMakeLists.txt | 2 +- plugins/CMakeLists.txt | 10 ++--- query_classifier/CMakeLists.txt | 2 +- server/core/CMakeLists.txt | 6 +-- server/core/gateway.c | 30 +++++++------- server/core/load_utils.c | 4 +- server/core/service.c | 2 +- server/include/gw.h | 4 +- server/modules/filter/CMakeLists.txt | 20 +++++----- server/modules/filter/hint/CMakeLists.txt | 4 +- server/modules/monitor/CMakeLists.txt | 8 ++-- server/modules/protocol/CMakeLists.txt | 12 +++--- server/modules/routing/CMakeLists.txt | 12 +++--- server/modules/routing/binlog/CMakeLists.txt | 4 +- server/modules/routing/maxinfo/CMakeLists.txt | 4 +- .../routing/readwritesplit/CMakeLists.txt | 2 +- 19 files changed, 95 insertions(+), 103 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78d205936..ba669131c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,23 +6,24 @@ endif() message(STATUS "CMake version: ${CMAKE_VERSION}") + include(${CMAKE_SOURCE_DIR}/cmake/macros.cmake) + +# Set the installation layout +set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, RPM, DEB") include(${CMAKE_SOURCE_DIR}/cmake/install_layout.cmake) + enable_testing() set_variables() set_maxscale_version() - -set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, RPM, DEB") -set_install_layout(${INSTALL_LAYOUT}) - set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") project(MaxScale) -#Disabled for now pending evaluation +#Do the platform check include(cmake/CheckPlatform.cmake) check_deps() @@ -40,7 +41,7 @@ if(NOT CURL_FOUND) message(FATAL_ERROR "Failed to locate dependency: libcurl") endif() -set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_DIR}:${MAXSCALE_LIBRARY_DIR}) +set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/${MAXSCALE_LIBDIR}) # Make sure the release notes for this release are present if it is a stable one if(${MAXSCALE_VERSION} MATCHES "-stable") @@ -143,15 +144,15 @@ ${CMAKE_SOURCE_DIR}/Documentation/Upgrading-To-MaxScale-1.1.0.md ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt) -install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION ${MAXSCALE_SHARE_DIR}) -install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION ${MAXSCALE_SHARE_DIR}) -install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION ${MAXSCALE_SHARE_DIR}) -install(FILES server/MaxScale_template.cnf DESTINATION ${MAXSCALE_CONFIG_DIR}) -install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION ${MAXSCALE_CONFIG_DIR}) -install(FILES ${ERRMSG} DESTINATION ${MAXSCALE_SHARE_DIR}) -install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION ${MAXSCALE_SHARE_DIR}) -install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION ${MAXSCALE_SHARE_DIR}) -install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${MAXSCALE_SHARE_DIR}) +install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES server/MaxScale_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES ${ERRMSG} DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${MAXSCALE_SHAREDIR}) # Install startup scripts and ldconfig files if(WITH_SCRIPTS) @@ -176,13 +177,13 @@ endif() if(PACKAGE) # Install the files copied by the postinst script into the share folder - install(FILES ${CMAKE_BINARY_DIR}/maxscale DESTINATION ${MAXSCALE_SHARE_DIR} + install(FILES ${CMAKE_BINARY_DIR}/maxscale DESTINATION ${MAXSCALE_SHAREDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(FILES ${CMAKE_BINARY_DIR}/maxscale.conf DESTINATION ${MAXSCALE_SHARE_DIR} + install(FILES ${CMAKE_BINARY_DIR}/maxscale.conf DESTINATION ${MAXSCALE_SHAREDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(FILES ${CMAKE_BINARY_DIR}/postinst DESTINATION ${MAXSCALE_SHARE_DIR} + install(FILES ${CMAKE_BINARY_DIR}/postinst DESTINATION ${MAXSCALE_SHAREDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install(FILES ${CMAKE_BINARY_DIR}/postrm DESTINATION ${MAXSCALE_SHARE_DIR} + install(FILES ${CMAKE_BINARY_DIR}/postrm DESTINATION ${MAXSCALE_SHAREDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) if(${CMAKE_VERSION} VERSION_LESS 2.8.12) message(WARNING "CMake version is ${CMAKE_VERSION}. Building of packages requires version 2.8.12 or greater.") diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 9b679aae0..32ab702ea 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -7,4 +7,4 @@ if(HIST) else() message(STATUS "Could not find editline library. MaxAdmin will be built without it.") endif() -install(TARGETS maxadmin DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) +install(TARGETS maxadmin DESTINATION ${MAXSCALE_BINDIR}) diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake index 0d594188f..821b2c474 100644 --- a/cmake/install_layout.cmake +++ b/cmake/install_layout.cmake @@ -3,27 +3,18 @@ # STANDALONE - Installs to /usr/local/mariadb-maxscale # RPM - Installs to /usr # DEB - Installs to /usr -function(set_install_layout TYPE) +if(${TYPE} MATCHES "STANDALONE") - if(${TYPE} MATCHES "STANDALONE") + set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") - set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") + # RPM and DEB are the same until differences are found +else() + set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") +endif() -# RPM and DEB are the same until differences are found - elseif(${TYPE} MATCHES "RPM") +set(MAXSCALE_LIBDIR lib64/maxscale CACHE PATH "Library installation path") +set(MAXSCALE_BINDIR bin CACHE PATH "Executable installation path") +set(MAXSCALE_SHAREDIR share/maxscale CACHE PATH "Share file installation path, includes licence and readme files") +set(MAXSCALE_DOCDIR share/doc/maxscale CACHE PATH "Documentation installation path, text versions only") +set(MAXSCALE_CONFDIR etc CACHE PATH "Configuration file installation path, this is not usually needed") - set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") - - elseif(${TYPE} MATCHES "DEB") - - set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") - - endif() - - set(MAXSCALE_MODULE_INSTALL lib64/maxscale CACHE PATH "Module installation path") - set(MAXSCALE_LIBRARY_INSTALL lib64/maxscale CACHE PATH "Library installation path") - set(MAXSCALE_EXECUTABLE_INSTALL bin CACHE PATH "Executable installation path") - set(MAXSCALE_SHARE_DIR share/maxscale CACHE PATH "Share file installation path, includes licence and readme files") - set(MAXSCALE_DOC_DIR ${MAXSCALE_SHARE_DIR}/doc CACHE PATH "Documentation installation path, text versions only") - set(MAXSCALE_CONFIG_DIR ${MAXSCALE_SHARE_DIR}/etc CACHE PATH "Configuration file installation path, example configurations will be placed here") -endfunction() diff --git a/log_manager/CMakeLists.txt b/log_manager/CMakeLists.txt index 607341d9a..3dfd883de 100644 --- a/log_manager/CMakeLists.txt +++ b/log_manager/CMakeLists.txt @@ -3,7 +3,7 @@ if(LOG_DEBUG) endif() add_library(log_manager SHARED log_manager.cc) target_link_libraries(log_manager pthread aio stdc++) -install(TARGETS log_manager DESTINATION ${MAXSCALE_LIBRARY_INSTALL}) +install(TARGETS log_manager DESTINATION ${MAXSCALE_LIBDIR}) if(BUILD_TESTS) add_subdirectory(test) endif() diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 1936ebe84..fc18cc602 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,5 +1,5 @@ -install(FILES nagios/check_maxscale_monitors.pl DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) -install(FILES nagios/check_maxscale_resources.pl DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) -install(FILES nagios/check_maxscale_threads.pl DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) -install(FILES nagios/maxscale_commands.cfg DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) -install(FILES nagios/server1.cfg DESTINATION ${MAXSCALE_SHARE_DIR}/plugins/nagios) +install(FILES nagios/check_maxscale_monitors.pl DESTINATION ${MAXSCALE_SHAREDIR}/plugins/nagios) +install(FILES nagios/check_maxscale_resources.pl DESTINATION ${MAXSCALE_SHAREDIR}/plugins/nagios) +install(FILES nagios/check_maxscale_threads.pl DESTINATION ${MAXSCALE_SHAREDIR}/plugins/nagios) +install(FILES nagios/maxscale_commands.cfg DESTINATION ${MAXSCALE_SHAREDIR}/plugins/nagios) +install(FILES nagios/server1.cfg DESTINATION ${MAXSCALE_SHAREDIR}/plugins/nagios) diff --git a/query_classifier/CMakeLists.txt b/query_classifier/CMakeLists.txt index 7fb36d6c6..19820ccdd 100644 --- a/query_classifier/CMakeLists.txt +++ b/query_classifier/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(query_classifier SHARED query_classifier.cc) -install(TARGETS query_classifier COMPONENT lib DESTINATION ${MAXSCALE_LIBRARY_INSTALL}) +install(TARGETS query_classifier COMPONENT lib DESTINATION ${MAXSCALE_LIBDIR}) if(BUILD_TESTS) add_subdirectory(test) endif() diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index ee01396d8..ead8560d3 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -18,15 +18,15 @@ if(WITH_TCMALLOC) endif() target_link_libraries(maxscale ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++) -install(TARGETS maxscale DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) +install(TARGETS maxscale DESTINATION ${MAXSCALE_BINDIR}) add_executable(maxkeys maxkeys.c secrets.c utils.c) target_link_libraries(maxkeys log_manager utils pthread crypt crypto) -install(TARGETS maxkeys DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) +install(TARGETS maxkeys DESTINATION ${MAXSCALE_BINDIR}) add_executable(maxpasswd maxpasswd.c secrets.c utils.c) target_link_libraries(maxpasswd log_manager utils pthread crypt crypto) -install(TARGETS maxpasswd DESTINATION ${MAXSCALE_EXECUTABLE_INSTALL}) +install(TARGETS maxpasswd DESTINATION ${MAXSCALE_BINDIR}) if(BUILD_TESTS) add_subdirectory(test) diff --git a/server/core/gateway.c b/server/core/gateway.c index 6b55b2661..a4901ec23 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -131,7 +131,7 @@ static char pidfile[PATH_MAX+1] = ""; static char* configdir = NULL; static char* logdir = NULL; -static char* moduledir = NULL; +static char* libdir = NULL; static char* cachedir = NULL; static char* langdir = NULL; /** @@ -158,7 +158,7 @@ static struct option long_options[] = { {"logdir", required_argument, 0, 'L'}, {"datadir", required_argument, 0, 'D'}, {"configdir",required_argument, 0, 'C'}, - {"moduledir",required_argument, 0, 'B'}, + {"libdir",required_argument, 0, 'B'}, {"cachedir",required_argument, 0, 'A'}, {"language",required_argument, 0, 'N'}, {"syslog", required_argument, 0, 's'}, @@ -204,9 +204,9 @@ static char* check_dir_access(char* dirname,bool,bool); * Get the directory with all the modules. * @return The module directory */ -char* get_moduledir() +char* get_libdir() { - return moduledir; + return libdir; } /** * Handler for SIGHUP signal. Reload the configuration for the @@ -1029,7 +1029,7 @@ static void usage(void) " (default: /var/lib/maxscale)\n" " -C|--configdir=... path to configuration file directory\n" " (default: /etc/)\n" - " -B|--moduledir=... path to module directory\n" + " -B|--libdir=... path to module directory\n" " (default: /var/lib/maxscale)\n" " -A|--cachedir=... path to cache directory\n" " (default: /var/cache/maxscale)\n" @@ -1274,7 +1274,7 @@ int main(int argc, char **argv) case 'B': if(handle_path_arg(&tmp_path,optarg,NULL,true,false)) { - moduledir = tmp_path; + libdir = tmp_path; } break; case 'A': @@ -1742,8 +1742,8 @@ int main(int argc, char **argv) cachedir = strdup(default_cachedir); if(langdir == NULL) langdir = strdup(default_langdir); - if(moduledir == NULL) - moduledir = strdup(default_moduledir); + if(libdir == NULL) + libdir = strdup(default_libdir); /** * Set a data directory for the mysqld library, we use * a unique directory name to avoid clauses if multiple @@ -1785,7 +1785,7 @@ int main(int argc, char **argv) cnf_file_path, logdir, datadir, - moduledir, + libdir, cachedir); } @@ -1807,7 +1807,7 @@ int main(int argc, char **argv) LOGIF(LM, (skygw_log_write_flush(LOGFILE_MESSAGE, "Module directory: %s", - moduledir))); + libdir))); LOGIF(LM, (skygw_log_write_flush(LOGFILE_MESSAGE, "Service cache: %s", @@ -1882,8 +1882,8 @@ int main(int argc, char **argv) } libmysqld_started = TRUE; - if(moduledir == NULL) - moduledir = strdup(default_moduledir); + if(libdir == NULL) + libdir = strdup(default_libdir); if (!config_load(cnf_file_path)) { @@ -2179,10 +2179,10 @@ static int cnf_preparser(void* data, const char* section, const char* name, cons if(logdir == NULL) handle_path_arg(&logdir,(char*)value,NULL,true,true); } - else if(strcmp(name, "moduledir") == 0) + else if(strcmp(name, "libdir") == 0) { - if(moduledir == NULL) - handle_path_arg(&moduledir,(char*)value,NULL,true,false); + if(libdir == NULL) + handle_path_arg(&libdir,(char*)value,NULL,true,false); } else if(strcmp(name, "datadir") == 0) { diff --git a/server/core/load_utils.c b/server/core/load_utils.c index c1ae57a3e..9451f6838 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -147,7 +147,7 @@ MODULE_INFO *mod_info = NULL; if (access(fname, F_OK) == -1) { - snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_moduledir(), module); + snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_libdir(), module); if (access(fname, F_OK) == -1) { @@ -155,7 +155,7 @@ MODULE_INFO *mod_info = NULL; LOGFILE_ERROR, "Error : Unable to find library for " "module: %s. Module dir: %s", - module, get_moduledir()))); + module, get_libdir()))); return NULL; } } diff --git a/server/core/service.c b/server/core/service.c index 9455921b7..bd22117ec 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -113,7 +113,7 @@ SERVICE *service; return NULL; if ((service->router = load_module(router, MODULE_ROUTER)) == NULL) { - char* home = get_moduledir(); + char* home = get_libdir(); char* ldpath = getenv("LD_LIBRARY_PATH"); LOGIF(LE, (skygw_log_write_flush( diff --git a/server/include/gw.h b/server/include/gw.h index 64db00204..e210fcfa2 100644 --- a/server/include/gw.h +++ b/server/include/gw.h @@ -25,7 +25,7 @@ static const char* default_cnf_fname = "MaxScale.cnf"; static const char* default_configdir = "/etc/"; static const char* default_logdir = "/var/log/maxscale/"; static const char* default_datadir = "/var/cache/maxscale/"; -static const char* default_moduledir = "/lib64/maxscale/"; +static const char* default_libdir = "/lib64/maxscale/"; static const char* default_cachedir = "/var/cache/maxscale/"; static const char* default_langdir = "/usr/share/mysql/english/"; /*< This is where the MariaDB * server installs errmsg.sys */ @@ -77,5 +77,5 @@ int gw_write(DCB *dcb, const void *buf, size_t nbytes); int gw_getsockerrno(int fd); int parse_bindconfig(char *, unsigned short, struct sockaddr_in *); int setipaddress(struct in_addr *, char *); -char* get_moduledir(); +char* get_libdir(); #endif diff --git a/server/modules/filter/CMakeLists.txt b/server/modules/filter/CMakeLists.txt index 77ebc7d0c..6bf6a5daa 100644 --- a/server/modules/filter/CMakeLists.txt +++ b/server/modules/filter/CMakeLists.txt @@ -3,48 +3,48 @@ if(BUILD_RABBITMQ) include_directories(${RABBITMQ_HEADERS}) add_library(mqfilter SHARED mqfilter.c) target_link_libraries(mqfilter query_classifier log_manager utils ${RABBITMQ_LIBRARIES}) - install(TARGETS mqfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) + install(TARGETS mqfilter DESTINATION ${MAXSCALE_LIBDIR}) endif() add_library(regexfilter SHARED regexfilter.c) target_link_libraries(regexfilter log_manager utils) -install(TARGETS regexfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS regexfilter DESTINATION ${MAXSCALE_LIBDIR}) add_library(testfilter SHARED testfilter.c) target_link_libraries(testfilter log_manager utils) -install(TARGETS testfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS testfilter DESTINATION ${MAXSCALE_LIBDIR}) add_library(qlafilter SHARED qlafilter.c) target_link_libraries(qlafilter log_manager utils) -install(TARGETS qlafilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS qlafilter DESTINATION ${MAXSCALE_LIBDIR}) add_library(tee SHARED tee.c) target_link_libraries(tee log_manager utils) -install(TARGETS tee DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS tee DESTINATION ${MAXSCALE_LIBDIR}) add_library(topfilter SHARED topfilter.c) target_link_libraries(topfilter log_manager utils) -install(TARGETS topfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS topfilter DESTINATION ${MAXSCALE_LIBDIR}) add_library(dbfwfilter SHARED dbfwfilter.c) target_link_libraries(dbfwfilter log_manager utils query_classifier) -install(TARGETS dbfwfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS dbfwfilter DESTINATION ${MAXSCALE_LIBDIR}) add_library(namedserverfilter SHARED namedserverfilter.c) target_link_libraries(namedserverfilter log_manager utils) -install(TARGETS namedserverfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS namedserverfilter DESTINATION ${MAXSCALE_LIBDIR}) if(BUILD_SLAVELAG) add_library(slavelag SHARED slavelag.c) target_link_libraries(slavelag log_manager utils query_classifier) - install(TARGETS slavelag DESTINATION ${MAXSCALE_MODULE_INSTALL}) + install(TARGETS slavelag DESTINATION ${MAXSCALE_LIBDIR}) endif() if(BUILD_TOOLS) add_executable(ruleparser dbfwfilter.c) target_compile_definitions(ruleparser PUBLIC "BUILD_RULE_PARSER") target_link_libraries(ruleparser ${EMBEDDED_LIB} log_manager utils query_classifier fullcore) - install(TARGETS ruleparser DESTINATION tools) + install(TARGETS ruleparser DESTINATION ${MAXSCALE_BINDIR}) endif() add_subdirectory(hint) diff --git a/server/modules/filter/hint/CMakeLists.txt b/server/modules/filter/hint/CMakeLists.txt index ecc3cbb85..c2d5e9ea1 100644 --- a/server/modules/filter/hint/CMakeLists.txt +++ b/server/modules/filter/hint/CMakeLists.txt @@ -1,4 +1,4 @@ add_library(hintfilter SHARED hintfilter.c hintparser.c) -set_target_properties(hintfilter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib) +set_target_properties(hintfilter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_LIBDIR}) target_link_libraries(hintfilter ssl log_manager utils) -install(TARGETS hintfilter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS hintfilter DESTINATION ${MAXSCALE_LIBDIR}) diff --git a/server/modules/monitor/CMakeLists.txt b/server/modules/monitor/CMakeLists.txt index 74a6f2870..b4d641934 100644 --- a/server/modules/monitor/CMakeLists.txt +++ b/server/modules/monitor/CMakeLists.txt @@ -1,16 +1,16 @@ add_library(mysqlmon SHARED mysql_mon.c) target_link_libraries(mysqlmon log_manager utils) -install(TARGETS mysqlmon DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS mysqlmon DESTINATION ${MAXSCALE_LIBDIR}) add_library(galeramon SHARED galera_mon.c) target_link_libraries(galeramon log_manager utils) -install(TARGETS galeramon DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS galeramon DESTINATION ${MAXSCALE_LIBDIR}) add_library(ndbclustermon SHARED ndbcluster_mon.c) target_link_libraries(ndbclustermon log_manager utils) -install(TARGETS ndbclustermon DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS ndbclustermon DESTINATION ${MAXSCALE_LIBDIR}) if(BUILD_MMMON) add_library(mmmon SHARED mm_mon.c) target_link_libraries(mmmon log_manager utils) - install(TARGETS mmmon DESTINATION ${MAXSCALE_MODULE_INSTALL}) + install(TARGETS mmmon DESTINATION ${MAXSCALE_LIBDIR}) endif() diff --git a/server/modules/protocol/CMakeLists.txt b/server/modules/protocol/CMakeLists.txt index 488f2e4b6..4ae3b8f2c 100644 --- a/server/modules/protocol/CMakeLists.txt +++ b/server/modules/protocol/CMakeLists.txt @@ -1,27 +1,27 @@ add_library(MySQLClient SHARED mysql_client.c mysql_common.c) target_link_libraries(MySQLClient log_manager utils) -install(TARGETS MySQLClient DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS MySQLClient DESTINATION ${MAXSCALE_LIBDIR}) add_library(MySQLBackend SHARED mysql_backend.c mysql_common.c) target_link_libraries(MySQLBackend log_manager utils) -install(TARGETS MySQLBackend DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS MySQLBackend DESTINATION ${MAXSCALE_LIBDIR}) add_library(telnetd SHARED telnetd.c) target_link_libraries(telnetd log_manager utils) -install(TARGETS telnetd DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS telnetd DESTINATION ${MAXSCALE_LIBDIR}) add_library(HTTPD SHARED httpd.c) target_link_libraries(HTTPD log_manager utils) -install(TARGETS HTTPD DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS HTTPD DESTINATION ${MAXSCALE_LIBDIR}) if(BUILD_TESTS) add_library(testprotocol SHARED testprotocol.c) - install(TARGETS testprotocol DESTINATION ${MAXSCALE_MODULE_INSTALL}) + install(TARGETS testprotocol DESTINATION ${MAXSCALE_LIBDIR}) endif() add_library(maxscaled SHARED maxscaled.c) target_link_libraries(maxscaled log_manager utils) -install(TARGETS maxscaled DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS maxscaled DESTINATION ${MAXSCALE_LIBDIR}) diff --git a/server/modules/routing/CMakeLists.txt b/server/modules/routing/CMakeLists.txt index b73edfa8c..2933e5ec8 100644 --- a/server/modules/routing/CMakeLists.txt +++ b/server/modules/routing/CMakeLists.txt @@ -2,28 +2,28 @@ if(BUILD_TESTS) add_subdirectory(test) add_library(testroute SHARED testroute.c) target_link_libraries(testroute log_manager utils) - install(TARGETS testroute DESTINATION ${MAXSCALE_MODULE_INSTALL}) + install(TARGETS testroute DESTINATION ${MAXSCALE_LIBDIR}) endif() add_library(schemarouter SHARED schemarouter/schemarouter.c) target_link_libraries(schemarouter log_manager utils query_classifier) -install(TARGETS schemarouter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS schemarouter DESTINATION ${MAXSCALE_LIBDIR}) add_library(shardrouter SHARED schemarouter/shardrouter.c) target_link_libraries(shardrouter log_manager utils query_classifier) -install(TARGETS shardrouter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS shardrouter DESTINATION ${MAXSCALE_LIBDIR}) add_library(readconnroute SHARED readconnroute.c) target_link_libraries(readconnroute log_manager utils) -install(TARGETS readconnroute DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS readconnroute DESTINATION ${MAXSCALE_LIBDIR}) add_library(debugcli SHARED debugcli.c debugcmd.c) target_link_libraries(debugcli log_manager utils) -install(TARGETS debugcli DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS debugcli DESTINATION ${MAXSCALE_LIBDIR}) add_library(cli SHARED cli.c debugcmd.c) target_link_libraries(cli log_manager utils) -install(TARGETS cli DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS cli DESTINATION ${MAXSCALE_LIBDIR}) add_subdirectory(readwritesplit) add_subdirectory(schemarouter/test) diff --git a/server/modules/routing/binlog/CMakeLists.txt b/server/modules/routing/binlog/CMakeLists.txt index 9fcd8536e..9a0c245de 100644 --- a/server/modules/routing/binlog/CMakeLists.txt +++ b/server/modules/routing/binlog/CMakeLists.txt @@ -1,4 +1,4 @@ add_library(binlogrouter SHARED blr.c blr_master.c blr_cache.c blr_slave.c blr_file.c) -set_target_properties(binlogrouter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_INSTALL}:${MAXSCALE_LIBRARY_INSTALL}) +set_target_properties(binlogrouter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_LIBDIR}) target_link_libraries(binlogrouter ssl pthread log_manager) -install(TARGETS binlogrouter DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS binlogrouter DESTINATION ${MAXSCALE_LIBDIR}) diff --git a/server/modules/routing/maxinfo/CMakeLists.txt b/server/modules/routing/maxinfo/CMakeLists.txt index 2585f2a2a..8e07a34a7 100644 --- a/server/modules/routing/maxinfo/CMakeLists.txt +++ b/server/modules/routing/maxinfo/CMakeLists.txt @@ -1,4 +1,4 @@ add_library(maxinfo SHARED maxinfo.c maxinfo_parse.c maxinfo_error.c maxinfo_exec.c) -set_target_properties(maxinfo PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_MODULE_INSTALL}:MAXSCALE_LIBRARY_INSTALL) +set_target_properties(maxinfo PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_LIBDIR}) target_link_libraries(maxinfo pthread log_manager) -install(TARGETS maxinfo DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS maxinfo DESTINATION ${MAXSCALE_LIBDIR}) diff --git a/server/modules/routing/readwritesplit/CMakeLists.txt b/server/modules/routing/readwritesplit/CMakeLists.txt index fe56582dc..c7e387290 100644 --- a/server/modules/routing/readwritesplit/CMakeLists.txt +++ b/server/modules/routing/readwritesplit/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(readwritesplit SHARED readwritesplit.c) target_link_libraries(readwritesplit ssl pthread log_manager utils query_classifier) -install(TARGETS readwritesplit DESTINATION ${MAXSCALE_MODULE_INSTALL}) +install(TARGETS readwritesplit DESTINATION ${MAXSCALE_LIBDIR}) if(BUILD_TESTS) add_subdirectory(test) endif() From c500d23d04b2566d6acecc4b6ee777540752b1f0 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 04:48:50 +0300 Subject: [PATCH 012/275] Moved default file search paths to gwdirs.h which is configured by CMake from gwdirs.h.in. --- CMakeLists.txt | 21 +-- Documentation/About/SETUP.md | 32 ++--- .../Getting-Started/Configuration-Guide.md | 8 +- .../Getting-Started-With-MaxScale.md | 6 +- .../Tutorials/Administration-Tutorial.md | 4 +- ...era-Cluster-Connection-Routing-Tutorial.md | 2 +- ...a-Cluster-Read-Write-Splitting-Tutorial.md | 2 +- .../Tutorials/MaxScale-Information-Schema.md | 53 +++++++- ...Replication-Connection-Routing-Tutorial.md | 121 +++++++----------- ...plication-Read-Write-Splitting-Tutorial.md | 2 +- ...eplication-Proxy-Binlog-Router-Tutorial.md | 2 +- Documentation/filters/Query-Log-All-Filter.md | 2 +- Documentation/filters/RabbitMQ-Filter.md | 2 +- Documentation/filters/Regex-Filter.md | 2 +- Documentation/filters/Tee-Filter.md | 2 +- Documentation/filters/Top-N-Filter.md | 2 +- cmake/install_layout.cmake | 20 +-- server/core/gateway.c | 71 +--------- server/include/gw.h | 32 +++-- server/include/gwdirs.h.in | 33 +++++ 20 files changed, 198 insertions(+), 221 deletions(-) create mode 100644 server/include/gwdirs.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index ba669131c..564cb43a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,23 +6,28 @@ endif() message(STATUS "CMake version: ${CMAKE_VERSION}") - include(${CMAKE_SOURCE_DIR}/cmake/macros.cmake) - -# Set the installation layout -set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, RPM, DEB") -include(${CMAKE_SOURCE_DIR}/cmake/install_layout.cmake) - enable_testing() + +set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, RPM, DEB") +if(${INSTALL_LAYOUT} MATCHES "STANDALONE") + set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") +else() + set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") +endif() + +# Set default values for cache entries and set the MaxScale version set_variables() set_maxscale_version() set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") project(MaxScale) +# Set the installation layout +include(${CMAKE_SOURCE_DIR}/cmake/install_layout.cmake) + #Do the platform check include(cmake/CheckPlatform.cmake) @@ -51,10 +56,10 @@ if(${MAXSCALE_VERSION} MATCHES "-stable") message(FATAL_ERROR "Could not find the release notes for this stable release: ${MAXSCALE_VERSION_NUMERIC}") endif() endif() -set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/${MAXSCALE_MODULE_INSTALL}:${CMAKE_INSTALL_PREFIX}/${MAXSCALE_LIBRARY_INSTALL}) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/server/include) configure_file(${CMAKE_SOURCE_DIR}/server/include/version.h.in ${CMAKE_BINARY_DIR}/server/include/version.h) +configure_file(${CMAKE_SOURCE_DIR}/server/include/gwdirs.h.in ${CMAKE_BINARY_DIR}/server/include/gwdirs.h) configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.h.in ${CMAKE_BINARY_DIR}/server/include/maxscale_test.h) configure_file(${CMAKE_SOURCE_DIR}/etc/postinst.in ${CMAKE_BINARY_DIR}/postinst) configure_file(${CMAKE_SOURCE_DIR}/etc/postrm.in ${CMAKE_BINARY_DIR}/postrm) diff --git a/Documentation/About/SETUP.md b/Documentation/About/SETUP.md index 2be316a4d..9cb5dd11b 100644 --- a/Documentation/About/SETUP.md +++ b/Documentation/About/SETUP.md @@ -1,37 +1,25 @@ Installation and startup Untar the binary distribution in the desired location, -e.g. /usr/local/mariadb +e.g. /usr/local/mariadb-maxscale Alternatively build from the source code using the instructions -in the README file and execute make install. +in the [Building MaxScale from Source Code](../Getting-Started/Building-MaxScale-from-Source-Code.md) document. -Simply set the environment variable MAXSCALE_HOME to point to the -MaxScale directory, found inside the path into which the files have been copied, -e.g. MAXSCALE_HOME=/usr/local/mariadb-maxscale - -Also you will need to optionally set LD_LIBRARY_PATH to include the 'lib' folder, -found inside the path into which the files have been copied, -e.g. LD_LIBRARY_PATH=/usr/local/mariadb-maxscale/lib - -Because we need the libmysqld library for parsing we must create a -valid my.cnf file to enable the library to be used. Copy the my.cnf -to $MAXSCALE_HOME/mysql/my.cnf. - -To start MaxScale execute the command 'maxscale' from the bin folder, -e.g. /usr/local/mariadb-maxscale/bin/maxscale +You can start MaxScale using `service maxscale start` or `systemctl start maxscale` if you installed the init.d scripts +or by manually starting the process from the bin folder of the installation directory. Configuration -You need to edit the file MaxScale.cnf in $MAXSCALE_HOME/etc, you should -define the set of server definitions you require, with the addresses -and ports of those servers. Also define the listening ports for your -various services. +You need to create or edit the MaxScale.cnf file in the /etc folder. +Define the services you wish to provide, the set of server definitions +you require, with the addresses and ports of those servers and also +define the listening ports for your various services. -In order to view the internal activity of the gateway you can telnet to +In order to view the internal activity of MaxScale you can either use +the maxadmin client interface with the cli routing module or telnet to the port defined for the telnet listener. Initially you may login with the user name of "admin" and the password "mariadb". Once connected type help for an overview of the commands and help for the more detailed help on commands. Use the add user command to add a new user, this will also remove the admin/mariadb user. - diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 5ce081a82..81d3c90e2 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -27,11 +27,9 @@ connection failover| When a connection currently being used between MaxScale and The MaxScale configuration is read from a file which can be located in a number of placing, MaxScale will search for the configuration file in a number of locations. -1. If the environment variable `MAXSCALE_HOME` is set then MaxScale will look for a configuration file called `MaxScale.cnf` in the directory `$MAXSCALE_HOME/etc`. +1. Location given with the --configdir= command line argument -2. If `MAXSCALE_HOME` is not set or the configuration file is not in the location above MaxScale will look for a file in `/etc/MaxScale.cnf`. - -Alternatively MaxScale can be started with the `-c` flag and the path of the MaxScale home directory tree. +2. MaxScale will look for a configuration file called `MaxScale.cnf` in the directory `/etc/MaxScale.cnf` An explicit path to a configuration file can be passed by using the `-f` option to MaxScale. @@ -524,7 +522,7 @@ Default value is `2`. Write Timeout is the timeout in seconds for each attempt t ## Protocol Modules -The protocols supported by MaxScale are implemented as external modules that are loaded dynamically into the MaxScale core. These modules reside in the directory `$MAXSCALE_HOME/modules`, if the environment variable `$MAXSCALE_HOME` is not set it defaults to `/usr/local/mariadb-maxscale`. It may also be set by passing the `-c` option on the MaxScale command line. +The protocols supported by MaxScale are implemented as external modules that are loaded dynamically into the MaxScale core. These modules reside in the directory `/usr/lib64/maxscale`. The location can be overridden with the `libdir=PATH` parameter under the `[maxscale]` section. It may also be set by passing the `-B PATH` or `--libdir=PATH` option on the MaxScale command line. ### MySQLClient diff --git a/Documentation/Getting-Started/Getting-Started-With-MaxScale.md b/Documentation/Getting-Started/Getting-Started-With-MaxScale.md index 24ee54b22..6b84d8d58 100644 --- a/Documentation/Getting-Started/Getting-Started-With-MaxScale.md +++ b/Documentation/Getting-Started/Getting-Started-With-MaxScale.md @@ -62,11 +62,9 @@ shared objects that are loaded on demand. In order for MaxScale to find these modules it will search using a predescribed search path. The rules are: 1. Look in the current directory for the module - 2. Look in $MAXSCALE_HOME/modules - 3. Look in /usr/local/mariadb-maxscale/modules - -Configuration is read by default from the file $MAXSCALE_HOME/etc/MaxScale.cnf, /etc/MaxScale.cnf. An example file is included in in the installation and can be found in the etc/ folder within the MaxScale installation. The default value of MAXSCALE_HOME can be overridden by using the -c flag on the command line. This should be immediately followed by the path to the MaxScale home directory. The -f flag can be used on the command line to set the name and the location of the configuration file. Without path expression the file is read from \$MAXSCALE_HOME/etc directory. + 2. Look in /usr/lib64/maxscale +Configuration is read by default from the file /etc/MaxScale.cnf. An example file is included in in the installation and can be found in the /usr/share/maxscale folder within the MaxScale installation. The -f flag can be used on the command line to set the name and the location of the configuration file. Without path expression the file is read from the /etc directory. ## Administration Of MaxScale diff --git a/Documentation/Tutorials/Administration-Tutorial.md b/Documentation/Tutorials/Administration-Tutorial.md index 929850eb5..894f89f94 100644 --- a/Documentation/Tutorials/Administration-Tutorial.md +++ b/Documentation/Tutorials/Administration-Tutorial.md @@ -45,7 +45,7 @@ Options may be passed to the MaxScale binary that alter this default behavior, t -f --config= - Use the filename passed as an argument instead of looking in $MAXSCALE_HOME/etc/MaxScale.cnf + Use the filename passed as an argument instead of looking in /etc/MaxScale.cnf -l| @@ -79,7 +79,7 @@ or MaxScale will also stop gracefully if it received a hangup signal, to find the process id of the MaxScale server use the ps command or read the contents of the maxscale.pid file located in the same directory as the logs. - $ kill -HUP `cat $MAXSCALE_HOME/log/maxscale.pid` + $ kill -HUP `cat /log/maxscale.pid` In order to shutdown MaxScale using the maxadmin command you may either connect with maxadmin in interactive mode or pass the "shutdown maxscale" command you wish to execute as an argument to maxadmin. diff --git a/Documentation/Tutorials/Galera-Cluster-Connection-Routing-Tutorial.md b/Documentation/Tutorials/Galera-Cluster-Connection-Routing-Tutorial.md index d75c6162a..d58ebc32c 100644 --- a/Documentation/Tutorials/Galera-Cluster-Connection-Routing-Tutorial.md +++ b/Documentation/Tutorials/Galera-Cluster-Connection-Routing-Tutorial.md @@ -60,7 +60,7 @@ If you wish to use two different usernames for the two different roles of monito ### Creating Your MaxScale Configuration -MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory $MAXSCALE_HOME/etc, if you have installed in the default location then this file is available in /usr/local/mariadb-maxscale/etc/MaxScale.cnf. This is not created as part of the installation process and must be manually created. A template file does exist within this directory that may be use as a basis for your configuration. +MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory /etc, if you have installed in the default location then this file is available in /usr/local/mariadb-maxscale/etc/MaxScale.cnf. This is not created as part of the installation process and must be manually created. A template file does exist within this directory that may be use as a basis for your configuration. A global, maxscale, section is included within every MaxScale configuration file; this is used to set the values of various MaxScale wide parameters, perhaps the most important of these is the number of threads that MaxScale will use to execute the code that forwards requests and handles responses for clients. diff --git a/Documentation/Tutorials/Galera-Cluster-Read-Write-Splitting-Tutorial.md b/Documentation/Tutorials/Galera-Cluster-Read-Write-Splitting-Tutorial.md index df57e9390..8717591d8 100644 --- a/Documentation/Tutorials/Galera-Cluster-Read-Write-Splitting-Tutorial.md +++ b/Documentation/Tutorials/Galera-Cluster-Read-Write-Splitting-Tutorial.md @@ -62,7 +62,7 @@ If you wish to use two different usernames for the two different roles of monito ### Creating Your MaxScale Configuration -MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory $MAXSCALE_HOME/etc, if you have installed in the default location then this file is available in /usr/local/mariadb-maxscale/etc/MaxScale.cnf. This is not created as part of the installation process and must be manually created. A template file does exist within this directory that may be use as a basis for your configuration. +MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory /etc, if you have installed in the default location then this file is available in /usr/local/mariadb-maxscale/etc/MaxScale.cnf. This is not created as part of the installation process and must be manually created. A template file does exist within this directory that may be use as a basis for your configuration. A global, maxscale, section is included within every MaxScale configuration file; this is used to set the values of various MaxScale wide parameters, perhaps the most important of these is the number of threads that MaxScale will use to execute the code that forwards requests and handles responses for clients. diff --git a/Documentation/Tutorials/MaxScale-Information-Schema.md b/Documentation/Tutorials/MaxScale-Information-Schema.md index c8ce5c08a..9872556b3 100644 --- a/Documentation/Tutorials/MaxScale-Information-Schema.md +++ b/Documentation/Tutorials/MaxScale-Information-Schema.md @@ -11,48 +11,59 @@ The service entry needs to define the service name, the type as service and the The specified user, with the password (plain or encrypted via maxpassword utility) is allowed to connect via MySQL protocol. Currently the user can connect to maxinfo from any remote IP and to localhost as well. +``` [MaxInfo] type=service router=maxinfo user=monitor passwd=EBD2F49C3B375812A8CDEBA632ED8BBC +``` The listener section defines the protocol, port and other information needed to create a listener for the service. To listen on a port using the MySQL protocol a section as shown below should be added to the configuration file. +``` [MaxInfo Listener] type=listener service=MaxInfo protocol=MySQLClient port=9003 +``` To listen with the HTTP protocol and hence return JSON documents a section as should below is required. +``` [MaxInfo JSON Listener] type=listener service=MaxInfo protocol=HTTPD port=8003 +``` + If both the MySQL and JSON responses are required then a single service can be configured with both types of listener. As with any other listeners within MaxScale the listeners can be bound to a particular interface by use of the address= parameter. This allows the access to the maxinfo data to be limited to the localhost by adding an address=localhost parameter in the configuration file. +``` [MaxInfo Listener] type=listener service=MaxInfo protocol=MySQLClient address=localhost port=9003 +``` # MySQL Interface to maxinfo The maxinfo supports a small subset of SQL statements in addition to the MySQL status and ping requests. These may be used for simple monitoring of MaxScale. +``` % mysqladmin -hmaxscale.mariadb.com -P9003 -umonitor -pxyz ping mysqld is alive % mysqladmin -hmaxscale.mariadb.com -P9003 -umonitor -pxyz status Uptime: 72 Threads: 1 Sessions: 11 % +``` The SQL command used to interact with maxinfo is the show command, a variety of show commands are available and will be described in the following sections. @@ -60,6 +71,7 @@ The SQL command used to interact with maxinfo is the show command, a variety of The show variables command will display a set of name and value pairs for a number of MaxScale system variables. +``` mysql> show variables; +--------------------+-------------------------+ | Variable_name | Value | @@ -77,9 +89,11 @@ The show variables command will display a set of name and value pairs for a numb 9 rows in set (0.02 sec) mysql> +``` The show variables command can also accept a limited like clause. This like clause must either be a literal string to match, a pattern starting with a %, a pattern ending with a % or a string with a % at both the start and the end. +``` mysql> show variables like 'version'; +---------------+----------------+ | Variable_name | Value | @@ -116,11 +130,13 @@ The show variables command can also accept a limited like clause. This like clau 3 rows in set (0.02 sec) mysql> +``` ## Show status The show status command displays a set of status counters, as with show variables the show status command can be passed a simplified like clause to limit the values returned. +``` mysql> show status; +---------------------------+-------+ | Variable_name | Value | @@ -151,11 +167,13 @@ The show status command displays a set of status counters, as with show variable 22 rows in set (0.02 sec) mysql> +``` ## Show services The show services command will return a set of basic statistics regarding each of the configured services within MaxScale. +``` mysql> show services; +----------------+----------------+--------------+----------------+ | Service Name | Router Module | No. Sessions | Total Sessions | @@ -172,6 +190,7 @@ The show services command will return a set of basic statistics regarding each o 8 rows in set (0.02 sec) mysql> +``` The show services command does not accept a like clause and will ignore any like clause that is given. @@ -179,6 +198,7 @@ The show services command does not accept a like clause and will ignore any like The show listeners command will return a set of status information for every listener defined within the MaxScale configuration file. +``` mysql> show listeners; +----------------+-----------------+-----------+------+---------+ | Service Name | Protocol Module | Address | Port | State | @@ -196,6 +216,7 @@ The show listeners command will return a set of status information for every lis 9 rows in set (0.02 sec) mysql> +``` The show listeners command will ignore any like clause passed to it. @@ -203,6 +224,7 @@ The show listeners command will ignore any like clause passed to it. The show sessions command returns information on every active session within MaxScale. It will ignore any like clause passed to it. +``` mysql> show sessions; +-----------+---------------+----------------+---------------------------+ | Session | Client | Service | State | @@ -222,11 +244,13 @@ The show sessions command returns information on every active session within Max 11 rows in set (0.02 sec) mysql> +``` ## Show clients The show clients command reports a row for every client application connected to MaxScale. Like clauses are not available of the show clients command. +``` mysql> show clients; +-----------+---------------+---------+---------------------------+ | Session | Client | Service | State | @@ -237,11 +261,13 @@ The show clients command reports a row for every client application connected to 2 rows in set (0.02 sec) mysql> +``` ## Show servers The show servers command returns data for each backend server configured within the MaxScale configuration file. This data includes the current number of connections MaxScale has to that server and the state of that server as monitored by MaxScale. +``` mysql> show servers; +---------+-----------+------+-------------+---------+ | Server | Address | Port | Connections | Status | @@ -254,11 +280,13 @@ The show servers command returns data for each backend server configured within 4 rows in set (0.02 sec) mysql> +``` ## Show modules The show modules command reports the information on the modules currently loaded into MaxScale. This includes the name type and version of each module. It also includes the API version the module has been written against and the current release status of the module. +``` mysql> show modules; +----------------+-------------+---------+-------------+----------------+ | Module Name | Module Type | Version | API Version | Status | @@ -277,12 +305,13 @@ The show modules command reports the information on the modules currently loaded 10 rows in set (0.02 sec) mysql> - +``` ## Show monitors The show monitors command reports each monitor configured within the system and the state of that monitor. +``` mysql> show monitors; +---------------+---------+ | Monitor | Status | @@ -292,12 +321,13 @@ The show monitors command reports each monitor configured within the system and 1 row in set (0.02 sec) mysql> - +``` ## Show eventTimes The show eventTimes command returns a table of statistics that reflect the performance of the event queuing and execution portion of the MaxScale core. +``` mysql> show eventTimes; +---------------+-------------------+---------------------+ | Duration | No. Events Queued | No. Events Executed | @@ -336,6 +366,7 @@ The show eventTimes command returns a table of statistics that reflect the perfo 30 rows in set (0.02 sec) mysql> +``` Each row represents a time interval, in 100ms increments, with the counts representing the number of events that were in the event queue for the length of time that row represents and the number of events that were executing of the time indicated by the row. @@ -347,6 +378,7 @@ The simplified JSON interface takes the URL of the request made to maxinfo and m The /variables URL will return the MaxScale variables, these variables can not be filtered via this interface. +``` $ curl http://maxscale.mariadb.com:8003/variables [ { "Variable_name" : "version", "Value" : "1.0.6-unstable"}, { "Variable_name" : "version_comment", "Value" : "MariaDB MaxScale"}, @@ -358,11 +390,13 @@ The /variables URL will return the MaxScale variables, these variables can not b { "Variable_name" : "MAXSCALE_UPTIME", "Value" : 3948}, { "Variable_name" : "MAXSCALE_SESSIONS", "Value" : 12}] $ +``` ## Status Use of the /status URI will return the status information that would normally be returned by the show status command. No filtering of the status information is available via this interface +``` $ curl http://maxscale.mariadb.com:8003/status [ { "Variable_name" : "Uptime", "Value" : 3831}, { "Variable_name" : "Uptime_since_flush_status", "Value" : 3831}, @@ -387,11 +421,13 @@ Use of the /status URI will return the status information that would normally be { "Variable_name" : "Max_event_queue_time", "Value" : 0}, { "Variable_name" : "Max_event_execution_time", "Value" : 1}] $ +``` ## Services The /services URI returns the data regarding the services defined within the configuration of MaxScale. Two counters are returned, the current number of sessions attached to this service and the total number connected since the service started. +``` $ curl http://maxscale.mariadb.com:8003/services [ { "Service Name" : "Test Service", "Router Module" : "readconnroute", "No. Sessions" : 1, "Total Sessions" : 1}, { "Service Name" : "Split Service", "Router Module" : "readwritesplit", "No. Sessions" : 1, "Total Sessions" : 1}, @@ -402,11 +438,13 @@ The /services URI returns the data regarding the services defined within the con { "Service Name" : "CLI", "Router Module" : "cli", "No. Sessions" : 1, "Total Sessions" : 1}, { "Service Name" : "MaxInfo", "Router Module" : "maxinfo", "No. Sessions" : 5, "Total Sessions" : 20}] $ +``` ## Listeners The /listeners URI will return a JSON array with one entry per listener, each entry is a JSON object that describes the configuration and state of that listener. +``` $ curl http://maxscale.mariadb.com:8003/listeners [ { "Service Name" : "Test Service", "Protocol Module" : "MySQLClient", "Address" : "*", "Port" : 4006, "State" : "Running"}, { "Service Name" : "Split Service", "Protocol Module" : "MySQLClient", "Address" : "*", "Port" : 4007, "State" : "Running"}, @@ -418,11 +456,13 @@ The /listeners URI will return a JSON array with one entry per listener, each en { "Service Name" : "MaxInfo", "Protocol Module" : "MySQLClient", "Address" : "*", "Port" : 9003, "State" : "Running"}, { "Service Name" : "MaxInfo", "Protocol Module" : "HTTPD", "Address" : "*", "Port" : 8003, "State" : "Running"}] $ +``` ## Modules The /modules URI returns data for each plugin that has been loaded into MaxScale. The plugin name, type and version are returned as is the version of the plugin API that the plugin was built against and the release status of the plugin. +``` $ curl http://maxscale.mariadb.com:8003/modules [ { "Module Name" : "HTTPD", "Module Type" : "Protocol", "Version" : "V1.0.1", "API Version" : "1.0.0", "Status" : "In Development"}, { "Module Name" : "maxscaled", "Module Type" : "Protocol", "Version" : "V1.0.0", "API Version" : "1.0.0", "Status" : "GA"}, @@ -435,11 +475,13 @@ The /modules URI returns data for each plugin that has been loaded into MaxScale { "Module Name" : "cli", "Module Type" : "Router", "Version" : "V1.0.0", "API Version" : "1.0.0", "Status" : "GA"}, { "Module Name" : "maxinfo", "Module Type" : "Router", "Version" : "V1.0.0", "API Version" : "1.0.0", "Status" : "Alpha"}] $ +``` ## Sessions The /sessions URI returns a JSON array with an object for each active session within MaxScale. +``` $ curl http://maxscale.mariadb.com:8003/sessions [ { "Session" : "0x1a8e9a0", "Client" : "80.176.79.245", "Service" : "MaxInfo", "State" : "Session ready for routing"}, { "Session" : "0x1a8e6d0", "Client" : "80.240.130.35", "Service" : "MaxInfo", "State" : "Session ready for routing"}, @@ -453,32 +495,38 @@ The /sessions URI returns a JSON array with an object for each active session wi { "Session" : "0x1a5c530", "Client" : , "Service" : "Split Service", "State" : "Listener Session"}, { "Session" : "0x19ac1c0", "Client" : , "Service" : "Test Service", "State" : "Listener Session"}] $ +``` ## Clients The /clients URI is a limited version of the /sessions, in this case it only returns an entry for a session that represents a client connection. +``` $ curl http://maxscale.mariadb.com:8003/clients [ { "Session" : "0x1a90be0", "Client" : "80.176.79.245", "Service" : "MaxInfo", "State" : "Session ready for routing"}, { "Session" : "0x1a8e9a0", "Client" : "127.0.0.1", "Service" : "MaxInfo", "State" : "Session ready for routing"}, { "Session" : "0x1a8e6d0", "Client" : "80.240.130.35", "Service" : "MaxInfo", "State" : "Session ready for routing"}] $ +``` ## Servers The /servers URI is used to retrieve information for each of the servers defined within the MaxScale configuration. This information includes the connection count and the current status as monitored by MaxScale. The connection count is only those connections made by MaxScale to those servers. +``` $ curl http://maxscale.mariadb.com:8003/servers [ { "Server" : "server1", "Address" : "127.0.0.1", "Port" : 3306, "Connections" : 0, "Status" : "Running"}, { "Server" : "server2", "Address" : "127.0.0.1", "Port" : 3307, "Connections" : 0, "Status" : "Down"}, { "Server" : "server3", "Address" : "127.0.0.1", "Port" : 3308, "Connections" : 0, "Status" : "Down"}, { "Server" : "server4", "Address" : "127.0.0.1", "Port" : 3309, "Connections" : 0, "Status" : "Down"}] $ +``` ## Event Times The /event/times URI returns an array of statistics that reflect the performance of the event queuing and execution portion of the MaxScale core. Each element is an object that represents a time bucket, in 100ms increments, with the counts representing the number of events that were in the event queue for the length of time that row represents and the number of events that were executing of the time indicated by the object. +``` $ curl http://maxscale.mariadb.com:8003/event/times [ { "Duration" : "< 100ms", "No. Events Queued" : 64, "No. Events Executed" : 63}, { "Duration" : " 100 - 200ms", "No. Events Queued" : 0, "No. Events Executed" : 0}, @@ -510,3 +558,4 @@ The /event/times URI returns an array of statistics that reflect the performance { "Duration" : "2700 - 2800ms", "No. Events Queued" : 0, "No. Events Executed" : 0}, { "Duration" : "2800 - 2900ms", "No. Events Queued" : 0, "No. Events Executed" : 0}, { "Duration" : "> 3000ms", "No. Events Queued" : 0, "No. Events Executed" : 0}] +``` diff --git a/Documentation/Tutorials/MySQL-Replication-Connection-Routing-Tutorial.md b/Documentation/Tutorials/MySQL-Replication-Connection-Routing-Tutorial.md index aac084f7b..8158bfa76 100644 --- a/Documentation/Tutorials/MySQL-Replication-Connection-Routing-Tutorial.md +++ b/Documentation/Tutorials/MySQL-Replication-Connection-Routing-Tutorial.md @@ -36,6 +36,7 @@ The first user required must be able to select data from the table mysql.user, t 2. Create the user, substituting the username, password and host on which maxscale runs within your environment +``` MariaDB [(none)]> create user '*username*'@'*maxscalehost*' identified by '*password*'; **Query OK, 0 rows affected (0.00 sec)** @@ -45,9 +46,11 @@ MariaDB [(none)]> create user '*username*'@'*maxscalehost*' identified by '*pass MariaDB [(none)]> grant SELECT on mysql.user to '*username*'@'*maxscalehost*'; **Query OK, 0 rows affected (0.03 sec)** +``` Additionally, GRANT SELECT on the mysql.db table and SHOW DATABASES privileges are required in order to load databases name and grants suitable for database name authorization. +``` MariaDB [(none)]> GRANT SELECT ON mysql.db TO 'username'@'maxscalehost'; **Query OK, 0 rows affected (0.00 sec)** @@ -55,9 +58,11 @@ MariaDB [(none)]> GRANT SELECT ON mysql.db TO 'username'@'maxscalehost'; MariaDB [(none)]> GRANT SHOW DATABASES ON *.* TO 'username'@'maxscalehost'; **Query OK, 0 rows affected (0.00 sec)** +``` The second user is used to monitored the state of the cluster. This user, which may be the same username as the first, requires permissions to access the various sources of monitoring data. In order to monitor a replication cluster this user must be granted the roles REPLICATION SLAVE and REPLICATION CLIENT +``` MariaDB [(none)]> grant REPLICATION SLAVE on *.* to '*username*'@'*maxscalehost*'; **Query OK, 0 rows affected (0.00 sec)** @@ -65,220 +70,174 @@ MariaDB [(none)]> grant REPLICATION SLAVE on *.* to '*username*'@'*maxscalehost* MariaDB [(none)]> grant REPLICATION CLIENT on *.* to '*username*'@'*maxscalehost*'; **Query OK, 0 rows affected (0.00 sec)** +``` If you wish to use two different usernames for the two different roles of monitoring and collecting user information then create a different username using the first two steps from above. ## Creating Your MaxScale Configuration -MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory $MAXSCALE_HOME/etc, if you have installed in the default location then this file is available in /usr/local/mariadb/maxscle/etc/MaxScale.cnf. This is not created as part of the installation process and must be manually created. A template file does exist within this directory that may be use as a basis for your configuration. +MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory /etc. This is not created as part of the installation process and must be manually created. A template file does exist in the `/usr/share/maxscale` folder that can be use as a basis for your configuration. A global, maxscale, section is included within every MaxScale configuration file; this is used to set the values of various MaxScale wide parameters, perhaps the most important of these is the number of threads that MaxScale will use to execute the code that forwards requests and handles responses for clients. +``` [maxscale] - threads=4 +``` Since we are using MySQL Replication and connection routing we want two different ports to which the client application can connect; one that will be directed to the current master within the replication cluster and another that will load balance between the slaves. To achieve this within MaxScale we need to define two services in the ini file; one for the read/write operations that should be executed on the master server and another for connections to one of the slaves. Create a section for each in your MaxScale.ini file and set the type to service, the section names are the names of the services themselves and should be meaningful to the administrator. Names may contain whitespace. +``` [Write Service] - type=service [Read Service] - type=service +``` The router for these two sections is identical, the readconnroute module, also the services should be provided with the list of servers that will be part of the cluster. The server names given here are actually the names of server sections in the configuration file and not the physical hostnames or addresses of the servers. +``` [Write Service] - type=service - router=readconnroute - servers=dbserv1, dbserv2, dbserv3 [Read Service] - type=service - router=readconnroute - servers=dbserv1, dbserv2, dbserv3 +``` In order to instruct the router to which servers it should route we must add router options to the service. The router options are compared to the status that the monitor collects from the servers and used to restrict the eligible set of servers to which that service may route. In our case we use the two options master and slave for our two services. +``` [Write Service] - type=service - router=readconnroute - router_options=master - servers=dbserv1, dbserv2, dbserv3 [Read Service] - type=service - router=readconnroute - router_options=slave - servers=dbserv1, dbserv2, dbserv3 +``` The final step in the service sections is to add the username and password that will be used to populate the user data from the database cluster. There are two options for representing the password, either plain text or encrypted passwords may be used. In order to use encrypted passwords a set of keys must be generated that will be used by the encryption and decryption process. To generate the keys use the maxkeys command and pass the name of the secrets file in which the keys are stored. -% maxkeys /usr/local/mariadb-maxscale/etc/.secrets - -% +``` +maxkeys /usr/local/mariadb-maxscale/etc/.secrets +``` Once the keys have been created the maxpasswd command can be used to generate the encrypted password. -% maxpasswd plainpassword - +``` +maxpasswd plainpassword 96F99AA1315BDC3604B006F427DD9484 - -% +``` The username and password, either encrypted or plain text, are stored in the service section using the user and passwd parameters. +``` [Write Service] - type=service - router=readconnroute - router_options=master - servers=dbserv1, dbserv2, dbserv3 - user=maxscale - passwd=96F99AA1315BDC3604B006F427DD9484 [Read Service] - type=service - router=readconnroute - router_options=slave - servers=dbserv1, dbserv2, dbserv3 - user=maxscale - passwd=96F99AA1315BDC3604B006F427DD9484 +``` This completes the definitions required by the services, however listening ports must be associated with the services in order to allow network connections. This is done by creating a series of listener sections. These sections again are named for the convenience of the administrator and should be of type listener with an entry labeled service which contains the name of the service to associate the listener with. Each service may have multiple listeners. +``` [Write Listener] - type=listener - service=Write Service [Read Listener] - type=listener - service=Read Service +``` A listener must also define the protocol module it will use for the incoming network protocol, currently this should be the MySQLClient protocol for all database listeners. The listener may then supply a network port to listen on and/or a socket within the file system. +``` [Write Listener] - type=listener - service=Write Service - protocol=MySQLClient - port=4306 - socket=/tmp/ClusterMaster [Read Listener] - type=listener - service=Read Service - protocol=MySQLClient - port=4307 +``` An address parameter may be given if the listener is required to bind to a particular network address when using hosts with multiple network addresses. The default behavior is to listen on all network interfaces. The next stage is the configuration is to define the server information. This defines how to connect to each of the servers within the cluster, again a section is created for each server, with the type set to server, the network address and port to connect to and the protocol to use to connect to the server. Currently the protocol for all database connections in MySQLBackend. +``` [dbserv1] - type=server - address=192.168.2.1 - port=3306 - protocol=MySQLBackend [dbserv2] - type=server - address=192.168.2.2 - port=3306 - protocol=MySQLBackend [dbserv3] - type=server - address=192.168.2.3 - port=3306 - protocol=MySQLBackend +``` In order for MaxScale to monitor the servers using the correct monitoring mechanisms a section should be provided that defines the monitor to use and the servers to monitor. Once again a section is created with a symbolic name for the monitor, with the type set to monitor. Parameters are added for the module to use, the list of servers to monitor and the username and password to use when connecting to the the servers with the monitor. +``` [Replication Monitor] - type=monitor - module=mysqlmon - servers=dbserv1, dbserv2, dbserv3 - user=maxscale - passwd=96F99AA1315BDC3604B006F427DD9484 +``` As with the password definition in the server either plain text or encrypted passwords may be used. The final stage in the configuration is to add the option service which is used by the maxadmin command to connect to MaxScale for monitoring and administration purposes. This creates a service section and a listener section. +``` [CLI] - type=service - router=cli [CLI Listener] - type=listener - service=CLI - protocol=maxscaled - address=localhost - port=6603 +``` In the case of the example above it should be noted that an address parameter has been given to the listener, this limits connections to maxadmin commands that are executed on the same machine that hosts MaxScale. @@ -286,14 +245,19 @@ In the case of the example above it should be noted that an address parameter ha Upon completion of the configuration process MaxScale is ready to be started for the first time. This may either be done manually by running the maxscale command or via the service interface. -% maxscale +``` +maxscale +``` or -% service maxscale start +``` +service maxscale start +``` -Check the error log in /usr/local/mariadb-maxscale/log to see if any errors are detected in the configuration file and to confirm MaxScale has been started. Also the maxadmin command may be used to confirm that MaxScale is running and the services, listeners etc have been correctly configured. +Check the error log in /var/log/lomaxscale/ to see if any errors are detected in the configuration file and to confirm MaxScale has been started. Also the maxadmin command may be used to confirm that MaxScale is running and the services, listeners etc have been correctly configured. +``` % maxadmin -pmariadb list services Services. @@ -349,6 +313,7 @@ CLI | maxscaled | localhost | 6603 | Running ---------------------+--------------------+-----------------+-------+-------- % +``` -MaxScale is now ready to start accepting client connections and routing them to the master or slaves within your cluster. Other configuration options are available that can alter the criteria used for routing, these include monitoring the replication lag within the cluster and routing only to slaves that are within a predetermined delay from the current master or using weights to obtain unequal balancing operations. These options may be found in the MaxScale Configuration Guide. More detail on the use of maxadmin can be found in the document "MaxAdmin - The MaxScale Administration & Monitoring Client Application". +MaxScale is now ready to start accepting client connections and routing them to the master or slaves within your cluster. Other configuration options are available that can alter the criteria used for routing, these include monitoring the replication lag within the cluster and routing only to slaves that are within a predetermined delay from the current master or using weights to obtain unequal balancing operations. These options may be found in the MaxScale Configuration Guide. More detail on the use of maxadmin can be found in the document [MaxAdmin - The MaxScale Administration & Monitoring Client Application](Administration-Tutorial.md). diff --git a/Documentation/Tutorials/MySQL-Replication-Read-Write-Splitting-Tutorial.md b/Documentation/Tutorials/MySQL-Replication-Read-Write-Splitting-Tutorial.md index 54e5412be..b34fcf71e 100644 --- a/Documentation/Tutorials/MySQL-Replication-Read-Write-Splitting-Tutorial.md +++ b/Documentation/Tutorials/MySQL-Replication-Read-Write-Splitting-Tutorial.md @@ -70,7 +70,7 @@ If you wish to use two different usernames for the two different roles of monito ## Creating Your MaxScale Configuration -MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory $MAXSCALE_HOME/etc, if you have installed in the default location then this file is available in /usr/local/mariadb-maxscale/etc/MaxScale.cnf. This is not created as part of the installation process and must be manually created. A template file does exist within this directory that may be use as a basis for your configuration. +MaxScale configuration is held in an ini file that is located in the file MaxScale.cnf in the directory /etc, if you have installed in the default location then this file is available in /usr/local/mariadb-maxscale/etc/MaxScale.cnf. This is not created as part of the installation process and must be manually created. A template file does exist within this directory that may be use as a basis for your configuration. A global, maxscale, section is included within every MaxScale configuration file; this is used to set the values of various MaxScale wide parameters, perhaps the most important of these is the number of threads that MaxScale will use to execute the code that forwards requests and handles responses for clients. diff --git a/Documentation/Tutorials/Replication-Proxy-Binlog-Router-Tutorial.md b/Documentation/Tutorials/Replication-Proxy-Binlog-Router-Tutorial.md index f07fd13a3..3f61638d1 100644 --- a/Documentation/Tutorials/Replication-Proxy-Binlog-Router-Tutorial.md +++ b/Documentation/Tutorials/Replication-Proxy-Binlog-Router-Tutorial.md @@ -84,7 +84,7 @@ This optional parameter allows for the administrator to define the number of the ### binlogdir -This parameter allows the location that MaxScale uses to store binlog files to be set. If this parameter is not set to a directory name then MaxScale will store the binlog files in the directory $MAXSCALE_HOME/. +This parameter allows the location that MaxScale uses to store binlog files to be set. If this parameter is not set to a directory name then MaxScale will store the binlog files in the directory /var/cache/maxscale/. ### heartbeat diff --git a/Documentation/filters/Query-Log-All-Filter.md b/Documentation/filters/Query-Log-All-Filter.md index e0c71e13f..87ea620c8 100644 --- a/Documentation/filters/Query-Log-All-Filter.md +++ b/Documentation/filters/Query-Log-All-Filter.md @@ -6,7 +6,7 @@ The Query Log All (QLA) filter is a filter module for MaxScale that is ## Configuration -The configuration block for the QLA filter requires the minimal filter options in it's section within the MaxScale.cnf file, stored in $MAXSCALE_HOME/etc/MaxScale.cnf. +The configuration block for the QLA filter requires the minimal filter options in it's section within the MaxScale.cnf file, stored in /etc/MaxScale.cnf. ``` [MyLogFilter] type=filter diff --git a/Documentation/filters/RabbitMQ-Filter.md b/Documentation/filters/RabbitMQ-Filter.md index f23313d0d..4068ceec5 100644 --- a/Documentation/filters/RabbitMQ-Filter.md +++ b/Documentation/filters/RabbitMQ-Filter.md @@ -5,7 +5,7 @@ This filter is designed to extract queries and transform them into a canonical f ## Configuration -The configuration block for the **mqfilter** filter requires the minimal filter options in it’s section within the MaxScale.cnf file, stored in $MAXSCALE_HOME/etc/MaxScale.cnf. Although the filter will start, it will use the default values which only work with a freshly installed RabbitMQ server and use its default values. This setup is mostly intended for testing the filter. +The configuration block for the **mqfilter** filter requires the minimal filter options in it’s section within the MaxScale.cnf file, stored in /etc/MaxScale.cnf. Although the filter will start, it will use the default values which only work with a freshly installed RabbitMQ server and use its default values. This setup is mostly intended for testing the filter. The following is an example of a mqfilter configuration in the MaxScale.cnf file used for actual logging of queries to a RabbitMQ broker on a different host. diff --git a/Documentation/filters/Regex-Filter.md b/Documentation/filters/Regex-Filter.md index 2d5ecd96d..e5a6744f2 100644 --- a/Documentation/filters/Regex-Filter.md +++ b/Documentation/filters/Regex-Filter.md @@ -6,7 +6,7 @@ The regex filter is a filter module for MaxScale that is able to rewrite query c # Configuration -The configuration block for the Regex filter requires the minimal filter options in it’s section within the MaxScale.cnf file, stored in $MAXSCALE_HOME/etc/MaxScale.cnf. +The configuration block for the Regex filter requires the minimal filter options in it’s section within the MaxScale.cnf file, stored in /etc/MaxScale.cnf. ``` [MyRegexFilter] diff --git a/Documentation/filters/Tee-Filter.md b/Documentation/filters/Tee-Filter.md index a8a95a5cc..868886ceb 100644 --- a/Documentation/filters/Tee-Filter.md +++ b/Documentation/filters/Tee-Filter.md @@ -6,7 +6,7 @@ The tee filter is a filter module for MaxScale is a "plumbing" fitting in the Ma # Configuration -The configuration block for the TEE filter requires the minimal filter parameters in it’s section within the MaxScale.cnf file, stored in $MAXSCALE_HOME/etc/MaxScale.cnf, that defines the filter to load and the service to send the duplicates to. Currently the tee filter does not support multi-statements. +The configuration block for the TEE filter requires the minimal filter parameters in it’s section within the MaxScale.cnf file, stored in /etc/MaxScale.cnf, that defines the filter to load and the service to send the duplicates to. Currently the tee filter does not support multi-statements. ``` [DataMartFilter] diff --git a/Documentation/filters/Top-N-Filter.md b/Documentation/filters/Top-N-Filter.md index d51ca43db..f52a6bedd 100644 --- a/Documentation/filters/Top-N-Filter.md +++ b/Documentation/filters/Top-N-Filter.md @@ -6,7 +6,7 @@ The top filter is a filter module for MaxScale that monitors every SQL statement # Configuration -The configuration block for the TOP filter requires the minimal filter options in it’s section within the MaxScale.cnf file, stored in $MAXSCALE_HOME/etc/MaxScale.cnf. +The configuration block for the TOP filter requires the minimal filter options in it’s section within the MaxScale.cnf file, stored in /etc/MaxScale.cnf. ``` [MyLogFilter] diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake index 821b2c474..1425b4d49 100644 --- a/cmake/install_layout.cmake +++ b/cmake/install_layout.cmake @@ -3,18 +3,12 @@ # STANDALONE - Installs to /usr/local/mariadb-maxscale # RPM - Installs to /usr # DEB - Installs to /usr -if(${TYPE} MATCHES "STANDALONE") +include(GNUInstallDirs) - set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") - - # RPM and DEB are the same until differences are found -else() - set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") -endif() - -set(MAXSCALE_LIBDIR lib64/maxscale CACHE PATH "Library installation path") -set(MAXSCALE_BINDIR bin CACHE PATH "Executable installation path") -set(MAXSCALE_SHAREDIR share/maxscale CACHE PATH "Share file installation path, includes licence and readme files") -set(MAXSCALE_DOCDIR share/doc/maxscale CACHE PATH "Documentation installation path, text versions only") -set(MAXSCALE_CONFDIR etc CACHE PATH "Configuration file installation path, this is not usually needed") +set(MAXSCALE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/maxscale CACHE PATH "Library installation path") +set(MAXSCALE_BINDIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Executable installation path") +set(MAXSCALE_SHAREDIR ${CMAKE_INSTALL_DATADIR}/maxscale CACHE PATH "Share file installation path, includes licence and readme files") +set(MAXSCALE_DOCDIR ${CMAKE_INSTALL_DOCDIR}/maxscale CACHE PATH "Documentation installation path, text versions only") +set(MAXSCALE_CONFDIR ${CMAKE_INSTALL_SYSCONFDIR} CACHE PATH "Configuration file installation path, this is not usually needed") +set(MAXSCALE_VARDIR /var CACHE PATH "Data file path (usually /var/)") diff --git a/server/core/gateway.c b/server/core/gateway.c index a4901ec23..f24cf8a11 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -505,15 +505,9 @@ static bool resolve_maxscale_conf_fname( * directory. * '-f MaxScale.cnf' */ - home_etc_dir = (char*)malloc(strlen(home_dir)+strlen("/etc")+1); - snprintf(home_etc_dir, - strlen(home_dir)+strlen("/etc")+1, - "%s/etc", - home_dir); *cnf_full_path = get_expanded_pathname(NULL, - home_etc_dir, + home_dir, cnf_file_arg); - free(home_etc_dir); if (*cnf_full_path != NULL) { @@ -1026,11 +1020,11 @@ static void usage(void) " -L|--logdir=... path to log file directory\n" " (default: /var/log/maxscale)\n" " -D|--datadir=... path to data directory\n" - " (default: /var/lib/maxscale)\n" + " (default: /usr/lib64/maxscale)\n" " -C|--configdir=... path to configuration file directory\n" " (default: /etc/)\n" - " -B|--libdir=... path to module directory\n" - " (default: /var/lib/maxscale)\n" + " -B|--libdir=... path to module directory\n" + " (default: /usr/lib64/maxscale)\n" " -A|--cachedir=... path to cache directory\n" " (default: /var/cache/maxscale)\n" " -s|--syslog= log messages to syslog.\n" @@ -1588,63 +1582,6 @@ int main(int argc, char **argv) sprintf(mysql_home, "%s/mysql", cachedir); setenv("MYSQL_HOME", mysql_home, 1); - /*< - * If MaxScale home directory wasn't set by command-line argument. - * Next, resolve it from environment variable and further on, - * try to use default. - */ -/* - - if (home_dir == NULL) - { - if (!resolve_maxscale_homedir(&home_dir)) - { - ss_dassert(home_dir != NULL); - rc = MAXSCALE_HOMELESS; - goto return_main; - } - - } - else - { - char* log_context = strdup("Home directory command-line argument"); - char* errstr; - - errstr = check_dir_access(home_dir,true,true); - - if (errstr != NULL) - { - char* logstr = (char*)malloc(strlen(log_context)+ - 1+ - strlen(errstr)+ - 1); - - snprintf(logstr, - strlen(log_context)+ - 1+ - strlen(errstr)+1, - "%s: %s", - log_context, - errstr); - - print_log_n_stderr(true, true, logstr, logstr, 0); - - free(errstr); - free(logstr); - rc = MAXSCALE_HOMELESS; - goto return_main; - } - else if (!daemon_mode) - { - fprintf(stderr, - "Using %s as MAXSCALE_HOME = %s\n", - log_context, - home_dir); - } - free(log_context); - } -*/ - /** * Resolve the full pathname for configuration file and check for * read accessibility. diff --git a/server/include/gw.h b/server/include/gw.h index e210fcfa2..b51bb0e2a 100644 --- a/server/include/gw.h +++ b/server/include/gw.h @@ -1,5 +1,25 @@ #ifndef _GW_HG #define _GW_HG + +/* + * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright MariaDB Corporation Ab 2013-2014 + */ + + #include #include #include @@ -19,17 +39,7 @@ #include #include #include - -/** Default file locations */ -static const char* default_cnf_fname = "MaxScale.cnf"; -static const char* default_configdir = "/etc/"; -static const char* default_logdir = "/var/log/maxscale/"; -static const char* default_datadir = "/var/cache/maxscale/"; -static const char* default_libdir = "/lib64/maxscale/"; -static const char* default_cachedir = "/var/cache/maxscale/"; -static const char* default_langdir = "/usr/share/mysql/english/"; /*< This is where the MariaDB - * server installs errmsg.sys */ -static const char* default_piddir = "/var/run/maxscale/"; +#include #define EXIT_FAILURE 1 diff --git a/server/include/gwdirs.h.in b/server/include/gwdirs.h.in new file mode 100644 index 000000000..3bc6c3f67 --- /dev/null +++ b/server/include/gwdirs.h.in @@ -0,0 +1,33 @@ +#ifndef _GW_DIRS_HG +#define _GW_DIRS_HG + +/* + * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright MariaDB Corporation Ab 2015 + */ + +/** Default file locations, configured by CMake */ +static const char* default_cnf_fname = "MaxScale.cnf"; +static const char* default_configdir = "/etc/"; +static const char* default_piddir = "/var/run/maxscale/"; +static const char* default_logdir = "/var/log/maxscale/"; +static const char* default_datadir = "/var/cache/maxscale/"; +static const char* default_libdir = "@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@"; +static const char* default_cachedir = "/var/cache/maxscale/"; +static const char* default_langdir = "/usr/share/mysql/english/"; /*< This is where the MariaDB + * server installs errmsg.sys */ + +#endif From 9eeec2e9d3f131b038c2977f24c8d39f199c71aa Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Sun, 26 Apr 2015 11:41:02 +0300 Subject: [PATCH 013/275] Added FindJemalloc.cmake --- CMakeLists.txt | 2 +- cmake/FindJemalloc.cmake | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 cmake/FindJemalloc.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 564cb43a5..34d2767ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ find_package(MySQLClient) find_package(MySQL) find_package(Pandoc) find_package(TCMalloc) - +find_package(Jemalloc) # You can find the variables set by this in the FindCURL.cmake file # which is a default module in CMake. find_package(CURL) diff --git a/cmake/FindJemalloc.cmake b/cmake/FindJemalloc.cmake new file mode 100644 index 000000000..3bea2d5a0 --- /dev/null +++ b/cmake/FindJemalloc.cmake @@ -0,0 +1,11 @@ +# this CMake file defines the following variables +# JEMALLOC_FOUND - Jemalloc was found +# JEMALLOC_LIBRARIES - Jemalloc library +find_library(JEMALLOC_LIBRARIES NAMES jemalloc libjemalloc.so.4 libjemalloc.so.4.2.2) +if(JEMALLOC_LIBRARIES) + set(JEMALLOC_FOUND TRUE CACHE INTERNAL "") + message(STATUS "Found libjemalloc: ${JEMALLOC_LIBRARIES}") +else() + set(JEMALLOC_FOUND FALSE CACHE INTERNAL "") + message(STATUS "Could not find libjemalloc, using system default malloc instead.") +endif() From 49907ffdea3f5caf62bd6dddcf6d1fb87de81e7b Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 05:57:16 +0300 Subject: [PATCH 014/275] Added optional jemalloc linkage. --- server/core/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index ead8560d3..36d87865f 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -1,7 +1,9 @@ if(BUILD_TESTS OR BUILD_TOOLS) file(GLOB FULLCORE_SRC *.c) add_library(fullcore STATIC ${FULLCORE_SRC}) - if(WITH_TCMALLOC) + if(WITH_JEMALLOC) + target_link_libraries(fullcore ${JEMALLOC_LIBRARIES}) + elseif(WITH_TCMALLOC) target_link_libraries(fullcore ${TCMALLOC_LIBRARIES}) endif() target_link_libraries(fullcore ${CURL_LIBRARIES} log_manager utils pthread ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ssl aio rt crypt dl crypto inih z m stdc++) @@ -13,7 +15,9 @@ add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c monitor.c adminusers.c secrets.c filter.c modutil.c hint.c housekeeper.c memlog.c resultset.c) -if(WITH_TCMALLOC) +if(WITH_JEMALLOC) + target_link_libraries(maxscale ${JEMALLOC_LIBRARIES}) +elseif(WITH_TCMALLOC) target_link_libraries(maxscale ${TCMALLOC_LIBRARIES}) endif() From 41ddc6fbfda25356be73aa9050e9176544ca7117 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 09:43:22 +0300 Subject: [PATCH 015/275] Switched over to gwbuf_clone_portion in modutils_get_complete_packets. Conflicts: server/core/modutil.c --- server/core/modutil.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/core/modutil.c b/server/core/modutil.c index 82890e334..c01c7623a 100644 --- a/server/core/modutil.c +++ b/server/core/modutil.c @@ -538,7 +538,7 @@ return_packetbuf: GWBUF* modutil_get_complete_packets(GWBUF** p_readbuf) { GWBUF *buff = NULL, *packet; - uint8_t *ptr,*end; + uint8_t *ptr; int len,blen,total = 0; if(p_readbuf == NULL || (*p_readbuf) == NULL || @@ -583,7 +583,6 @@ GWBUF* modutil_get_complete_packets(GWBUF** p_readbuf) "Error: Failed to partially clone buffer."); return NULL; } - gwbuf_consume(packet,total); return buff; } @@ -841,4 +840,4 @@ int modutil_count_statements(GWBUF* buffer) } return num; -} \ No newline at end of file +} From d5682bf7c089a486bcc18cb2f04c79331182fe58 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 10:10:55 +0300 Subject: [PATCH 016/275] Removed file globbing in the core CMake file and used explicit names instead. --- server/core/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 36d87865f..218d2b0c4 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -1,6 +1,5 @@ if(BUILD_TESTS OR BUILD_TOOLS) - file(GLOB FULLCORE_SRC *.c) - add_library(fullcore STATIC ${FULLCORE_SRC}) + add_library(fullcore STATIC adminusers.c atomic.c config.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.x modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c) if(WITH_JEMALLOC) target_link_libraries(fullcore ${JEMALLOC_LIBRARIES}) elseif(WITH_TCMALLOC) From 97653e98faa1cb73113354a7bfad0e5de712f188 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 10:14:47 +0300 Subject: [PATCH 017/275] Fixed a typo in the core CMakeLists.txt --- server/core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 218d2b0c4..25bf74c35 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -1,5 +1,5 @@ if(BUILD_TESTS OR BUILD_TOOLS) - add_library(fullcore STATIC adminusers.c atomic.c config.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.x modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c) + add_library(fullcore STATIC adminusers.c atomic.c config.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c) if(WITH_JEMALLOC) target_link_libraries(fullcore ${JEMALLOC_LIBRARIES}) elseif(WITH_TCMALLOC) From 2fce1144830a06c474c3a6a19b4a73c0849e0408 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 10:17:55 +0300 Subject: [PATCH 018/275] Added missing buffer.c from fullcore static lib. --- server/core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 25bf74c35..52ebf2b1e 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -1,5 +1,5 @@ if(BUILD_TESTS OR BUILD_TOOLS) - add_library(fullcore STATIC adminusers.c atomic.c config.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c) + add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c) if(WITH_JEMALLOC) target_link_libraries(fullcore ${JEMALLOC_LIBRARIES}) elseif(WITH_TCMALLOC) From 0cfcad55dad5e03cb6ee4b62ab23c07368b5d3c3 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 11:06:11 +0300 Subject: [PATCH 019/275] Moved get_libdir function to its own file. --- server/core/CMakeLists.txt | 4 ++-- server/core/gateway.c | 15 ++------------- server/core/gwdirs.c | 10 ++++++++++ server/include/gwdirs.h.in | 10 ++++++++++ 4 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 server/core/gwdirs.c diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 52ebf2b1e..c952f5a1a 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -1,5 +1,5 @@ if(BUILD_TESTS OR BUILD_TOOLS) - add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c) + add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c gwdirs.c) if(WITH_JEMALLOC) target_link_libraries(fullcore ${JEMALLOC_LIBRARIES}) elseif(WITH_TCMALLOC) @@ -12,7 +12,7 @@ add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c monitor.c adminusers.c secrets.c filter.c modutil.c hint.c - housekeeper.c memlog.c resultset.c) + housekeeper.c memlog.c resultset.c gwdirs.c) if(WITH_JEMALLOC) target_link_libraries(maxscale ${JEMALLOC_LIBRARIES}) diff --git a/server/core/gateway.c b/server/core/gateway.c index f24cf8a11..77afe994b 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -129,11 +129,7 @@ static bool datadir_defined = false; /*< If the datadir was already set */ /* The data directory we created for this gateway instance */ static char pidfile[PATH_MAX+1] = ""; -static char* configdir = NULL; -static char* logdir = NULL; -static char* libdir = NULL; -static char* cachedir = NULL; -static char* langdir = NULL; + /** * exit flag for log flusher. */ @@ -200,14 +196,7 @@ static bool resolve_maxscale_homedir( static char* check_dir_access(char* dirname,bool,bool); -/** - * Get the directory with all the modules. - * @return The module directory - */ -char* get_libdir() -{ - return libdir; -} + /** * Handler for SIGHUP signal. Reload the configuration for the * gateway. diff --git a/server/core/gwdirs.c b/server/core/gwdirs.c new file mode 100644 index 000000000..af7edd9de --- /dev/null +++ b/server/core/gwdirs.c @@ -0,0 +1,10 @@ +#include + +/** + * Get the directory with all the modules. + * @return The module directory + */ +char* get_libdir() +{ + return libdir?libdir:(char*)default_libdir; +} diff --git a/server/include/gwdirs.h.in b/server/include/gwdirs.h.in index 3bc6c3f67..40bf3ba26 100644 --- a/server/include/gwdirs.h.in +++ b/server/include/gwdirs.h.in @@ -19,6 +19,8 @@ * Copyright MariaDB Corporation Ab 2015 */ +#include + /** Default file locations, configured by CMake */ static const char* default_cnf_fname = "MaxScale.cnf"; static const char* default_configdir = "/etc/"; @@ -30,4 +32,12 @@ static const char* default_cachedir = "/var/cache/maxscale/"; static const char* default_langdir = "/usr/share/mysql/english/"; /*< This is where the MariaDB * server installs errmsg.sys */ +static char* configdir = NULL; +static char* logdir = NULL; +static char* libdir = NULL; +static char* cachedir = NULL; +static char* langdir = NULL; + +char* get_libdir(); + #endif From bbcecc0db53b54087ad242405fb587c807ccf9a9 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 13:10:06 +0300 Subject: [PATCH 020/275] Changed all MaxScale.cnf code references to maxscale.cnf --- CMakeLists.txt | 8 ++-- cmake/testall.cmake | 2 +- server/core/gateway.c | 42 +++++++++---------- server/core/gwdirs.c | 9 ++++ server/core/service.c | 15 +++---- server/include/gwdirs.h.in | 2 +- ...cnf => maxscale_binlogserver_template.cnf} | 0 ...ale_template.cnf => maxscale_template.cnf} | 0 server/modules/filter/test/tee_recursion.sh | 4 +- .../{MaxScale_test.cnf => maxscale_test.cnf} | 4 ++ 10 files changed, 46 insertions(+), 40 deletions(-) rename server/{MaxScale_BinlogServer_template.cnf => maxscale_binlogserver_template.cnf} (100%) rename server/{MaxScale_template.cnf => maxscale_template.cnf} (100%) rename server/test/{MaxScale_test.cnf => maxscale_test.cnf} (92%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34d2767ea..550724505 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ configure_file(${CMAKE_SOURCE_DIR}/server/include/gwdirs.h.in ${CMAKE_BINARY_DIR configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.h.in ${CMAKE_BINARY_DIR}/server/include/maxscale_test.h) configure_file(${CMAKE_SOURCE_DIR}/etc/postinst.in ${CMAKE_BINARY_DIR}/postinst) configure_file(${CMAKE_SOURCE_DIR}/etc/postrm.in ${CMAKE_BINARY_DIR}/postrm) +configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.cnf ${CMAKE_BINARY_DIR}/maxscale.cnf) set(FLAGS "-Wall -Wno-unused-variable -Wno-unused-function -fPIC" CACHE STRING "Compilation flags") set(DEBUG_FLAGS "-ggdb -pthread -pipe -Wformat -fstack-protector --param=ssp-buffer-size=4" CACHE STRING "Debug compilation flags") @@ -152,9 +153,9 @@ ${CMAKE_SOURCE_DIR}/Documentation/Upgrading-To-MaxScale-1.1.0.md install(FILES ${CMAKE_BINARY_DIR}/Changelog.txt DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION ${MAXSCALE_SHAREDIR}) -install(FILES server/MaxScale_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) -install(FILES server/MaxScale_BinlogServer_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) -install(FILES ${ERRMSG} DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES server/maxscale_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES server/maxscale_binlogserver_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) +install(FILES ${ERRMSG} DESTINATION /usr/share/mysql/english/) install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${MAXSCALE_SHAREDIR}) @@ -245,7 +246,6 @@ add_custom_target(buildtestsx add_custom_target(testall COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR} -DWITH_SCRIPTS=N ${CMAKE_SOURCE_DIR} COMMAND make install - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/server/test/MaxScale_test.cnf ${CMAKE_BINARY_DIR}/etc/MaxScale.cnf COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake/testall.cmake COMMENT "Running full test suite..." VERBATIM) diff --git a/cmake/testall.cmake b/cmake/testall.cmake index fedbdf273..1a438bc1a 100644 --- a/cmake/testall.cmake +++ b/cmake/testall.cmake @@ -1,4 +1,4 @@ -execute_process(COMMAND /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null 2> /dev/null > /dev/null") +execute_process(COMMAND /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -f ${CMAKE_BINARY_DIR}/etc/maxscale.cnf &>/dev/null 2> /dev/null > /dev/null") execute_process(COMMAND make test RESULT_VARIABLE RVAL) execute_process(COMMAND killall maxscale) if(NOT RVAL EQUAL 0) diff --git a/server/core/gateway.c b/server/core/gateway.c index 77afe994b..ae6f1c5c0 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -999,29 +999,25 @@ return_cnf_file_buf: static void usage(void) { fprintf(stderr, - "\nUsage : %s [-h] | [-d] [-c ] [-f ]\n\n" - " -d|--nodaemon enable running in terminal process (default:disabled)\n" - " -c|--homedir=... relative|absolute MaxScale home directory\n" - " -f|--config=... relative|absolute pathname of MaxScale configuration file\n" - " (default: $MAXSCALE_HOME/etc/MaxScale.cnf)\n" - " -l|--log=... log to file or shared memory\n" - " -lfile or -lshm - defaults to shared memory\n" - " -L|--logdir=... path to log file directory\n" - " (default: /var/log/maxscale)\n" - " -D|--datadir=... path to data directory\n" - " (default: /usr/lib64/maxscale)\n" - " -C|--configdir=... path to configuration file directory\n" - " (default: /etc/)\n" - " -B|--libdir=... path to module directory\n" - " (default: /usr/lib64/maxscale)\n" - " -A|--cachedir=... path to cache directory\n" - " (default: /var/cache/maxscale)\n" - " -s|--syslog= log messages to syslog.\n" - " True or false - defaults to true\n" - " -S|--maxscalelog= log messages to MaxScale log.\n" - " True or false - defaults to true\n" - " -v|--version print version info and exit\n" - " -?|--help show this help\n" + "\nUsage : %s [OPTION]...\n\n" + " -d, --nodaemon enable running in terminal process (default:disabled)\n" + " -f, --config=FILE relative|absolute pathname of MaxScale configuration file\n" + " (default:/etc/maxscale.cnf)\n" + " -l, --log=[file|shm] log to file or shared memory (default: shm)\n" + " -L, --logdir=PATH path to log file directory\n" + " (default: /var/log/maxscale)\n" + " -D, --datadir=PATH path to data directory\n" + " (default: /usr/lib64/maxscale)\n" + " -C, --configdir=PATH path to configuration file directory\n" + " (default: /etc/)\n" + " -B, --libdir=PATH path to module directory\n" + " (default: /usr/lib64/maxscale)\n" + " -A, --cachedir=PATH path to cache directory\n" + " (default: /var/cache/maxscale)\n" + " -s, --syslog=[yes|no] log messages to syslog (default:yes)\n" + " -S, --maxscalelog=[yes|no] log messages to MaxScale log (default: yes)\n" + " -v, --version print version info and exit\n" + " -?, --help show this help\n" , progname); } diff --git a/server/core/gwdirs.c b/server/core/gwdirs.c index af7edd9de..9bf0185cd 100644 --- a/server/core/gwdirs.c +++ b/server/core/gwdirs.c @@ -8,3 +8,12 @@ char* get_libdir() { return libdir?libdir:(char*)default_libdir; } + +/** + * Get the service cache directory + * @return The path to the cache directory + */ +char* get_cachedir() +{ + return cachedir?cachedir:(char*)default_cachedir; +} diff --git a/server/core/service.c b/server/core/service.c index bd22117ec..d529cc54a 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -62,6 +62,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -259,15 +260,11 @@ GWPROTOCOL *funcs; else { /* Save authentication data to file cache */ - char *ptr, path[4097]; + char *ptr, path[PATH_MAX + 1]; int mkdir_rval = 0; - strcpy(path, "/usr/local/mariadb-maxscale"); - if ((ptr = getenv("MAXSCALE_HOME")) != NULL) - { - strncpy(path, ptr, 4096); - } + strcpy(path, get_cachedir()); strncat(path, "/", 4096); - strncat(path, service->name, 4096); + strncat(path, service->name, PATH_MAX); if (access(path, R_OK) == -1) { mkdir_rval = mkdir(path, 0777); @@ -282,7 +279,7 @@ GWPROTOCOL *funcs; mkdir_rval = 0; } - strncat(path, "/.cache", 4096); + strncat(path, "/.cache", PATH_MAX); if (access(path, R_OK) == -1) { mkdir_rval = mkdir(path, 0777); @@ -296,7 +293,7 @@ GWPROTOCOL *funcs; strerror(errno)); mkdir_rval = 0; } - strncat(path, "/dbusers", 4096); + strncat(path, "/dbusers", PATH_MAX); dbusers_save(service->users, path); } if (loaded == 0) diff --git a/server/include/gwdirs.h.in b/server/include/gwdirs.h.in index 40bf3ba26..e62696aab 100644 --- a/server/include/gwdirs.h.in +++ b/server/include/gwdirs.h.in @@ -22,7 +22,7 @@ #include /** Default file locations, configured by CMake */ -static const char* default_cnf_fname = "MaxScale.cnf"; +static const char* default_cnf_fname = "maxscale.cnf"; static const char* default_configdir = "/etc/"; static const char* default_piddir = "/var/run/maxscale/"; static const char* default_logdir = "/var/log/maxscale/"; diff --git a/server/MaxScale_BinlogServer_template.cnf b/server/maxscale_binlogserver_template.cnf similarity index 100% rename from server/MaxScale_BinlogServer_template.cnf rename to server/maxscale_binlogserver_template.cnf diff --git a/server/MaxScale_template.cnf b/server/maxscale_template.cnf similarity index 100% rename from server/MaxScale_template.cnf rename to server/maxscale_template.cnf diff --git a/server/modules/filter/test/tee_recursion.sh b/server/modules/filter/test/tee_recursion.sh index 015bb9a8e..82a8080e2 100755 --- a/server/modules/filter/test/tee_recursion.sh +++ b/server/modules/filter/test/tee_recursion.sh @@ -49,8 +49,8 @@ USER=$3 PWD=$4 HOST=$5 PORT=$6 -CONF=$BINDIR/etc/MaxScale.cnf -OLDCONF=$BINDIR/etc/MaxScale.cnf.old +CONF=$BINDIR/etc/maxscale.cnf +OLDCONF=$BINDIR/etc/maxscale.cnf.old MAXPID=$BINDIR/log/$(ls -1 $BINDIR/log|grep maxscale) TEST1=$SRCDIR/server/modules/filter/test/tee_recursion1.cnf TEST2=$SRCDIR/server/modules/filter/test/tee_recursion2.cnf diff --git a/server/test/MaxScale_test.cnf b/server/test/maxscale_test.cnf similarity index 92% rename from server/test/MaxScale_test.cnf rename to server/test/maxscale_test.cnf index 06b783ca5..2fd6ad0d8 100644 --- a/server/test/MaxScale_test.cnf +++ b/server/test/maxscale_test.cnf @@ -1,5 +1,9 @@ [maxscale] threads=4 +libdir=@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@ +logdir=@CMAKE_INSTALL_PREFIX@/log +datadir=@CMAKE_INSTALL_PREFIX@/data +cachedir=@CMAKE_INSTALL_PREFIX@/cache [feedback] feedback_enable=true From 55249193a9f9687f3e63b8e2fbc766b47c08938a Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 14:30:47 +0300 Subject: [PATCH 021/275] Updated post-install scripts and binlogrouter Binlogrouter: Switched hard-coded maximum path values to PATH_MAX and used cache directory instead of MAXSCALE_HOME Scripts: Updated with new executable file paths --- etc/init.d/maxscale.in | 13 ++++---- etc/postinst.in | 1 + etc/ubuntu/init.d/maxscale.in | 9 +++-- server/core/gateway.c | 4 +-- server/modules/routing/binlog/blr_file.c | 42 +++++++++--------------- 5 files changed, 28 insertions(+), 41 deletions(-) diff --git a/etc/init.d/maxscale.in b/etc/init.d/maxscale.in index 88f026e18..c8822109c 100755 --- a/etc/init.d/maxscale.in +++ b/etc/init.d/maxscale.in @@ -18,12 +18,11 @@ ### END INIT INFO ############################################# -# MaxScale HOME, PIDFILE, LIB +# MaxScale PIDFILE and LIB ############################################# -export MAXSCALE_HOME=@CMAKE_INSTALL_PREFIX@ -export MAXSCALE_PIDFILE=$MAXSCALE_HOME/log/maxscale.pid -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MAXSCALE_HOME/lib +export MAXSCALE_PIDFILE=/var/run/maxscale/maxscale.pid +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@/maxscale ############################### # LSB Exit codes (non-Status) @@ -56,7 +55,7 @@ start() { CHECK_RET=$? [ $CHECK_RET -eq 0 ] && echo -n " found $my_check" && success && CHECK_RET=0 - daemon --pidfile $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale >& /dev/null + daemon --pidfile $MAXSCALE_PIDFILE @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale >& /dev/null RETVAL=$? [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$servicename @@ -68,7 +67,7 @@ start() { [ $CHECK_RET -eq 0 ] && echo -n $my_check && success || failure fi - # Return rigth code + # Return right code if [ $RETVAL -ne 0 ]; then failure RETVAL=$_RETVAL_NOT_RUNNING @@ -100,7 +99,7 @@ stop() { reload() { echo -n $"Reloading MaxScale: " - killproc -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale -HUP + killproc -p $MAXSCALE_PIDFILE @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale -HUP RETVAL=$? echo } diff --git a/etc/postinst.in b/etc/postinst.in index c04850019..464e240f1 100755 --- a/etc/postinst.in +++ b/etc/postinst.in @@ -3,6 +3,7 @@ mkdir -p /var/log/maxscale mkdir -p /var/cache/maxscale mkdir -p /var/run/maxscale +mkdir -p @CMAKE_INSTALL_PREFIX@/@MAXSCALE_SHARE_DIR@/ cp @CMAKE_INSTALL_PREFIX@/@MAXSCALE_SHARE_DIR@/maxscale /etc/init.d/ cp @CMAKE_INSTALL_PREFIX@/@MAXSCALE_SHARE_DIR@/maxscale.conf /etc/ld.so.conf.d/ /sbin/ldconfig diff --git a/etc/ubuntu/init.d/maxscale.in b/etc/ubuntu/init.d/maxscale.in index caf7d1408..9b8ff84e9 100755 --- a/etc/ubuntu/init.d/maxscale.in +++ b/etc/ubuntu/init.d/maxscale.in @@ -21,9 +21,8 @@ # MaxScale HOME, PIDFILE, LIB ############################################# -export MAXSCALE_HOME=@CMAKE_INSTALL_PREFIX@ -export MAXSCALE_PIDFILE=$MAXSCALE_HOME/log/maxscale.pid -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MAXSCALE_HOME/lib +export MAXSCALE_PIDFILE=/var/run/maxscale/maxscale.pid +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@/maxscale ############################### # LSB Exit codes (non-Status) @@ -45,7 +44,7 @@ _RETVAL_STATUS_NOT_RUNNING=3 # stop/start/status related vars ################################# NAME=maxscale -DAEMON=$MAXSCALE_HOME/bin/maxscale +DAEMON=@CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale # Source function library. . /lib/lsb/init-functions @@ -82,7 +81,7 @@ reload() { } maxscale_wait_stop() { - PIDTMP=$(pidofproc -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale) + PIDTMP=$(pidofproc -p $MAXSCALE_PIDFILE @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale) kill -TERM "${PIDTMP:-}" 2> /dev/null; if [ -n "${PIDTMP:-}" ] && kill -0 "${PIDTMP:-}" 2> /dev/null; then local i=0 diff --git a/server/core/gateway.c b/server/core/gateway.c index ae6f1c5c0..a5ad3e2fe 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -1006,8 +1006,8 @@ static void usage(void) " -l, --log=[file|shm] log to file or shared memory (default: shm)\n" " -L, --logdir=PATH path to log file directory\n" " (default: /var/log/maxscale)\n" - " -D, --datadir=PATH path to data directory\n" - " (default: /usr/lib64/maxscale)\n" + " -D, --datadir=PATH path to data directory, stored embedded mysql tables\n" + " (default: /var/cache/maxscale)\n" " -C, --configdir=PATH path to configuration file directory\n" " (default: /etc/)\n" " -B, --libdir=PATH path to module directory\n" diff --git a/server/modules/routing/binlog/blr_file.c b/server/modules/routing/binlog/blr_file.c index b8e201227..32fbad28c 100644 --- a/server/modules/routing/binlog/blr_file.c +++ b/server/modules/routing/binlog/blr_file.c @@ -71,7 +71,7 @@ static void blr_log_header(logfile_id_t file, char *msg, uint8_t *ptr); int blr_file_init(ROUTER_INSTANCE *router) { -char *ptr, path[PATH_MAX], filename[PATH_MAX]; +char *ptr, path[PATH_MAX+1], filename[PATH_MAX+1]; int file_found, n = 1; int root_len, i; DIR *dirp; @@ -79,12 +79,8 @@ struct dirent *dp; if (router->binlogdir == NULL) { - strcpy(path, "/usr/local/mariadb-maxscale"); - if ((ptr = getenv("MAXSCALE_HOME")) != NULL) - { - strncpy(path, ptr,PATH_MAX); - } - strncat(path, "/",PATH_MAX); + strcpy(path, get_cachedir()); + strncat(path,"/",PATH_MAX); strncat(path, router->service->name,PATH_MAX); if (access(path, R_OK) == -1) @@ -659,24 +655,20 @@ struct stat statb; void blr_cache_response(ROUTER_INSTANCE *router, char *response, GWBUF *buf) { -char path[4097], *ptr; +char path[PATH_MAX+1], *ptr; int fd; - strcpy(path, "/usr/local/mariadb-maxscale"); - if ((ptr = getenv("MAXSCALE_HOME")) != NULL) - { - strncpy(path, ptr, 4096); - } - strncat(path, "/", 4096); - strncat(path, router->service->name, 4096); + strcpy(path,get_cachedir()); + strncat(path,"/",PATH_MAX); + strncat(path, router->service->name, PATH_MAX); if (access(path, R_OK) == -1) mkdir(path, 0777); - strncat(path, "/.cache", 4096); + strncat(path, "/.cache", PATH_MAX); if (access(path, R_OK) == -1) mkdir(path, 0777); strncat(path, "/", 4096); - strncat(path, response, 4096); + strncat(path, response, PATH_MAX); if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) return; @@ -697,19 +689,15 @@ GWBUF * blr_cache_read_response(ROUTER_INSTANCE *router, char *response) { struct stat statb; -char path[4097], *ptr; +char path[PATH_MAX+1], *ptr; int fd; GWBUF *buf; - strcpy(path, "/usr/local/mariadb-maxscale"); - if ((ptr = getenv("MAXSCALE_HOME")) != NULL) - { - strncpy(path, ptr, 4096); - } - strncat(path, "/", 4096); - strncat(path, router->service->name, 4096); - strncat(path, "/.cache/", 4096); - strncat(path, response, 4096); + strcpy(path, get_cachedir()); + strncat(path, "/", PATH_MAX); + strncat(path, router->service->name, PATH_MAX); + strncat(path, "/.cache/", PATH_MAX); + strncat(path, response, PATH_MAX); if ((fd = open(path, O_RDONLY)) == -1) return NULL; From 1cc6ced505c47e18757d09388b5923b4a2677abc Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 15:06:45 +0300 Subject: [PATCH 022/275] Updated old references to MAXSCALE_HOME --- server/core/adminusers.c | 26 +++++--------------------- server/core/load_utils.c | 11 ----------- server/core/maxkeys.c | 24 +++++++++++++----------- server/include/modules.h | 1 - 4 files changed, 18 insertions(+), 44 deletions(-) diff --git a/server/core/adminusers.c b/server/core/adminusers.c index 64ea5f224..e20f9d1c3 100644 --- a/server/core/adminusers.c +++ b/server/core/adminusers.c @@ -26,6 +26,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -119,12 +120,7 @@ char fname[1024], *home; char uname[80], passwd[80]; initialise(); - if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){ - sprintf(fname, "%s/etc/passwd", home); - } - else{ - sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd"); - } + sprintf(fname, "%s/passwd", get_cachedir()); if ((fp = fopen(fname, "r")) == NULL) return NULL; if ((rval = users_alloc()) == NULL) @@ -155,12 +151,7 @@ FILE *fp; char fname[1024], *home, *cpasswd; initialise(); - if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){ - sprintf(fname, "%s/etc/passwd", home); - } - else{ - sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd"); - } + sprintf(fname, "%s/passwd", get_cachedir()); if (users == NULL) { @@ -253,15 +244,8 @@ char* admin_remove_user( /** * Open passwd file and remove user from the file. */ - if ((home = getenv("MAXSCALE_HOME")) != NULL && - strnlen(home,PATH_MAX) < PATH_MAX && - strnlen(home,PATH_MAX) > 0) { - sprintf(fname, "%s/etc/passwd", home); - sprintf(fname_tmp, "%s/etc/passwd_tmp", home); - } else { - sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd"); - sprintf(fname_tmp, "/usr/local/mariadb-maxscale/etc/passwd_tmp"); - } + sprintf(fname, "%s/passwd", get_cachedir()); + sprintf(fname_tmp, "%s/passwd_tmp", get_cachedir()); /** * Rewrite passwd file from memory. */ diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 9451f6838..7e4a10c37 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -105,17 +105,6 @@ WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) return realsize; } -char* get_maxscale_home(void) -{ - char* home = getenv("MAXSCALE_HOME"); - if (home == NULL) - { - home = "/usr/local/mariadb-maxscale"; - } - return home; -} - - /** * Load the dynamic library related to a gateway module. The routine * will look for library files in the current directory, diff --git a/server/core/maxkeys.c b/server/core/maxkeys.c index 0d5c938ff..6cb4501ec 100644 --- a/server/core/maxkeys.c +++ b/server/core/maxkeys.c @@ -31,6 +31,7 @@ #include #include #include +#include int main(int argc, char **argv) { int arg_count = 3; @@ -52,19 +53,20 @@ int main(int argc, char **argv) return 1; } + if(access("/var/log/maxscale/maxkeys/",F_OK) != 0) + { + if(mkdir("/var/log/maxscale/maxkeys/",0777) == -1) + { + if(errno != EEXIST) + { + fprintf(stderr,"Error: %d - %s",errno,strerror(errno)); + return 1; + } + } + } arg_vector[0] = strdup("logmanager"); arg_vector[1] = strdup("-j"); - - if ((home = getenv("MAXSCALE_HOME")) != NULL) - { - arg_vector[2] = (char*)malloc((strlen(home) + strlen("/log"))*sizeof(char)); - sprintf(arg_vector[2],"%s/log",home); - } - else - { - arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log"); - } - + arg_vector[2] = strdup("/var/log/maxscale/maxkeys"); arg_vector[3] = NULL; skygw_logmanager_init(arg_count,arg_vector); skygw_log_enable(LOGFILE_TRACE); diff --git a/server/include/modules.h b/server/include/modules.h index 51e10b29d..96d322402 100644 --- a/server/include/modules.h +++ b/server/include/modules.h @@ -68,7 +68,6 @@ extern void unload_all_modules(); extern void printModules(); extern void dprintAllModules(DCB *); extern RESULTSET *moduleGetList(); -extern char *get_maxscale_home(void); extern void module_feedback_send(void*); extern void moduleShowFeedbackReport(DCB *dcb); From 9e0a2bfc12f5d962b16f28b023de697f090ef0e7 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 21:38:49 +0300 Subject: [PATCH 023/275] Changed relevant files to use get_cachedir() instead of using the now deprecated MAXSCALE_HOME. --- etc/init.d/maxscale.in | 6 +- etc/ubuntu/init.d/maxscale.in | 2 +- server/core/CMakeLists.txt | 4 +- server/core/gateway.c | 206 +--------------------- server/core/load_utils.c | 3 +- server/core/maxpasswd.c | 11 +- server/core/secrets.c | 10 +- server/core/service.c | 6 +- server/core/test/CMakeLists.txt | 15 -- server/core/test/testadminusers.c | 9 +- server/core/test/testfeedback.c | 13 +- server/include/gwdirs.h.in | 2 +- server/maxscale_binlogserver_template.cnf | 5 +- server/modules/filter/dbfwfilter.c | 12 +- server/modules/filter/test/CMakeLists.txt | 10 -- 15 files changed, 29 insertions(+), 285 deletions(-) diff --git a/etc/init.d/maxscale.in b/etc/init.d/maxscale.in index c8822109c..4ee5ce0f4 100755 --- a/etc/init.d/maxscale.in +++ b/etc/init.d/maxscale.in @@ -38,7 +38,7 @@ _RETVAL_STATUS_OK=0 _RETVAL_STATUS_NOT_RUNNING=3 # Sanity checks. -[ -x $MAXSCALE_HOME/bin/maxscale ] || exit $_RETVAL_NOT_INSTALLED +[ -x @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale ] || exit $_RETVAL_NOT_INSTALLED # Source function library. . /etc/rc.d/init.d/functions @@ -51,7 +51,7 @@ RETVAL=0 start() { echo -n $"Starting MaxScale: " - my_check=`status -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale` + my_check=`status -p $MAXSCALE_PIDFILE @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale` CHECK_RET=$? [ $CHECK_RET -eq 0 ] && echo -n " found $my_check" && success && CHECK_RET=0 @@ -62,7 +62,7 @@ start() { if [ $CHECK_RET -ne 0 ]; then sleep 2 - my_check=`status -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale` + my_check=`status -p $MAXSCALE_PIDFILE @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale` CHECK_RET=$? [ $CHECK_RET -eq 0 ] && echo -n $my_check && success || failure fi diff --git a/etc/ubuntu/init.d/maxscale.in b/etc/ubuntu/init.d/maxscale.in index 9b8ff84e9..27a73092c 100755 --- a/etc/ubuntu/init.d/maxscale.in +++ b/etc/ubuntu/init.d/maxscale.in @@ -38,7 +38,7 @@ _RETVAL_STATUS_OK=0 _RETVAL_STATUS_NOT_RUNNING=3 # Sanity checks. -[ -x $MAXSCALE_HOME/bin/maxscale ] || exit $_RETVAL_NOT_INSTALLED +[ -x @CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale ] || exit $_RETVAL_NOT_INSTALLED ################################# # stop/start/status related vars diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index c952f5a1a..39983e6ff 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -23,11 +23,11 @@ endif() target_link_libraries(maxscale ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++) install(TARGETS maxscale DESTINATION ${MAXSCALE_BINDIR}) -add_executable(maxkeys maxkeys.c secrets.c utils.c) +add_executable(maxkeys maxkeys.c secrets.c utils.c gwdirs.c) target_link_libraries(maxkeys log_manager utils pthread crypt crypto) install(TARGETS maxkeys DESTINATION ${MAXSCALE_BINDIR}) -add_executable(maxpasswd maxpasswd.c secrets.c utils.c) +add_executable(maxpasswd maxpasswd.c secrets.c utils.c gwdirs.c) target_link_libraries(maxpasswd log_manager utils pthread crypt crypto) install(TARGETS maxpasswd DESTINATION ${MAXSCALE_BINDIR}) diff --git a/server/core/gateway.c b/server/core/gateway.c index a5ad3e2fe..cf0f41525 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -191,8 +191,6 @@ static bool resolve_maxscale_conf_fname( char** cnf_full_path, char* home_dir, char* cnf_file_arg); -static bool resolve_maxscale_homedir( - char** p_home_dir); static char* check_dir_access(char* dirname,bool,bool); @@ -575,149 +573,6 @@ return_succp: return succp; } - -static bool resolve_maxscale_homedir( - char** p_home_dir) -{ - bool succp = false; - char* tmp; - char* tmp2; - char* log_context = NULL; - - ss_dassert(*p_home_dir == NULL); - - if (*p_home_dir != NULL) - { - log_context = strdup("Command-line argument"); - tmp = NULL; - goto check_home_dir; - } - /*< - * 1. if home dir wasn't specified by a command-line argument, - * read env. variable MAXSCALE_HOME. - */ - if (getenv("MAXSCALE_HOME") != NULL) - { - tmp = strndup(getenv("MAXSCALE_HOME"), PATH_MAX); - get_expanded_pathname(p_home_dir, tmp, NULL); - - if (*p_home_dir != NULL) - { - log_context = strdup("MAXSCALE_HOME"); - goto check_home_dir; - } - free(tmp); - } - else - { - fprintf(stderr, "\n*\n* Warning : MAXSCALE_HOME environment variable " - "is not set.\n*\n"); - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Warning : MAXSCALE_HOME environment " - "variable is not set."))); - } - /*< - * 2. if home dir wasn't specified in MAXSCALE_HOME, - * try access /etc/MaxScale/ - */ - tmp = strdup("/etc/MaxScale"); - get_expanded_pathname(p_home_dir, tmp, NULL); - - if (*p_home_dir != NULL) - { - log_context = strdup("/etc/MaxScale"); - goto check_home_dir; - } - free(tmp); - /*< - * 3. if /etc/MaxScale/MaxScale.cnf didn't exist or wasn't accessible, home - * isn't specified. Thus, try to access $PWD/MaxScale.cnf . - */ - char *pwd = getenv("PWD"); - tmp = strndup(pwd ? pwd : "PWD_NOT_SET", PATH_MAX); - tmp2 = get_expanded_pathname(p_home_dir, tmp, default_cnf_fname); - free(tmp2); /*< full path isn't needed so simply free it */ - - if (*p_home_dir != NULL) - { - log_context = strdup("Current working directory"); - } - -check_home_dir: - if (*p_home_dir != NULL) - { - if (!file_is_readable(*p_home_dir)) - { - char* tailstr = "MaxScale doesn't have read permission " - "to MAXSCALE_HOME."; - char* logstr = (char*)malloc(strlen(log_context)+ - 1+ - strlen(tailstr)+ - 1); - snprintf(logstr, - strlen(log_context)+ - 1+ - strlen(tailstr)+1, - "%s:%s", - log_context, - tailstr); - print_log_n_stderr(true, true, logstr, logstr, 0); - free(logstr); - goto return_succp; - } - -#if WRITABLE_HOME - if (!file_is_writable(*p_home_dir)) - { - char* tailstr = "MaxScale doesn't have write permission " - "to MAXSCALE_HOME. Exiting."; - char* logstr = (char*)malloc(strlen(log_context)+ - 1+ - strlen(tailstr)+ - 1); - snprintf(logstr, - strlen(log_context)+ - 1+ - strlen(tailstr)+1, - "%s:%s", - log_context, - tailstr); - print_log_n_stderr(true, true, logstr, logstr, 0); - free(logstr); - goto return_succp; - } -#endif - if (!daemon_mode) - { - fprintf(stderr, - "Using %s as MAXSCALE_HOME = %s\n", - log_context, - tmp); - } - succp = true; - goto return_succp; - } - -return_succp: - free (tmp); - - - if (log_context != NULL) - { - free(log_context); - } - - if (!succp) - { - char* logstr = "MaxScale was unable to locate home directory " - "with read and write permissions. \n*\n* Exiting."; - print_log_n_stderr(true, true, logstr, logstr, 0); - usage(); - } - return succp; -} - /** * Check read and write accessibility to a directory. * @param dirname directory to be checked @@ -1042,19 +897,13 @@ static void usage(void) * This is not obvious solution because stderr is often directed to somewhere, * but currently this is the case. * - * The configuration file is by default \/etc/MaxScale.cnf + * The configuration file is by default /etc/maxscale.cnf * The name of configuration file and its location can be specified by * command-line argument. * - * \ is resolved in the following order: - * 1. from '-c ' command-line argument - * 2. from MAXSCALE_HOME environment variable - * 3. /etc/ if MaxScale.cnf is found from there - * 4. current working directory if MaxScale.cnf is found from there - * * \ is resolved in the following order: * 1. from '-f \' command-line argument - * 2. by using default value "MaxScale.cnf" + * 2. by using default value "maxscale.cnf" * */ int main(int argc, char **argv) @@ -1131,56 +980,6 @@ int main(int argc, char **argv) /*< Debug mode, maxscale runs in this same process */ daemon_mode = false; break; - - case 'c': - /*< - * Create absolute path pointing to MaxScale home - * directory. User-provided home directory may be - * either absolute or relative. If latter, it is - * expanded and stored in home_dir if succeed. - */ - if (optarg[0] != '-') - { - struct stat sb; - - if (stat(optarg, &sb) != -1 - && (! S_ISDIR(sb.st_mode))) - { - char* logerr = "Home directory argument " - "identifier \'-c\' was specified but " - "the argument didn't specify a valid " - "a directory."; - print_log_n_stderr(true, true, logerr, logerr, 0); - usage(); - succp = false; - } - else - { - get_expanded_pathname(&home_dir, optarg, NULL); - } - } - - if (home_dir != NULL) - { - /*< - * MAXSCALE_HOME is set. - * It is used to assist in finding the modules - * to be loaded into MaxScale. - */ - setenv("MAXSCALE_HOME", home_dir, 1); - } - else - { - char* logerr = "Home directory argument " - "identifier \'-c\' was specified but " - "the argument didn't specify \n a valid " - "home directory or the argument was " - "missing."; - print_log_n_stderr(true, true, logerr, logerr, 0); - usage(); - succp = false; - } - break; case 'f': /*< @@ -1589,7 +1388,6 @@ int main(int argc, char **argv) sprintf(datadir,"%s",default_datadir); /** * Init Log Manager for MaxScale. - * If $MAXSCALE_HOME is set then write the logs into $MAXSCALE_HOME/log. * The skygw_logmanager_init expects to take arguments as passed to main * and proesses them with getopt, therefore we need to give it a dummy * argv[0] diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 7e4a10c37..5ecbe7f34 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -49,6 +49,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -108,7 +109,7 @@ WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) /** * Load the dynamic library related to a gateway module. The routine * will look for library files in the current directory, - * $MAXSCALE_HOME/modules and /usr/local/mariadb-maxscale/modules. + * the configured folder and /usr/lib64/maxscale. * * @param module Name of the module to load * @param type Type of module, used purely for registration diff --git a/server/core/maxpasswd.c b/server/core/maxpasswd.c index 4da1dbde1..159fbae49 100644 --- a/server/core/maxpasswd.c +++ b/server/core/maxpasswd.c @@ -62,16 +62,7 @@ main(int argc, char **argv) arg_vector[0] = strdup("logmanager"); arg_vector[1] = strdup("-j"); - - if ((home = getenv("MAXSCALE_HOME")) != NULL) - { - arg_vector[2] = (char*)malloc((strlen(home) + strlen("/log"))*sizeof(char)); - sprintf(arg_vector[2],"%s/log",home); - } - else - { - arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log"); - } + arg_vector[2] = strdup("/var/log/maxscale"); arg_vector[3] = NULL; skygw_logmanager_init(arg_count,arg_vector); diff --git a/server/core/secrets.c b/server/core/secrets.c index 3eae2cc48..b0ddc084b 100644 --- a/server/core/secrets.c +++ b/server/core/secrets.c @@ -22,6 +22,7 @@ #include #include #include +#include /** Defined in log_manager.cc */ extern int lm_enabled_logfiles_bitmask; @@ -62,7 +63,7 @@ int i; static MAXKEYS * secrets_readKeys() { -char secret_file[255]; +char secret_file[PATH_MAX+1]; char *home; MAXKEYS *keys; struct stat secret_stats; @@ -70,12 +71,7 @@ int fd; int len; static int reported = 0; - home = getenv("MAXSCALE_HOME"); - - if (home == NULL) { - home = "/usr/local/mariadb-maxscale"; - } - snprintf(secret_file, 255, "%s/etc/.secrets", home); + snprintf(secret_file, PATH_MAX, "%s/.secrets", get_cachedir()); /* Try to access secrets file */ if (access(secret_file, R_OK) == -1) diff --git a/server/core/service.c b/server/core/service.c index d529cc54a..5ba5d539d 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -232,11 +232,7 @@ GWPROTOCOL *funcs; { /* Try loading authentication data from file cache */ char *ptr, path[4097]; - strcpy(path, "/usr/local/mariadb-maxscale"); - if ((ptr = getenv("MAXSCALE_HOME")) != NULL) - { - strncpy(path, ptr, 4096); - } + strcpy(path, get_cachedir()); strncat(path, "/", 4096); strncat(path, service->name, 4096); strncat(path, "/.cache/dbusers", 4096); diff --git a/server/core/test/CMakeLists.txt b/server/core/test/CMakeLists.txt index 626a75f3e..a1933aa0d 100644 --- a/server/core/test/CMakeLists.txt +++ b/server/core/test/CMakeLists.txt @@ -44,19 +44,4 @@ add_test(Internal-TestUsers test_users) add_test(Internal-TestAdminUsers test_adminusers) add_test(Internal-TestMemlog testmemlog) add_test(TestFeedback testfeedback) -set_tests_properties(Internal-TestMySQLUsers - Internal-TestHash - Internal-TestHint - Internal-TestSpinlock - Internal-TestFilter - Internal-TestBuffer - Internal-TestDCB - Internal-TestModutil - Internal-TestPoll - Internal-TestService - Internal-TestServer - Internal-TestUsers - Internal-TestAdminUsers - Internal-TestMemlog - TestFeedback PROPERTIES ENVIRONMENT MAXSCALE_HOME=${CMAKE_BINARY_DIR}/) set_tests_properties(TestFeedback PROPERTIES TIMEOUT 30) diff --git a/server/core/test/testadminusers.c b/server/core/test/testadminusers.c index ae52bd8b7..f9c34e500 100644 --- a/server/core/test/testadminusers.c +++ b/server/core/test/testadminusers.c @@ -30,7 +30,7 @@ #include #include #include - +#include #include @@ -40,7 +40,7 @@ * Test that the username password admin/mariadb is accepted if no users * have been created and that no other users are accepted * - * WARNING: $MAXSCALE_HOME/etc/passwd must be removed before this test is run + * WARNING: The passwd file must be removed before this test is run */ static int test1() @@ -269,9 +269,8 @@ int result = 0; char *home, buf[1024]; /* Unlink any existing password file before running this test */ - if ((home = getenv("MAXSCALE_HOME")) == NULL || strlen(home) >= 1024) - home = "/usr/local/mariadb-maxscale"; - sprintf(buf, "%s/etc/passwd", home); + + sprintf(buf, "%s/passwd", default_cachedir); if(!is_valid_posix_path(buf)) exit(1); if (strcmp(buf, "/etc/passwd") != 0) diff --git a/server/core/test/testfeedback.c b/server/core/test/testfeedback.c index 6549305c3..3b281537e 100644 --- a/server/core/test/testfeedback.c +++ b/server/core/test/testfeedback.c @@ -73,17 +73,8 @@ int main(int argc, char** argv) char* cnf; hkinit(); - home = getenv("MAXSCALE_HOME"); - if(home == NULL) - { - FAILTEST("MAXSCALE_HOME was not defined."); - } - printf("Home: %s\n",home); - - cnf = malloc(strlen(home) + strlen("/etc/MaxScale.cnf") + 1); - strcpy(cnf,home); - strcat(cnf,"/etc/MaxScale.cnf"); + cnf = strdup("/etc/MaxScale.cnf"); printf("Config: %s\n",cnf); @@ -116,4 +107,4 @@ int main(int argc, char** argv) } mysql_library_end(); return 0; -} \ No newline at end of file +} diff --git a/server/include/gwdirs.h.in b/server/include/gwdirs.h.in index e62696aab..bd878bb59 100644 --- a/server/include/gwdirs.h.in +++ b/server/include/gwdirs.h.in @@ -39,5 +39,5 @@ static char* cachedir = NULL; static char* langdir = NULL; char* get_libdir(); - +char* get_cachedir(); #endif diff --git a/server/maxscale_binlogserver_template.cnf b/server/maxscale_binlogserver_template.cnf index dddd74163..f9cc112aa 100644 --- a/server/maxscale_binlogserver_template.cnf +++ b/server/maxscale_binlogserver_template.cnf @@ -1,5 +1,5 @@ # -# Example MaxScale.cnf for the Binlog Server. +# Example maxscale.cnf for the Binlog Server. # # @@ -37,14 +37,13 @@ threads=6 # The MaxScale Binlog Server Service. # # The name of this service will be used as the directory name -# in $MAXSCALE_HOME where the binlogs will be saved. +# in the cache directory where the binlogs will be saved. # If this name is changed, it must be changed in the listener # configuration below. [Binlog_Service] # type must be service # router must be binlogrouter -# (corresponding to the so file in $MAXSCALE_HOME/modules). type=service router=binlogrouter diff --git a/server/modules/filter/dbfwfilter.c b/server/modules/filter/dbfwfilter.c index 9cdc2816f..d796bb3c0 100644 --- a/server/modules/filter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter.c @@ -2133,15 +2133,13 @@ int main(int argc, char** argv) return 1; } - if((home = getenv("MAXSCALE_HOME")) == NULL) + home = malloc(sizeof(char)*(PATH_MAX+1)); + if(getcwd(home,PATH_MAX) == NULL) { - home = malloc(sizeof(char)*(PATH_MAX+1)); - if(getcwd(home,PATH_MAX) == NULL) - { - free(home); - home = NULL; - } + free(home); + home = NULL; } + printf("Log files written to: %s\n",home?home:"/tpm"); int argc_ = 11; diff --git a/server/modules/filter/test/CMakeLists.txt b/server/modules/filter/test/CMakeLists.txt index 2ad0c2201..4e1006bfb 100644 --- a/server/modules/filter/test/CMakeLists.txt +++ b/server/modules/filter/test/CMakeLists.txt @@ -1,10 +1,3 @@ -aux_source_directory(${CMAKE_SOURCE_DIR}/server/core CORE_ALL) -foreach(VAR ${CORE_ALL}) - if(NOT( (${VAR} MATCHES "max[a-z_]*.c") OR (${VAR} MATCHES "gateway.c"))) - list(APPEND CORE ${VAR}) - endif() -endforeach() - include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_executable(harness_ui harness_ui.c harness_common.c) add_executable(harness harness_util.c harness_common.c ${CORE}) @@ -32,6 +25,3 @@ add_test(TestTeeRecursion ${CMAKE_CURRENT_SOURCE_DIR}/tee_recursion.sh ${TEST_HOST} ${TEST_PORT}) -set_tests_properties(TestHintfilter TestRegexfilter TestFwfilter1 TestFwfilter2 TestTeeRecursion -PROPERTIES -ENVIRONMENT MAXSCALE_HOME=${CMAKE_BINARY_DIR}/) From e681d18fdd011c4dbcc0da3403b888cd84832302 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 27 Apr 2015 23:11:49 +0300 Subject: [PATCH 024/275] Split packaging to RPM and DEB cmake files. --- CMakeLists.txt | 71 +++++++++++++++++++---------------------- cmake/package_deb.cmake | 6 ++++ cmake/package_rpm.cmake | 23 +++++++++++++ 3 files changed, 62 insertions(+), 38 deletions(-) create mode 100644 cmake/package_deb.cmake create mode 100644 cmake/package_rpm.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 550724505..eff114eb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,14 @@ message(STATUS "CMake version: ${CMAKE_VERSION}") include(${CMAKE_SOURCE_DIR}/cmake/macros.cmake) enable_testing() -set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, RPM, DEB") +# Packaging builds install to /usr and other builds to /usr/local/mariadb-maxscale +if(PACKAGE) + set(INSTALL_LAYOUT "PACKAGE" CACHE STRING "Install layout, options are: STANDALONE, PACKAGE") +else() + set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, PACKAGE") +endif() + +# Installation prefixes for different layouts if(${INSTALL_LAYOUT} MATCHES "STANDALONE") set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") else() @@ -58,12 +65,12 @@ if(${MAXSCALE_VERSION} MATCHES "-stable") endif() file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/server/include) -configure_file(${CMAKE_SOURCE_DIR}/server/include/version.h.in ${CMAKE_BINARY_DIR}/server/include/version.h) -configure_file(${CMAKE_SOURCE_DIR}/server/include/gwdirs.h.in ${CMAKE_BINARY_DIR}/server/include/gwdirs.h) -configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.h.in ${CMAKE_BINARY_DIR}/server/include/maxscale_test.h) -configure_file(${CMAKE_SOURCE_DIR}/etc/postinst.in ${CMAKE_BINARY_DIR}/postinst) -configure_file(${CMAKE_SOURCE_DIR}/etc/postrm.in ${CMAKE_BINARY_DIR}/postrm) -configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.cnf ${CMAKE_BINARY_DIR}/maxscale.cnf) +configure_file(${CMAKE_SOURCE_DIR}/server/include/version.h.in ${CMAKE_BINARY_DIR}/server/include/version.h @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/server/include/gwdirs.h.in ${CMAKE_BINARY_DIR}/server/include/gwdirs.h @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.h.in ${CMAKE_BINARY_DIR}/server/include/maxscale_test.h @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/etc/postinst.in ${CMAKE_BINARY_DIR}/postinst @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/etc/postrm.in ${CMAKE_BINARY_DIR}/postrm @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.cnf ${CMAKE_BINARY_DIR}/maxscale.cnf @ONLY) set(FLAGS "-Wall -Wno-unused-variable -Wno-unused-function -fPIC" CACHE STRING "Compilation flags") set(DEBUG_FLAGS "-ggdb -pthread -pipe -Wformat -fstack-protector --param=ssp-buffer-size=4" CACHE STRING "Debug compilation flags") @@ -81,7 +88,7 @@ if(CMAKE_VERSION VERSION_GREATER 2.6) endif() -IF(DEFINED OLEVEL ) +IF(DEFINED OLEVEL) if((OLEVEL GREATER -1) AND (OLEVEL LESS 4) ) set(FLAGS "${FLAGS} -O${OLEVEL}" CACHE STRING "Compilation flags") message(STATUS "Optimization level at: ${OLEVEL}") @@ -181,7 +188,9 @@ if(WITH_SCRIPTS) endif() endif() +# Only do packaging if configured if(PACKAGE) + # Install the files copied by the postinst script into the share folder install(FILES ${CMAKE_BINARY_DIR}/maxscale DESTINATION ${MAXSCALE_SHAREDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) @@ -194,23 +203,8 @@ if(PACKAGE) if(${CMAKE_VERSION} VERSION_LESS 2.8.12) message(WARNING "CMake version is ${CMAKE_VERSION}. Building of packages requires version 2.8.12 or greater.") else() - # See if we are on a RPM-capable or DEB-capable system - find_program(RPMBUILD rpmbuild) - find_program(DEBBUILD dpkg-buildpackage) - set(CPACK_GENERATOR "TGZ") - if(NOT ( ${RPMBUILD} STREQUAL "RPMBUILD-NOTFOUND" ) ) - message(STATUS "Generating RPM packages") - set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM") - endif() - - if(NOT ( ${DEBBUILD} STREQUAL "DEBBUILD-NOTFOUND" ) ) - set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB") - execute_process(COMMAND dpgk --print-architecture OUTPUT_VARIABLE DEB_ARCHITECTURE) - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEB_ARCHITECTURE}) - set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) - message(STATUS "Generating DEB packages for ${DEB_ARCHITECTURE}") - endif() + # Generic CPack configuration variables set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MaxScale") set(CPACK_PACKAGE_VERSION_MAJOR "${MAXSCALE_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${MAXSCALE_VERSION_MINOR}") @@ -221,23 +215,25 @@ if(PACKAGE) set(CPACK_PACKAGE_VENDOR "MariaDB Corporation Ab") set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_SOURCE_DIR}/etc/DESCRIPTION) set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") - set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/postinst;{CMAKE_BINARY_DIR}/postrm") - set(CPACK_RPM_PACKAGE_RELEASE ${MAXSCALE_BUILD_NUMBER}) - set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${CMAKE_BINARY_DIR}/postinst) - set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE ${CMAKE_BINARY_DIR}/postrm) - set(CPACK_RPM_PACKAGE_NAME "maxscale") - set(CPACK_RPM_PACKAGE_VENDOR "MariaDB Corporation Ab") - set(CPACK_RPM_PACKAGE_LICENSE "GPLv2") - set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/etc /etc/ld.so.conf.d /etc/init.d /etc/rc.d/init.d") - set(CPACK_RPM_SPEC_MORE_DEFINE "%define ignore \#") - set(CPACK_RPM_USER_FILELIST "%ignore /etc/init.d") - set(CPACK_RPM_USER_FILELIST "%ignore /etc/ld.so.conf.d") - set(CPACK_RPM_USER_FILELIST "%ignore /etc") + + # See if we are on a RPM-capable or DEB-capable system + find_program(RPMBUILD rpmbuild) + find_program(DEBBUILD dpkg-buildpackage) + set(CPACK_GENERATOR "TGZ") + + if(NOT ( ${RPMBUILD} STREQUAL "RPMBUILD-NOTFOUND" ) ) + include(cmake/package_rpm.cmake) + message(STATUS "Generating RPM packages") + elseif(NOT ( ${DEBBUILD} STREQUAL "DEBBUILD-NOTFOUND" ) ) + include(cmake/package_deb.cmake) + message(STATUS "Generating DEB packages for ${DEB_ARCHITECTURE}") + endif() + include(CPack) endif() endif() -add_custom_target(buildtestsx +add_custom_target(buildtests COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR} -DWITH_SCRIPTS=N ${CMAKE_SOURCE_DIR} COMMAND make COMMENT "Building test suite..." VERBATIM @@ -252,7 +248,6 @@ add_custom_target(testall add_custom_target(testcore COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR} -DWITH_SCRIPTS=N ${CMAKE_SOURCE_DIR} COMMAND make install - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/server/test/MaxScale_test.cnf ${CMAKE_BINARY_DIR}/etc/MaxScale.cnf COMMAND ctest -R Internal COMMENT "Running core test suite..." VERBATIM) diff --git a/cmake/package_deb.cmake b/cmake/package_deb.cmake new file mode 100644 index 000000000..90d66d4bc --- /dev/null +++ b/cmake/package_deb.cmake @@ -0,0 +1,6 @@ +# DEB specific CPack configuration parameters +set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB") +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/postinst;{CMAKE_BINARY_DIR}/postrm") +execute_process(COMMAND dpgk --print-architecture OUTPUT_VARIABLE DEB_ARCHITECTURE) +set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEB_ARCHITECTURE}) +set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) diff --git a/cmake/package_rpm.cmake b/cmake/package_rpm.cmake new file mode 100644 index 000000000..0f65bcdd2 --- /dev/null +++ b/cmake/package_rpm.cmake @@ -0,0 +1,23 @@ +# RPM specific CPack configuration parameters +set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MaxScale") +set(CPACK_PACKAGE_VERSION_MAJOR "${MAXSCALE_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${MAXSCALE_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${MAXSCALE_VERSION_PATCH}") +set(CPACK_PACKAGE_CONTACT "MariaDB Corporation Ab") +set(CPACK_PACKAGE_FILE_NAME "maxscale-${MAXSCALE_VERSION}") +set(CPACK_PACKAGE_NAME "maxscale") +set(CPACK_PACKAGE_VENDOR "MariaDB Corporation Ab") +set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_SOURCE_DIR}/etc/DESCRIPTION) +set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") +set(CPACK_RPM_PACKAGE_RELEASE ${MAXSCALE_BUILD_NUMBER}) +set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${CMAKE_BINARY_DIR}/postinst) +set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE ${CMAKE_BINARY_DIR}/postrm) +set(CPACK_RPM_PACKAGE_NAME "maxscale") +set(CPACK_RPM_PACKAGE_VENDOR "MariaDB Corporation Ab") +set(CPACK_RPM_PACKAGE_LICENSE "GPLv2") +set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/etc /etc/ld.so.conf.d /etc/init.d /etc/rc.d/init.d") +set(CPACK_RPM_SPEC_MORE_DEFINE "%define ignore \#") +set(CPACK_RPM_USER_FILELIST "%ignore /etc/init.d") +set(CPACK_RPM_USER_FILELIST "%ignore /etc/ld.so.conf.d") +set(CPACK_RPM_USER_FILELIST "%ignore /etc") From 71531cde3ed0e69d826721ab00e806c91dece731 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 28 Apr 2015 11:09:49 +0300 Subject: [PATCH 025/275] Updated package installation and started documentation update. --- CMakeLists.txt | 1 + .../Getting-Started/Configuration-Guide.md | 14 +++-- cmake/install_layout.cmake | 3 +- cmake/macros.cmake | 62 ------------------- etc/maxscale.service.in | 11 ++++ 5 files changed, 21 insertions(+), 70 deletions(-) create mode 100644 etc/maxscale.service.in diff --git a/CMakeLists.txt b/CMakeLists.txt index eff114eb5..43ede7f92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,7 @@ install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${MAXSCALE_SHAREDIR}) # Install startup scripts and ldconfig files if(WITH_SCRIPTS) configure_file(${CMAKE_SOURCE_DIR}/maxscale.conf.in ${CMAKE_BINARY_DIR}/maxscale.conf @ONLY) + configure_file(${CMAKE_SOURCE_DIR}/etc/maxscale.service.in ${CMAKE_BINARY_DIR}/maxscale.service @ONLY) if(DEB_BASED) configure_file(${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale.in ${CMAKE_BINARY_DIR}/maxscale @ONLY) else() diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 81d3c90e2..3f3dee484 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -1244,7 +1244,7 @@ In addition parameters may be added to define patterns to match against to eithe The top filter is a filter module for MaxScale that monitors every SQL statement that passes through the filter. It measures the duration of that statement, the time between the statement being sent and the first result being returned. The top N times are kept, along with the SQL text itself and a list sorted on the execution times of the query is written to a file upon closure of the client session. -The configuration block for the **top** filter requires the minimal filter options in its section within the `MaxScale.cnf` file, stored in `$MAXSCALE_HOME/etc/MaxScale.cnf`. +The configuration block for the **top** filter requires the minimal filter options in its section within the `MaxScale.cnf` file, stored in `/etc/MaxScale.cnf`. ``` [MyLogFilter] @@ -1258,9 +1258,11 @@ In addition parameters may be added to define patterns to match against to eithe ## Encrypting Passwords -Passwords stored in the MaxScale.cnf file may optionally be encrypted for added security. This is done by creation of an encryption key on installation of MaxScale. Encryption keys may be created manually by executing the maxkeys utility with the argument of the filename to store the key. +Passwords stored in the MaxScale.cnf file may optionally be encrypted for added security. This is done by creation of an encryption key on installation of MaxScale. Encryption keys may be created manually by executing the maxkeys utility with the argument of the filename to store the key. The default location MaxScale stores the keys is `/var/cache/maxscale`. - maxkeys $MAXSCALE_HOME/etc/.secrets +``` +maxkeys /var/cache/maxscale/.secrets +``` Changing the encryption key for MaxScale will invalidate any currently encrypted keys stored in the MaxScale.cnf file. @@ -1352,7 +1354,7 @@ and short notations ## Error Reporting -MaxScale is designed to be executed as a service, therefore all error reports, including configuration errors, are written to the MaxScale error log file. MaxScale will log to a set of files in the directory `$MAXSCALE_HOME/log`, the only exception to this is if the log directory is not writable, in which case a message is sent to the standard error descriptor. +MaxScale is designed to be executed as a service, therefore all error reports, including configuration errors, are written to the MaxScale error log file. By default, MaxScale will log to a set of files in the directory `/var/log/maxscale`, the only exception to this is if the log directory is not writable, in which case a message is sent to the standard error descriptor. ### Troubleshooting @@ -1367,11 +1369,11 @@ Example: ``` [Galera Listener] type=listener -address=192.1681.3.33 +address=192.168.3.33 port=4408 socket=/servers/maxscale/galera.sock ``` -TCP/IP Traffic must be permitted to 192.1681.3.33 port 4408 +TCP/IP Traffic must be permitted to 192.168.3.33 port 4408 For Unix socket, the socket file path (example: `/servers/maxscale/galera.sock`) must be writable by the Unix user MaxScale runs as. diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake index 1425b4d49..f7ce45441 100644 --- a/cmake/install_layout.cmake +++ b/cmake/install_layout.cmake @@ -1,8 +1,7 @@ # Set the install layout # Possible values: # STANDALONE - Installs to /usr/local/mariadb-maxscale -# RPM - Installs to /usr -# DEB - Installs to /usr +# PACKAGE - Installs to /usr include(GNUInstallDirs) set(MAXSCALE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/maxscale CACHE PATH "Library installation path") diff --git a/cmake/macros.cmake b/cmake/macros.cmake index 440c3fed5..aaed9cd69 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -196,68 +196,6 @@ debugmsg("Search returned: ${MYSQL_DIR_LOC}") set(ERRMSG ${ERRMSG_FILE} CACHE FILEPATH "Path to the errmsg.sys file." FORCE) unset(ERRMSG_FILE) - # Find the embedded mysql library - - # if (DEFINED EMBEDDED_LIB) - # if( NOT (IS_DIRECTORY ${EMBEDDED_LIB}) ) - # debugmsg("EMBEDDED_LIB is not a directory: ${EMBEDDED_LIB}") - # if(${CMAKE_VERSION} VERSION_LESS 2.8.12 ) - # set(COMP_VAR PATH) - # else() - # set(COMP_VAR DIRECTORY) - # endif() - # get_filename_component(EMBEDDED_LIB ${EMBEDDED_LIB} ${COMP_VAR}) - # debugmsg("EMBEDDED_LIB directory component: ${EMBEDDED_LIB}") - # endif() - # debugmsg("Searching for the embedded library at: ${EMBEDDED_LIB}") - # endif() - - # if(STATIC_EMBEDDED) - - # debugmsg("Using the static embedded library...") - # set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - # set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") - # if (DEFINED EMBEDDED_LIB) - # debugmsg("Searching for libmysqld.a at: ${EMBEDDED_LIB}") - # find_library(EMBEDDED_LIB_STATIC libmysqld.a PATHS ${EMBEDDED_LIB} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH) - # else() - # find_library(EMBEDDED_LIB_STATIC libmysqld.a PATH_SUFFIXES mysql mariadb) - # endif() - # debugmsg("Search returned: ${EMBEDDED_LIB_STATIC}") - - # set(EMBEDDED_LIB ${EMBEDDED_LIB_STATIC} CACHE FILEPATH "Path to libmysqld" FORCE) - # set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) - - # else() - # debugmsg("Using the dynamic embedded library...") - # set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - # set(CMAKE_FIND_LIBRARY_SUFFIXES ".so") - # if (DEFINED EMBEDDED_LIB) - # debugmsg("Searching for libmysqld.so at: ${EMBEDDED_LIB}") - # find_library(EMBEDDED_LIB_DYNAMIC mysqld PATHS ${EMBEDDED_LIB} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH) - # else() - # find_library(EMBEDDED_LIB_DYNAMIC mysqld PATH_SUFFIXES mysql mariadb) - # endif() - # debugmsg("Search returned: ${EMBEDDED_LIB_DYNAMIC}") - # set(EMBEDDED_LIB ${EMBEDDED_LIB_DYNAMIC} CACHE FILEPATH "Path to libmysqld" FORCE) - # set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) - - # endif() - - # unset(EMBEDDED_LIB_DYNAMIC) - # unset(EMBEDDED_LIB_STATIC) - # unset(OLD_SUFFIXES) - - # # Inform the user about the embedded library - # if( (${EMBEDDED_LIB} MATCHES "NOTFOUND") OR (${EMBEDDED_LIB} MATCHES "NOTFOUND")) - # set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") - # message(FATAL_ERROR "Library not found: libmysqld. If your install of MySQL is in a non-default location, please provide the location with -DEMBEDDED_LIB=") - # else() - # get_filename_component(EMBEDDED_LIB ${EMBEDDED_LIB} REALPATH) - # message(STATUS "Using embedded library: ${EMBEDDED_LIB}") - # endif() - - # Check which init.d script to install find_file(RPM_FNC functions PATHS /etc/rc.d/init.d) if(${RPM_FNC} MATCHES "RPM_FNC-NOTFOUND") diff --git a/etc/maxscale.service.in b/etc/maxscale.service.in new file mode 100644 index 000000000..56b49d98f --- /dev/null +++ b/etc/maxscale.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=MariaDB MaxScale Database Proxy +After=network.target + +[Service] +Type=forking +PIDFile=/var/run/maxscale/maxscale.pid +ExecStart=@CMAKE_INSTALL_PREFIX@/@MAXSCALE_BINDIR@/maxscale + +[Install] +WantedBy=multi-user.target From 3501ffb689f02d54824291e65eb8473da1c8642d Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 28 Apr 2015 16:39:52 +0300 Subject: [PATCH 026/275] Updated documentation --- .../Getting-Started/Configuration-Guide.md | 2 +- .../Reference/Debug-And-Diagnostic-Support.md | 10 ++-- .../Tutorials/Administration-Tutorial.md | 53 ++++++------------- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 3f3dee484..19d4c2b6e 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -1268,7 +1268,7 @@ Changing the encryption key for MaxScale will invalidate any currently encrypted ### Creating Encrypted Passwords -Encrypted passwords are created by executing the maxpasswd command with the password you require to encrypt as an argument. The environment variable `MAXSCALE_HOME` must be set, or MaxScale must be installed in the default location before maxpasswd can be executed. +Encrypted passwords are created by executing the maxpasswd command with the password you require to encrypt as an argument. maxpasswd MaxScalePw001 61DD955512C39A4A8BC4BB1E5F116705 diff --git a/Documentation/Reference/Debug-And-Diagnostic-Support.md b/Documentation/Reference/Debug-And-Diagnostic-Support.md index 34fda6653..d9bffa268 100644 --- a/Documentation/Reference/Debug-And-Diagnostic-Support.md +++ b/Documentation/Reference/Debug-And-Diagnostic-Support.md @@ -1711,7 +1711,7 @@ User admin already exists. **MaxScale>**** ** -If you should forget or lose the the account details you may simply remove the passwd file in $MAXSCALE_HOME/etc and the system will revert to the default behavior with admin/mariadb as the account. +If you should forget or lose the the account details you may simply remove the passwd file in /var/cache/maxscale and the system will revert to the default behavior with admin/mariadb as the account. ## Enable/disable log @@ -1745,7 +1745,7 @@ MaxScale generates output of its behavior to four distinct logs, error, messages ## Log contents -By default all log files are located in : $MAXSCALE_HOME/log and named as : +By default all log files are located in : /var/log/maxscale and named as : skygw_errW.log, skygw_msgX.log, skygw_traceY.log and skygw_debugZ.log @@ -1837,7 +1837,7 @@ MariaDB Corporation MaxScale /home/jdoe/bin/develop/log/skygw_msg1.log Tue Dec ### Trace log -Trace log includes information about available servers and their states, client sessions, queries being executed, routing decisions and other routing related data. Trace log can be found from the same directory with other logs but it is physically stored elsewhere, to OSs shared memory to reduce the latency caused by logging. The location of physical file is : /dev/shm//skygw_traceX.log where ‘X’ is the same sequence number as in the file name in the $MAXSCALE_HOME/log directory. +Trace log includes information about available servers and their states, client sessions, queries being executed, routing decisions and other routing related data. Trace log can be found from the same directory with other logs but it is physically stored elsewhere, to OSs shared memory to reduce the latency caused by logging. The location of physical file is : /dev/shm//skygw_traceX.log where ‘X’ is the same sequence number as in the file name in the /var/log/maxscale directory. Individual trace log entry looks similar to those in other logs but there is some difference too. Some log entries include a number within square brackets to specify which client session they belong to. For example: @@ -1923,11 +1923,11 @@ In the log, session’s life cycle is covered by annotating its beginning and th The log files are located in -$MAXSCALE_HOME/log +/var/log/maxscale by default. If, however, trace and debug logs are enabled, only a soft link is created there. MaxScale process creates a directory under -/dev/shm/ +/dev/shm/maxscale. where it stores the physical trace and debug log files. Link and physical files share the same name. These logs consume the main memory of the host they run on so it is important to archive or remove them periodically to avoid unnecessary main-memory consumption. diff --git a/Documentation/Tutorials/Administration-Tutorial.md b/Documentation/Tutorials/Administration-Tutorial.md index 894f89f94..943ecaa27 100644 --- a/Documentation/Tutorials/Administration-Tutorial.md +++ b/Documentation/Tutorials/Administration-Tutorial.md @@ -26,43 +26,20 @@ It is also possible to start MaxScale by executing the maxscale command itself, Options may be passed to the MaxScale binary that alter this default behavior, this options are documented in the table below. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SwitchLong OptionDescription
-d--nodaemonRun MaxScale attached to the terminal rather than as a daemon process. This is useful for debugging purposes.
-c--homedir=Ignore the environment variable MAXSCALE_HOME and use the supplied argument instead.
-f--config=Use the filename passed as an argument instead of looking in /etc/MaxScale.cnf
-l|--log=Control where logs are written for the debug and trace level log messages. the default is to write these to a shared memory device, however using the -lfile or --log=file option will forced these to be written to regular files.
-v--versionPrint version information for MaxScale
-?--helpPrint usage information for MaxScale
+Switch|Long Option|Description +------|-----------|----------- +`-d`|`--nodaemon`|enable running in terminal process (default:disabled) +`-f FILE`|`--config=FILE`|relative or absolute pathname of MaxScale configuration file (default:/etc/maxscale.cnf) +`-l[file shm]`|`--log=[file shm]`|log to file or shared memory (default: shm) +`-L PATH`|`--logdir=PATH`|path to log file directory (default: /var/log/maxscale) +`-D PATH`|`--datadir=PATH`|path to data directory, stored embedded mysql tables (default: /var/cache/maxscale) +`-C PATH`|`--configdir=PATH`|path to configuration file directory (default: /etc/) +`-B PATH`|`--libdir=PATH`|path to module directory (default: /usr/lib64/maxscale) +`-A PATH`|`--cachedir=PATH`|path to cache directory (default: /var/cache/maxscale) +`-s [yes no]`|`--syslog=[yes no]`|log messages to syslog (default:yes) +`-S [yes no]`|`--maxscalelog=[yes no]`|log messages to MaxScale log (default: yes) +`-v`|`--version`|print version info and exit +`-?`|`--help`|show this help ### Stopping MaxScale @@ -90,6 +67,7 @@ In order to shutdown MaxScale using the maxadmin command you may either connect It is possible to use the maxadmin command to obtain statistics regarding the services that are configured within your MaxScale configuration file. The maxadmin command "list services" will give very basic information regarding the services that are define. This command may be either run in interactive mode or passed on the maxadmin command line. +``` $ maxadmin -pmariadb MaxScale> list services @@ -110,6 +88,7 @@ It is possible to use the maxadmin command to obtain statistics regarding the se --------------------------+----------------------+--------+--------------- MaxScale> +``` It should be noted that network listeners count as a user of the service, therefore there will always be one user per network port in which the service listens. More detail can be obtained by use of the "show service" command which is passed a service name. From 5394b4d0fab6d71272f0f1da595f71c17baf4e69 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 05:42:58 +0300 Subject: [PATCH 027/275] Changed standard installation directory from /usr/local/mariadb-maxscale to /usr/local. --- CMakeLists.txt | 11 +---------- cmake/install_layout.cmake | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43ede7f92..28b3229d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,17 +9,8 @@ message(STATUS "CMake version: ${CMAKE_VERSION}") include(${CMAKE_SOURCE_DIR}/cmake/macros.cmake) enable_testing() -# Packaging builds install to /usr and other builds to /usr/local/mariadb-maxscale +# Packaging builds install to /usr and other builds to /usr/local if(PACKAGE) - set(INSTALL_LAYOUT "PACKAGE" CACHE STRING "Install layout, options are: STANDALONE, PACKAGE") -else() - set(INSTALL_LAYOUT "STANDALONE" CACHE STRING "Install layout, options are: STANDALONE, PACKAGE") -endif() - -# Installation prefixes for different layouts -if(${INSTALL_LAYOUT} MATCHES "STANDALONE") - set(CMAKE_INSTALL_PREFIX "/usr/local/mariadb-maxscale" CACHE PATH "Prefix prepended to install directories.") -else() set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Prefix prepended to install directories.") endif() diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake index f7ce45441..c55a25a32 100644 --- a/cmake/install_layout.cmake +++ b/cmake/install_layout.cmake @@ -1,6 +1,6 @@ # Set the install layout # Possible values: -# STANDALONE - Installs to /usr/local/mariadb-maxscale +# STANDALONE - Installs to /usr/local # PACKAGE - Installs to /usr include(GNUInstallDirs) From c035f4b8b75eb9a11b7cea9ef334ba8d2d632083 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 07:03:05 +0300 Subject: [PATCH 028/275] Removed current directory from the module search path. --- server/core/load_utils.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 5ecbe7f34..9d7d69220 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -133,21 +133,17 @@ MODULE_INFO *mod_info = NULL; * * Search of the shared object. */ - snprintf(fname,MAXPATHLEN+1, "./lib%s.so", module); - + + snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_libdir(), module); + if (access(fname, F_OK) == -1) { - snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_libdir(), module); - - if (access(fname, F_OK) == -1) - { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Unable to find library for " - "module: %s. Module dir: %s", - module, get_libdir()))); - return NULL; - } + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error : Unable to find library for " + "module: %s. Module dir: %s", + module, get_libdir()))); + return NULL; } if ((dlhandle = dlopen(fname, RTLD_NOW|RTLD_LOCAL)) == NULL) From 9ce225c2cb57fe27f8a4e177e4b638b554328be6 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 11:20:40 +0300 Subject: [PATCH 029/275] Added log manager initialization flag that prints all logs to stdout. --- log_manager/log_manager.cc | 78 ++++++++++++++---------- server/core/maxkeys.c | 8 +-- server/core/maxpasswd.c | 7 ++- server/modules/filter/dbfwfilter.c | 8 +-- utils/skygw_utils.cc | 96 ++++++++---------------------- utils/skygw_utils.h | 70 ++++++++++++++++++++++ 6 files changed, 152 insertions(+), 115 deletions(-) diff --git a/log_manager/log_manager.cc b/log_manager/log_manager.cc index 05f5044c6..acce7326c 100644 --- a/log_manager/log_manager.cc +++ b/log_manager/log_manager.cc @@ -54,7 +54,7 @@ static simple_mutex_t msg_mutex; static int highprec = 0; static int do_syslog = 1; static int do_maxscalelog = 1; - +static int use_stdout = 0; /** * Variable holding the enabled logfiles information. * Used from log users to check enabled logs prior calling @@ -1331,12 +1331,14 @@ static bool logfile_set_enabled( } lf = &lm->lm_logfile[id]; CHK_LOGFILE(lf); - - if (val) { - logstr = strdup("---\tLogging to file is enabled\t--"); - } else { - logstr = strdup("---\tLogging to file is disabled\t--"); - } + if(use_stdout == 0) + { + if (val) { + logstr = strdup("---\tLogging to file is enabled\t--"); + } else { + logstr = strdup("---\tLogging to file is disabled\t--"); + } + oldval = lf->lf_enabled; lf->lf_enabled = val; err = logmanager_write_log(id, @@ -1348,7 +1350,7 @@ static bool logfile_set_enabled( logstr, notused); free(logstr); - + } if (err != 0) { lf->lf_enabled = oldval; fprintf(stderr, @@ -1445,7 +1447,7 @@ int skygw_log_write( * Find out the length of log string (to be formatted str). */ va_start(valist, str); - len = vsnprintf(NULL, 0, str, valist); + len = vsnprintf(NULL, 0, str, valist); va_end(valist); /** * Add one for line feed. @@ -1695,9 +1697,12 @@ static bool fnames_conf_init( fn->fn_chk_tail = CHK_NUM_FNAMES; #endif optind = 1; /**fn_debug_prefix = strndup(optarg, MAX_PREFIXLEN); break; @@ -2153,8 +2158,14 @@ static bool logfile_open_file( bool succp; char* start_msg_str; int err; - - if (lf->lf_store_shmem) + + if(use_stdout) + { + fw->fwr_file[lf->lf_id] = skygw_file_init_stdout ( + lf->lf_full_file_name, + lf->lf_full_link_name); + } + else if (lf->lf_store_shmem) { /** Create symlink pointing to log file */ fw->fwr_file[lf->lf_id] = skygw_file_init( @@ -2177,32 +2188,35 @@ static bool logfile_open_file( succp = false; goto return_succp; } - - if (lf->lf_enabled) - { + + if(use_stdout == 0) + { + if (lf->lf_enabled) + { start_msg_str = strdup("---\tLogging is enabled.\n"); - } - else - { + } + else + { start_msg_str = strdup("---\tLogging is disabled.\n"); - } - err = skygw_file_write(fw->fwr_file[lf->lf_id], - (void *)start_msg_str, - strlen(start_msg_str), - true); - - if (err != 0) - { + } + err = skygw_file_write(fw->fwr_file[lf->lf_id], + (void *)start_msg_str, + strlen(start_msg_str), + true); + + if (err != 0) + { fprintf(stderr, - "Error : writing to file %s failed due to %d, %s. " + "Error : writing to file %s failed due to %d, %s. " "Exiting MaxScale.\n", - lf->lf_full_file_name, - err, - strerror(err)); + lf->lf_full_file_name, + err, + strerror(err)); succp = false; goto return_succp; - } - free(start_msg_str); + } + free(start_msg_str); + } succp = true; return_succp: diff --git a/server/core/maxkeys.c b/server/core/maxkeys.c index 0d5c938ff..2d245d52c 100644 --- a/server/core/maxkeys.c +++ b/server/core/maxkeys.c @@ -33,7 +33,7 @@ #include int main(int argc, char **argv) { - int arg_count = 3; + int arg_count = 4; char *home; char** arg_vector; @@ -44,7 +44,7 @@ int main(int argc, char **argv) exit(1); } - arg_vector = malloc(sizeof(char*)*4); + arg_vector = malloc(sizeof(char*)*5); if(arg_vector == NULL) { @@ -64,8 +64,8 @@ int main(int argc, char **argv) { arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log"); } - - arg_vector[3] = NULL; + arg_vector[3] = "-o"; + arg_vector[4] = NULL; skygw_logmanager_init(arg_count,arg_vector); skygw_log_enable(LOGFILE_TRACE); skygw_log_enable(LOGFILE_DEBUG); diff --git a/server/core/maxpasswd.c b/server/core/maxpasswd.c index 4da1dbde1..d568124f1 100644 --- a/server/core/maxpasswd.c +++ b/server/core/maxpasswd.c @@ -41,7 +41,7 @@ int main(int argc, char **argv) { char *enc, *pw; - int arg_count = 3; + int arg_count = 4; char *home; char** arg_vector; @@ -52,7 +52,7 @@ main(int argc, char **argv) exit(1); } - arg_vector = malloc(sizeof(char*)*4); + arg_vector = malloc(sizeof(char*)*5); if(arg_vector == NULL) { @@ -73,7 +73,8 @@ main(int argc, char **argv) arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log"); } - arg_vector[3] = NULL; + arg_vector[3] = "-o"; + arg_vector[4] = NULL; skygw_logmanager_init(arg_count,arg_vector); skygw_log_enable(LOGFILE_TRACE); skygw_log_enable(LOGFILE_DEBUG); diff --git a/server/modules/filter/dbfwfilter.c b/server/modules/filter/dbfwfilter.c index 9cdc2816f..8e756f715 100644 --- a/server/modules/filter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter.c @@ -2144,15 +2144,11 @@ int main(int argc, char** argv) } printf("Log files written to: %s\n",home?home:"/tpm"); - int argc_ = 11; + int argc_ = 2; char* argv_[] = { "log_manager", - "-j",home?home:"/tmp", - "-a","ruleparser_debug", - "-c","ruleparser_trace", - "-e","ruleparser_message", - "-g","ruleparser_error", + "-o", NULL }; diff --git a/utils/skygw_utils.cc b/utils/skygw_utils.cc index 78a37d43a..101393c1b 100644 --- a/utils/skygw_utils.cc +++ b/utils/skygw_utils.cc @@ -30,76 +30,6 @@ #include #include "skygw_utils.h" -const char* timestamp_formatstr = "%04d-%02d-%02d %02d:%02d:%02d "; -/** One for terminating '\0' */ -const size_t timestamp_len = (4+1 +2+1 +2+1 +2+1 +2+1 +2+3 +1) * sizeof(char); - - -const char* timestamp_formatstr_hp = "%04d-%02d-%02d %02d:%02d:%02d.%03d "; -/** One for terminating '\0' */ -const size_t timestamp_len_hp = (4+1 +2+1 +2+1 +2+1 +2+1 +2+1+3+3 +1) * sizeof(char); - -/** Single-linked list for storing test cases */ - -struct slist_node_st { - skygw_chk_t slnode_chk_top; - slist_t* slnode_list; - slist_node_t* slnode_next; - void* slnode_data; - size_t slnode_cursor_refcount; - skygw_chk_t slnode_chk_tail; -}; - -struct slist_st { - skygw_chk_t slist_chk_top; - slist_node_t* slist_head; - slist_node_t* slist_tail; - int slist_nelems; - slist_t* slist_cursors_list; - skygw_chk_t slist_chk_tail; -}; - -struct slist_cursor_st { - skygw_chk_t slcursor_chk_top; - slist_t* slcursor_list; - slist_node_t* slcursor_pos; - skygw_chk_t slcursor_chk_tail; -}; - -struct skygw_thread_st { - skygw_chk_t sth_chk_top; - bool sth_must_exit; - simple_mutex_t* sth_mutex; - pthread_t sth_parent; - pthread_t sth_thr; - int sth_errno; -#if defined(SS_DEBUG) - skygw_thr_state_t sth_state; -#endif - char* sth_name; - void* (*sth_thrfun)(void* data); - void* sth_data; - skygw_chk_t sth_chk_tail; -}; - -struct skygw_message_st { - skygw_chk_t mes_chk_top; - bool mes_sent; - pthread_mutex_t mes_mutex; - pthread_cond_t mes_cond; - skygw_chk_t mes_chk_tail; -}; - -struct skygw_file_st { - skygw_chk_t sf_chk_top; - char* sf_fname; - FILE* sf_file; - int sf_fd; - skygw_chk_t sf_chk_tail; -}; - -/** End of structs and types */ - #if defined(MLIST) @@ -2033,6 +1963,32 @@ return_file: return file; } + +skygw_file_t* skygw_file_init_stdout( + char* fname, + char* symlinkname) +{ + skygw_file_t* file; + + if ((file = (skygw_file_t *)calloc(1, sizeof(skygw_file_t))) == NULL) + { + fprintf(stderr, + "* Error : Memory allocation for file %s failed.\n", + fname); + perror("SkyGW file allocation\n"); + goto return_file; + } + ss_dassert(file != NULL); + file->sf_chk_top = CHK_NUM_FILE; + file->sf_chk_tail = CHK_NUM_FILE; + file->sf_fname = strdup(fname); + file->sf_file = stdout; + CHK_FILE(file); + +return_file: + return file; +} + void skygw_file_close( skygw_file_t* file, bool shutdown) diff --git a/utils/skygw_utils.h b/utils/skygw_utils.h index ff4055fc7..b4cd3cb45 100644 --- a/utils/skygw_utils.h +++ b/utils/skygw_utils.h @@ -80,6 +80,75 @@ struct mlist_node_st { typedef enum { THR_INIT, THR_RUNNING, THR_STOPPED, THR_DONE } skygw_thr_state_t; typedef enum { MES_RC_FAIL, MES_RC_SUCCESS, MES_RC_TIMEOUT } skygw_mes_rc_t; + +static const char* timestamp_formatstr = "%04d-%02d-%02d %02d:%02d:%02d "; +/** One for terminating '\0' */ +static const size_t timestamp_len = (4+1 +2+1 +2+1 +2+1 +2+1 +2+3 +1) * sizeof(char); + + +static const char* timestamp_formatstr_hp = "%04d-%02d-%02d %02d:%02d:%02d.%03d "; +/** One for terminating '\0' */ +static const size_t timestamp_len_hp = (4+1 +2+1 +2+1 +2+1 +2+1 +2+1+3+3 +1) * sizeof(char); + +/** Single-linked list for storing test cases */ + +struct slist_node_st { + skygw_chk_t slnode_chk_top; + slist_t* slnode_list; + slist_node_t* slnode_next; + void* slnode_data; + size_t slnode_cursor_refcount; + skygw_chk_t slnode_chk_tail; +}; + +struct slist_st { + skygw_chk_t slist_chk_top; + slist_node_t* slist_head; + slist_node_t* slist_tail; + int slist_nelems; + slist_t* slist_cursors_list; + skygw_chk_t slist_chk_tail; +}; + +struct slist_cursor_st { + skygw_chk_t slcursor_chk_top; + slist_t* slcursor_list; + slist_node_t* slcursor_pos; + skygw_chk_t slcursor_chk_tail; +}; + +struct skygw_thread_st { + skygw_chk_t sth_chk_top; + bool sth_must_exit; + simple_mutex_t* sth_mutex; + pthread_t sth_parent; + pthread_t sth_thr; + int sth_errno; +#if defined(SS_DEBUG) + skygw_thr_state_t sth_state; +#endif + char* sth_name; + void* (*sth_thrfun)(void* data); + void* sth_data; + skygw_chk_t sth_chk_tail; +}; + +struct skygw_message_st { + skygw_chk_t mes_chk_top; + bool mes_sent; + pthread_mutex_t mes_mutex; + pthread_cond_t mes_cond; + skygw_chk_t mes_chk_tail; +}; + +struct skygw_file_st { + skygw_chk_t sf_chk_top; + char* sf_fname; + FILE* sf_file; + int sf_fd; + skygw_chk_t sf_chk_tail; +}; + EXTERN_C_BLOCK_BEGIN slist_cursor_t* slist_init(void); @@ -148,6 +217,7 @@ EXTERN_C_BLOCK_END /** Skygw file routines */ skygw_file_t* skygw_file_init(char* fname, char* symlinkname); +skygw_file_t* skygw_file_init_stdout(char* fname, char* symlinkname); void skygw_file_close(skygw_file_t* file, bool shutdown); int skygw_file_write( skygw_file_t* file, From 8bff81e0a9674449c59391d776051a0ee47e3081 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 11:39:17 +0300 Subject: [PATCH 030/275] Fixed rule parsing failing if at_times is used with on_queries. --- server/modules/filter/dbfwfilter.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/modules/filter/dbfwfilter.c b/server/modules/filter/dbfwfilter.c index 9cdc2816f..58eedcc4b 100644 --- a/server/modules/filter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter.c @@ -946,6 +946,8 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) while(tok) { + reparse_rule: + if(strcmp(tok,"wildcard") == 0) { ruledef->type = RT_WILDCARD; @@ -974,7 +976,8 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) tok = strtok_r(NULL, " ,",&saveptr); TIMERANGE *tr = NULL; while(tok){ - + if(strcmp(tok,"on_queries") == 0) + goto reparse_rule; if(!check_time(tok)) { skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, malformed time definition: %s",tok); From 1755706ada87ca7cb44cda97816c3d846a31983f Mon Sep 17 00:00:00 2001 From: MassimilianoPinto Date: Wed, 29 Apr 2015 10:50:21 +0200 Subject: [PATCH 031/275] Master/Slave detection based on variable only Master/Slave role setting is now based on variable value only. Replication is checked and, if working, master_id, slave_id are saved into server struct --- server/modules/monitor/mm_mon.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/server/modules/monitor/mm_mon.c b/server/modules/monitor/mm_mon.c index a71d2cc7d..60acea825 100644 --- a/server/modules/monitor/mm_mon.c +++ b/server/modules/monitor/mm_mon.c @@ -531,18 +531,20 @@ char *server_string; } /* get variable 'read_only' set by an external component */ - if (mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0 - && (result = mysql_store_result(database->con)) != NULL) - { - num_fields = mysql_num_fields(result); - while ((row = mysql_fetch_row(result))) - { - if (strncasecmp(row[1], "OFF", 3) == 0) { - ismaster = 1; - } - } - mysql_free_result(result); - } + if (mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0 + && (result = mysql_store_result(database->con)) != NULL) + { + num_fields = mysql_num_fields(result); + while ((row = mysql_fetch_row(result))) + { + if (strncasecmp(row[1], "OFF", 3) == 0) { + ismaster = 1; + } else { + isslave = 1; + } + } + mysql_free_result(result); + } /* Remove addition info */ monitor_clear_pending_status(database, SERVER_STALE_STATUS); @@ -563,7 +565,7 @@ char *server_string; } /* Set the Master role */ - if (isslave && ismaster) + if (ismaster) { monitor_clear_pending_status(database, SERVER_SLAVE); monitor_set_pending_status(database, SERVER_MASTER); From c190433c7d31a623d7fc1741757896bbcdc4c0c7 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 14:29:43 +0300 Subject: [PATCH 032/275] Fixed dbfwfilter rules. Fixed at_times not working if combined with on_queries. --- server/modules/filter/dbfwfilter.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/modules/filter/dbfwfilter.c b/server/modules/filter/dbfwfilter.c index 58eedcc4b..372309034 100644 --- a/server/modules/filter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter.c @@ -977,7 +977,7 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) TIMERANGE *tr = NULL; while(tok){ if(strcmp(tok,"on_queries") == 0) - goto reparse_rule; + break; if(!check_time(tok)) { skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, malformed time definition: %s",tok); @@ -1003,8 +1003,12 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) tr = tmp; tok = strtok_r(NULL, " ,",&saveptr); } + ruledef->active = tr; + if(strcmp(tok,"on_queries") == 0) + goto reparse_rule; + } else if(strcmp(tok,"regex") == 0) { From 87133388dc8e89f898706e25659ff4db1b972dff Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 15:08:18 +0300 Subject: [PATCH 033/275] Added a note to the dbfwfilter documentation about using local time. --- Documentation/filters/Database-Firewall-Filter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/filters/Database-Firewall-Filter.md b/Documentation/filters/Database-Firewall-Filter.md index cf4db676d..9e76cb1de 100644 --- a/Documentation/filters/Database-Firewall-Filter.md +++ b/Documentation/filters/Database-Firewall-Filter.md @@ -74,7 +74,7 @@ Each mandatory rule accepts one or more optional parameters. These are to be def #### `at_times` -This rule expects a list of time ranges that define the times when the rule in question is active. The time formats are expected to be ISO-8601 compliant and to be separated by a single dash (the - character). For example, to define the active period of a rule to be 5pm to 7pm, you would include `at times 17:00:00-19:00:00` in the rule definition. +This rule expects a list of time ranges that define the times when the rule in question is active. The time formats are expected to be ISO-8601 compliant and to be separated by a single dash (the - character). For example, to define the active period of a rule to be 5pm to 7pm, you would include `at times 17:00:00-19:00:00` in the rule definition. The rule uses local time to check if the rule is active. #### `on_queries` From 47e5b12eb8106b3a8d2a4bc85a54d45a063428ed Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 18:25:04 +0300 Subject: [PATCH 034/275] Added a function that frees the skygw_file_t memory but doesn't close it. --- log_manager/log_manager.cc | 5 ++++- utils/skygw_utils.cc | 28 ++++++++++++++++++++++++++++ utils/skygw_utils.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/log_manager/log_manager.cc b/log_manager/log_manager.cc index acce7326c..19d644900 100644 --- a/log_manager/log_manager.cc +++ b/log_manager/log_manager.cc @@ -2741,7 +2741,10 @@ static void filewriter_done( for (i=LOGFILE_FIRST; i<=LOGFILE_LAST; i++) { id = (logfile_id_t)i; - skygw_file_close(fw->fwr_file[id], true); + if(use_stdout) + skygw_file_close_stdout(fw->fwr_file[id], true); + else + skygw_file_close(fw->fwr_file[id], true); } fw->fwr_state = DONE; case DONE: diff --git a/utils/skygw_utils.cc b/utils/skygw_utils.cc index 101393c1b..a2f37fc01 100644 --- a/utils/skygw_utils.cc +++ b/utils/skygw_utils.cc @@ -1989,6 +1989,34 @@ return_file: return file; } + +void skygw_file_close_stdout( + skygw_file_t* file, + bool shutdown) +{ + int fd; + int err; + + if (file != NULL) + { + CHK_FILE(file); + + if (!file_write_footer(file, shutdown)) + { + fprintf(stderr, + "* Writing footer to log file %s failed.\n", + file->sf_fname); + perror("Write fike footer\n"); + } + fd = fileno(file->sf_file); + fsync(fd); + + ss_dfprintf(stderr, "Closed %s\n", file->sf_fname); + free(file->sf_fname); + free(file); + } +} + void skygw_file_close( skygw_file_t* file, bool shutdown) diff --git a/utils/skygw_utils.h b/utils/skygw_utils.h index b4cd3cb45..9370c91cd 100644 --- a/utils/skygw_utils.h +++ b/utils/skygw_utils.h @@ -219,6 +219,7 @@ EXTERN_C_BLOCK_END skygw_file_t* skygw_file_init(char* fname, char* symlinkname); skygw_file_t* skygw_file_init_stdout(char* fname, char* symlinkname); void skygw_file_close(skygw_file_t* file, bool shutdown); +void skygw_file_close_stdout(skygw_file_t*, bool); int skygw_file_write( skygw_file_t* file, void* data, From 00abb3868971450194fc08895bb7251c9802c5d4 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Wed, 29 Apr 2015 19:19:36 +0300 Subject: [PATCH 035/275] Fixed rule parsing --- .../filters/Database-Firewall-Filter.md | 2 +- server/modules/filter/dbfwfilter.c | 73 ++++++++++++++++++- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Documentation/filters/Database-Firewall-Filter.md b/Documentation/filters/Database-Firewall-Filter.md index 9e76cb1de..b448b65be 100644 --- a/Documentation/filters/Database-Firewall-Filter.md +++ b/Documentation/filters/Database-Firewall-Filter.md @@ -74,7 +74,7 @@ Each mandatory rule accepts one or more optional parameters. These are to be def #### `at_times` -This rule expects a list of time ranges that define the times when the rule in question is active. The time formats are expected to be ISO-8601 compliant and to be separated by a single dash (the - character). For example, to define the active period of a rule to be 5pm to 7pm, you would include `at times 17:00:00-19:00:00` in the rule definition. The rule uses local time to check if the rule is active. +This rule expects a list of time ranges that define the times when the rule in question is active. The time formats are expected to be ISO-8601 compliant and to be separated by a single dash (the - character). For example, to define the active period of a rule to be 5pm to 7pm, you would include `at times 17:00:00-19:00:00` in the rule definition. The rule uses local time to check if the rule is active and has a precision of one second. #### `on_queries` diff --git a/server/modules/filter/dbfwfilter.c b/server/modules/filter/dbfwfilter.c index 372309034..ccf2a2800 100644 --- a/server/modules/filter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter.c @@ -86,6 +86,14 @@ MODULE_INFO info = { static char *version_str = "V1.0.0"; +static char* required_rules[] = { + "wildcard", + "columns", + "regex", + "limit_queries", + "no_where_clause", + NULL +}; /* * The filter entry points */ @@ -861,6 +869,10 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) bool allow,deny,mode; RULE* ruledef = NULL; bool rval = true; + bool req_defined,oq_def,at_def; + int i; + + req_defined = oq_def = at_def = false; if(tok == NULL) { @@ -920,7 +932,7 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) } else { - skygw_log_write(LOGFILE_ERROR,"Error : Unknown token in rule file: %s",tok); + skygw_log_write(LOGFILE_ERROR,"Error : Unknown token in rule '%s': %s",rule,tok); rval = false; goto retblock; } @@ -947,6 +959,23 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) while(tok) { reparse_rule: + + for(i = 0;required_rules[i] != NULL;i++) + { + if(strcmp(tok,required_rules[i]) == 0) + { + if(req_defined) + { + skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, Multiple non-optional rules: %s",rule); + rval = false; + goto retblock; + } + else + { + req_defined = true; + } + } + } if(strcmp(tok,"wildcard") == 0) { @@ -972,7 +1001,13 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) } else if(strcmp(tok,"at_times") == 0) { - + if(at_def) + { + skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, multiple 'at_times' tokens: %s",rule); + rval = false; + goto retblock; + } + at_def = true; tok = strtok_r(NULL, " ,",&saveptr); TIMERANGE *tr = NULL; while(tok){ @@ -1126,14 +1161,24 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule parsing failed, not a number: '%s'.", tok); goto retblock; } + + if(qs->limit < 1){ + free(qs); + rval = false; + skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Bad query amount: %s", tok); + goto retblock; + } + errptr = NULL; tok = strtok_r(NULL," ",&saveptr); + if(tok == NULL){ free(qs); rval = false; skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Missing parameter in limit_queries: '%s'.", rule); goto retblock; } + qs->period = strtod(tok,&errptr); if(errptr && *errptr != '\0') @@ -1143,9 +1188,17 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule parsing failed, not a number: '%s'.", tok); goto retblock; } - errptr = NULL; + if(qs->period < 1){ + free(qs); + rval = false; + skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Bad time period: %s", tok); + goto retblock; + } + + errptr = NULL; tok = strtok_r(NULL," ",&saveptr); + if(tok == NULL){ free(qs); rval = false; @@ -1162,6 +1215,13 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) goto retblock; } + if(qs->cooldown < 1){ + free(qs); + rval = false; + skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Bad blocking period: %s", tok); + goto retblock; + } + ruledef->type = RT_THROTTLE; ruledef->data = (void*)qs; } @@ -1172,6 +1232,13 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) } else if(strcmp(tok,"on_queries") == 0) { + if(oq_def) + { + skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, multiple 'on_queries' tokens: %s",rule); + rval = false; + goto retblock; + } + oq_def = true; tok = strtok_r(NULL," ",&saveptr); if(tok == NULL) From 7c988c4fd52c8b6919f03285c6837b409f5cdbd9 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Thu, 30 Apr 2015 04:26:48 +0300 Subject: [PATCH 036/275] Removed stdout specific functions in skygw_utils and moved the logic to log_manager instead. --- log_manager/log_manager.cc | 11 +++-- utils/skygw_utils.cc | 90 ++++++++++++-------------------------- utils/skygw_utils.h | 4 +- 3 files changed, 36 insertions(+), 69 deletions(-) diff --git a/log_manager/log_manager.cc b/log_manager/log_manager.cc index 19d644900..9358a9f97 100644 --- a/log_manager/log_manager.cc +++ b/log_manager/log_manager.cc @@ -2161,9 +2161,9 @@ static bool logfile_open_file( if(use_stdout) { - fw->fwr_file[lf->lf_id] = skygw_file_init_stdout ( - lf->lf_full_file_name, - lf->lf_full_link_name); + fw->fwr_file[lf->lf_id] = skygw_file_alloc ( + lf->lf_full_file_name); + fw->fwr_file[lf->lf_id]->sf_file = stdout; } else if (lf->lf_store_shmem) { @@ -2742,7 +2742,7 @@ static void filewriter_done( { id = (logfile_id_t)i; if(use_stdout) - skygw_file_close_stdout(fw->fwr_file[id], true); + skygw_file_free(fw->fwr_file[id]); else skygw_file_close(fw->fwr_file[id], true); } @@ -2876,6 +2876,9 @@ static void* thr_filewriter_fun( } else if ((succp = logfile_open_file(fwr, lf))) { + if(use_stdout) + skygw_file_free (file); + else skygw_file_close(file, false); /*< close old file */ } diff --git a/utils/skygw_utils.cc b/utils/skygw_utils.cc index a2f37fc01..4ebcada2d 100644 --- a/utils/skygw_utils.cc +++ b/utils/skygw_utils.cc @@ -1882,24 +1882,37 @@ return_rc: return rc; } +skygw_file_t* skygw_file_alloc( + char* fname) +{ + skygw_file_t* file; + + if ((file = (skygw_file_t *)calloc(1, sizeof(skygw_file_t))) == NULL) + { + fprintf(stderr, + "* Error : Memory allocation for file %s failed.\n", + fname); + perror("SkyGW file allocation\n"); + return NULL; + } + ss_dassert(file != NULL); + file->sf_chk_top = CHK_NUM_FILE; + file->sf_chk_tail = CHK_NUM_FILE; + file->sf_fname = strdup(fname); + return file; +} + skygw_file_t* skygw_file_init( char* fname, char* symlinkname) { skygw_file_t* file; - if ((file = (skygw_file_t *)calloc(1, sizeof(skygw_file_t))) == NULL) + if ((file = skygw_file_alloc (fname)) == NULL) { - fprintf(stderr, - "* Error : Memory allocation for file %s failed.\n", - fname); - perror("SkyGW file allocation\n"); + /** Error was reported in skygw_file_alloc */ goto return_file; } - ss_dassert(file != NULL); - file->sf_chk_top = CHK_NUM_FILE; - file->sf_chk_tail = CHK_NUM_FILE; - file->sf_fname = strdup(fname); if ((file->sf_file = fopen(file->sf_fname, "a")) == NULL) { @@ -1963,58 +1976,10 @@ return_file: return file; } - -skygw_file_t* skygw_file_init_stdout( - char* fname, - char* symlinkname) +void skygw_file_free(skygw_file_t* file) { - skygw_file_t* file; - - if ((file = (skygw_file_t *)calloc(1, sizeof(skygw_file_t))) == NULL) - { - fprintf(stderr, - "* Error : Memory allocation for file %s failed.\n", - fname); - perror("SkyGW file allocation\n"); - goto return_file; - } - ss_dassert(file != NULL); - file->sf_chk_top = CHK_NUM_FILE; - file->sf_chk_tail = CHK_NUM_FILE; - file->sf_fname = strdup(fname); - file->sf_file = stdout; - CHK_FILE(file); - -return_file: - return file; -} - - -void skygw_file_close_stdout( - skygw_file_t* file, - bool shutdown) -{ - int fd; - int err; - - if (file != NULL) - { - CHK_FILE(file); - - if (!file_write_footer(file, shutdown)) - { - fprintf(stderr, - "* Writing footer to log file %s failed.\n", - file->sf_fname); - perror("Write fike footer\n"); - } - fd = fileno(file->sf_file); - fsync(fd); - - ss_dfprintf(stderr, "Closed %s\n", file->sf_fname); - free(file->sf_fname); - free(file); - } + free(file->sf_fname); + free(file); } void skygw_file_close( @@ -2037,7 +2002,7 @@ void skygw_file_close( } fd = fileno(file->sf_file); fsync(fd); - + if ((err = fclose(file->sf_file)) != 0) { fprintf(stderr, @@ -2049,8 +2014,7 @@ void skygw_file_close( else { ss_dfprintf(stderr, "Closed %s\n", file->sf_fname); - free(file->sf_fname); - free(file); + skygw_file_free (file); } } } diff --git a/utils/skygw_utils.h b/utils/skygw_utils.h index 9370c91cd..b2022cc54 100644 --- a/utils/skygw_utils.h +++ b/utils/skygw_utils.h @@ -216,10 +216,10 @@ EXTERN_C_BLOCK_END /** Skygw thread routines */ /** Skygw file routines */ +skygw_file_t* skygw_file_alloc(char* fname); +void skygw_file_free(skygw_file_t* file); skygw_file_t* skygw_file_init(char* fname, char* symlinkname); -skygw_file_t* skygw_file_init_stdout(char* fname, char* symlinkname); void skygw_file_close(skygw_file_t* file, bool shutdown); -void skygw_file_close_stdout(skygw_file_t*, bool); int skygw_file_write( skygw_file_t* file, void* data, From 6e4aa9862d76ed52627a5d7d1d176cd3c036c9c2 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Thu, 30 Apr 2015 04:52:35 +0300 Subject: [PATCH 037/275] Fixed a segfaul caused by a null pointer in dbfwfilter rule parsing. --- server/modules/filter/dbfwfilter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/modules/filter/dbfwfilter.c b/server/modules/filter/dbfwfilter.c index ccf2a2800..255eb6aba 100644 --- a/server/modules/filter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter.c @@ -1041,7 +1041,7 @@ bool parse_rule(char* rule, FW_INSTANCE* instance) ruledef->active = tr; - if(strcmp(tok,"on_queries") == 0) + if(tok && strcmp(tok,"on_queries") == 0) goto reparse_rule; } From 416ffea9b76fd45a4d643dcecd8da61d2f2326fb Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Thu, 30 Apr 2015 10:37:06 +0300 Subject: [PATCH 038/275] Changed errmsg.sys installation location to /var/lib/maxscale --- CMakeLists.txt | 2 +- server/include/gwdirs.h.in | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28b3229d8..33627ba15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,7 +153,7 @@ install(FILES ${CMAKE_BINARY_DIR}/ReleaseNotes.txt DESTINATION ${MAXSCALE_SHARED install(FILES ${CMAKE_BINARY_DIR}/UpgradingToMaxScale110.txt DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES server/maxscale_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES server/maxscale_binlogserver_template.cnf DESTINATION ${MAXSCALE_SHAREDIR}) -install(FILES ${ERRMSG} DESTINATION /usr/share/mysql/english/) +install(FILES ${ERRMSG} DESTINATION ${MAXSCALE_VARDIR}/lib/maxscale) install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION ${MAXSCALE_SHAREDIR}) install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${MAXSCALE_SHAREDIR}) diff --git a/server/include/gwdirs.h.in b/server/include/gwdirs.h.in index bd878bb59..ac8fcf4af 100644 --- a/server/include/gwdirs.h.in +++ b/server/include/gwdirs.h.in @@ -29,8 +29,7 @@ static const char* default_logdir = "/var/log/maxscale/"; static const char* default_datadir = "/var/cache/maxscale/"; static const char* default_libdir = "@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@"; static const char* default_cachedir = "/var/cache/maxscale/"; -static const char* default_langdir = "/usr/share/mysql/english/"; /*< This is where the MariaDB - * server installs errmsg.sys */ +static const char* default_langdir = "@MAXSCALE_VARDIR@/lib/maxscale/"; static char* configdir = NULL; static char* logdir = NULL; From 360db8b235924e134cb7108dc4f979f9b63139fb Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Thu, 30 Apr 2015 10:58:35 +0300 Subject: [PATCH 039/275] Changed all atoi calls to config_truth_value when they were used to generate boolean values. --- server/core/config.c | 14 +++++++------- server/modules/filter/qlafilter.c | 2 +- server/modules/filter/slavelag.c | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/server/core/config.c b/server/core/config.c index 390e3153c..764a606c8 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -1308,7 +1308,7 @@ int i; } else if (strcmp(name, "ms_timestamp") == 0) { - skygw_set_highp(atoi(value)); + skygw_set_highp(config_truth_value(value)); } else { @@ -1316,7 +1316,7 @@ int i; { if (strcasecmp(name, lognames[i].logname) == 0) { - if (atoi(value)) + if (config_truth_value(value)) skygw_log_enable(lognames[i].logfile); else skygw_log_disable(lognames[i].logfile); @@ -1495,10 +1495,10 @@ SERVER *server; user, auth); if (enable_root_user) - serviceEnableRootUser(service, atoi(enable_root_user)); + serviceEnableRootUser(service, config_truth_value(enable_root_user)); if (connection_timeout) - serviceSetTimeout(service, atoi(connection_timeout)); + serviceSetTimeout(service, config_truth_value(connection_timeout)); if(auth_all_servers) @@ -1511,7 +1511,7 @@ SERVER *server; if (allow_localhost_match_wildcard_host) serviceEnableLocalhostMatchWildcardHost( service, - atoi(allow_localhost_match_wildcard_host)); + config_truth_value(allow_localhost_match_wildcard_host)); /** Read, validate and set max_slave_connections */ max_slave_conn_str = @@ -1651,7 +1651,7 @@ SERVER *server; user, auth); if (enable_root_user) - serviceEnableRootUser(obj->element, atoi(enable_root_user)); + serviceEnableRootUser(obj->element, config_truth_value(enable_root_user)); if (connection_timeout) serviceSetTimeout(obj->element, atoi(connection_timeout)); @@ -1659,7 +1659,7 @@ SERVER *server; if (allow_localhost_match_wildcard_host) serviceEnableLocalhostMatchWildcardHost( obj->element, - atoi(allow_localhost_match_wildcard_host)); + config_truth_value(allow_localhost_match_wildcard_host)); } } } diff --git a/server/modules/filter/qlafilter.c b/server/modules/filter/qlafilter.c index c9af0a839..5362cf61e 100644 --- a/server/modules/filter/qlafilter.c +++ b/server/modules/filter/qlafilter.c @@ -95,7 +95,7 @@ static FILTER_OBJECT MyObject = { * are logged. * * To this base a session number is attached such that each session will - * have a nique name. + * have a unique name. */ typedef struct { int sessions; /* The count of sessions */ diff --git a/server/modules/filter/slavelag.c b/server/modules/filter/slavelag.c index c12d7a2a7..eb6b9536d 100644 --- a/server/modules/filter/slavelag.c +++ b/server/modules/filter/slavelag.c @@ -41,10 +41,10 @@ extern __thread log_info_t tls_log_info; * Two optional parameters that define the behavior after a data modifying query * is executed: * - * count= Queries to route to master after data modification. - * time=