resolving conflicts

This commit is contained in:
Timofey Turenko
2015-01-09 10:34:56 +02:00
331 changed files with 27407 additions and 4897 deletions

1
.gitignore vendored
View File

@ -30,6 +30,7 @@ depend.mk
*~ *~
*# *#
.#* .#*
._*
# Vi swap files # Vi swap files
.*.swp .*.swp

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
message(STATUS "CMake version: ${CMAKE_VERSION}")
include(macros.cmake) include(macros.cmake)
enable_testing() enable_testing()
@ -8,25 +8,43 @@ set_maxscale_version()
set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR}" CACHE INTERNAL "Prefix prepended to install directories." FORCE) set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR}" CACHE INTERNAL "Prefix prepended to install directories." FORCE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/")
project(MaxScale) project(MaxScale)
check_deps() check_deps()
check_dirs() check_dirs()
find_package(Valgrind)
find_package(MySQLClient)
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/modules) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/modules)
configure_file(${CMAKE_SOURCE_DIR}/server/include/version.h.in ${CMAKE_SOURCE_DIR}/server/include/version.h) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/server/include)
configure_file(${CMAKE_SOURCE_DIR}/maxscale.conf.in ${CMAKE_SOURCE_DIR}/maxscale.conf.prep @ONLY) configure_file(${CMAKE_SOURCE_DIR}/server/include/version.h.in ${CMAKE_BINARY_DIR}/server/include/version.h)
configure_file(${CMAKE_SOURCE_DIR}/etc/init.d/maxscale.in ${CMAKE_SOURCE_DIR}/etc/init.d/maxscale.prep @ONLY) configure_file(${CMAKE_SOURCE_DIR}/maxscale.conf.in ${CMAKE_BINARY_DIR}/maxscale.conf.prep @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale.in ${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale.prep @ONLY) configure_file(${CMAKE_SOURCE_DIR}/etc/init.d/maxscale.in ${CMAKE_BINARY_DIR}/etc/init.d/maxscale.prep @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale.in ${CMAKE_BINARY_DIR}/etc/ubuntu/init.d/maxscale.prep @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.h.in ${CMAKE_BINARY_DIR}/server/include/maxscale_test.h)
set(CMAKE_C_FLAGS "-Wall -fPIC") set(CMAKE_C_FLAGS "-Wall -fPIC")
set(CMAKE_CXX_FLAGS "-Wall -fPIC") set(CMAKE_CXX_FLAGS "-Wall -fPIC")
set(DEBUG_FLAGS "-ggdb -pthread -pipe -Wformat -fstack-protector --param=ssp-buffer-size=4")
if(BUILD_TYPE MATCHES Debug) if((CMAKE_C_COMPILER_ID STREQUAL "GNU") AND (NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.2)))
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -pthread -pipe -DSS_DEBUG -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4") message(STATUS "C Compiler supports: -Werror=format-security")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -pthread -pipe -DSS_DEBUG -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4") set(DEBUG_FLAGS "${DEBUG_FLAGS} -Werror=format-security")
endif()
if(BUILD_TYPE STREQUAL Debug)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DEBUG_FLAGS} -DSS_DEBUG")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DEBUG_FLAGS} -DSS_DEBUG")
message(STATUS "Generating debugging symbols and enabling debugging code")
elseif(BUILD_TYPE STREQUAL DebugSymbols)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DEBUG_FLAGS}")
message(STATUS "Generating debugging symbols") message(STATUS "Generating debugging symbols")
elseif(BUILD_TYPE MATCHES Optimized) elseif(BUILD_TYPE MATCHES Optimized)
if(NOT (DEFINED OLEVEL)) if(NOT (DEFINED OLEVEL))
@ -54,6 +72,10 @@ if(GCOV)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov")
endif() endif()
if(FAKE_CODE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFAKE_CODE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFAKE_CODE")
endif()
subdirs(MYSQL_DIR_ALL ${MYSQL_DIR}) subdirs(MYSQL_DIR_ALL ${MYSQL_DIR})
foreach(DIR ${MYSQL_DIR_ALL}) foreach(DIR ${MYSQL_DIR_ALL})
@ -67,22 +89,26 @@ include_directories(query_classifier)
include_directories(server/include) include_directories(server/include)
include_directories(server/inih) include_directories(server/inih)
include_directories(server/modules/include) include_directories(server/modules/include)
include_directories(${CMAKE_BINARY_DIR}/server/include)
add_subdirectory(utils) add_subdirectory(utils)
add_subdirectory(log_manager) add_subdirectory(log_manager)
add_subdirectory(query_classifier) add_subdirectory(query_classifier)
add_subdirectory(server) add_subdirectory(server)
add_subdirectory(client) add_subdirectory(client)
if(BUILD_RABBITMQ)
find_package(RabbitMQ)
add_subdirectory(rabbitmq_consumer)
endif()
# Install startup scripts and ldconfig files # Install startup scripts and ldconfig files
if( NOT ( (DEFINED INSTALL_SYSTEM_FILES) AND ( NOT ( INSTALL_SYSTEM_FILES ) ) ) ) if( NOT ( (DEFINED INSTALL_SYSTEM_FILES) AND ( NOT ( INSTALL_SYSTEM_FILES ) ) ) )
install(FILES maxscale.conf.prep RENAME maxscale.conf DESTINATION /etc/ld.so.conf.d/ PERMISSIONS WORLD_EXECUTE WORLD_READ) install(FILES ${CMAKE_BINARY_DIR}/maxscale.conf.prep RENAME maxscale.conf DESTINATION /etc/ld.so.conf.d/ PERMISSIONS WORLD_EXECUTE WORLD_READ)
if(DEB_BASED) if(DEB_BASED)
install(FILES etc/ubuntu/init.d/maxscale.prep RENAME maxscale DESTINATION /etc/init.d/ PERMISSIONS WORLD_EXECUTE) install(FILES ${CMAKE_BINARY_DIR}/etc/ubuntu/init.d/maxscale.prep RENAME maxscale DESTINATION /etc/init.d/ PERMISSIONS WORLD_EXECUTE)
else() else()
install(FILES etc/init.d/maxscale.prep RENAME maxscale DESTINATION /etc/init.d/ PERMISSIONS WORLD_EXECUTE) install(FILES ${CMAKE_BINARY_DIR}/etc/init.d/maxscale.prep RENAME maxscale DESTINATION /etc/init.d/ PERMISSIONS WORLD_EXECUTE)
endif() endif()
message(STATUS "Installing maxscale.conf to: /etc/ld.so.conf.d") message(STATUS "Installing maxscale.conf to: /etc/ld.so.conf.d")
message(STATUS "Installing startup scripts to: /etc/init.d") message(STATUS "Installing startup scripts to: /etc/init.d")
@ -94,48 +120,102 @@ message(STATUS "Installing MaxScale to: ${CMAKE_INSTALL_PREFIX}/")
install(FILES server/MaxScale_template.cnf DESTINATION etc) install(FILES server/MaxScale_template.cnf DESTINATION etc)
install(FILES ${ERRMSG} DESTINATION mysql) install(FILES ${ERRMSG} DESTINATION mysql)
install(FILES ${DOCS} DESTINATION Documentation) install(FILES ${DOCS} DESTINATION Documentation)
install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION ${CMAKE_INSTALL_PREFIX}/)
install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION ${CMAKE_INSTALL_PREFIX}/)
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/)
install(FILES ${CMAKE_SOURCE_DIR}/SETUP DESTINATION ${CMAKE_INSTALL_PREFIX}/)
install(DIRECTORY DESTINATION log)
# See if we are on a RPM-capable or DEB-capable system if(${CMAKE_VERSION} VERSION_LESS 2.8.12)
find_program(RPMBUILD rpmbuild) message(WARNING "CMake version is ${CMAKE_VERSION}. Building of packages requires version 2.8.12 or greater.")
find_program(DEBBUILD dpkg-buildpackage) else()
# See if we are on a RPM-capable or DEB-capable system
if(NOT ( ${RPMBUILD} STREQUAL "RPMBUILD-NOTFOUND" ) ) find_program(RPMBUILD rpmbuild)
find_program(DEBBUILD dpkg-buildpackage)
set(CPACK_GENERATOR "TGZ")
if(NOT ( ${RPMBUILD} STREQUAL "RPMBUILD-NOTFOUND" ) )
message(STATUS "Generating RPM packages") message(STATUS "Generating RPM packages")
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM") set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
endif() endif()
if(NOT ( ${DEBBUILD} STREQUAL "DEBBUILD-NOTFOUND" ) ) if(NOT ( ${DEBBUILD} STREQUAL "DEBBUILD-NOTFOUND" ) )
set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB") set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB")
execute_process(COMMAND dpgk --print-architecture OUTPUT_VARIABLE DEB_ARCHITECTURE) execute_process(COMMAND dpgk --print-architecture OUTPUT_VARIABLE DEB_ARCHITECTURE)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEB_ARCHITECTURE}) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEB_ARCHITECTURE})
set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
message(STATUS "Generating DEB packages for ${DEB_ARCHITECTURE}") message(STATUS "Generating DEB packages for ${DEB_ARCHITECTURE}")
endif()
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}/README)
set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
set(CPACK_RPM_SPEC_INSTALL_POST "/sbin/ldconfig")
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")
include(CPack)
endif() endif()
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MaxScale")
set(CPACK_PACKAGE_VERSION_MAJOR "${MAXSCALE_VERSION_MAJOR}") add_custom_target(buildtests
set(CPACK_PACKAGE_VERSION_MINOR "${MAXSCALE_VERSION_MINOR}") COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DBUILD_TYPE=Debug -DINSTALL_DIR=${CMAKE_BINARY_DIR} -DINSTALL_SYSTEM_FILES=N ${CMAKE_SOURCE_DIR}
set(CPACK_PACKAGE_VERSION_PATCH "${MAXSCALE_VERSION_PATCH}") COMMAND make
set(CPACK_PACKAGE_CONTACT "SkySQL Ab") COMMENT "Building test suite..." VERBATIM
set(CPACK_PACKAGE_FILE_NAME "maxscale-${MAXSCALE_VERSION}") )
set(CPACK_PACKAGE_NAME "maxscale")
set(CPACK_PACKAGE_VENDOR "SkySQL Ab")
set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_SOURCE_DIR}/README)
set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
set(CPACK_RPM_SPEC_INSTALL_POST "/sbin/ldconfig")
set(CPACK_RPM_PACKAGE_NAME "maxscale")
set(CPACK_RPM_PACKAGE_VENDOR "SkySQL Ab")
set(CPACK_RPM_PACKAGE_LICENSE "GPLv2")
set(CPACK_RPM_PACKAGE_AUTOREQPROV " no")
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")
include(CPack)
add_custom_target(testall add_custom_target(testall
COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DBUILD_TYPE=Debug -DINSTALL_DIR=${CMAKE_BINARY_DIR} -DINSTALL_SYSTEM_FILES=N ${CMAKE_SOURCE_DIR} COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DBUILD_TYPE=Debug -DINSTALL_DIR=${CMAKE_BINARY_DIR} -DINSTALL_SYSTEM_FILES=N ${CMAKE_SOURCE_DIR}
COMMAND make install 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 /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null" COMMAND /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null"
COMMAND make test COMMAND /bin/sh -c "make test || echo \"Test results written to: ${CMAKE_BINARY_DIR}/Testing/Temporary/\""
COMMAND /bin/sh -c "killall -KILL maxscale" COMMAND killall maxscale
COMMENT "Running full test suite") COMMENT "Running full test suite..." VERBATIM)
# uninstall target
# see http://www.cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/doxygate.in"
"${CMAKE_CURRENT_BINARY_DIR}/doxygate"
IMMEDIATE @ONLY)
add_custom_target(documentation
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygate)
endif()
# Testall target with Valgrind
if(VALGRIND_FOUND)
add_custom_target(testall-valgrind
COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DBUILD_TYPE=Debug -DINSTALL_DIR=${CMAKE_BINARY_DIR} -DINSTALL_SYSTEM_FILES=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 /bin/sh -c "valgrind --track-fds=yes --leak-check=full --show-leak-kinds=all --log-file=${CMAKE_BINARY_DIR}/valgrind.log ${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null"
COMMAND /bin/sh -c "make test || echo \"Test results written to: ${CMAKE_BINARY_DIR}/Testing/Temporary/\""
COMMAND killall maxscale
COMMENT "Running full test suite with Valgrind..." VERBATIM)
endif()

View File

@ -1,4 +1,4 @@
This source code is distributed as part of SkySQL MaxScale. It is free This source code is distributed as part of MariaDB Corporation MaxScale. It is free
software: you can redistribute it and/or modify it under the terms of the 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, GNU General Public License as published by the Free Software Foundation,
version 2. version 2.
@ -12,9 +12,9 @@ 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 this program; if not, write to the Free Software Foundation, Inc., 51
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Copyright SkySQL Ab 2013 Copyright MariaDB Corporation Ab 2013
SkySQL Corporation Ab MariaDB Corporation Corporation Ab
Tekniikantie 12 Tekniikantie 12
02150 Espoo 02150 Espoo
Finland Finland

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,999 @@
MaxScale
Configuration & Usage Scenarios
Mark Riddoch
Last Updated: 2nd July 2014
== Contents
Contents
Document History
Introduction
Terms
Configuration
Global Settings
Threads
Service
Router
Filters
Servers
User
Passwd
weightby
Server
Address
Port
Protocol
Monitoruser
MonitorPw
Listener
Service
Protocol
Address
Port
Filter
Module
Options
Other Parameters
Monitor
Module
Servers
User
Passwd
Protocol Modules
MySQLClient
MySQLBackend
Telnetd
maxscaled
HTTPD
Router Modules
Connection Based Routing
Statement Based Routing
Available Routing Modules
Readconnroute
Master/Slave Replication Setup
Galera Cluster Configuration
Readwritesplit
Master/Slave Replication Setup
Debugcli
Debug CLI Configuration
CLI
CLI Configuration
Monitor Modules
Mysqlmon
Galeramon
Filter Modules
Statement Counting Filter
Query Log All Filter
Regular Expression Filter
Tee Filter
Encrypting Passwords
Creating Encrypted Passwords
Configuration Updates
Limitations
Authentication
Wildcard Hosts
Limitations
Error Reporting
==
==
== Document History
|===
|*Date*|*Change*|*Who*
|21st July 2013|Initial version|Mark Riddoch
|23rd July 2013|Addition of default user and password for a monitor and discussion of monitor user requirements|Mark Riddoch
|13th November 2013|state for Galera Monitor is “synced”|Massimiliano Pinto
|2nd December 2013|Updated the description of the command line arguments to match the code updates.|Mark Riddoch
|6th February 2014|Added “enable_root_user” as a service parameter|Massimiliano Pinto
|7th February 2014|Addition of bind address information|Mark Riddoch
|3rd March 2014|MySQL authentication with hostnames|Massimiliano Pinto
|3rd March 2014|Addition of section that describes authentication requirements and the rules for creating user credentials|Mark Riddoch
|28th March 2014|Unix socket support|Massimiliano Pinto
|8th May 2014|Added “version_string” parameter in service|Massimiliano Pinto
|29th May 2014|Added troubleshooting section|Massimiliano Pinto
|2nd June 2014|Correction of some typos, clarification of the meaning of session modification statements and the default user for the CLI.|Mark Riddoch
|4th June 2014|Addition of “monitor_interval” for monitors|Massimiliano Pinto
|6th June 2014|Addition of filters sections|Mark Riddoch
|27th June 2014|Addition of server weighting, the configuration for the maxadmin client|Mark Riddoch
|2nd July 2014|Addition of new readwritesplit router options with description and examples.|Vilho Raatikka
|===
==
== Introduction
The purpose of this document is to describe how to configure MaxScale and to discuss some possible usage scenarios for MaxScale. MaxScale is designed with flexibility in mind, and consists of an event processing core with various support functions and plugin modules that tailor the behaviour of the MaxScale itself.
=== Terms
|===
|*Term*|*Description*
|service|A service represents a set of databases with a specific access mechanism that is offered to clients of MaxScale. The access mechanism defines the algorithm that MaxScale will use to direct particular requests to the individual databases.
|server|A server represents an individual database server to which a client can be connected via MaxScale.
|router|A router is a module within MaxScale that will route client requests to the various database servers which MaxScale provides a service interface to.
|connection routing|Connection routing is a method of handling requests in which MaxScale will accept connections from a client and route data on that connection to a single database using a single connection. Connection based routing will not examine individual quests on a connection and it will not move that connection once it is established.
|statement routing|Statement routing is a method of handling requests in which each request within a connection will be handled individually. Requests may be sent to one or more servers and connections may be dynamically added or removed from the session.
|protocol|A protocol is a module of software that is used to communicate with another software entity within the system. MaxScale supports the dynamic loading of protocol modules to allow for increased flexibility.
|module|A module is a separate code entity that may be loaded dynamically into MaxScale to increase the available functionality. Modules are implemented as run-time loadable shared objects.
|monitor|A monitor is a module that can be executed within MaxScale to monitor the state of a set of database. The use of an internal monitor is optional, monitoring may be performed externally to MaxScale.
|listener|A listener is the network endpoint that is used to listen for connections to MaxScale from the client applications. A listener is associated to a single service, however a service may have many listeners.
|connection failover|When a connection currently being used between MaxScale and the database server fails a replacement will be automatically created to another server by MaxScale without client intervention
|backend database|A term used to refer to a database that sits behind MaxScale and is accessed by applications via MaxScale.
|filter|A module that can be placed between the client and the MaxScale router module. All client data passes through the filter module and may be examined or modified by the filter modules.
|===
==
==
== Configuration
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.
. 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
. 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.
An explicit path to a configuration file can be passed by using the -f option to MaxScale.
The configuration file itself is based on the “ini” file format and consists of various sections that are used to build the configuration, these sections define services, servers, listeners, monitors and global settings.
=== Global Settings
The global settings, in a section named [MaxScale], allow various parameters that affect MaxScale as a whole to be tuned. Currently the only setting that is supported is the number of threads to use to handle the network traffic. MaxScale will also accept the section name of [gateway] for global settings. This is for backward compatibility with versions prior to the naming of MaxScale.
==== Threads
To control the number of threads that poll for network traffic set the parameter threads to a number. It is recommended that you start with a single thread and add more as you find the performance is not satisfactory. MaxScale is implemented to be very thread efficient, so a small number of threads is usually adequate to support reasonably heavy workloads. Adding more threads may not improve performance and can consume resources needlessly.
----
# Valid options are:
# threads=<number of epoll threads>
[MaxScale]
threads=1
----
It should be noted that additional threads will be created to execute other internal services within MaxScale, this setting is merely used to configure the number of threads that will be used to manage the user connections.
=== Service
A service represents the database service that MaxScale offers to the clients. In general a service consists of a set of backend database servers and a routing algorithm that determines how MaxScale decides to send statements or route connections to those backend servers.
A service may be considered as a virtual database server that MaxScale makes available to its clients.
Several different services may be defined using the same set of backend servers. For example a connection based routing service might be used by clients that already performed internal read/write splitting, whilst a different statement based router may be used by clients that are not written with this functionality in place. Both sets of applications could access the same data in the same databases.
A service is identified by a service name, which is the name of the configuration file section and a type parameter of service
----
[Test Service]
type=service
----
In order for MaxScale to forward any requests it must have at least one service defined within the configuration file. The definition of a service alone is not enough to allow MaxScale to forward requests however, the service is merely present to link together the other configuration elements.
==== Router
The router parameter of a service defines the name of the router module that will be used to implement the routing algorithm between the client of MaxScale and the backend databases. Additionally routers may also be passed a comma separated list of options that are used to control the behaviour of the routing algorithm. The two parameters that control the routing choice are router and router_options. The router options are specific to a particular router and are used to modify the behaviour of the router. The read connection router can be passed options of master, slave or synced, an example of configuring a service to use this router and limiting the choice of servers to those in slave state would be as follows.
----
router=readconnroute
router_options=slave
----
To change the router to connect on to servers in the master state as well as slave servers, the router options can be modified to include the master state.
----
router=readconnroute
router_options=master,slave
----
A more complete description of router options and what is available for a given router is included with the documentation of the router itself.
==== Filters
The filters option allow a set of filters to be defined for a service; requests from the client are passed through these filters before being sent to the router for dispatch to the backend server. The filters parameter takes one or more filter names, as defined within the filter definition section of the configuration file. Multiple filters are separated using the | character.
+filters=counter | QLA+
The requests pass through the filters from left to right in the order defined in the configuration parameter.
==== Servers
The servers parameter in a service definition provides a comma separated list of the backend servers that comprise the service. The server names are those used in the name section of a block with a type parameter of server (see below).
+servers=server1,server2,server3+
==== User
The user parameter, along with the passwd parameter are used to define the credentials used to connect to the backend servers to extract the list of database users from the backend database that is used for the client authentication.
----
user=maxscale
passwd=Mhu87p2D
----
Authentication of incoming connections is performed by MaxScale itself rather than by the database server to which the client is connected. The client will authenticate itself with MaxScale, using the username, hostname and password information that MaxScale has extracted from the backend database servers. For a detailed discussion of how this impacts the authentication process please see the “Authentication” section below.
The host matching criteria is restricted to IPv4, IPv6 will be added in a future release.
Existing user configuration in the backend databases must be checked and may be updated before successful MaxScale authentication:
In order for MaxScale to obtain all the data it must be given a username it can use to connect to the database and retrieve that data. This is the parameter that gives MaxScale the username to use for this purpose.
The account used must be able to select from the mysql.user table, the following is an example showing how to create this user.
----
MariaDB [mysql]> create user 'maxscale'@'maxscalehost' identified by 'Mhu87p2D';
Query OK, 0 rows affected (0.01 sec)
MariaDB [mysql]> grant SELECT on mysql.user to 'maxscale'@'maxscalehost';
----
Query OK, 0 rows affected (0.00 sec)
==== Passwd
The auth parameter provides the password information for the above user and may be either a plain text password or it may be an encrypted password. See the section on encrypting passwords for use in the MaxScale.cnf file. This user must be capable of connecting to the backend database and executing the SQL statement “SELECT user, host, password FROM mysql.user”.
*enable_root_user* +
This parameter controls the ability of the root user to connect to MaxScale and hence onwards to the backend servers via MaxScale.
The default value is 0, disabling the ability of the root user to connect to MaxScale.
Example for enabling root user: +
enable_root_user=1
Values of “on” or “true” may also be given to enable the root user and “off” or “false” may be given to disable the use of the root user. +
+enable_root_user=true+
*version_string* +
This parameter sets a custom version string that is sent in the MySQL Handshake from MaxScale to clients.
Example: +
version_string=5.5.37-MariaDB-RWsplit
If not set, the default value is the server version of the embedded MySQL/MariaDB library. Example: 5.5.35-MariaDB
==== weightby
The weightby parameter is used in conjunction with server parameters in order to control the load balancing applied in the router in use by the service. This allows varying weights to be applied to each server to create a non-uniform distribution of the load amongst the servers.
An example of this might be to define a parameter for each server that represents the amount of resource available on the server, we could call this serversize. Every server should then have a serversize parameter set for the server.
+serversize=10+
The service would then have the parameter weightby set. If there are 4 servers defined in the service, serverA, serverB, serverC and serverD, with the serversize set as shown in the table below, the connections would balanced using the percentages in this table.
|===
|Server|serversize|% connections
|serverA|10|18%
|serverB|15|27%
|serverC|10|18%
|serverD|20|36%
|===
=== Server
Server sections are used to define the backend database servers that can be formed into a service. A server may be a member of one or more services within MaxScale. Servers are identified by a server name which is the section name in the configuration file. Servers have a type parameter of server, plus address port and protocol parameters.
----
[server1]
type=server
address=127.0.0.1
port=3000
protocol=MySQLBackend
----
==== Address
The IP address or hostname of the machine running the database server that is being defined. MaxScale will use this address to connect to the backend database server.
==== Port
The port on which the database listens for incoming connections. MaxScale will use this port to connect to the database server.
==== Protocol
The name for the protocol module to use to connect MaxScale to the database. Currently only one backend protocol is supported, the MySQLBackend module.
==== Monitoruser
The monitor has a username and password that is used to connect to all servers for monitoring purposes, this may be overridden by supplying a monitoruser statement for each individual server
+monitoruser=mymonitoruser+
==== MonitorPw
The monitor has a username and password that is used to connect to all servers for monitoring purposes, this may be overridden by supplying a monpasswd statement for the individual servers
----
monitorpw=mymonitorpasswd
----
The monpasswd parameter may be either a plain text password or it may be an encrypted password. See the section on encrypting passwords for use in the MaxScale.cnf file.
=== Listener
The listener defines a port and protocol pair that is used to listen for connections to a service. A service may have multiple listeners associated with it, either to support multiple protocols or multiple ports. As with other elements of the configuration the section name is the listener name and a type parameter is used to identify the section as a listener definition.
----
[Test Listener]
type=listener
service=Test Service
protocol=MySQLClient
address=localhost
port=4008
socket=/tmp/testlistener.sock
----
==== Service
The service to which the listener is associated. This is the name of a service that is defined elsewhere in the configuration file.
==== Protocol
The name of the protocol module that is used for the communication between the client and MaxScale itself.
==== Address
The address option sets the address that will be used to bind the listening socket. The address may be specified as an IP address in ‘dot notation’ or as a hostname. If the address option is not included in the listener definition the listener will bind to all network interfaces.
==== Port
The port to use to listen for incoming connections to MaxScale from the clients. If the port is omitted from the configuration a default port for the protocol will be used.
*Socket* +
The socket option may be included in a listener definition, this configures the listener to use Unix domain sockets to listen for incoming connections. The parameter value given is the name of the socket to use.
If a socket option and an address option is given then the listener will listen on both the specific IP address and the Unix socket.
=== Filter
Filters provide a means to manipulate or process requests as they pass through MaxScale between the client side protocol and the query router. A filter should be defined in a section with a type of filter.
----
[QLA]
type=filter
module=qlafilter
options=/tmp/QueryLog
----
The section name may then be used in one or more services by using the filters= parameter in the service section. In order to use the above filter for a service called “QLA Service”, an entry of the following form would exist for that service.
----
[QLA Service]
type=service
router=readconnroute
router_options=slave
servers=server1,server2,server3,server4
user=massi
passwd=6628C50E07CCE1F0392EDEEB9D1203F3
filters=QLA
----
See the Services section for more details on how to configure the various options of a service.
==== Module
The module parameter defines the name of the loadable module that implements the filter.
==== Options
The options parameter is used to pass options to the filter to control the actions the filter will perform. The values that can be passed differ between filter implementation, the inclusion of an options parameter is optional.
==== Other Parameters
Any other parameters present in the filters section will be passed to the filter to be interpreted by the filter. An example of this is the regexfilter that requires the two parameters match and replace
----
[regex]
type=filter
module=regexfilter
match=form
replace=from
----
=== Monitor
In order for the various router modules to function correctly they require information about the state of the servers that are part of the service they provide. MaxScale has the ability to internally monitor the state of the back-end database servers or that state may be feed into MaxScale from external monitoring systems. If automated monitoring and failover of services is required this is achieved by running a monitor module that is designed for the particular database architecture that is in use.
Monitors are defined in much the same way as other elements in the configuration file, with the section name being the name of the monitor instance and the type being set to monitor.
----
[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2,server3
user=dbmonitoruser
passwd=dbmonitorpwd
monitor_interval=8000
----
==== Module
The module parameter defines the name of the loadable module that implements the monitor. This module is loaded and executed on a separate thread within MaxScale.
==== Servers
The servers parameter is a comma separated list of server names to monitor, these are the names defined elsewhere in the configuration file. The set of servers monitored by a single monitor need not be the same as the set of servers used within any particular server, a single monitor instance may monitor servers in multiple servers.
==== User
The user parameter defines the username that the monitor will use to connect to the monitored databases. Depending on the monitoring module used this user will require specific privileges in order to determine the state of the nodes, details of those privileges can be found in the sections on each of the monitor modules.
Individual servers may define override values for the user and password the monitor uses by setting the monuser and monpasswd parameters in the server section.
==== Passwd
The password parameter may be either a plain text password or it may be an encrypted password. See the section on encrypting passwords for use in the MaxScale.cnf file.
*Monitor_interval* +
The monitor_interval parameter sets the sampling interval in milliseconds for each monitor, the default value is 10000 milliseconds.
==
==
== 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/module, if the environment variable $MAXSCALE_HOME is not set it defaults to /usr/local/skysql/MaxScale. It may also be set by passing the -c option on the MaxScale command line.
=== MySQLClient
This is the implementation of the MySQL protocol that is used by clients of MaxScale to connect to MaxScale.
=== MySQLBackend
The MySQLBackend protocol module is the implementation of the protocol that MaxScale uses to connect to the backend MySQL, MariaDB and Percona Server databases. This implementation is tailored for the MaxScale to MySQL Database traffic and is not a general purpose implementation of the MySQL protocol.
=== Telnetd
The telnetd protocol module is used for connections to MaxScale itself for the purposes of creating interactive user sessions with the MaxScale instance itself. Currently this is used in conjunction with a special router implementation, the debugcli.
=== maxscaled
The protocol used used by the maxadmin client application in order to connect to MaxScale and access the command line interface.
=== HTTPD
This protocol module is currently still under development, it provides a means to create HTTP connections to MaxScale for use by web browsers or RESTful API clients.
==
==
== Router Modules
The main task of MaxScale is to accept database connections from client applications and route the connections or the statements sent over those connections to the various services supported by MaxScale.
There are two flavours of routing that MaxScale can perform, connection based routing and statement based routine. These each have their own characteristics and costs associated with them.
=== Connection Based Routing
Connection based routing is a mechanism by which MaxScale will, for each incoming connection decide on an appropriate outbound server and will forward all statements to that server without examining the internals of the statement. Once an inbound connection is associated to a particular backend database it will remain connected to that server until the connection is closed or the server fails.
=== Statement Based Routing
Statement based routing is somewhat different, the routing modules examine every statement the client sends and determines, on a per statement basis, which of the set of backend servers in the service is best to execute the statement. This gives better dynamic balancing of the load within the cluster but comes at a cost. The query router must understand the statement that is being routing and will typically need to parse the statement in order to achieve this. This parsing within the router adds a significant overhead to the cost of routing and makes this type of router only really suitable for loads in which the gains outweigh this added cost.
=== Available Routing Modules
Currently a small number of query routers are available, these are in different stages of completion and offer different facilities.
==== Readconnroute
This is a statement based query router that was originally targeted at environments in which the clients already performed splitting of read and write queries into separate connections.
Whenever a new connection is received the router will examine the state of all the servers that form part of the service and route the connection to the server with least connections currently that matches the filter constraints given in the router options. This results in a balancing of the active connections, however different connections may have different lifetimes and the connections may become unbalanced when later viewed.
The readconnroute router can be configured to balance the connections from the clients across all the backend servers that are running, just those backend servers that are currently replication slaves or those that are replication masters when routing to a master slave replication environment. When a Galera cluster environment is in use the servers can be filtered to just the set that are part of the cluster and in the ‘synced’ state. These options are configurable via the router_options that can be set within a service. The router_option strings supported are “master”, “slave” and “synced”.
===== Master/Slave Replication Setup
To setup MaxScale to route connections evenly between all the current slave servers in a replication cluster, a service entry of the form shown below is required.
----
[Read Service]
type=service
router=readconnroute
router_options=slave
servers=server1,server2,server3,server4
user=maxscale
auth=thepasswd
----
With the addition of a listener for this service, which defines the port and protocol that MaxScale uses +
----
[Read Listener]
type=listener
service=Read Service
protocol=MySQLClient
port=4006
----
the client can now connect to port 4006 on the host which is running MaxScale. Statements sent using this connection will then be routed to one of the slaves in the server set defined in the Read Service. Exactly which is selected will be determined by balancing the number of connections to each of those whose current state is “slave”.
Altering the router options to be slave, master would result in the connections being balanced between all the servers within the cluster.
It is assumed that the client will have a separate connection to the master server, however this can be routed via MaxScale, allowing MaxScale to manage the determination of which server is master. To do this you would add a second service and listener definition for the master server.
----
[Write Service]
type=service
router=readconnroute
router_options=master
servers=server1,server2,server3,server4
user=maxscale
auth=thepasswd
[Write Listener]
type=listener
service=Write Service
protocol=MySQLClient
port=4007
----
This allows the clients to direct write requests to port 4007 and read requests to port 4006 of the MaxScale host without the clients needing to understand the configuration of the Master/Slave replication cluster.
Connections to port 4007 would automatically be directed to the server that is the master for replication at the time connection is opened. Whilst this is a simple mapping to a single server it does give the advantage that the clients have no requirement to track which server is currently the master, devolving responsibility for managing the failover to MaxScale.
In order for MaxScale to be able to determine the state of these servers the mysqlmon monitor module should be run against the set of servers that comprise the service.
===== Galera Cluster Configuration
Although not primarily designed for a multi-master replication setup, it is possible to use the readconnroute in this situation. The readconnroute connection router can be used to balance the connections across a Galera cluster. A special monitor is available that detects if nodes are joined to a Galera Cluster, with the addition of a router option to only route connections to nodes marked as synced. MaxScale can ensure that users are never connected to a node that is not a full cluster member.
----
[Galera Service]
type=service
router=readconnroute
router_options=synced
servers=server1,server2,server3,server4
user=maxscale
auth=thepasswd
[Galera Listener]
type=listener
service=Galera Service
protocol=MySQLClient
port=3336
----
----
[Galera Monitor]
type=monitor
module=galeramon
servers=server1,server2,server3,server4
user=galeramon
passwd=galeramon
----
The specialized Galera monitor can also select one of the node in the cluster as master, the others will be marked as slave. +
These roles are only assigned to synced nodes.
It then possible to have services/listeners with router_options=master or slave accessing a subset of all galera nodes. +
The “synced” simply means: access all nodes.
Examples:
----
[Galera Master Service]
type=service
router=readconnroute
router_options=master
[Galera Slave Service]
type=service
router=readconnroute
router_options=slave
----
The Master and Slave roles are also available for the Read/Write Split router operation
==== Readwritesplit
The readwritesplit is a statement based router that has been designed for use within Master/Slave replication environments. It examines every statement, parsing it to determine if the statement falls into one of three categories;
* read only statement
* possible write statement
session modification statement
Each of these three categories has a different action associated with it. Read only statements are sent to a slave server in the replication cluster. Possible write statements, which may include read statements that have an undeterminable side effect, are sent to the current replication master. Statements that modify the session are sent to all the servers, with the result that is generated by the master server being returned to the user.
Session modification statements must be replicated as they affect the future results of read and write operations, so they must be executed on all servers that could execute statements on behalf of this client.
Currently the readwritesplit router module is under development and has the following limitations:
* Connection failover support has not yet been implemented. Client connections will fail if the master server fails over.
===== Master/Slave Replication Setup
To setup the readwritesplit connection router in a master/slave failover environment is extremely simple, a service definition is required with the router defined for the service and an associated listener. +
The router_options parameter is not required but it can be used to specify how slave(s) are selected. Available option is slave_selection_criteria and possible value are LEAST_BEHIND_MASTER and LEAST_CURRENT_OPERATIONS. +
max_slave_connections is a readwritesplit-only option, which sets the upper limit for the number of slaves a router session can use. max_slave_replication_lag is (currently) another readwritesplit-specific option, which sets maximum allowed lag for slave in seconds. The criteria is checked when router chooses slaves and only slaves having smaller lag are eligible for selection. The lag is not checked after connection phase.
----
[Split Service]
type=service
router=readwritesplit
router_options=slave_selection_criteria=LEAST_BEHIND_MASTER
max_slave_connections=50%
max_slave_replication_lag=30
servers=server1,server2,server3,server4
user=maxscale
auth=thepasswd
[Split Listener]
type=listener
service=Split Service
protocol=MySQLClient
port=3336
----
The client would merely connect to port 3336 on the MaxScale host and statements would be directed to the master or slave as appropriate. Determination of the master or slave status may be done via a monitor module within MaxScale or externally. In this latter case the server flags would need to be set via the MaxScale debug interface, in future versions an API will be available for this purpose.
+++<u>Galera Cluster Configuration</u>+++ +
Master and Slave roles that galera monitor assign to nodes make possible the Read Write split approach to Galera Cluster as well.
Simply configure a Split Service with galera nodes:
----
[Galera Split Service]
type=service
router=readwritesplit
----
servers=galera_node1,galera_node2,galera_node3
==== Debugcli
The debugcli is a special case of a statement based router. Rather than direct the statements at an external data source they are handled internally. These statements are simple text commands and the results are the output of debug commands within MaxScale. The service and listener definitions for a debug cli service only differ from other services in that they require no backend server definitions.
===== Debug CLI Configuration
The definition of the debug cli service is illustrated below
----
[Debug Service]
type=service
router=debugcli
[Debug Listener]
type=listener
service=Debug Service
protocol=telnetd
port=4442
----
Connections using the telnet protocol to port 4442 of the MaxScale host will result in a new debug CLI session. A default username and password are used for this module, new users may be created using the add user command. As soon as any users are explicitly created the default username will no longer continue to work. The default username is admin with a password of skysql.
The debugcli supports two modes of operation, developer mode and user mode. The mode is set via the router_options parameter of the debugcli. The user mode is more suited to end-users and administrators, whilst the develop mode is explicitly targeted to software developing adding or maintaining the MaxScale code base. Details of the differences between the modes can be found in the debugging guide for MaxScale. The default mode for the debugcli is user mode. The following service definition would enable a developer version of the debugcli.
----
[Debug Service]
type=service
router=debugcli
----
router_options=developer
It should be noted that both a user and a developer version of the debugcli may be defined within the same instance of MaxScale, however they must be defined as two distinct services, each with a distinct listener.
----
[Debug Service]
type=service
router=debugcli
router_options=developer
[Debug Listener]
type=listener
service=Debug Service
protocol=telnetd
port=4442
[Admin Service]
type=service
router=debugcli
[Admin Listener]
type=listener
service=Debug Service
protocol=telnetd
----
port=4242
==== CLI
The command line interface as used by maxadmin. This is a variant of the debugcli that is built slightly differently so that it may be accessed by the client application maxadmin. The CLI requires the use of the maxscaled protocol.
===== CLI Configuration
There are two components to the definition required in order to run the command line interface to use with MaxAdmin; a service and a listener. +
The default entries required are shown below.
----
[CLI]
type=service
router=cli
[CLI Listener]
type=listener
service=CLI
protocol=maxscaled
address=localhost
port=6603
----
Note that this uses the default port of 6603 and confines the connections to localhost connections only. Remove the address= entry to allow connections from any machine on your network. Changing the port from 6603 will mean that you must allows pass a -p option to the MaxAdmin command.
==
==
== Monitor Modules
Monitor modules are used by MaxScale to internally monitor the state of the backend databases in order to set the server flags for each of those servers. The router modules then use these flags to determine if the particular server is a suitable destination for routing connections for particular query classifications. The monitors are run within separate threads of MaxScale and do not affect the MaxScale performance.
The use of monitors is optional, it is possible to run MaxScale with external monitoring, in which case arrangements must be made for an external entity to set the status of each of the servers that MaxScale can route to.
=== Mysqlmon
The MySQLMon monitor is a simple monitor designed for use with MySQL Master/Slave replication cluster. To execute the mysqlmon monitor an entry as shown below should be added to the MaxScale configuration file.
----
[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2,server3,server4
----
This will monitor the 4 servers; server1, server2, server3 and server4. It will set the status of running or failed and master or slave for each of the servers.
The monitor uses the username given in the monitor section or the server specific user that is given in the server section to connect to the server. This user must have sufficient permissions on the database to determine the state of replication. The roles that must be granted to this user are REPLICATION SLAVE and REPLICATION CLIENT.
To create a user that can be used to monitor the state of the cluster, the following commands could be used.
----
MariaDB [mysql]> create user 'maxscalemon'@'maxscalehost' identified by 'Ha79hjds';
Query OK, 0 rows affected (0.01 sec)
MariaDB [mysql]> grant REPLICATION SLAVE on *.* to 'maxscalemon'@'maxscalehost';
Query OK, 0 rows affected (0.00 sec)
MariaDB [mysql]> grant REPLICATION CLIENT on *.* to 'maxscalemon'@'maxscalehost';
Query OK, 0 rows affected (0.00 sec)
MariaDB [mysql]>
----
Assuming that MaxScale is running on the host maxscalehost.
=== Galeramon
The Galeramon monitor is a simple router designed for use with MySQL Galera cluster. To execute the galeramon monitor an entry as shown below should be added to the MaxScale configuration file.
----
[Galera Monitor]
type=monitor
module=galeramon
servers=server1,server2,server3,server4
----
This will monitor the 4 servers; server1, server2, server3 and server4. It will set the status of running or failed and joined for those servers that reported the Galera JOINED status.
The user that is configured for use with the Galera monitor must have sufficient privileges to select from the information_schema database and GLOBAL_STATUS table within that database.
To create a user that can be used to monitor the state of the cluster, the following commands could be used.
----
MariaDB [mysql]> create user 'maxscalemon'@'maxscalehost' identified by 'Ha79hjds';
Query OK, 0 rows affected (0.01 sec)
MariaDB [mysql]> grant SELECT on INFORMATION_SCHEMA.GLOBAL_STATUS to 'maxscalemon'@'maxscalehost';
Query OK, 0 rows affected (0.00 sec)
MariaDB [mysql]>
----
Assuming that MaxScale is running on the host maxscalehost.
The Galera monitor can also assign Master and Slave roles to the configured nodes:
among the set of synced servers, the one with the lowest value of ‘wsrep_local_index’ is selected as the current master while the others are slaves.
This way is possible to configure the node access based not only on ‘synced’ state but even on Master and Slave role enabling the use of Read Write split operation on a Galera cluster and avoiding any possible write conflict.
Example status for a Galera server node is:
----
Server 0x261fe50 (server2)
Server: 192.168.1.101
----
Status: Master, Synced, Running
==
==
== Filter Modules
Currently four example filters are included in the MaxScale distribution
|===
|*Module*|*Description*
|testfilter|Statement counting Filter - a simple filter that counts the number of SQL statements executed within a session. Results may be viewed via the debug interface.
|qlafilter|Query Logging Filter - a simple query logging filter that write all statements for a session into a log file for that session.
|regexfilter|Query Rewrite Filter - an example of how filters can alter the query contents. This filter allows a regular expression to be defined, along with replacement text that should be substituted for every match of that regular expression.
|tee|A filter that duplicates SQL requests and sends the duplicates to another service within MaxScale.
|===
These filters are merely examples of what may be achieved with the filter API and are not sophisticated or consider as suitable for production use, they merely illustrate the functionality possible.
=== Statement Counting Filter
The statement counting filter is implemented in the module names testfilter and merely keeps a count of the number of SQL statements executed. The filter requires no options to be passed and takes no parameters. The statement count can be viewed via the diagnostic and debug interface of MaxScale.
In order to add this filter to an existing service create a filter section to name the filter as follows
----
[counter]
type=filter
module=testfilter
----
Then add the filter to your service by including the filters= parameter in the service section.
+filters=counter+
=== Query Log All Filter
The QLA filter simply writes all SQL statements to a log file along with a timestamp for the statement. An example of the file produced by the QLA filter is shown below
----
00:36:04.922 5/06/2014, select @@version_comment limit 1
00:36:12.663 5/06/2014, SELECT DATABASE()
00:36:12.664 5/06/2014, show databases
00:36:12.665 5/06/2014, show tables
----
A new file is created for each client connection, the name of the logfile can be controlled by the use of the router options. No parameters are used by the QLA filter. The filter is implemented by the loadable module qlafilter.
To add the QLA filter to a service you must create a filter section to name the filter, associated the loadable module and define the filename option.
----
[QLA]
type=filter
module=qlafilter
options=/tmp/QueryLog
----
Then add the filters= parameter into the service that you wish to log by adding this parameter to the service section
+filters=QLA+
A log file will be created for each client connection, the name of that log file will be /tmp/QueryLog.<number>
=== Regular Expression Filter
The regular expression filter is a simple text based query rewriting filter. It allows a regular expression to be used to match text in a SQL query and then a string replacement to be made against that match. The filter is implemented by the regexfilter loadable module and is passed two parameters, a match string and a replacement string.
To add the filter to your service you must first create a filter section to name the filter and give the match and replacement strings. Here we define a filter that will convert to MariaDB 10 command show all slaves status to the older form of show slave status for MariaDB 5.5.
----
[slavestatus]
type=filter
module=regexfilter
match=show *all *slaves
replace=show slave
----
You must then add this filter to your service by adding the filters= option
+filters=slavestatus+
Another example would be a filter to convert from the MySQL 5.1 create table syntax that used the TYPE keyword to the newer ENGINE keyword.
----
[EnginerFilter]
type=filter
module=regexfilter
match=TYPE
replace=ENGINE
----
This would then change the SQL sent by a client application written to work with MySQL 5.1 into SQL that was compliant with MySQL 5.5. The statement
+create table supplier(id integer, name varchar(80)) type=innodb+
would be replaced with
+create table supplier(id integer, name varchar(80)) ENGINE=innodb+
before being sent to the server. Note that the text in the match string is case independent.
=== Tee Filter
The tee filter is a filter module for MaxScale is a “plumbing” fitting in the MaxScale filter toolkit. It can be used in a filter pipeline of a service to make a copy of requests from the client and dispatch a copy of the request to another service within MaxScale.
The configuration block for the TEE filter requires the minimal filter parameters in it’s section within the MaxScale.cnf file that defines the filter to load and the service to send the duplicates to.
----
[ArchieveFilter]
type=filter
module=tee
service=Archieve
----
In addition parameters may be added to define patterns to match against to either include or exclude particular SQL statements to be duplicated. You may also define that the filter is only active for connections from a particular source or when a particular user is connected.
==
==
== 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.
+maxkeys $MAXSCALE_HOME/etc/.secrets+
Changing the encryption key for MaxScale will invalidate any currently encrypted keys stored in the MaxScale.cnf file.
=== 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.
----
maxpasswd MaxScalePw001
61DD955512C39A4A8BC4BB1E5F116705
----
The output of the maxpasswd command is a hexadecimal string, this should be inserted into the MaxScale.cnf file in place of the ordinary, plain text, password. MaxScale will determine this as an encrypted password and automatically decrypt it before sending it the database server.
----
[Split Service]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
user=maxscale
password=61DD955512C39A4A8BC4BB1E5F116705
----
==
==
== Configuration Updates
The current MaxScale configuration may be updating by editing the configuration file and then forcing MaxScale to reread the configuration file. To force MaxScale to reread the configuration file a SIGTERM signal is sent to the MaxScale process.
Some changes in configuration can not be dynamically changed and require a complete restart of MaxScale, whilst others will take some time to be applied.
=== Limitations
Services that are removed via the configuration update mechanism can not be physically removed from MaxScale until there are no longer any connections using the service.
When the number of threads is decreased the threads will not actually be terminated until such time as they complete the current operation of that thread.
Monitors can not be completely removed from the running MaxScale.
==
==
== Authentication
MySQL uses username, passwords and the client host in order to authenticate a user, so a typical user would be defined as user X at host Y and would be given a password to connect. MaxScale uses exactly the same rules as MySQL when users connect to the MaxScale instance, i.e. it will check the address from which the client is connecting and treat this in exactly the same way that MySQL would. MaxScale will pull the authentication data from one of the backend servers and use this to match the incoming connections, the assumption being that all the backend servers for a particular service will share the same set of user credentials.
It is important to understand, however, that when MaxScale itself makes connections to the backend servers the backend server will see all connections as originating from the host that runs MaxScale and not the original host from which the client connected to MaxScale. Therefore the backend servers should be configured to allow connections from the MaxScale host for every user that can connect from any host. Since there is only a single password within the database server for a given host, this limits the configuration such that a given user name must have the same password for every host from which they can connect.
To clarify, if a user X is defined as using password _pass1_ from host a and _pass2_ from host b then there must be an entry in the user table for user X form the MaxScale host, say _pass1_.
This would result in rows in the user table as follows
|===
|*Username*|*Password*|*Client Host*
|X|pass1|a
|X|pass2|b
|X|pass1|MaxScale
|===
In this case the user X would be able to connect to MaxScale from host a giving the password of _pass1_. In addition MaxScale would be able to create connections for this user to the backend servers using the username X and password _pass1_, since the MaxScale host is also defined to have password _pass1_. User X would not however be able to connect from host b since they would need to provide the password _pass2_ in order to connect to MaxScale, but then MaxScale would not be able to connect to the backends as it would also use the password _pass2_ for these connections.
=== Wildcard Hosts
Hostname mapping in MaxScale works in exactly the same way as for MySQL, if the wildcard is used for the host then any host other than the localhost (127.0.0.1) will match. It is important to consider that the localhost check will be performed at the MaxScale level and at the MySQL server level.
If MaxScale and the databases are on separate hosts there are two important changes in behaviour to consider:
. Clients running on the same machine as the backend database now may access the database using the wildcard entry. The localhost check between the client and MaxScale will allow the use of the wildcard, since the client is not running on the MaxScale host. Also the wildcard entry can be used on the database host as MaxScale is making that connection and it is not running on the same host as the database.
. Clients running on the same host as MaxScale can not access the database via MaxScale using the wildcard entry since the connection to MaxScale will be from the localhost. These clients are able to access the database directly, as they will use the wildcard entry.
If MaxScale is running on the same host as one or more of the database nodes to which it is acting as a proxy then the wildcard host entries can be used to connect to MaxScale but not to connect onwards to the database running on the same node.
In all these cases the issue may be solved by adding an explicit entry for the localhost address that has the same password as the wildcard entry. This may be done using a statement as below for each of the databases that are required:
+MariaDB [mysql]> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP ON employee.* 'user1'@'localhost' IDENTIFIED BY ‘xxx’;+ +
Query OK, 0 rows affected (0.00 sec)
=== Limitations
At the time of writing the authentication mechanism within MaxScale does not support IPV6 address matching in connections rules. This is also in line with the current protocol modules that do not support IPV6.
Partial address matching, such as 10.% is also not supported in the current version of MaxScale.
==
== 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.
Troubleshooting +
MaxScale binds on TCP ports and UNIX sockets as well.
If there is a local firewall in the server where MaxScale is installed, the IP and port must be configured in order to receive connections from outside.
If the firewall is a network facility among all the involved servers, a configuration update is required as well.
Example: +
----
[Galera Listener]
type=listener
----
address=192.1681.3.33 +
----
port=4408
socket=/servers/maxscale/galera.sock
----
TCP/IP Traffic must be permitted to 192.1681.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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

33
FindMySQLClient.cmake Normal file
View File

@ -0,0 +1,33 @@
# This CMake file tries to find the the MySQL client library
# The following variables are set:
# MYSQLCLIENT_FOUND - System has MySQL client
# MYSQLCLIENT_STATIC_FOUND - System has statically linked MySQL client
# MYSQLCLIENT_LIBRARIES - The MySQL client library
# MYSQLCLIENT_STATIC_LIBRARIES - The static MySQL client library
# MYSQLCLIENT_HEADERS - The MySQL client headers
find_library(MYSQLCLIENT_LIBRARIES NAMES mysqlclient PATH_SUFFIXES mysql mariadb)
if(${MYSQLCLIENT_LIBRARIES} MATCHES "NOTFOUND")
set(MYSQLCLIENT_FOUND FALSE CACHE INTERNAL "")
message(STATUS "Dynamic MySQL client library not found.")
unset(MYSQLCLIENT_LIBRARIES)
else()
set(MYSQLCLIENT_FOUND TRUE CACHE INTERNAL "")
message(STATUS "Found dynamic MySQL client library: ${MYSQLCLIENT_LIBRARIES}")
endif()
set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
find_library(MYSQLCLIENT_STATIC_LIBRARIES NAMES mysqlclient PATH_SUFFIXES mysql mariadb)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES})
if(${MYSQLCLIENT_STATIC_LIBRARIES} MATCHES "NOTFOUND")
set(MYSQLCLIENT_STATIC_FOUND FALSE CACHE INTERNAL "")
message(STATUS "Static MySQL client library not found.")
unset(MYSQLCLIENT_STATIC_LIBRARIES)
else()
set(MYSQLCLIENT_STATIC_FOUND TRUE CACHE INTERNAL "")
message(STATUS "Found statc MySQL client library: ${MYSQLCLIENT_STATIC_LIBRARIES}")
endif()
find_path(MYSQLCLIENT_HEADERS mysql.h PATH_SUFFIXES mysql mariadb)

23
FindRabbitMQ.cmake Normal file
View File

@ -0,0 +1,23 @@
# This CMake file tries to find the the RabbitMQ library
# The following variables are set:
# RABBITMQ_FOUND - System has RabbitMQ client
# RABBITMQ_LIBRARIES - The RabbitMQ client library
# RABBITMQ_HEADERS - The RabbitMQ client headers
include(CheckCSourceCompiles)
find_library(RABBITMQ_LIBRARIES NAMES rabbitmq)
find_path(RABBITMQ_HEADERS amqp.h PATH_SUFFIXES mysql mariadb)
if(${RABBITMQ_LIBRARIES} MATCHES "NOTFOUND")
set(RABBITMQ_FOUND FALSE CACHE INTERNAL "")
message(STATUS "RabbitMQ library not found.")
unset(RABBITMQ_LIBRARIES)
else()
set(RABBITMQ_FOUND TRUE CACHE INTERNAL "")
message(STATUS "Found RabbitMQ library: ${RABBITMQ_LIBRARIES}")
endif()
set(CMAKE_REQUIRED_INCLUDES ${RABBITMQ_HEADERS})
check_c_source_compiles("#include <amqp.h>\n int main(){if(AMQP_DELIVERY_PERSISTENT){return 0;}return 1;}" HAVE_RABBITMQ50)
if(NOT HAVE_RABBITMQ50)
message(FATAL_ERROR "Old version of RabbitMQ-C library found. Version 0.5 or newer is required.")
endif()

13
FindValgrind.cmake Normal file
View File

@ -0,0 +1,13 @@
# This CMake file tries to find the Valgrind executable
# The following variables are set:
# VALGRIND_FOUND - System has Valgrind
# VALGRIND_EXECUTABLE - The Valgrind executable file
find_program(VALGRIND_EXECUTABLE valgrind)
if(VALGRIND_EXECUTABLE STREQUAL "VALGRIND_EXECUTABLE-NOTFOUND")
message(STATUS "Valgrind not found.")
set(VALGRIND_FOUND FALSE CACHE INTERNAL "")
unset(VALGRIND_EXECUTABLE)
else()
message(STATUS "Valgrind found: ${VALGRIND_EXECUTABLE}")
set(VALGRIND_FOUND TRUE CACHE INTERNAL "")
endif()

View File

@ -1,4 +1,4 @@
# This file is distributed as part of the SkySQL Gateway. It is free # 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 # 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, # GNU General Public License as published by the Free Software Foundation,
# version 2. # version 2.
@ -12,7 +12,7 @@
# this program; if not, write to the Free Software Foundation, Inc., 51 # this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# #
# Copyright SkySQL Ab 2013 # Copyright MariaDB Corporation Ab 2013
# #
# Revision History # Revision History
# Date Who Description # Date Who Description

178
README
View File

@ -1,16 +1,16 @@
/** \mainpage MariaDB MaxScale /** \mainpage MaxScale by MariaDB Corporation
MaxScale is an intelligent proxy that allows forwarding of The MariaDB Corporation MaxScale is an intelligent proxy that allows forwarding of
database statements to one or more database servers using complex rules, database statements to one or more database servers using complex rules,
a semantic understanding of the database statements and the roles of a semantic understanding of the database statements and the roles of
the various servers within the backend cluster of databases. the various servers within the backend cluster of databases.
MaxScale is designed to provide load balancing and high availability MaxScale is designed to provide load balancing and high availability
functionality transparantly to the applications. In addition it provides functionality transparently to the applications. In addition it provides
a highly scalable and flexibile architecture, with plugin components to a highly scalable and flexibile architecture, with plugin components to
support different protocols and routing decissions. support different protocols and routing decissions.
MaxScale is implemented in C and makes entensive use of the MaxScale is implemented in C and makes extensive use of the
asynchronous I/O capabilities of the Linux operating system. The epoll asynchronous I/O capabilities of the Linux operating system. The epoll
system is used to provide the event driven framework for the input and system is used to provide the event driven framework for the input and
output via sockets. output via sockets.
@ -28,99 +28,11 @@ issues and communicate with the MaxScale community.
Send email to [maxscale@googlegroups.com](mailto:maxscale@googlegroups.com) Send email to [maxscale@googlegroups.com](mailto:maxscale@googlegroups.com)
or use the [forum](http://groups.google.com/forum/#!forum/maxscale) interface or use the [forum](http://groups.google.com/forum/#!forum/maxscale) interface
Bugs can be reported in the MariaDB bugs database Bugs can be reported in the MariaDB Corporation bugs database
[bug.skysql.com](http://bugs.mariadb.com) [bug.mariadb.com](http://bugs.mariadb.com)
There are two options if you would like to try MaxScale, either building
from the source code contained in GitHub or by downloading pre-built packages
from the MariaDB website. http://www.mariadb.com/downloads.
\section Branching policy within the MaxScale repository
The branching policy within this repository is resonably simple, the master branch will always
contain the last released MaxScale code. The develop branch is the latest development copy of
MaxScale and is aimed to be always buildable and useable. Features will be developed on seperate
branches and only merged into the develop branch when they are complete.
\section Building Building MaxScale \section Building Building MaxScale
There are two methods that make be used to build this version of MaxScale, either
with hadncrafted makefiles or by using cmake. CMake is a newer implementation of
the MaxScale build system and is the prefered choice for creating MaxScale executables
and packages from the source code.
\section Building Building MaxScale with CMake
You can also build MaxScale with CMake which makes the build process a bit more simple.
All the same dependencies are required as with the normal MaxScale build with the addition of CMake
version 2.6 for regular builds and 2.8.12 or newer if you wish to generate packages.
CMake tries to find all the required directories and files on its own but if it can't find them or you wish to
explicitly state the locations you can pass additional options to CMake by using the -D flag. To confirm the variable
values, you can run CMake in interactive mode by using the -i flag or use a CMake GUI (for example, ccmake for command line).
It is highly recommended to make a separate build directory to build into. This keeps the source and build trees clean and
makes it easy to get rid of everything you built by simply deleting the build directory.
To build MaxScale using CMake:
cd <path to MaxScale source>
mkdir build
cd build
cmake ..
make
make install
This generates the required makefiles in the current directory, compiles and links all the programs and installs
all the required files in their right places.
If you have your headers and libraries in non-standard locations, you can define those locations at configuration time as such:
cmake -D<variable>=<value>
By default, MaxScale installs to '/usr/local/skysql/maxscale' and places init.d scripts and ldconfig files into their folders. Change the INSTALL_DIR
variable to your desired installation directory and set INSTALL_SYSTEM_FILES=N to prevent the init.d script and ldconfig file installation.
If you run into any trouble while configuring CMake, you can always remove the 'CMakeCache.txt' file to clear CMake's
internal cache. This resets all values to their defaults and can be used to fix a 'stuck' configuration of CMake. This
is also a good reason why you should always build into a separate directory, because you can safely wipe the build directory clean without the
danger of deleting important files when something goes wrong.
The default values that CMake uses can be found in the 'macros.cmake' file. If you wish to change these, edit the 'macros.cmake' file
or define the variables manually at configuration time.
All the variables that control the CMake build process:
INSTALL_DIR=<path> Installation directory
BUILD_TYPE=[None|Debug|Release] Type of the build, defaults to Release (optimized)
INSTALL_SYSTEM_FILES=[Y|N] Install startup scripts and ld configuration files
EMBEDDED_LIB=<path> Path to the embedded library location (libmysqld.a for static and libmysqld.so for dynamic)
MYSQL_DIR=<path> Path to MySQL headers
ERRMSG=<path> Path to errmsg.sys file
STATIC_EMBEDDED=[Y|N] Whether to link the static or the dynamic verson of the library
GCOV=[Y|N] Generate gcov output
OLEVEL=<0-3> Level of optimization
BUILD_TESTS=[Y|N] Build tests
DEPS_OK=[Y|N] Check dependencies, use N when you want to force a recheck of values
DEBUG_OUTPUT=[Y|N] Produce debugging output when configuring CMake
RABBITMQ_LIB=<path> Path to RabbitMQ-C libraries
RABBITMQ_HEADERS=<path> Path to RabbitMQ-C headers
MYSQL_CLIENT_LIB=<path> Path to MySQL client libraries
MYSQL_CLIENT_HEADERS=<path> Path to MySQL client headers
/section Building MaxScale without cmake
This method of building MaxScale was the initial mechanism that was implemented
however it has now been superceeded by the use of cmake. Currently it may still
be used, however the plan is to withdraw this mechanism by the end of 2014 and
move completely to the use of cmake for building MaxScale.
Edit the file build_gateway.inc in your MaxScale directory and set Edit the file build_gateway.inc in your MaxScale directory and set
the ROOT_PATH to the directory in which you have installed the the ROOT_PATH to the directory in which you have installed the
MaxScale source code. Set the INC_PATH/MYSQL_ROOT/MYSQL_HEADERS variables MaxScale source code. Set the INC_PATH/MYSQL_ROOT/MYSQL_HEADERS variables
@ -135,18 +47,22 @@ MariaDB-5.5.34-centos6-x86_64-common.rpm
MariaDB-5.5.34-centos6-x86_64-compat.rpm MariaDB-5.5.34-centos6-x86_64-compat.rpm
MariaDB-5.5.34-centos6-x86_64-devel.rpm MariaDB-5.5.34-centos6-x86_64-devel.rpm
Please backup any existent my.cnf file before installing the RPMs Please backup any existing my.cnf file before installing the RPMs
Install the RPM files using: Install the RPM files using:
rpm -i MariaDB-5.5.34-centos6-x86_64-common.rpm MariaDB-5.5.34-centos6-x86_64-compat.rpm MariaDB-5.5.34-centos6-x86_64-devel.rpm rpm -i MariaDB-5.5.34-centos6-x86_64-common.rpm MariaDB-5.5.34-centos6-x86_64-compat.rpm MariaDB-5.5.34-centos6-x86_64-devel.rpm
Note, if you wish to relocate the package to avoid an exisitng MariaDB Note, if you wish to relocate the package to avoid an existing MariaDB
or MySQL installation you will need to use the --force option in addition or MySQL installation you will need to use the --force option in addition
to the --relocate option. to the --relocate option.
rpm -i --force --relocate=/usr/=$PREFIX/usr/ MariaDB-5.5.34-centos6-x86_64-common.rpm MariaDB-5.5.34-centos6-x86_64-compat.rpm MariaDB-5.5.34-centos6-x86_64-devel.rpm rpm -i --force --relocate=/usr/=$PREFIX/usr/ MariaDB-5.5.34-centos6-x86_64-common.rpm MariaDB-5.5.34-centos6-x86_64-compat.rpm MariaDB-5.5.34-centos6-x86_64-devel.rpm
You can also use the included 'unpack_rpm.sh' script to unpack the RPMs without installing them.
./unpack_rpm <location of MariaDB RPMs> <extraction destination>
This README assumes $PREFIX = $HOME. This README assumes $PREFIX = $HOME.
MaxScale may be built with the embedded MariaDB library either linked MaxScale may be built with the embedded MariaDB library either linked
@ -178,7 +94,7 @@ Example:
Please note the errmsg.sys file is NOT included in the RPMs at the Please note the errmsg.sys file is NOT included in the RPMs at the
curent time, it must be taken from an existing MariaDB setup. The current time, it must be taken from an existing MariaDB setup. The
version of the errmsg.sys file must match the version of the developer version of the errmsg.sys file must match the version of the developer
package you are using. A version mismatch will cause the library to fail package you are using. A version mismatch will cause the library to fail
to initialise. to initialise.
@ -240,6 +156,74 @@ max_connections=4096
Please check errmsg.sys is found in the MaxScale install_dir DEST/MaxScale/mysql Please check errmsg.sys is found in the MaxScale install_dir DEST/MaxScale/mysql
\section Building Building MaxScale with CMake
You can also build MaxScale with CMake which makes the build process a bit more simple.
All the same dependencies are required as with the normal MaxScale build with the addition of CMake
version 2.6 for regular builds and 2.8.12 or newer if you wish to generate packages.
CMake tries to find all the required directories and files on its own but if it can't find them or you wish to
explicitly state the locations you can pass additional options to CMake by using the -D flag. To confirm the variable
values, you can run CMake in interactive mode by using the -i flag or use a CMake GUI (for example, ccmake for command line).
It is highly recommended to make a separate build directory to build into. This keeps the source and build trees clean and
makes it easy to get rid of everything you built by simply deleting the build directory.
To build MaxScale using CMake:
cd <path to MaxScale source>
mkdir build
cd build
cmake ..
make
make install
This generates the required makefiles in the current directory, compiles and links all the programs and installs
all the required files in their right places.
If you have your headers and libraries in non-standard locations, you can define those locations at configuration time as such:
cmake -D<variable>=<value>
By default, MaxScale installs to '/usr/local/skysql/maxscale' and places init.d scripts and ldconfig files into their folders. Change the INSTALL_DIR
variable to your desired installation directory and set INSTALL_SYSTEM_FILES=N to prevent the init.d script and ldconfig file installation.
If you run into any trouble while configuring CMake, you can always remove the 'CMakeCache.txt' file to clear CMake's
internal cache. This resets all values to their defaults and can be used to fix a 'stuck' configuration of CMake. This
is also a good reason why you should always build into a separate directory, because you can safely wipe the build directory clean without the
danger of deleting important files when something goes wrong.
The default values that CMake uses can be found in the 'macros.cmake' file. If you wish to change these, edit the 'macros.cmake' file
or define the variables manually at configuration time.
All the variables that control the CMake build process:
INSTALL_DIR=<path> Installation directory
BUILD_TYPE=<type> Type of the build. One of None, Debug, DebugSymbols, Optimized. (default None)
DebugSymbols enables debugging symbols, Debug enables debugging symbols and code, Optimized builds an optimized version.
INSTALL_SYSTEM_FILES=[Y|N] Install startup scripts and ld configuration files
EMBEDDED_LIB=<path> Path to the embedded library location (libmysqld.a for static and libmysqld.so for dynamic)
MYSQL_DIR=<path> Path to MySQL headers
ERRMSG=<path> Path to errmsg.sys file
STATIC_EMBEDDED=[Y|N] Whether to link the static or the dynamic verson of the library
GCOV=[Y|N] Generate gcov output
OLEVEL=<0-3> Level of optimization
BUILD_TESTS=[Y|N] Build tests
DEPS_OK=[Y|N] Check dependencies, use N when you want to force a recheck of values
DEBUG_OUTPUT=[Y|N] Produce debugging output when configuring CMake
RABBITMQ_LIBRARIES=<path> Path to RabbitMQ-C libraries
RABBITMQ_HEADERS=<path> Path to RabbitMQ-C headers
MYSQLCLIENT_LIBRARIES=<path> Path to MySQL client libraries
MYSQLCLIENT_HEADERS=<path> Path to MySQL client headers
\section Running Running MaxScale \section Running Running MaxScale
MaxScale consists of a core executable and a number of modules that implement MaxScale consists of a core executable and a number of modules that implement

View File

@ -1 +1 @@
1.0.1-beta 1.0.2-beta

View File

@ -12,7 +12,7 @@
# this program; if not, write to the Free Software Foundation, Inc., 51 # this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# #
# Copyright SkySQL Ab 2014 # Copyright MariaDB Corporation Ab 2014
# #
# Revision History # Revision History
# Date Who Description # Date Who Description

View File

@ -13,7 +13,7 @@
* this program; if not, write to the Free Software Foundation, Inc., 51 * this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* *
* Copyright SkySQL Ab 2014 * Copyright MariaDB Corporation Ab 2014
*/ */
/** /**
@ -183,10 +183,21 @@ char c;
len += strlen(argv[i]) + 1; len += strlen(argv[i]) + 1;
} }
cmd = malloc(len); cmd = malloc(len + (2 * argc)); // Allow for quotes
strcpy(cmd, argv[optind]); strncpy(cmd, argv[optind],len + (2 * argc));
for (i = optind +1; i < argc; i++) { for (i = optind +1; i < argc; i++)
{
strcat(cmd, " "); strcat(cmd, " ");
/* Arguments after the seconf are quoted to allow for names
* that contain white space
*/
if (i - optind > 1)
{
strcat(cmd, "\"");
strcat(cmd, argv[i]);
strcat(cmd, "\"");
}
else
strcat(cmd, argv[i]); strcat(cmd, argv[i]);
} }
@ -317,6 +328,7 @@ int keepalive = 1;
{ {
fprintf(stderr, "Unable to connect to MaxScale at %s, %s: %s\n", fprintf(stderr, "Unable to connect to MaxScale at %s, %s: %s\n",
hostname, port, strerror(errno)); hostname, port, strerror(errno));
close(so);
return -1; return -1;
} }
if (setsockopt(so, SOL_SOCKET, if (setsockopt(so, SOL_SOCKET,

View File

@ -206,5 +206,110 @@ do
fi fi
done done
maxadmin -pskysql list services | \
awk -F\| '{ if (NF > 1) { sub(/ +$/, "", $1); printf("show service \"%s\"\n", $1); } }' > script1.$$
grep -cs "show service" script1.$$ >/dev/null
if [ $? -ne "0" ]; then
echo "list services: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "list services: Passed"
fi
maxadmin -pskysql script1.$$ | grep -cs 'Service' > /dev/null
if [ $? -ne "0" ]; then
echo "Show Service: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "Show Service: Passed"
fi
rm -f script1.$$
maxadmin -pskysql list monitors | \
awk -F\| '{ if (NF > 1) { sub(/ +$/, "", $1); printf("show monitor \"%s\"\n", $1); } }' > script1.$$
grep -cs "show monitor" script1.$$ >/dev/null
if [ $? -ne "0" ]; then
echo "list monitors: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "list monitors: Passed"
fi
maxadmin -pskysql script1.$$ | grep -cs 'Monitor' > /dev/null
if [ $? -ne "0" ]; then
echo "Show Monitor: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "Show Monitor: Passed"
fi
rm -f script1.$$
maxadmin -pskysql list sessions | \
awk -F\| ' /^0x/ { if (NF > 1) { sub(/ +$/, "", $1); printf("show session \"%s\"\n", $1); } }' > script1.$$
grep -cs "show session" script1.$$ >/dev/null
if [ $? -ne "0" ]; then
echo "list sessions: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "list sessions: Passed"
fi
maxadmin -pskysql script1.$$ | grep -cs 'Session' > /dev/null
if [ $? -ne "0" ]; then
echo "Show Session: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "Show Session: Passed"
fi
rm -f script1.$$
maxadmin -pskysql list dcbs | \
awk -F\| ' /^ 0x/ { if (NF > 1) { sub(/ +$/, "", $1); sub(/ 0x/, "0x", $1); printf("show dcb \"%s\"\n", $1); } }' > script1.$$
grep -cs "show dcb" script1.$$ >/dev/null
if [ $? -ne "0" ]; then
echo "list dcbs: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "list dcbs: Passed"
fi
maxadmin -pskysql script1.$$ | grep -cs 'DCB' > /dev/null
if [ $? -ne "0" ]; then
echo "Show DCB: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "Show DCB: Passed"
fi
rm -f script1.$$
maxadmin -pskysql list services | \
awk -F\| '{ if (NF > 1) { sub(/ +$/, "", $1); printf("show dbusers \"%s\"\n", $1); } }' > script1.$$
grep -cs "show dbusers" script1.$$ >/dev/null
if [ $? -ne "0" ]; then
echo "list services: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "list services: Passed"
fi
maxadmin -pskysql script1.$$ | grep -cs 'Users table data' > /dev/null
if [ $? -ne "0" ]; then
echo "Show dbusers: Failed"
failure=`expr $failure + 1`
else
passed=`expr $passed + 1`
echo "Show dbusers: Passed"
fi
rm -f script1.$$
echo "Test run complete. $passed passes, $failure failures" echo "Test run complete. $passed passes, $failure failures"
exit $failure exit $failure

24
cmake_uninstall.cmake.in Normal file
View File

@ -0,0 +1,24 @@
# "make uninstall" helper
# see http://www.cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

4
debian/changelog vendored
View File

@ -2,9 +2,9 @@ maxscale (1.0-beta) UNRELEASED; urgency=low
* Beta release * Beta release
-- Timofey Turenko <timofey.turenko@skysql.com> Fri, 05 Jul 2014 14:00:00 +0200 -- Timofey Turenko <timofey.turenko@mariadb.com> Fri, 05 Jul 2014 14:00:00 +0200
maxscale (0.7-1) UNRELEASED; urgency=low maxscale (0.7-1) UNRELEASED; urgency=low
* Initial release. (Closes: #XXXXXX) * Initial release. (Closes: #XXXXXX)
-- Timofey Turenko <timofey.turenko@skysql.com> Tue, 11 Mar 2014 22:59:35 +0200 -- Timofey Turenko <timofey.turenko@mariadb.com> Tue, 11 Mar 2014 22:59:35 +0200

2
debian/control vendored
View File

@ -9,7 +9,7 @@ Package: maxscale
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}
Description: MaxScale Description: MaxScale
The SkySQL MaxScale is an intelligent proxy that allows forwarding of The MariaDB Corporation MaxScale is an intelligent proxy that allows forwarding of
database statements to one or more database servers using complex rules, database statements to one or more database servers using complex rules,
a semantic understanding of the database statements and the roles of a semantic understanding of the database statements and the roles of
the various servers within the backend cluster of databases. the various servers within the backend cluster of databases.

1520
doxygate.in Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# maxscale: The SkySQL MaxScale database proxy # maxscale: The MariaDB Corporation MaxScale database proxy
# #
# description: MaxScale provides database specific proxy functionality # description: MaxScale provides database specific proxy functionality
# #

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# maxscale: The SkySQL MaxScale database proxy # maxscale: The MariaDB Corporation MaxScale database proxy
# #
# description: MaxScale provides database specific proxy functionality # description: MaxScale provides database specific proxy functionality
# #

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# maxscale: The SkySQL MaxScale database proxy # maxscale: The MariaDB Corporation MaxScale database proxy
# #
# description: MaxScale provides database specific proxy functionality # description: MaxScale provides database specific proxy functionality
# #

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# maxscale: The SkySQL MaxScale database proxy # maxscale: The MariaDB Corporation MaxScale database proxy
# #
# description: MaxScale provides database specific proxy functionality # description: MaxScale provides database specific proxy functionality
# #

View File

@ -1,3 +1,6 @@
if(LOG_DEBUG)
add_definitions(-DSS_LOG_DEBUG)
endif()
add_library(log_manager SHARED log_manager.cc) add_library(log_manager SHARED log_manager.cc)
target_link_libraries(log_manager pthread aio stdc++) target_link_libraries(log_manager pthread aio stdc++)
install(TARGETS log_manager DESTINATION lib) install(TARGETS log_manager DESTINATION lib)

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* /*
* This file is distributed as part of the SkySQL Gateway. It is free * 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 * 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, * GNU General Public License as published by the Free Software Foundation,
* version 2. * version 2.
@ -13,9 +13,10 @@
* this program; if not, write to the Free Software Foundation, Inc., 51 * this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* *
* Copyright SkySQL Ab 2013 * Copyright MariaDB Corporation Ab 2013-2014
*/ */
#if !defined(LOG_MANAGER_H)
# define LOG_MANAGER_H
typedef struct filewriter_st filewriter_t; typedef struct filewriter_st filewriter_t;
typedef struct logfile_st logfile_t; typedef struct logfile_st logfile_t;
@ -41,17 +42,55 @@ typedef enum {
typedef enum { FILEWRITER_INIT, FILEWRITER_RUN, FILEWRITER_DONE } typedef enum { FILEWRITER_INIT, FILEWRITER_RUN, FILEWRITER_DONE }
filewriter_state_t; filewriter_state_t;
/**
* Thread-specific logging information.
*/
typedef struct log_info_st
{
size_t li_sesid;
int li_enabled_logs;
} log_info_t;
#define LE LOGFILE_ERROR #define LE LOGFILE_ERROR
#define LM LOGFILE_MESSAGE #define LM LOGFILE_MESSAGE
#define LT LOGFILE_TRACE #define LT LOGFILE_TRACE
#define LD LOGFILE_DEBUG #define LD LOGFILE_DEBUG
/**
* Check if specified log type is enabled in general or if it is enabled
* for the current session.
*/
#define LOG_IS_ENABLED(id) (((lm_enabled_logfiles_bitmask & id) || \
(log_ses_count[id] > 0 && \
tls_log_info.li_enabled_logs & id)) ? true : false)
#define LOG_MAY_BE_ENABLED(id) (((lm_enabled_logfiles_bitmask & id) || \
log_ses_count[id] > 0) ? true : false)
/**
* Execute the given command if specified log is enabled in general or
* if there is at least one session for whom the log is enabled.
*/
#define LOGIF_MAYBE(id,cmd) if (LOG_MAY_BE_ENABLED(id)) \
{ \
cmd; \
}
/**
* Execute the given command if specified log is enabled in general or
* if the log is enabled for the current session.
*/
#define LOGIF(id,cmd) if (LOG_IS_ENABLED(id)) \
{ \
cmd; \
}
#if !defined(LOGIF)
#define LOGIF(id,cmd) if (lm_enabled_logfiles_bitmask & id) \ #define LOGIF(id,cmd) if (lm_enabled_logfiles_bitmask & id) \
{ \ { \
cmd; \ cmd; \
} \ }
#endif
#define LOG_IS_ENABLED(id) ((lm_enabled_logfiles_bitmask & id) ? true : false)
/** /**
* UNINIT means zeroed memory buffer allocated for the struct. * UNINIT means zeroed memory buffer allocated for the struct.
@ -74,10 +113,11 @@ void skygw_logmanager_exit(void);
void skygw_log_done(void); void skygw_log_done(void);
int skygw_log_write(logfile_id_t id, const char* format, ...); int skygw_log_write(logfile_id_t id, const char* format, ...);
int skygw_log_flush(logfile_id_t id); int skygw_log_flush(logfile_id_t id);
int skygw_log_rotate(logfile_id_t id);
int skygw_log_write_flush(logfile_id_t id, const char* format, ...); int skygw_log_write_flush(logfile_id_t id, const char* format, ...);
int skygw_log_enable(logfile_id_t id); int skygw_log_enable(logfile_id_t id);
int skygw_log_disable(logfile_id_t id); int skygw_log_disable(logfile_id_t id);
void skygw_log_sync_all(void);
EXTERN_C_BLOCK_END EXTERN_C_BLOCK_END
@ -90,3 +130,5 @@ const char* get_msg_suffix_default(void);
const char* get_err_prefix_default(void); const char* get_err_prefix_default(void);
const char* get_err_suffix_default(void); const char* get_err_suffix_default(void);
const char* get_logpath_default(void); const char* get_logpath_default(void);
#endif /** LOG_MANAGER_H */

View File

@ -1,5 +1,5 @@
/* /*
* This file is distributed as part of the SkySQL Gateway. It is free * 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 * 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, * GNU General Public License as published by the Free Software Foundation,
* version 2. * version 2.
@ -13,7 +13,7 @@
* this program; if not, write to the Free Software Foundation, Inc., 51 * this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* *
* Copyright SkySQL Ab 2013 * Copyright MariaDB Corporation Ab 2013-2014
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* This file is distributed as part of the SkySQL Gateway. It is free * 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 * 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, * GNU General Public License as published by the Free Software Foundation,
* version 2. * version 2.
@ -13,7 +13,7 @@
* this program; if not, write to the Free Software Foundation, Inc., 51 * this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* *
* Copyright SkySQL Ab 2013 * Copyright MariaDB Corporation Ab 2013-2014
*/ */
#include <unistd.h> #include <unistd.h>
@ -33,7 +33,8 @@ int main(int argc, char** argv)
char *message; char *message;
char** optstr; char** optstr;
long msg_index = 1; long msg_index = 1;
struct timespec ts1;
ts1.tv_sec = 0;
memset(cwd,0,1024); memset(cwd,0,1024);
if( argc <4){ if( argc <4){
@ -45,8 +46,9 @@ int main(int argc, char** argv)
} }
block_size = atoi(argv[3]); block_size = atoi(argv[3]);
if(block_size < 1){ if(block_size < 1 || block_size > 1024){
fprintf(stderr,"Message size too small, must be at least 1 byte long."); fprintf(stderr,"Message size too small or large, must be at least 1 byte long and must not exceed 1024 bytes.");
return 1;
} }
@ -78,7 +80,12 @@ int main(int argc, char** argv)
for(i = 0;i<iterations;i++){ for(i = 0;i<iterations;i++){
sprintf(message,"message|%ld",msg_index++); sprintf(message,"message|%ld",msg_index++);
memset(message + strlen(message),' ',block_size - strlen(message)); int msgsize = block_size - strlen(message);
if(msgsize < 0 || msgsize > 8192){
fprintf(stderr,"Error: Message too long");
break;
}
memset(message + strlen(message), ' ', msgsize);
memset(message + block_size - 1,'\0',1); memset(message + block_size - 1,'\0',1);
if(interval > 0 && i % interval == 0){ if(interval > 0 && i % interval == 0){
err = skygw_log_write_flush(LOGFILE_ERROR, message); err = skygw_log_write_flush(LOGFILE_ERROR, message);
@ -89,8 +96,8 @@ int main(int argc, char** argv)
fprintf(stderr,"Error: log_manager returned %d",err); fprintf(stderr,"Error: log_manager returned %d",err);
break; break;
} }
usleep(100); ts1.tv_nsec = 100*1000000;
//printf("%s\n",message); nanosleep(&ts1, NULL);
} }
skygw_log_flush(LOGFILE_ERROR); skygw_log_flush(LOGFILE_ERROR);

View File

@ -1,11 +1,17 @@
function(debugmsg MSG)
if(DEBUG_OUTPUT)
message(STATUS "DEBUG: ${MSG}")
endif()
endfunction()
macro(set_maxscale_version) macro(set_maxscale_version)
#MaxScale version number #MaxScale version number
set(MAXSCALE_VERSION_MAJOR "1") set(MAXSCALE_VERSION_MAJOR "1")
set(MAXSCALE_VERSION_MINOR "0") set(MAXSCALE_VERSION_MINOR "0")
set(MAXSCALE_VERSION_PATCH "1") set(MAXSCALE_VERSION_PATCH "4")
set(MAXSCALE_VERSION_NUMERIC "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}") set(MAXSCALE_VERSION_NUMERIC "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")
set(MAXSCALE_VERSION "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}-beta") set(MAXSCALE_VERSION "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}-stable")
endmacro() endmacro()
@ -21,17 +27,20 @@ macro(set_variables)
set(TEST_HOST "127.0.0.1" CACHE STRING "hostname or IP address of MaxScale's host") set(TEST_HOST "127.0.0.1" CACHE STRING "hostname or IP address of MaxScale's host")
# port of read connection router module # port of read connection router module
set(TEST_PORT_RW "4008" CACHE STRING "port of read connection router module") set(TEST_PORT "4008" CACHE STRING "port of read connection router module")
# port of read/write split router module # port of read/write split router module
set(TEST_PORT_RW "4006" CACHE STRING "port of read/write split router module") set(TEST_PORT_RW "4006" CACHE STRING "port of read/write split router module")
# port of read/write split router module with hints # port of read/write split router module with hints
set(TEST_PORT_RW_HINT "4006" CACHE STRING "port of read/write split router module with hints") set(TEST_PORT_RW_HINT "4009" CACHE STRING "port of read/write split router module with hints")
# master test server server_id # master test server server_id
set(TEST_MASTER_ID "3000" CACHE STRING "master test server server_id") set(TEST_MASTER_ID "3000" CACHE STRING "master test server server_id")
# master test server port
set(MASTER_PORT "3000" CACHE STRING "master test server port")
# username of MaxScale user # username of MaxScale user
set(TEST_USER "maxuser" CACHE STRING "username of MaxScale user") set(TEST_USER "maxuser" CACHE STRING "username of MaxScale user")
@ -51,17 +60,18 @@ macro(set_variables)
set(INSTALL_SYSTEM_FILES TRUE CACHE BOOL "Install init.d scripts and ldconf configuration files") set(INSTALL_SYSTEM_FILES TRUE CACHE BOOL "Install init.d scripts and ldconf configuration files")
# Build tests # Build tests
set(BUILD_TESTS TRUE CACHE BOOL "Build tests") set(BUILD_TESTS FALSE CACHE BOOL "Build tests")
endmacro() endmacro()
macro(check_deps) macro(check_deps)
# Check for libraries MaxScale depends on # Check for libraries MaxScale depends on
set(MAXSCALE_DEPS aio ssl crypt crypto z m dl rt pthread) set(MAXSCALE_DEPS aio ssl crypt crypto z m dl rt pthread)
foreach(lib ${MAXSCALE_DEPS}) foreach(lib ${MAXSCALE_DEPS})
find_library(lib${lib} ${lib}) find_library(lib${lib} ${lib})
if((DEFINED lib${lib}) AND (${lib${lib}} STREQUAL "lib${lib}-NOTFOUND")) if((DEFINED lib${lib}) AND (${lib${lib}} MATCHES "NOTFOUND"))
set(DEPS_ERROR TRUE) set(DEPS_ERROR TRUE)
set(FAILED_DEPS "${FAILED_DEPS} lib${lib}") set(FAILED_DEPS "${FAILED_DEPS} lib${lib}")
elseif(DEBUG_OUTPUT) elseif(DEBUG_OUTPUT)
@ -82,79 +92,105 @@ macro(check_dirs)
set(DEPS_OK TRUE CACHE BOOL "If all the dependencies were found.") set(DEPS_OK TRUE CACHE BOOL "If all the dependencies were found.")
# Find the MySQL headers if they were not defined # Find the MySQL headers if they were not defined
if(DEFINED MYSQL_DIR) if(DEFINED MYSQL_DIR)
if(DEBUG_OUTPUT) debugmsg("Searching for MySQL headers at: ${MYSQL_DIR}")
message(STATUS "Searching for MySQL headers at: ${MYSQL_DIR}")
endif()
find_path(MYSQL_DIR_LOC mysql.h PATHS ${MYSQL_DIR} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH) find_path(MYSQL_DIR_LOC mysql.h PATHS ${MYSQL_DIR} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH)
endif() else()
find_path(MYSQL_DIR_LOC mysql.h PATH_SUFFIXES mysql mariadb) find_path(MYSQL_DIR_LOC mysql.h PATH_SUFFIXES mysql mariadb)
if(DEBUG_OUTPUT)
message(STATUS "Search returned: ${MYSQL_DIR_LOC}")
endif() endif()
if(${MYSQL_DIR_LOC} STREQUAL "MYSQL_DIR_LOC-NOTFOUND")
debugmsg("Search returned: ${MYSQL_DIR_LOC}")
if(${MYSQL_DIR_LOC} MATCHES "NOTFOUND")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
message(FATAL_ERROR "Fatal Error: MySQL headers were not found.") message(FATAL_ERROR "Fatal Error: MySQL headers were not found.")
else() else()
message(STATUS "Using MySQL headers found at: ${MYSQL_DIR}")
set(MYSQL_DIR ${MYSQL_DIR_LOC} CACHE PATH "Path to MySQL headers" FORCE) set(MYSQL_DIR ${MYSQL_DIR_LOC} CACHE PATH "Path to MySQL headers" FORCE)
message(STATUS "Using MySQL headers found at: ${MYSQL_DIR}")
endif() endif()
set(MYSQL_DIR_LOC "" INTERNAL)
unset(MYSQL_DIR_LOC)
# Find the errmsg.sys file if it was not defied # Find the errmsg.sys file if it was not defied
if( DEFINED ERRMSG ) if( DEFINED ERRMSG )
find_file(ERRMSG_FILE errmsg.sys PATHS ${ERRMSG} NO_DEFAULT_PATH) debugmsg("Looking for errmsg.sys at: ${ERRMSG}")
if(NOT(IS_DIRECTORY ${ERRMSG}))
get_filename_component(ERRMSG ${ERRMSG} PATH)
debugmsg("Path to file is: ${ERRMSG}")
endif() endif()
find_file(ERRMSG_FILE errmsg.sys PATHS ${ERRMSG} NO_DEFAULT_PATH)
if(${ERRMSG_FILE} MATCHES "NOTFOUND")
message(FATAL_ERROR "Fatal Error: The errmsg.sys file was not found at ${ERRMSG}")
else()
message(STATUS "Using custom errmsg.sys found at: ${ERRMSG_FILE}")
endif()
else()
find_file(ERRMSG_FILE errmsg.sys PATHS /usr/share/mysql /usr/local/share/mysql PATH_SUFFIXES english) find_file(ERRMSG_FILE errmsg.sys PATHS /usr/share/mysql /usr/local/share/mysql PATH_SUFFIXES english)
if(${ERRMSG_FILE} MATCHES "ERRMSG_FILE-NOTFOUND") if(${ERRMSG_FILE} MATCHES "NOTFOUND")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
message(FATAL_ERROR "Fatal Error: The errmsg.sys file was not found, please define the path to it by using -DERRMSG=<path>") message(FATAL_ERROR "Fatal Error: The errmsg.sys file was not found, please define the path to it by using -DERRMSG=<path>")
else() else()
message(STATUS "Using errmsg.sys found at: ${ERRMSG_FILE}") message(STATUS "Using errmsg.sys found at: ${ERRMSG_FILE}")
endif() endif()
endif()
set(ERRMSG ${ERRMSG_FILE} CACHE FILEPATH "Path to the errmsg.sys file." FORCE) set(ERRMSG ${ERRMSG_FILE} CACHE FILEPATH "Path to the errmsg.sys file." FORCE)
set(ERRMSG_FILE "" INTERNAL) unset(ERRMSG_FILE)
# Find the embedded mysql library # 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.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) if(STATIC_EMBEDDED)
debugmsg("Using the static embedded library...")
set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
if (DEFINED EMBEDDED_LIB) if (DEFINED EMBEDDED_LIB)
if(DEBUG_OUTPUT) debugmsg("Searching for libmysqld.a at: ${EMBEDDED_LIB}")
message(STATUS "Searching for libmysqld.a at: ${EMBEDDED_LIB}")
endif()
find_library(EMBEDDED_LIB_STATIC libmysqld.a PATHS ${EMBEDDED_LIB} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH) find_library(EMBEDDED_LIB_STATIC libmysqld.a PATHS ${EMBEDDED_LIB} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH)
else() else()
find_library(EMBEDDED_LIB_STATIC libmysqld.a PATH_SUFFIXES mysql mariadb) find_library(EMBEDDED_LIB_STATIC libmysqld.a PATH_SUFFIXES mysql mariadb)
endif() endif()
if(DEBUG_OUTPUT) debugmsg("Search returned: ${EMBEDDED_LIB_STATIC}")
message(STATUS "Search returned: ${EMBEDDED_LIB_STATIC}")
endif()
set(EMBEDDED_LIB ${EMBEDDED_LIB_STATIC} CACHE FILEPATH "Path to libmysqld" FORCE) set(EMBEDDED_LIB ${EMBEDDED_LIB_STATIC} CACHE FILEPATH "Path to libmysqld" FORCE)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES})
set(OLD_SUFFIXES "" INTERNAL)
else() else()
debugmsg("Using the dynamic embedded library...")
set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".so")
if (DEFINED EMBEDDED_LIB) if (DEFINED EMBEDDED_LIB)
if(DEBUG_OUTPUT) debugmsg("Searching for libmysqld.so at: ${EMBEDDED_LIB}")
message(STATUS "Searching for libmysqld.so at: ${EMBEDDED_LIB}")
endif()
find_library(EMBEDDED_LIB_DYNAMIC mysqld PATHS ${EMBEDDED_LIB} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH) find_library(EMBEDDED_LIB_DYNAMIC mysqld PATHS ${EMBEDDED_LIB} PATH_SUFFIXES mysql mariadb NO_DEFAULT_PATH)
else() else()
find_library(EMBEDDED_LIB_DYNAMIC mysqld PATH_SUFFIXES mysql mariadb) find_library(EMBEDDED_LIB_DYNAMIC mysqld PATH_SUFFIXES mysql mariadb)
endif() endif()
if(DEBUG_OUTPUT) debugmsg("Search returned: ${EMBEDDED_LIB_DYNAMIC}")
message(STATUS "Search returned: ${EMBEDDED_LIB_DYNAMIC}")
endif()
set(EMBEDDED_LIB ${EMBEDDED_LIB_DYNAMIC} CACHE FILEPATH "Path to libmysqld" FORCE) set(EMBEDDED_LIB ${EMBEDDED_LIB_DYNAMIC} CACHE FILEPATH "Path to libmysqld" FORCE)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES})
endif() endif()
set(EMBEDDED_LIB_DYNAMIC "" INTERNAL)
set(EMBEDDED_LIB_STATIC "" INTERNAL) unset(EMBEDDED_LIB_DYNAMIC)
unset(EMBEDDED_LIB_STATIC)
unset(OLD_SUFFIXES)
# Inform the user about the embedded library # Inform the user about the embedded library
if( (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_STATIC-NOTFOUND") OR (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_DYNAMIC-NOTFOUND")) if( (${EMBEDDED_LIB} MATCHES "NOTFOUND") OR (${EMBEDDED_LIB} MATCHES "NOTFOUND"))
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") 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=<path to library>") 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=<path to library>")
else() else()
@ -176,43 +212,63 @@ macro(check_dirs)
else() else()
set(DEB_BASED FALSE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.") set(DEB_BASED FALSE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.")
endif() endif()
set(DEB_FNC "" INTERNAL) unset(DEB_FNC)
set(RPM_FNC "" INTERNAL) unset(RPM_FNC)
#Find the MySQL client library
# find_library(MYSQLCLIENT_LIBRARIES NAMES mysqlclient PATH_SUFFIXES mysql mariadb)
# if(${MYSQLCLIENT_LIBRARIES} MATCHES "NOTFOUND")
# set(MYSQLCLIENT_FOUND FALSE CACHE INTERNAL "")
# message(STATUS "Cannot find MySQL client library: Login tests disabled.")
# else()
# set(MYSQLCLIENT_FOUND TRUE CACHE INTERNAL "")
# message(STATUS "Found MySQL client library: ${MYSQLCLIENT_LIBRARIES}")
# endif()
#Check RabbitMQ headers and libraries #Check RabbitMQ headers and libraries
if(BUILD_RABBITMQ) if(BUILD_RABBITMQ)
find_package(RabbitMQ)
if(DEFINED RABBITMQ_LIB) # include(CheckCSourceCompiles)
find_library(RMQ_LIB rabbitmq PATHS ${RABBITMQ_LIB} NO_DEFAULT_PATH) #
endif() # if(DEFINED RABBITMQ_LIB)
find_library(RMQ_LIB rabbitmq) # find_library(RMQ_LIB rabbitmq PATHS ${RABBITMQ_LIB} NO_DEFAULT_PATH)
if(RMQ_LIB STREQUAL "RMQ_LIB-NOTFOUND") # else()
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") # find_library(RMQ_LIB rabbitmq)
message(FATAL_ERROR "Cannot find RabbitMQ libraries, please define the path to the libraries with -DRABBITMQ_LIB=<path>") # endif()
else() # if(RMQ_LIB MATCHES "NOTFOUND")
set(RABBITMQ_LIB ${RMQ_LIB} CACHE PATH "Path to RabbitMQ libraries" FORCE) # set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
message(STATUS "Using RabbitMQ libraries found at: ${RABBITMQ_LIB}") # message(FATAL_ERROR "Cannot find RabbitMQ libraries, please define the path to the libraries with -DRABBITMQ_LIB=<path>")
endif() # else()
# set(RABBITMQ_LIB ${RMQ_LIB} CACHE PATH "Path to RabbitMQ libraries" FORCE)
if(DEFINED RABBITMQ_HEADERS) # message(STATUS "Using RabbitMQ libraries found at: ${RABBITMQ_LIB}")
find_file(RMQ_HEADERS amqp.h PATHS ${RABBITMQ_HEADERS} NO_DEFAULT_PATH) # endif()
endif() #
find_file(RMQ_HEADERS amqp.h) # if(DEFINED RABBITMQ_HEADERS)
if(RMQ_HEADERS STREQUAL "RMQ_HEADERS-NOTFOUND") # find_file(RMQ_HEADERS amqp.h PATHS ${RABBITMQ_HEADERS} NO_DEFAULT_PATH)
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") # else()
message(FATAL_ERROR "Cannot find RabbitMQ headers, please define the path to the headers with -DRABBITMQ_HEADERS=<path>") # find_file(RMQ_HEADERS amqp.h)
else() # endif()
set(RABBITMQ_HEADERS ${RMQ_HEADERS} CACHE PATH "Path to RabbitMQ headers" FORCE) # if(RMQ_HEADERS MATCHES "NOTFOUND")
message(STATUS "Using RabbitMQ headers found at: ${RABBITMQ_HEADERS}") # set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
endif() # message(FATAL_ERROR "Cannot find RabbitMQ headers, please define the path to the headers with -DRABBITMQ_HEADERS=<path>")
# else()
# set(RABBITMQ_HEADERS ${RMQ_HEADERS} CACHE PATH "Path to RabbitMQ headers" FORCE)
# message(STATUS "Using RabbitMQ headers found at: ${RABBITMQ_HEADERS}")
# endif()
#
# set(CMAKE_REQUIRED_INCLUDES ${RABBITMQ_HEADERS})
# check_c_source_compiles("#include <amqp.h>\n int main(){if(AMQP_DELIVERY_PERSISTENT){return 0;}return 1;}" HAVE_RMQ50)
# if(NOT HAVE_RMQ50)
# message(FATAL_ERROR "Old version of RabbitMQ-C library found. Version 0.5 or newer is required.")
# endif()
#
endif() endif()
endmacro() endmacro()
function(subdirs VAR DIRPATH) function(subdirs VAR DIRPATH)
if(${CMAKE_VERSION} VERSION_LESS 2.12 ) if(${CMAKE_VERSION} VERSION_LESS 2.8.12 )
set(COMP_VAR PATH) set(COMP_VAR PATH)
else() else()
set(COMP_VAR DIRECTORY) set(COMP_VAR DIRECTORY)

View File

@ -25,7 +25,7 @@ endif
# -O2 -g -pipe -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -fPIC # -O2 -g -pipe -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -fPIC
CFLAGS := $(CFLAGS) -Wall CFLAGS := $(CFLAGS) -Wall
LDLIBS := $(LDLIBS) -pthread LDLIBS := $(LDLIBS) -pthread -lm
LDMYSQL := -lmysqld LDMYSQL := -lmysqld
CPP_LDLIBS := -lstdc++ CPP_LDLIBS := -lstdc++

View File

@ -1,5 +1,4 @@
add_library(query_classifier SHARED query_classifier.cc) add_library(query_classifier SHARED query_classifier.cc)
target_link_libraries(query_classifier ${EMBEDDED_LIB})
install(TARGETS query_classifier DESTINATION lib) install(TARGETS query_classifier DESTINATION lib)
if(BUILD_TESTS) if(BUILD_TESTS)
add_subdirectory(test) add_subdirectory(test)

View File

@ -1,7 +1,7 @@
/** /**
* @section LICENCE * @section LICENCE
* *
* This file is distributed as part of the SkySQL Gateway. It is * This file is distributed as part of the MariaDB Corporation MaxScale. It is
* free software: you can redistribute it and/or modify it under * free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the * the terms of the GNU General Public License as published by the
* Free Software Foundation, version 2. * Free Software Foundation, version 2.
@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA. * 02110-1301 USA.
* *
* Copyright SkySQL Ab * Copyright MariaDB Corporation Ab
* *
* @file * @file
* *
@ -30,12 +30,7 @@
# undef MYSQL_CLIENT # undef MYSQL_CLIENT
#endif #endif
#include <query_classifier.h> #include <my_config.h>
#include "../utils/skygw_types.h"
#include "../utils/skygw_debug.h"
#include <log_manager.h>
#include <mysql_client_server_protocol.h>
#include <mysql.h> #include <mysql.h>
#include <my_sys.h> #include <my_sys.h>
#include <my_global.h> #include <my_global.h>
@ -55,12 +50,20 @@
#include <strfunc.h> #include <strfunc.h>
#include <item_func.h> #include <item_func.h>
#include "../utils/skygw_types.h"
#include "../utils/skygw_debug.h"
#include <log_manager.h>
#include <query_classifier.h>
#include <mysql_client_server_protocol.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
extern int lm_enabled_logfiles_bitmask; extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
extern __thread log_info_t tls_log_info;
#define QTYPE_LESS_RESTRICTIVE_THAN_WRITE(t) (t<QUERY_TYPE_WRITE ? true : false) #define QTYPE_LESS_RESTRICTIVE_THAN_WRITE(t) (t<QUERY_TYPE_WRITE ? true : false)
@ -148,7 +151,7 @@ bool parse_query (
THD* thd; THD* thd;
uint8_t* data; uint8_t* data;
size_t len; size_t len;
char* query_str; char* query_str = NULL;
parsing_info_t* pi; parsing_info_t* pi;
CHK_GWBUF(querybuf); CHK_GWBUF(querybuf);
@ -170,9 +173,9 @@ bool parse_query (
/** Extract query and copy it to different buffer */ /** Extract query and copy it to different buffer */
data = (uint8_t*)GWBUF_DATA(querybuf); data = (uint8_t*)GWBUF_DATA(querybuf);
len = MYSQL_GET_PACKET_LEN(data)-1; /*< distract 1 for packet type byte */ len = MYSQL_GET_PACKET_LEN(data)-1; /*< distract 1 for packet type byte */
query_str = (char *)malloc(len+1);
if (query_str == NULL)
if (len < 1 || len >= ~((size_t)0) - 1 || (query_str = (char *)malloc(len+1)) == NULL)
{ {
/** Free parsing info data */ /** Free parsing info data */
parsing_info_done(pi); parsing_info_done(pi);
@ -359,50 +362,29 @@ static bool create_parse_tree(
Parser_state parser_state; Parser_state parser_state;
bool failp = FALSE; bool failp = FALSE;
const char* virtual_db = "skygw_virtual"; const char* virtual_db = "skygw_virtual";
#if defined(SS_DEBUG_EXTRA)
LOGIF(LM, (skygw_log_write_flush( if (parser_state.init(thd, thd->query(), thd->query_length()))
LOGFILE_MESSAGE, {
"[readwritesplit:create_parse_tree] 1.")));
#endif
if (parser_state.init(thd, thd->query(), thd->query_length())) {
failp = TRUE; failp = TRUE;
goto return_here; goto return_here;
} }
#if defined(SS_DEBUG_EXTRA)
LOGIF(LM, (skygw_log_write_flush(
LOGFILE_MESSAGE,
"[readwritesplit:create_parse_tree] 2.")));
#endif
mysql_reset_thd_for_next_command(thd); mysql_reset_thd_for_next_command(thd);
#if defined(SS_DEBUG_EXTRA)
LOGIF(LM, (skygw_log_write_flush(
LOGFILE_MESSAGE,
"[readwritesplit:create_parse_tree] 3.")));
#endif
/** /**
* Set some database to thd so that parsing won't fail because of * Set some database to thd so that parsing won't fail because of
* missing database. Then parse. * missing database. Then parse.
*/ */
failp = thd->set_db(virtual_db, strlen(virtual_db)); failp = thd->set_db(virtual_db, strlen(virtual_db));
#if defined(SS_DEBUG_EXTRA) if (failp)
LOGIF(LM, (skygw_log_write_flush( {
LOGFILE_MESSAGE,
"[readwritesplit:create_parse_tree] 4.")));
#endif
if (failp) {
LOGIF(LE, (skygw_log_write_flush( LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR, LOGFILE_ERROR,
"Error : Failed to set database in thread context."))); "Error : Failed to set database in thread context.")));
} }
failp = parse_sql(thd, &parser_state, NULL); failp = parse_sql(thd, &parser_state, NULL);
#if defined(SS_DEBUG_EXTRA) if (failp)
LOGIF(LM, (skygw_log_write_flush( {
LOGFILE_MESSAGE,
"[readwritesplit:create_parse_tree] 5.")));
#endif
if (failp) {
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG, LOGFILE_DEBUG,
"%lu [readwritesplit:create_parse_tree] failed to " "%lu [readwritesplit:create_parse_tree] failed to "
@ -414,16 +396,14 @@ return_here:
} }
/** /**
* @node Set new query type if new is more restrictive than old. * Set new query type if new is more restrictive than old.
* *
* Parameters: * Parameters:
* @param qtype - <usage> * @param qtype Existing type
* <description>
* *
* @param new_type - <usage> * @param new_type New query type
* <description>
* *
* @return * @return Query type as an unsigned int value which must be casted to qtype.
* *
* *
* @details The implementation relies on that enumerated values correspond * @details The implementation relies on that enumerated values correspond
@ -440,13 +420,11 @@ static u_int32_t set_query_type(
} }
/** /**
* @node Detect query type, read-only, write, or session update * Detect query type by examining parsed representation of it.
* *
* Parameters: * @param thd MariaDB thread context.
* @param thd - <usage>
* <description>
* *
* @return * @return Copy of query type value.
* *
* *
* @details Query type is deduced by checking for certain properties * @details Query type is deduced by checking for certain properties
@ -470,11 +448,12 @@ static skygw_query_type_t resolve_query_type(
* When force_data_modify_op_replication is TRUE, gateway distributes * When force_data_modify_op_replication is TRUE, gateway distributes
* all write operations to all nodes. * all write operations to all nodes.
*/ */
#if defined(NOT_IN_USE)
bool force_data_modify_op_replication; bool force_data_modify_op_replication;
force_data_modify_op_replication = FALSE;
#endif /* NOT_IN_USE */
ss_info_dassert(thd != NULL, ("thd is NULL\n")); ss_info_dassert(thd != NULL, ("thd is NULL\n"));
force_data_modify_op_replication = FALSE;
lex = thd->lex; lex = thd->lex;
/** SELECT ..INTO variable|OUTFILE|DUMPFILE */ /** SELECT ..INTO variable|OUTFILE|DUMPFILE */
@ -584,6 +563,7 @@ static skygw_query_type_t resolve_query_type(
if (is_log_table_write_query(lex->sql_command) || if (is_log_table_write_query(lex->sql_command) ||
is_update_query(lex->sql_command)) is_update_query(lex->sql_command))
{ {
#if defined(NOT_IN_USE)
if (thd->variables.sql_log_bin == 0 && if (thd->variables.sql_log_bin == 0 &&
force_data_modify_op_replication) force_data_modify_op_replication)
{ {
@ -591,12 +571,13 @@ static skygw_query_type_t resolve_query_type(
type |= QUERY_TYPE_SESSION_WRITE; type |= QUERY_TYPE_SESSION_WRITE;
} }
else else
#endif /* NOT_IN_USE */
{ {
/** Written to binlog, that is, replicated except tmp tables */ /** Written to binlog, that is, replicated except tmp tables */
type |= QUERY_TYPE_WRITE; /*< to master */ type |= QUERY_TYPE_WRITE; /*< to master */
if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE && if (lex->sql_command == SQLCOM_CREATE_TABLE &&
lex->sql_command == SQLCOM_CREATE_TABLE) (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{ {
type |= QUERY_TYPE_CREATE_TMP_TABLE; /*< remember in router */ type |= QUERY_TYPE_CREATE_TMP_TABLE; /*< remember in router */
} }
@ -613,6 +594,7 @@ static skygw_query_type_t resolve_query_type(
break; break;
case SQLCOM_SELECT: case SQLCOM_SELECT:
case SQLCOM_SHOW_SLAVE_STAT:
type |= QUERY_TYPE_READ; type |= QUERY_TYPE_READ;
break; break;
@ -640,6 +622,16 @@ static skygw_query_type_t resolve_query_type(
goto return_qtype; goto return_qtype;
break; break;
case SQLCOM_SHOW_DATABASES:
type |= QUERY_TYPE_SHOW_DATABASES;
goto return_qtype;
break;
case SQLCOM_SHOW_TABLES:
type |= QUERY_TYPE_SHOW_TABLES;
goto return_qtype;
break;
default: default:
break; break;
} }
@ -823,8 +815,7 @@ static skygw_query_type_t resolve_query_type(
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG, LOGFILE_DEBUG,
"%lu [resolve_query_type] " "%lu [resolve_query_type] "
"Unknown functype %d. Something " "Functype %d.",
"has gone wrong.",
pthread_self(), pthread_self(),
ftype))); ftype)));
break; break;
@ -852,6 +843,11 @@ return_qtype:
* Checks if statement causes implicit COMMIT. * Checks if statement causes implicit COMMIT.
* autocommit_stmt gets values 1, 0 or -1 if stmt is enable, disable or * autocommit_stmt gets values 1, 0 or -1 if stmt is enable, disable or
* something else than autocommit. * something else than autocommit.
*
* @param lex Parse tree
* @param autocommit_stmt memory address for autocommit status
*
* @return true if statement causes implicit commit and false otherwise
*/ */
static bool skygw_stmt_causes_implicit_commit( static bool skygw_stmt_causes_implicit_commit(
LEX* lex, LEX* lex,
@ -881,7 +877,7 @@ static bool skygw_stmt_causes_implicit_commit(
} }
else else
{ {
succp =false; succp = false;
} }
break; break;
default: default:
@ -897,7 +893,9 @@ return_succp:
* Finds out if stmt is SET autocommit * Finds out if stmt is SET autocommit
* and if the new value matches with the enable_cmd argument. * and if the new value matches with the enable_cmd argument.
* *
* Returns 1, 0, or -1 if command was: * @param lex parse tree
*
* @return 1, 0, or -1 if command was:
* enable, disable, or not autocommit, respectively. * enable, disable, or not autocommit, respectively.
*/ */
static int is_autocommit_stmt( static int is_autocommit_stmt(
@ -968,9 +966,11 @@ char* skygw_query_classifier_get_stmtname(
} }
/** /**
*Returns the LEX struct of the parsed GWBUF * Get the parse tree from parsed querybuf.
*@param The parsed GWBUF * @param querybuf The parsed GWBUF
*@return Pointer to the LEX struct or NULL if an error occurred or the query was not parsed *
* @return Pointer to the LEX struct or NULL if an error occurred or the query
* was not parsed
*/ */
LEX* get_lex(GWBUF* querybuf) LEX* get_lex(GWBUF* querybuf)
{ {
@ -1040,10 +1040,11 @@ char** skygw_get_table_names(GWBUF* querybuf,int* tblsize, bool fullnames)
TABLE_LIST* tbl; TABLE_LIST* tbl;
int i = 0, int i = 0,
currtblsz = 0; currtblsz = 0;
char **tables, char **tables = NULL,
**tmp; **tmp = NULL;
if((lex = get_lex(querybuf)) == NULL) if( (lex = get_lex(querybuf)) == NULL ||
lex->current_select == NULL )
{ {
goto retblock; goto retblock;
} }
@ -1075,7 +1076,7 @@ char** skygw_get_table_names(GWBUF* querybuf,int* tblsize, bool fullnames)
} }
} }
if(tmp != NULL){
char *catnm = NULL; char *catnm = NULL;
if(fullnames) if(fullnames)
@ -1100,6 +1101,7 @@ char** skygw_get_table_names(GWBUF* querybuf,int* tblsize, bool fullnames)
tbl=tbl->next_local; tbl=tbl->next_local;
} }
}
lex->current_select = lex->current_select->next_select_in_list(); lex->current_select = lex->current_select->next_select_in_list();
} }
@ -1177,7 +1179,7 @@ bool is_drop_table_query(GWBUF* querybuf)
lex->sql_command == SQLCOM_DROP_TABLE; lex->sql_command == SQLCOM_DROP_TABLE;
} }
/* /**
* Replace user-provided literals with question marks. Return a copy of the * Replace user-provided literals with question marks. Return a copy of the
* querystr with replacements. * querystr with replacements.
* *
@ -1375,3 +1377,49 @@ static void parsing_info_set_plain_str(
pi->pi_query_plain_str = str; pi->pi_query_plain_str = str;
} }
/**
* Generate a string of query type value.
* Caller must free the memory of the resulting string.
*
* @param qtype Query type value, combination of values listed in
* query_classifier.h
*
* @return string representing the query type value
*/
char* skygw_get_qtype_str(
skygw_query_type_t qtype)
{
int t1 = (int)qtype;
int t2 = 1;
skygw_query_type_t t = QUERY_TYPE_UNKNOWN;
char* qtype_str = NULL;
/**
* Test values (bits) and clear matching bits from t1 one by one until
* t1 is completely cleared.
*/
while (t1 != 0)
{
if (t1&t2)
{
t = (skygw_query_type_t)t2;
if (qtype_str == NULL)
{
qtype_str = strdup(STRQTYPE(t));
}
else
{
size_t len = strlen(STRQTYPE(t));
/** reallocate space for delimiter, new string and termination */
qtype_str = (char *)realloc(qtype_str, strlen(qtype_str)+1+len+1);
snprintf(qtype_str+strlen(qtype_str), 1+len+1, "|%s", STRQTYPE(t));
}
/** Remove found value from t1 */
t1 &= ~t2;
}
t2 <<= 1;
}
return qtype_str;
}

View File

@ -1,5 +1,5 @@
/* /*
This file is distributed as part of the SkySQL Gateway. It is free 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 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, GNU General Public License as published by the Free Software Foundation,
version 2. version 2.
@ -13,11 +13,12 @@ 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 this program; if not, write to the Free Software Foundation, Inc., 51
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Copyright SkySQL Ab Copyright MariaDB Corporation Ab
*/ */
/** getpid */ /** getpid */
#include <my_config.h>
#include <unistd.h> #include <unistd.h>
#include <mysql.h> #include <mysql.h>
#include <skygw_utils.h> #include <skygw_utils.h>
@ -54,7 +55,9 @@ typedef enum {
QUERY_TYPE_PREPARE_STMT = 0x020000, /*< Prepared stmt with id provided by server:all */ QUERY_TYPE_PREPARE_STMT = 0x020000, /*< Prepared stmt with id provided by server:all */
QUERY_TYPE_EXEC_STMT = 0x040000, /*< Execute prepared statement:master or any */ QUERY_TYPE_EXEC_STMT = 0x040000, /*< Execute prepared statement:master or any */
QUERY_TYPE_CREATE_TMP_TABLE = 0x080000, /*< Create temporary table:master (could be all) */ QUERY_TYPE_CREATE_TMP_TABLE = 0x080000, /*< Create temporary table:master (could be all) */
QUERY_TYPE_READ_TMP_TABLE = 0x100000 /*< Read temporary table:master (could be any) */ QUERY_TYPE_READ_TMP_TABLE = 0x100000, /*< Read temporary table:master (could be any) */
QUERY_TYPE_SHOW_DATABASES = 0x200000, /*< Show list of databases */
QUERY_TYPE_SHOW_TABLES = 0x400000 /*< Show list of tables */
} skygw_query_type_t; } skygw_query_type_t;
@ -91,6 +94,7 @@ bool parse_query (GWBUF* querybuf);
parsing_info_t* parsing_info_init(void (*donefun)(void *)); parsing_info_t* parsing_info_init(void (*donefun)(void *));
void parsing_info_done(void* ptr); void parsing_info_done(void* ptr);
bool query_is_parsed(GWBUF* buf); bool query_is_parsed(GWBUF* buf);
char* skygw_get_qtype_str(skygw_query_type_t qtype);
EXTERN_C_BLOCK_END EXTERN_C_BLOCK_END

View File

@ -1 +1,14 @@
if(${ERRMSG} MATCHES "ERRMSG-NOTFOUND")
message(FATAL_ERROR "The errmsg.sys file was not found, please define the path with -DERRMSG=<path>")
else()
if(${CMAKE_VERSION} VERSION_LESS 2.8)
execute_process(COMMAND cp ${ERRMSG} ${CMAKE_CURRENT_BINARY_DIR})
else()
file(COPY ${ERRMSG} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
endif()
endif()
add_subdirectory(canonical_tests) add_subdirectory(canonical_tests)
add_executable(classify classify.c)
target_link_libraries(classify query_classifier fullcore)
add_test(TestQueryClassifier classify ${CMAKE_CURRENT_SOURCE_DIR}/input.sql ${CMAKE_CURRENT_SOURCE_DIR}/expected.sql)

View File

@ -1,6 +1,11 @@
file(COPY ${ERRMSG} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
if(${ERRMSG} MATCHES "ERRMSG-NOTFOUND") if(${ERRMSG} MATCHES "ERRMSG-NOTFOUND")
message(FATAL_ERROR "The errmsg.sys file was not found, please define the path with -DERRMSG=<path>") message(FATAL_ERROR "The errmsg.sys file was not found, please define the path with -DERRMSG=<path>")
else()
if(${CMAKE_VERSION} VERSION_LESS 2.8)
execute_process(COMMAND cp ${ERRMSG} ${CMAKE_CURRENT_BINARY_DIR})
else()
file(COPY ${ERRMSG} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
endif()
endif() endif()
add_executable(canonizer canonizer.c) add_executable(canonizer canonizer.c)
target_link_libraries(canonizer pthread query_classifier z dl ssl aio crypt crypto rt m ${EMBEDDED_LIB} fullcore stdc++) target_link_libraries(canonizer pthread query_classifier z dl ssl aio crypt crypto rt m ${EMBEDDED_LIB} fullcore stdc++)

View File

@ -1,3 +1,4 @@
#include <my_config.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
@ -7,7 +8,7 @@
#include <mysql.h> #include <mysql.h>
static char* server_options[] = { static char* server_options[] = {
"SkySQL Gateway", "MariaDB Corporation MaxScale",
"--datadir=./", "--datadir=./",
"--language=./", "--language=./",
"--skip-innodb", "--skip-innodb",
@ -27,95 +28,52 @@ static char* server_groups[] = {
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int fdin,fdout,i=0,fnamelen,fsz,lines = 0;
unsigned int psize; unsigned int psize;
GWBUF** qbuff; GWBUF* qbuff;
char *qin, *outnm, *buffer, *tok; char *tok;
char readbuff[4092];
FILE* infile;
FILE* outfile;
if(argc != 3){ if(argc != 3){
printf("Usage: canonizer <input file> <output file>\n"); printf("Usage: canonizer <input file> <output file>\n");
return 1; return 1;
} }
if(mysql_library_init(num_elements, server_options, server_groups)){
bool failed = mysql_library_init(num_elements, server_options, server_groups);
if(failed){
printf("Embedded server init failed.\n"); printf("Embedded server init failed.\n");
return 1; return 1;
} }
fnamelen = strlen(argv[1]) + 16; infile = fopen(argv[1],"rb");
fdin = open(argv[1],O_RDONLY); outfile = fopen(argv[2],"wb");
fsz = lseek(fdin,0,SEEK_END);
lseek(fdin,0,SEEK_SET);
if(!(buffer = malloc(sizeof(char)*fsz + 1))){ if(infile == NULL || outfile == NULL){
printf("Error: Failed to allocate memory."); printf("Opening files failed.\n");
return 1; return 1;
} }
read(fdin,buffer,fsz); while(!feof(infile))
buffer[fsz] = '\0'; {
fgets(readbuff,4092,infile);
psize = strlen(readbuff);
if(psize < 4092){
i = 0; qbuff = gwbuf_alloc(psize + 7);
int bsz = 4,z=0; *(qbuff->sbuf->data + 0) = (unsigned char)psize;
qbuff = calloc(bsz,sizeof(GWBUF*)); *(qbuff->sbuf->data + 1) = (unsigned char)(psize>>8);
tok = strtok(buffer,"\n"); *(qbuff->sbuf->data + 2) = (unsigned char)(psize>>16);
*(qbuff->sbuf->data + 4) = 0x03;
while(tok){ memcpy(qbuff->start + 5,readbuff,psize + 1);
parse_query(qbuff);
if(i>=bsz){ tok = skygw_get_canonical(qbuff);
GWBUF** tmp = calloc(bsz*2,sizeof(GWBUF*)); fprintf(outfile,"%s\n",tok);
if(!tmp){ free(tok);
printf("Error: Failed to allocate memory."); gwbuf_free(qbuff);
return 1;
}
for(z=0;z<bsz;z++){
tmp[z] = qbuff[z];
}
free(qbuff);
qbuff = tmp;
bsz *= 2;
}
if(strlen(tok) > 0){
qin = strdup(tok);
psize = strlen(qin);
qbuff[i] = gwbuf_alloc(psize + 6);
*(qbuff[i]->sbuf->data + 0) = (unsigned char)psize;
*(qbuff[i]->sbuf->data + 1) = (unsigned char)(psize>>8);
*(qbuff[i]->sbuf->data + 2) = (unsigned char)(psize>>16);
*(qbuff[i]->sbuf->data + 4) = 0x03;
memcpy(qbuff[i]->sbuf->data + 5,qin,psize);
*(qbuff[i]->sbuf->data + 5 + psize) = 0x00;
tok = strtok(NULL,"\n\0");
free(qin);
i++;
} }
} }
fclose(infile);
fdout = open(argv[2],O_TRUNC|O_CREAT|O_WRONLY,S_IRWXU|S_IXGRP|S_IXOTH); fclose(outfile);
mysql_library_end();
for(i = 0;i<bsz;i++){
if(qbuff[i]){
parse_query(qbuff[i]);
tok = skygw_get_canonical(qbuff[i]);
write(fdout,tok,strlen(tok));
write(fdout,"\n",1);
gwbuf_free(qbuff[i]);
}
}
free(qbuff);
free(buffer);
close(fdin);
close(fdout);
return 0; return 0;
} }

View File

@ -1,17 +1,18 @@
select md5("?") =?, sleep(?), rand(?) select md5("?") =?, sleep(?), rand(?);
select * from my1 where md5("?") =? select * from my1 where md5("?") =?;
select md5("?") =? select md5("?") =?;
select * from my1 where md5("?") =? select * from my1 where md5("?") =?;
select sleep(?) select sleep(?);
select * from tst where lname='?' select * from tst where lname='?';
select ?,?,?,?,?,? from tst select ?,?,?,?,?,? from tst;
select * from tst where fname like '?' select * from tst where fname like '?';
select * from tst where lname like '?' order by fname select * from tst where lname like '?' order by fname;
insert into tst values ("?","?"),("?",?),("?","?") insert into tst values ("?","?"),("?",?),("?","?");
drop table if exists tst drop table if exists tst;
create table tst(fname varchar(30), lname varchar(30)) create table tst(fname varchar(30), lname varchar(30));
update tst set lname="?" where fname like '?' or lname like '?' update tst set lname="?" where fname like '?' or lname like '?';
delete from tst where lname like '?' and fname like '?' delete from tst where lname like '?' and fname like '?';
select ? from tst where fname='?' or lname like '?' select ? from tst where fname='?' or lname like '?';
select ?,?,?,? from tst where name='?' or name='?' or name='?' or name='?' select ?,?,?,? from tst where name='?' or name='?' or name='?' or name='?';
select count(?),count(?),count(?),count(?),count (?),count(?) from tst select count(?),count(?),count(?),count(?),count (?),count(?) from tst;
select count(?),count(?),count(?),count(?),count (?),count(?) from tst;

View File

@ -0,0 +1,181 @@
#include <my_config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <query_classifier.h>
#include <buffer.h>
#include <mysql.h>
#include <unistd.h>
static char* server_options[] = {
"MariaDB Corporation MaxScale",
"--no-defaults",
"--datadir=.",
"--language=.",
"--skip-innodb",
"--default-storage-engine=myisam",
NULL
};
const int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
static char* server_groups[] = {
"embedded",
"server",
"server",
NULL
};
int main(int argc, char** argv)
{
if(argc < 3){
fprintf(stderr,"Usage: classify <input> <expected output>");
return 1;
}
int rd = 0,buffsz = getpagesize(),strsz = 0,ex_val = 0;
char buffer[1024], *strbuff = (char*)calloc(buffsz,sizeof(char));
FILE *input,*expected;
if(mysql_library_init(num_elements, server_options, server_groups))
{
printf("Error: Cannot initialize Embedded Library.");
return 1;
}
input = fopen(argv[1],"rb");
expected = fopen(argv[2],"rb");
while((rd = fread(buffer,sizeof(char),1023,input))){
/**Fill the read buffer*/
if(strsz + rd >= buffsz){
char* tmp = realloc(strbuff,(buffsz*2)*sizeof(char));
if(tmp == NULL){
free(strbuff);
fclose(input);
fclose(expected);
mysql_library_end();
fprintf(stderr,"Error: Memory allocation failed.");
return 1;
}
strbuff = tmp;
buffsz *= 2;
}
memcpy(strbuff+strsz,buffer,rd);
strsz += rd;
*(strbuff+strsz) = '\0';
char *tok,*nlptr;
/**Remove newlines*/
while((nlptr = strpbrk(strbuff,"\n")) != NULL && (nlptr - strbuff) < strsz){
memmove(nlptr,nlptr+1,strsz - (nlptr + 1 - strbuff));
strsz -= 1;
}
/**Parse read buffer for full queries*/
while(strpbrk(strbuff,";") != NULL){
tok = strpbrk(strbuff,";");
unsigned int qlen = tok - strbuff + 1;
GWBUF* buff = gwbuf_alloc(qlen+6);
*((unsigned char*)(buff->start)) = qlen;
*((unsigned char*)(buff->start + 1)) = (qlen >> 8);
*((unsigned char*)(buff->start + 2)) = (qlen >> 16);
*((unsigned char*)(buff->start + 3)) = 0x00;
*((unsigned char*)(buff->start + 4)) = 0x03;
memcpy(buff->start+5, strbuff, qlen);
memmove(strbuff,tok + 1, strsz - qlen);
strsz -= qlen;
memset(strbuff + strsz,0,buffsz - strsz);
skygw_query_type_t type = query_classifier_get_type(buff);
char qtypestr[64];
char expbuff[256];
int expos = 0;
while((rd = fgetc(expected)) != '\n' && !feof(expected)){
expbuff[expos++] = rd;
}
expbuff[expos] = '\0';
if(type == QUERY_TYPE_UNKNOWN){
sprintf(qtypestr,"QUERY_TYPE_UNKNOWN");
}
if(type & QUERY_TYPE_LOCAL_READ){
sprintf(qtypestr,"QUERY_TYPE_LOCAL_READ");
}
if(type & QUERY_TYPE_READ){
sprintf(qtypestr,"QUERY_TYPE_READ");
}
if(type & QUERY_TYPE_WRITE){
sprintf(qtypestr,"QUERY_TYPE_WRITE");
}
if(type & QUERY_TYPE_MASTER_READ){
sprintf(qtypestr,"QUERY_TYPE_MASTER_READ");
}
if(type & QUERY_TYPE_SESSION_WRITE){
sprintf(qtypestr,"QUERY_TYPE_SESSION_WRITE");
}
if(type & QUERY_TYPE_USERVAR_READ){
sprintf(qtypestr,"QUERY_TYPE_USERVAR_READ");
}
if(type & QUERY_TYPE_SYSVAR_READ){
sprintf(qtypestr,"QUERY_TYPE_SYSVAR_READ");
}
if(type & QUERY_TYPE_GSYSVAR_READ){
sprintf(qtypestr,"QUERY_TYPE_GSYSVAR_READ");
}
if(type & QUERY_TYPE_GSYSVAR_WRITE){
sprintf(qtypestr,"QUERY_TYPE_GSYSVAR_WRITE");
}
if(type & QUERY_TYPE_BEGIN_TRX){
sprintf(qtypestr,"QUERY_TYPE_BEGIN_TRX");
}
if(type & QUERY_TYPE_ENABLE_AUTOCOMMIT){
sprintf(qtypestr,"QUERY_TYPE_ENABLE_AUTOCOMMIT");
}
if(type & QUERY_TYPE_DISABLE_AUTOCOMMIT){
sprintf(qtypestr,"QUERY_TYPE_DISABLE_AUTOCOMMIT");
}
if(type & QUERY_TYPE_ROLLBACK){
sprintf(qtypestr,"QUERY_TYPE_ROLLBACK");
}
if(type & QUERY_TYPE_COMMIT){
sprintf(qtypestr,"QUERY_TYPE_COMMIT");
}
if(type & QUERY_TYPE_PREPARE_NAMED_STMT){
sprintf(qtypestr,"QUERY_TYPE_PREPARE_NAMED_STMT");
}
if(type & QUERY_TYPE_PREPARE_STMT){
sprintf(qtypestr,"QUERY_TYPE_PREPARE_STMT");
}
if(type & QUERY_TYPE_EXEC_STMT){
sprintf(qtypestr,"QUERY_TYPE_EXEC_STMT");
}
if(type & QUERY_TYPE_CREATE_TMP_TABLE){
sprintf(qtypestr,"QUERY_TYPE_CREATE_TMP_TABLE");
}
if(type & QUERY_TYPE_READ_TMP_TABLE){
sprintf(qtypestr,"QUERY_TYPE_READ_TMP_TABLE");
}
if(strcmp(qtypestr,expbuff) != 0){
printf("Error in output: '%s' was expected but got '%s'",expbuff,qtypestr);
ex_val = 1;
}
gwbuf_free(buff);
}
}
fclose(input);
fclose(expected);
mysql_library_end();
free(strbuff);
return ex_val;
}

View File

@ -0,0 +1,13 @@
QUERY_TYPE_READ
QUERY_TYPE_READ
QUERY_TYPE_WRITE
QUERY_TYPE_WRITE
QUERY_TYPE_CREATE_TMP_TABLE
QUERY_TYPE_GSYSVAR_WRITE
QUERY_TYPE_SYSVAR_READ
QUERY_TYPE_USERVAR_READ
QUERY_TYPE_COMMIT
QUERY_TYPE_DISABLE_AUTOCOMMIT
QUERY_TYPE_BEGIN_TRX
QUERY_TYPE_ROLLBACK
QUERY_TYPE_COMMIT

View File

@ -0,0 +1,13 @@
select sleep(2);
select * from tst where lname like '%e%' order by fname;
insert into tst values ("Jane","Doe"),("Daisy","Duck"),("Marie","Curie");
update tst set fname="Farmer", lname="McDonald" where lname="%Doe" and fname="John";
create temporary table tmp as select * from t1;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
select @@server_id;
select @OLD_SQL_NOTES;
SET autocommit=1;
SET autocommit=0;
BEGIN;
ROLLBACK;
COMMIT;

View File

@ -13,7 +13,7 @@ static char datadir[1024] = "";
static char mysqldir[1024] = ""; static char mysqldir[1024] = "";
static char* server_options[] = { static char* server_options[] = {
"SkySQL Gateway", "MariaDB Corporation MaxScale",
"--datadir=", "--datadir=",
"--default-storage-engine=myisam", "--default-storage-engine=myisam",
NULL NULL

View File

@ -1,19 +1,17 @@
if (NOT ( DEFINED MYSQL_CLIENT_LIB ) ) if(RABBITMQ_FOUND AND MYSQLCLIENT_FOUND)
find_library(MYSQL_CLIENT_LIB NAMES mysqlclient PATHS /usr/lib /usr/lib64 PATH_SUFFIXES mysql mariadb)
endif()
if (NOT ( DEFINED MYSQL_CLIENT_HEADERS ) ) include_directories(${MYSQLCLIENT_HEADERS})
find_path(MYSQL_CLIENT_HEADERS NAMES mysql.h PATH_SUFFIXES mysql mariadb)
endif()
if( ( RABBITMQ_LIB AND RABBITMQ_HEADERS ) AND ( NOT ( ${MYSQL_CLIENT_LIB} STREQUAL "MYSQL_CLIENT_LIB-NOTFOUND" ) ) AND ( NOT ( ${MYSQL_CLIENT_HEADERS} STREQUAL "MYSQL_CLIENT_HEADERS-NOTFOUND" ) ) )
include_directories(${MYSQL_CLIENT_HEADERS})
add_executable (consumer consumer.c) add_executable (consumer consumer.c)
target_link_libraries(consumer ${MYSQL_CLIENT_LIB} rabbitmq inih)
if(MYSQLCLIENT_FOUND)
target_link_libraries(consumer ${MYSQLCLIENT_LIBRARIES} rabbitmq inih)
elseif(MYSQLCLIENT_STATIC_FOUND)
target_link_libraries(consumer ${MYSQLCLIENT_STATIC_LIBRARIES} rabbitmq inih)
endif()
install(TARGETS consumer DESTINATION bin) install(TARGETS consumer DESTINATION bin)
install(FILES consumer.cnf DESTINATION etc) install(FILES consumer.cnf DESTINATION etc)
else() else()
message(FATAL_ERROR "Error: Can not find requred libraries and headers: librabbitmq libmysqlclient") message(FATAL_ERROR "Error: Can not find requred libraries and headers: librabbitmq libmysqlclient")

View File

@ -143,7 +143,7 @@ int connectToServer(MYSQL* server)
} }
memset(qstr,0,bsz); memset(qstr,0,bsz);
sprintf(qstr,DB_TABLE); sprintf(qstr,"%s",DB_TABLE);
if(mysql_query(server,qstr)){ if(mysql_query(server,qstr)){
fprintf(stderr,"Error: Could not send query MySQL server: %s\n",mysql_error(server)); fprintf(stderr,"Error: Could not send query MySQL server: %s\n",mysql_error(server));
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
Portions of this software contain modifications contributed by SkySQL, Ab. Portions of this software contain modifications contributed by MariaDB Corporation, Ab.
These contributions are used with the following license: These contributions are used with the following license:
Copyright (c) 2013, SkySQL Ab. All rights reserved. Copyright (c) 2013, MariaDB Corporation Ab. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@ -12,7 +12,7 @@ are met:
copyright notice, this list of conditions and the following copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials disclaimer in the documentation and/or other materials
provided with the distribution. provided with the distribution.
* Neither the name of the SkySQL Ab. nor the names of its * Neither the name of the MariaDB Corporation Ab. nor the names of its
contributors may be used to endorse or promote products contributors may be used to endorse or promote products
derived from this software without specific prior written derived from this software without specific prior written
permission. permission.

Some files were not shown because too many files have changed in this diff Show More