diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..c548d8cbe --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,138 @@ +cmake_minimum_required(VERSION 2.6) + +include(macros.cmake) + +enable_testing() +set_variables() +set_maxscale_version() + +set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR}" CACHE INTERNAL "Prefix prepended to install directories." FORCE) + +project(MaxScale) + +check_deps() +check_dirs() + +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) +configure_file(${CMAKE_SOURCE_DIR}/maxscale.conf.in ${CMAKE_SOURCE_DIR}/maxscale.conf @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/etc/init.d/maxscale.in ${CMAKE_SOURCE_DIR}/etc/init.d/maxscale @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale.in ${CMAKE_SOURCE_DIR}/etc/ubuntu/init.d/maxscale @ONLY) + + +set(CMAKE_C_FLAGS "-Wall -fPIC") +set(CMAKE_CXX_FLAGS "-Wall -fPIC") + +if(BUILD_TYPE MATCHES Debug) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -pthread -pipe -DSS_DEBUG -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -pthread -pipe -DSS_DEBUG -Wformat -Werror=format-security -fstack-protector --param=ssp-buffer-size=4") + message(STATUS "Generating debugging symbols") +elseif(BUILD_TYPE MATCHES Optimized) + if(NOT (DEFINED OLEVEL)) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") + message(STATUS "Optimization level at: 2") + endif() +else() + +endif() + +if(DEFINED OLEVEL ) + if((OLEVEL GREATER -1) AND (OLEVEL LESS 4) ) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O${OLEVEL}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O${OLEVEL}") + message(STATUS "Optimization level at: ${OLEVEL}") + else() + message(WARNING "Optimization level was set to a bad value, ignoring it. (Valid values are 0-3)") + endif() +endif() + +if(GCOV) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov") +endif() + + +include_directories(${MYSQL_DIR}) +include_directories(${MYSQL_DIR}/private) +include_directories(${MYSQL_DIR}/extra) +include_directories(${MYSQL_DIR}/..) +include_directories(utils) +include_directories(log_manager) +include_directories(query_classifier) +include_directories(server/include) +include_directories(server/inih) +include_directories(server/modules/include) + +add_subdirectory(utils) +add_subdirectory(log_manager) +add_subdirectory(query_classifier) +add_subdirectory(server) +add_subdirectory(client) + + +# Install startup scripts and ldconfig files +if( NOT ( (DEFINED INSTALL_SYSTEM_FILES) AND ( NOT ( INSTALL_SYSTEM_FILES ) ) ) ) + install(FILES maxscale.conf DESTINATION /etc/ld.so.conf.d/ PERMISSIONS WORLD_EXECUTE WORLD_READ) + if(DEB_BASED) + install(FILES etc/ubuntu/init.d/maxscale DESTINATION /etc/init.d/ PERMISSIONS WORLD_EXECUTE) + else() + install(FILES etc/init.d/maxscale DESTINATION /etc/init.d/ PERMISSIONS WORLD_EXECUTE) + endif() + message(STATUS "Installing maxscale.conf to: /etc/ld.so.conf.d") + message(STATUS "Installing startup scripts to: /etc/init.d") +endif() + +file(GLOB DOCS Documentation/*.pdf) +message(STATUS "Installing MaxScale to: ${CMAKE_INSTALL_PREFIX}/") + +install(FILES server/MaxScale_template.cnf DESTINATION etc) +install(FILES ${ERRMSG} DESTINATION mysql) +install(FILES ${DOCS} DESTINATION Documentation) + +# See if we are on a RPM-capable or DEB-capable system +find_program(RPMBUILD rpmbuild) +find_program(DEBBUILD dpkg-buildpackage) + +if(NOT ( ${RPMBUILD} STREQUAL "RPMBUILD-NOTFOUND" ) ) + message(STATUS "Generating RPM packages") + set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM") +endif() + +if(NOT ( ${DEBBUILD} STREQUAL "DEBBUILD-NOTFOUND" ) ) + set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB") + execute_process(COMMAND dpgk --print-architecture OUTPUT_VARIABLE DEB_ARCHITECTURE) + set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEB_ARCHITECTURE}) + 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 "SkySQL Ab") +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 + 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 /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null" + COMMAND make test + COMMAND /bin/sh -c "killall -KILL maxscale" + COMMENT "Running full test suite") \ No newline at end of file diff --git a/README b/README index cdc9b35ac..c1ea8b066 100644 --- a/README +++ b/README @@ -152,6 +152,71 @@ max_connections=4096 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 + + 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= + +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= 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 to the embedded library location (libmysqld.a for static and libmysqld.so for dynamic) +MYSQL_DIR= Path to MySQL headers +ERRMSG= 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 to RabbitMQ-C libraries +RABBITMQ_HEADERS= Path to RabbitMQ-C headers +MYSQL_CLIENT_LIB= Path to MySQL client libraries +MYSQL_CLIENT_HEADERS= Path to MySQL client headers + \section Running Running MaxScale MaxScale consists of a core executable and a number of modules that implement diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 000000000..c284931b2 --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,7 @@ +add_executable(maxadmin maxadmin.c) +find_library(HIST edit) +if(HIST) + add_definitions(-DHISTORY) + target_link_libraries(maxadmin ${HIST}) +endif() +install(TARGETS maxadmin DESTINATION bin) \ No newline at end of file diff --git a/client/Makefile b/client/Makefile index 19f38785f..22220db2d 100644 --- a/client/Makefile +++ b/client/Makefile @@ -33,7 +33,7 @@ endif CC=cc -CFLAGS=-c -Wall -g $(HISTFLAG) +CFLAGS=-c -Wall -g $(HISTFLAG) -I ../server/include SRCS= maxadmin.c diff --git a/client/maxadmin.c b/client/maxadmin.c index 683916e9f..97459171e 100644 --- a/client/maxadmin.c +++ b/client/maxadmin.c @@ -47,6 +47,9 @@ #include #include #include +#include + +#include #ifdef HISTORY #include @@ -59,6 +62,7 @@ static int sendCommand(int so, char *cmd); static void DoSource(int so, char *cmd); static void DoUsage(); static int isquit(char *buf); +static void PrintVersion(const char *progname); #ifdef HISTORY static char * @@ -70,6 +74,16 @@ prompt(EditLine *el __attribute__((__unused__))) } #endif +static struct option long_options[] = { + {"host", required_argument, 0, 'h'}, + {"user", required_argument, 0, 'u'}, + {"password", required_argument, 0, 'p'}, + {"port", required_argument, 0, 'P'}, + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, '?'}, + {0, 0, 0, 0} +}; + /** * The main for the maxadmin client * @@ -79,7 +93,7 @@ prompt(EditLine *el __attribute__((__unused__))) int main(int argc, char **argv) { -int i, num, rv, fatal = 0; +int i, num, rv; #ifdef HISTORY char *buf; EditLine *el = NULL; @@ -94,109 +108,36 @@ char *hostname = "localhost"; char *port = "6603"; char *user = "admin"; char *passwd = NULL; -int so, cmdlen; -char *cmd; -int argno = 0; +int so; +int option_index = 0; +char c; - cmd = malloc(1); - *cmd = 0; - cmdlen = 1; - - for (i = 1; i < argc; i++) - { - if (argv[i][0] == '-') - { - switch (argv[i][1]) - { - case 'u': /* User */ - if (argv[i][2]) - user = &(argv[i][2]); - else if (i + 1 < argc) - user = argv[++i]; - else - { - fprintf(stderr, "Missing username" - "in -u option.\n"); - fatal = 1; - } - break; - case 'p': /* Password */ - if (argv[i][2]) - passwd = &(argv[i][2]); - else if (i + 1 < argc) - passwd = argv[++i]; - else - { - fprintf(stderr, "Missing password " - "in -p option.\n"); - fatal = 1; - } - break; - case 'h': /* hostname */ - if (argv[i][2]) - hostname = &(argv[i][2]); - else if (i + 1 < argc) - hostname = argv[++i]; - else - { - fprintf(stderr, "Missing hostname value " - "in -h option.\n"); - fatal = 1; - } - break; - case 'P': /* Port */ - if (argv[i][2]) - port = &(argv[i][2]); - else if (i + 1 < argc) - port = argv[++i]; - else - { - fprintf(stderr, "Missing Port value " - "in -P option.\n"); - fatal = 1; - } - break; - case '-': - { - char *word; - - word = &argv[i][2]; - if (strcmp(word, "help") == 0) - { - DoUsage(); - exit(0); - } - break; - } - } - } - else - { - /* Arguments after the second argument are quoted - * to allow for quoted names on the command line - * to be passed on in quotes. - */ - if (argno++ > 1) - { - cmdlen += strlen(argv[i]) + 3; - cmd = realloc(cmd, cmdlen); - strcat(cmd, "\""); - strcat(cmd, argv[i]); - strcat(cmd, "\" "); - } - else - { - cmdlen += strlen(argv[i]) + 1; - cmd = realloc(cmd, cmdlen); - strcat(cmd, argv[i]); - strcat(cmd, " "); - } - } + while ((c = getopt_long(argc, argv, "h:p:P:u:v?", + long_options, &option_index)) + >= 0) + { + switch (c) { + case 'h': + hostname = strdup(optarg); + break; + case 'p': + passwd = strdup(optarg); + break; + case 'P': + port = strdup(optarg); + break; + case 'u': + user = strdup(optarg); + break; + case 'v': + PrintVersion(*argv); + exit(EXIT_SUCCESS); + case '?': + DoUsage(*argv); + exit(optopt ? EXIT_FAILURE : EXIT_SUCCESS); + } } - if (fatal) - exit(1); - if (passwd == NULL) { struct termios tty_attr; @@ -234,14 +175,28 @@ int argno = 0; exit(1); } - if (cmdlen > 1) - { - cmd[cmdlen - 2] = '\0'; /* Remove trailing space */ - if (access(cmd, R_OK) == 0) - DoSource(so, cmd); - else - sendCommand(so, cmd); - exit(0); + if (optind < argc) { + int i, len = 0; + char *cmd; + + for (i = optind; i < argc; i++) { + len += strlen(argv[i]) + 1; + } + + cmd = malloc(len); + strcpy(cmd, argv[optind]); + for (i = optind +1; i < argc; i++) { + strcat(cmd, " "); + strcat(cmd, argv[i]); + } + + if (access(cmd, R_OK) == 0) + DoSource(so, cmd); + else + sendCommand(so, cmd); + + free(cmd); + exit(0); } (void) setlocale(LC_CTYPE, ""); @@ -318,7 +273,10 @@ int argno = 0; } else if (*buf) { - sendCommand(so, buf); + if (!sendCommand(so, buf)) + { + return 0; + } } } @@ -343,6 +301,7 @@ connectMaxScale(char *hostname, char *port) { struct sockaddr_in addr; int so; +int keepalive = 1; if ((so = socket(AF_INET, SOCK_STREAM, 0)) < 0) { @@ -360,6 +319,9 @@ int so; hostname, port, strerror(errno)); return -1; } + if (setsockopt(so, SOL_SOCKET, + SO_KEEPALIVE, &keepalive , sizeof(keepalive ))) + perror("setsockopt"); return so; } @@ -432,11 +394,14 @@ authMaxScale(int so, char *user, char *password) { char buf[20]; - read(so, buf, 4); + if (read(so, buf, 4) != 4) + return 0; write(so, user, strlen(user)); - read(so, buf, 8); + if (read(so, buf, 8) != 8) + return 0; write(so, password, strlen(password)); - read(so, buf, 6); + if (read(so, buf, 6) != 6) + return 0; return strncmp(buf, "FAILED", 6); } @@ -445,7 +410,7 @@ char buf[20]; * Send a comamnd using the MaxScaled protocol, display the return data * on standard output. * - * Input terminates with a lien containing jsut the text OK + * Input terminates with a lien containing just the text OK * * @param so The socket connect to MaxScale * @param cmd The command to send @@ -455,12 +420,13 @@ static int sendCommand(int so, char *cmd) { char buf[80]; -int i, j, newline = 0; +int i, j, newline = 1; - write(so, cmd, strlen(cmd)); + if (write(so, cmd, strlen(cmd)) == -1) + return 0; while (1) { - if ((i = read(so, buf, 80)) == -1) + if ((i = read(so, buf, 80)) <= 0) return 0; for (j = 0; j < i; j++) { @@ -533,23 +499,34 @@ FILE *fp; return; } +/** + * Print version information + */ +static void +PrintVersion(const char *progname) +{ + printf("%s Version %s\n", progname, MAXSCALE_VERSION); +} + /** * Display the --help text. */ static void -DoUsage() +DoUsage(const char *progname) { - printf("maxadmin: The MaxScale administrative and monitor client.\n\n"); - printf("Usage: maxadmin [-u user] [-p password] [-h hostname] [-P port] [ | ]\n\n"); - printf(" -u user The user name to use for the connection, default\n"); + PrintVersion(progname); + printf("The MaxScale administrative and monitor client.\n\n"); + printf("Usage: %s [-u user] [-p password] [-h hostname] [-P port] [ | ]\n\n", progname); + printf(" -u|--user=... The user name to use for the connection, default\n"); printf(" is admin.\n"); - printf(" -p password The user password, if not given the password will\n"); + printf(" -p|--password=... The user password, if not given the password will\n"); printf(" be prompted for interactively\n"); - printf(" -h hostname The maxscale host to connecto to. The default is\n"); + printf(" -h|--hostname=... The maxscale host to connecto to. The default is\n"); printf(" localhost\n"); - printf(" -P port The port to use for the connection, the default\n"); + printf(" -P|--port=... The port to use for the connection, the default\n"); printf(" port is 6603.\n"); - printf(" --help Print this help text.\n"); + printf(" -v|--version print version information and exit\n"); + printf(" -?|--help Print this help text.\n"); printf("Any remaining arguments are treated as MaxScale commands or a file\n"); printf("containing commands to execute.\n"); } diff --git a/client/test/maxadmin_test.sh b/client/test/maxadmin_test.sh new file mode 100644 index 000000000..b04312da4 --- /dev/null +++ b/client/test/maxadmin_test.sh @@ -0,0 +1,210 @@ +#!/bin/sh +failure=0 +passed=0 +maxadmin -pskysql help >& /dev/null +if [ $? -eq "1" ]; then + echo "Auth test (correct password): Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Auth test (correct password): Passed" +fi +maxadmin -pwrongpasswd help >& /dev/null +if [ $? -eq "0" ]; then + echo "Auth test (wrong password): Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Auth test (wrong password): Passed" +fi +maxadmin --password=skysql help >& /dev/null +if [ $? -eq "1" ]; then + echo "Auth test (long option): Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Auth test (long option): Passed" +fi + +maxadmin -pskysql enable log debug >& /dev/null +if [ $? -eq "1" ]; then + echo "Enable debug log: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Enable debug log: Passed" +fi + +maxadmin -pskysql enable log trace >& /dev/null +if [ $? -eq "1" ]; then + echo "Enable trace log: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Enable trace log: Passed" +fi + +maxadmin -pskysql disable log debug >& /dev/null +if [ $? -eq "1" ]; then + echo "Disable debug log: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Disable debug log: Passed" +fi + +maxadmin -pskysql disable log trace >& /dev/null +if [ $? -eq "1" ]; then + echo "Disable trace log: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Disable trace log: Passed" +fi + +for cmd in clients dcbs filters listeners modules monitors services servers sessions threads +do + maxadmin -pskysql list $cmd | grep -s '-' >& /dev/null + if [ $? -eq "1" ]; then + echo "list command ($cmd): Failed" + failure=`expr $failure + 1` + else + passed=`expr $passed + 1` + echo "list command ($cmd): Passed" + fi +done + +for cmd in dcbs dbusers epoll filters modules monitors services servers sessions threads users +do + maxadmin -pskysql show $cmd | grep -s ' ' >& /dev/null + if [ $? -eq "1" ]; then + echo "show command ($cmd): Failed" + failure=`expr $failure + 1` + else + passed=`expr $passed + 1` + echo "show command ($cmd): Passed" + fi +done + +master=`maxadmin -pskysql list servers | awk '/Master/ { print $1; }'` +if [ $? -eq "1" ]; then + echo "Extract master server: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Extract master server: Passed" +fi +if [ "$master" = "" ]; then + echo "Get master server: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Get master server: Passed" +fi +maxadmin -pskysql show server $master | grep -s 'Master' >& /dev/null +if [ $? -eq "1" ]; then + echo "show server master: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "show server master: Passed" +fi + +maxadmin -pskysql set server $master maint >& /dev/null +if [ $? -eq "1" ]; then + echo "set server: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "set server: Passed" +fi +maxadmin -pskysql list servers | grep $master | grep -s Maint >& /dev/null +if [ $? -eq "1" ]; then + echo "set maintenance mode: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "set maintenance mode: Passed" +fi +maxadmin -pskysql clear server $master maint >& /dev/null +if [ $? -eq "1" ]; then + echo "clear server: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "clear server: Passed" +fi +maxadmin -pskysql list servers | grep $master | grep -s Maint >& /dev/null +if [ $? -eq "0" ]; then + echo "clear maintenance mode: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "clear maintenance mode: Passed" +fi + +dcbs=`maxadmin -pskysql list dcbs | awk -F\| '/listening/ { if ( NF > 1 ) print $1 }'` +if [ $? -eq "1" ]; then + echo "Get dcb listeners: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Get dcb listeners: Passed" +fi + +for i in $dcbs +do + maxadmin -pskysql show dcb $i | grep -s 'listening' >& /dev/null + if [ $? -eq "1" ]; then + echo "show dcb listeners: Failed" + failure=`expr $failure + 1` + else + passed=`expr $passed + 1` + echo "show dcb listeners: Passed" + fi +done + +sessions=`maxadmin -pskysql list sessions | awk -F\| '/Listener/ { if ( NF > 1 ) print $1 }'` +if [ $? -eq "1" ]; then + echo "Get listener sessions: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Get listener sessions: Passed" +fi + +for i in $sessions +do + maxadmin -pskysql show session $i | grep -s 'Listener' >& /dev/null + if [ $? -eq "1" ]; then + echo "show session listeners: Failed" + failure=`expr $failure + 1` + else + passed=`expr $passed + 1` + echo "show session listeners: Passed" + fi +done + +filters=`maxadmin -pskysql list filters | awk -F\| '{ if ( NF > 1 ) print $1 }'| grep -v Options` +if [ $? -eq "1" ]; then + echo "Get Filter list: Failed" + failure=`expr $failure + 1` +else + passed=`expr $passed + 1` + echo "Get filter list: Passed" +fi + +for i in $filters +do + maxadmin -pskysql show filter $i | grep -s 'Filter' >& /dev/null + if [ $? -eq "1" ]; then + echo "show filter: Failed" + failure=`expr $failure + 1` + else + passed=`expr $passed + 1` + echo "show filter: Passed" + fi +done + +echo "Test run complete. $passed passes, $failure failures" +exit $failure diff --git a/etc/init.d/maxscale.in b/etc/init.d/maxscale.in new file mode 100755 index 000000000..bf96d6f32 --- /dev/null +++ b/etc/init.d/maxscale.in @@ -0,0 +1,157 @@ +#!/bin/sh +# +# maxscale: The SkySQL MaxScale database proxy +# +# description: MaxScale provides database specific proxy functionality +# +# processname: maxscale +# +### BEGIN INIT INFO +# Provides: maxscale +# Required-Start: $syslog $local_fs +# Required-Stop: $syslog $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: The maxscale database proxy +# Description: MaxScale is a database proxy server that can be used to front end +# database clusters offering different routing, filtering and protocol choices +### END INIT INFO + +############################################# +# MaxScale HOME, PIDFILE, LIB +############################################# + +export MAXSCALE_HOME=@INSTALL_DIR@ +export MAXSCALE_PIDFILE=$MAXSCALE_HOME/log/maxscale.pid +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MAXSCALE_HOME/lib + +############################### +# LSB Exit codes (non-Status) +############################### +_RETVAL_GENERIC=1 +_RETVAL_NOT_INSTALLED=5 +_RETVAL_NOT_RUNNING=7 + +############################### +# LSB Status action Exit codes +############################### +_RETVAL_STATUS_OK=0 +_RETVAL_STATUS_NOT_RUNNING=3 + +# Sanity checks. +[ -x $MAXSCALE_HOME/bin/maxscale ] || exit $_RETVAL_NOT_INSTALLED + +# Source function library. +. /etc/rc.d/init.d/functions + +# we can rearrange this easily +processname=maxscale +servicename=maxscale + +RETVAL=0 + +start() { + echo -n $"Starting MaxScale: " + my_check=`status -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale` + CHECK_RET=$? + [ $CHECK_RET -eq 0 ] && echo -n " found $my_check" && success && CHECK_RET=0 + + daemon --pidfile $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale >& /dev/null + + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$servicename + + if [ $CHECK_RET -ne 0 ]; then + sleep 2 + my_check=`status -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale` + CHECK_RET=$? + [ $CHECK_RET -eq 0 ] && echo -n $my_check && success || failure + fi + + # Return rigth code + if [ $RETVAL -ne 0 ]; then + failure + RETVAL=$_RETVAL_NOT_RUNNING + fi + + echo + + return $RETVAL +} + +stop() { + echo -n $"Stopping MaxScale: " + killproc -p $MAXSCALE_PIDFILE -TERM + + RETVAL=$? + + echo + + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$servicename + + # Return rigth code + if [ $RETVAL -ne 0 ]; then + RETVAL=$_RETVAL_NOT_RUNNING + fi + + return $RETVAL +} + +reload() { + echo -n $"Reloading MaxScale: " + + killproc -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale -HUP + RETVAL=$? + echo +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + # return 0 on success + # return 3 on any error + + echo -n $"Checking MaxScale status: " + status -p $MAXSCALE_PIDFILE 'MaxScale' + RETVAL=$? + + if [ $RETVAL -ne 0 ]; then + echo -ne "\033[1A" + [ $RETVAL -eq 1 ] && warning || failure + echo -ne "\033[1B" + + RETVAL=$_RETVAL_STATUS_NOT_RUNNING + else + echo -ne "\033[1A" + success + echo -ne "\033[1B" + RETVAL=$_RETVAL_STATUS_OK + fi + + exit $RETVAL + ;; + restart) + stop + start + ;; + condrestart) + if [ -f /var/lock/subsys/$servicename ]; then + stop + start + fi + ;; + reload) + reload + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}" + ;; +esac +exit $RETVAL diff --git a/etc/ubuntu/init.d/maxscale.in b/etc/ubuntu/init.d/maxscale.in new file mode 100644 index 000000000..600e8f5f8 --- /dev/null +++ b/etc/ubuntu/init.d/maxscale.in @@ -0,0 +1,145 @@ +#!/bin/sh +# +# maxscale: The SkySQL MaxScale database proxy +# +# description: MaxScale provides database specific proxy functionality +# +# processname: maxscale +# +### BEGIN INIT INFO +# Provides: maxscale +# Required-Start: $syslog $local_fs +# Required-Stop: $syslog $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: The maxscale database proxy +# Description: MaxScale is a database proxy server that can be used to front end +# database clusters offering different routing, filtering and protocol choices +### END INIT INFO + +############################################# +# MaxScale HOME, PIDFILE, LIB +############################################# + +export MAXSCALE_HOME=@INSTALL_DIR@ +export MAXSCALE_PIDFILE=$MAXSCALE_HOME/log/maxscale.pid +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MAXSCALE_HOME/lib + +############################### +# LSB Exit codes (non-Status) +############################### +_RETVAL_GENERIC=1 +_RETVAL_NOT_INSTALLED=5 +_RETVAL_NOT_RUNNING=7 + +############################### +# LSB Status action Exit codes +############################### +_RETVAL_STATUS_OK=0 +_RETVAL_STATUS_NOT_RUNNING=3 + +# Sanity checks. +[ -x $MAXSCALE_HOME/bin/maxscale ] || exit $_RETVAL_NOT_INSTALLED + +################################# +# stop/start/status related vars +################################# +NAME=maxscale +DAEMON=$MAXSCALE_HOME/bin/maxscale + +# Source function library. +. /lib/lsb/init-functions + +# we can rearrange this easily +processname=maxscale +servicename=maxscale + +RETVAL=0 + +start() { + log_daemon_msg "Starting MaxScale" + start_daemon -p $MAXSCALE_PIDFILE $DAEMON 2> /dev/null + + sleep 2 + + status_of_proc -p $MAXSCALE_PIDFILE $DAEMON $NAME + + log_end_msg $? +} + +stop() { + log_daemon_msg "Stopping MaxScale" + killproc -p $PIDFILE $DAEMON 2>&1 /dev/null + + maxscale_wait_stop + + log_end_msg $? +} + +reload() { + log_daemon_msg "Reloading MaxScale" + + killproc -p $MAXSCALE_PIDFILE $DAEMON 1 + + log_end_msg $? +} + +maxscale_wait_stop() { + PIDTMP=$(pidofproc -p $MAXSCALE_PIDFILE $MAXSCALE_HOME/bin/maxscale) + kill -TERM "${PIDTMP:-}" 2> /dev/null; + if [ -n "${PIDTMP:-}" ] && kill -0 "${PIDTMP:-}" 2> /dev/null; then + local i=0 + while kill -0 "${PIDTMP:-}" 2> /dev/null; do + if [ $i = '60' ]; then + break + STATUS=2 + fi + [ "$VERBOSE" != no ] && log_progress_msg "." + sleep 1 + i=$(($i+1)) + done + return $STATUS + else + return $STATUS + fi +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + # return 0 on success + # return 3 on any error + + log_daemon_msg "Checking MaxScale" + status_of_proc -p $MAXSCALE_PIDFILE $DAEMON $NAME + RETVAL=$? + + if [ $RETVAL -ne 0 ]; then + [ $RETVAL -eq 1 ] + + RETVAL=$_RETVAL_STATUS_NOT_RUNNING + else + RETVAL=$_RETVAL_STATUS_OK + fi + + log_end_msg $RETVAL + ;; + restart) + stop + start + ;; + reload) + reload + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|reload}" + ;; +esac +exit $RETVAL diff --git a/log_manager/CMakeLists.txt b/log_manager/CMakeLists.txt new file mode 100644 index 000000000..1cbe6cd87 --- /dev/null +++ b/log_manager/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(log_manager SHARED log_manager.cc) +target_link_libraries(log_manager pthread aio stdc++) +install(TARGETS log_manager DESTINATION lib) +if(BUILD_TESTS) + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/log_manager/log_manager.cc b/log_manager/log_manager.cc index 9bfc9dd41..2b274a610 100644 --- a/log_manager/log_manager.cc +++ b/log_manager/log_manager.cc @@ -255,7 +255,7 @@ static int logmanager_write_log( bool use_valist, bool spread_down, size_t len, - char* str, + const char* str, va_list valist); static blockbuf_t* blockbuf_init(logfile_id_t id); @@ -609,7 +609,7 @@ static int logmanager_write_log( bool use_valist, bool spread_down, size_t str_len, - char* str, + const char* str, va_list valist) { logfile_t* lf; @@ -623,7 +623,7 @@ static int logmanager_write_log( CHK_LOGMANAGER(lm); if (id < LOGFILE_FIRST || id > LOGFILE_LAST) { - char* errstr = "Invalid logfile id argument."; + const char* errstr = "Invalid logfile id argument."; /** * invalid id, since we don't have logfile yet. */ @@ -1181,7 +1181,7 @@ static bool logfile_set_enabled( CHK_LOGMANAGER(lm); if (id < LOGFILE_FIRST || id > LOGFILE_LAST) { - char* errstr = "Invalid logfile id argument."; + const char* errstr = "Invalid logfile id argument."; /** * invalid id, since we don't have logfile yet. */ @@ -1235,7 +1235,7 @@ return_succp: int skygw_log_write_flush( logfile_id_t id, - char* str, + const char* str, ...) { int err = 0; @@ -1291,7 +1291,7 @@ return_err: int skygw_log_write( logfile_id_t id, - char* str, + const char* str, ...) { int err = 0; diff --git a/log_manager/log_manager.h b/log_manager/log_manager.h index d9932d640..6a4c1d6cc 100644 --- a/log_manager/log_manager.h +++ b/log_manager/log_manager.h @@ -72,9 +72,9 @@ void skygw_logmanager_exit(void); * free private write buffer list */ void skygw_log_done(void); -int skygw_log_write(logfile_id_t id, char* format, ...); +int skygw_log_write(logfile_id_t id, const char* format, ...); int skygw_log_flush(logfile_id_t id); -int skygw_log_write_flush(logfile_id_t id, 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_disable(logfile_id_t id); diff --git a/log_manager/test/CMakeLists.txt b/log_manager/test/CMakeLists.txt new file mode 100644 index 000000000..d3a22939e --- /dev/null +++ b/log_manager/test/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(testlog testlog.c) +add_executable(testorder testorder.c) +target_link_libraries(testlog pthread log_manager utils) +target_link_libraries(testorder pthread log_manager utils) +add_test(NAME TestLogOrder COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/logorder.sh ${CMAKE_CURRENT_BINARY_DIR}/test.log 500 0 500 ${CMAKE_CURRENT_BINARY_DIR}) \ No newline at end of file diff --git a/log_manager/test/logorder.sh b/log_manager/test/logorder.sh index bbdcaf0f7..49ca43c83 100755 --- a/log_manager/test/logorder.sh +++ b/log_manager/test/logorder.sh @@ -2,24 +2,33 @@ if [[ $# -lt 4 ]] then - echo "Usage: logorder.sh " + echo "Usage: logorder.sh " echo "To disable log flushing, use 0 for flush frequency" exit fi rm *.log +if [ $# -eq 5 ] +then + TDIR=$5 +else + TDIR=$PWD +fi + #Create large messages -$PWD/testorder $1 $2 $3 + +$TDIR/testorder $1 $2 $3 TESTLOG=$4 MCOUNT=$1 -BLOCKS=`cat skygw_err1.log |tr -s ' '|grep -o 'block:[[:digit:]]\+'|cut -d ':' -f 2` -MESSAGES=`cat skygw_err1.log |tr -s ' '|grep -o 'message|[[:digit:]]\+'|cut -d '|' -f 2` +BLOCKS=`cat $TDIR/skygw_err1.log |tr -s ' '|grep -o 'block:[[:digit:]]\+'|cut -d ':' -f 2` +MESSAGES=`cat $TDIR/skygw_err1.log |tr -s ' '|grep -o 'message|[[:digit:]]\+'|cut -d '|' -f 2` prev=0 error=0 +all_errors=0 for i in $BLOCKS do @@ -27,6 +36,7 @@ do if [[ $i -le $prev ]] then error=1 + all_errors=1 echo "block mismatch: $i was after $prev." >> $TESTLOG fi prev=$i @@ -48,6 +58,7 @@ do if [[ $i -ne $(( prev + 1 )) ]] then error=1 + all_errors=1 echo "message mismatch: $i was after $prev." >> $TESTLOG fi prev=$i @@ -59,3 +70,9 @@ then else echo "Error: block buffer messages were written in the wrong order" >> $TESTLOG fi + +if [ $# -eq 5 ] +then + cat $TESTLOG + exit $all_errors +fi diff --git a/macros.cmake b/macros.cmake new file mode 100644 index 000000000..71a7137a1 --- /dev/null +++ b/macros.cmake @@ -0,0 +1,210 @@ +macro(set_maxscale_version) + + #MaxScale version number + set(MAXSCALE_VERSION_MAJOR "1") + set(MAXSCALE_VERSION_MINOR "0") + set(MAXSCALE_VERSION_PATCH "0") + set(MAXSCALE_VERSION "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}-beta") + +endmacro() + +macro(set_variables) + + # Installation directory + set(INSTALL_DIR "/usr/local/skysql/maxscale/" CACHE PATH "MaxScale installation directory.") + + # Build type + set(BUILD_TYPE "None" CACHE STRING "Build type, possible values are:None, Debug, Optimized.") + + # 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 + set(TEST_PORT_RW "4008" CACHE STRING "port of read connection router module") + + # 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 + set(TEST_PORT_RW_HINT "4006" CACHE STRING "port of read/write split router module with hints") + + # master test server server_id + set(TEST_MASTER_ID "3000" CACHE STRING "master test server server_id") + + # username of MaxScale user + set(TEST_USER "maxuser" CACHE STRING "username of MaxScale user") + + # password of MaxScale user + set(TEST_PASSWORD "maxpwd" CACHE STRING "password of MaxScale user") + + # Use static version of libmysqld + set(STATIC_EMBEDDED TRUE CACHE BOOL "Use static version of libmysqld") + + # Build RabbitMQ components + set(BUILD_RABBITMQ FALSE CACHE BOOL "Build RabbitMQ components") + + # Use gcov build flags + set(GCOV FALSE CACHE BOOL "Use gcov build flags") + + # 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 + set(BUILD_TESTS TRUE CACHE BOOL "Build tests") + +endmacro() + +macro(check_deps) + + # Check for libraries MaxScale depends on + set(MAXSCALE_DEPS aio ssl crypt crypto z m dl rt pthread) + foreach(lib ${MAXSCALE_DEPS}) + find_library(lib${lib} ${lib}) + if((DEFINED lib${lib}) AND (${lib${lib}} STREQUAL "lib${lib}-NOTFOUND")) + set(DEPS_ERROR TRUE) + set(FAILED_DEPS "${FAILED_DEPS} lib${lib}") + elseif(DEBUG_OUTPUT) + message(STATUS "Library was found at: ${lib${lib}}") + endif() + endforeach() + + if(DEPS_ERROR) + set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") + message(FATAL_ERROR "Cannot find dependencies: ${FAILED_DEPS}") + endif() + +endmacro() + +macro(check_dirs) + + # This variable is used to prevent redundant checking of dependencies + set(DEPS_OK TRUE CACHE BOOL "If all the dependencies were found.") + + # Find the MySQL headers if they were not defined + if(DEFINED MYSQL_DIR) + if(DEBUG_OUTPUT) + 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) + endif() + find_path(MYSQL_DIR_LOC mysql.h PATH_SUFFIXES mysql mariadb) + if(DEBUG_OUTPUT) + message(STATUS "Search returned: ${MYSQL_DIR_LOC}") + endif() + if(${MYSQL_DIR_LOC} STREQUAL "MYSQL_DIR_LOC-NOTFOUND") + set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") + message(FATAL_ERROR "Fatal Error: MySQL headers were not found.") + else() + message(STATUS "Using MySQL headers found at: ${MYSQL_DIR}") + set(MYSQL_DIR ${MYSQL_DIR_LOC} CACHE PATH "Path to MySQL headers" FORCE) + endif() + set(MYSQL_DIR_LOC "" INTERNAL) + + # Find the errmsg.sys file if it was not defied + if( DEFINED ERRMSG ) + find_file(ERRMSG_FILE errmsg.sys PATHS ${ERRMSG} NO_DEFAULT_PATH) + endif() + find_file(ERRMSG_FILE errmsg.sys PATHS /usr/share/mysql /usr/local/share/mysql PATH_SUFFIXES english) + if(${ERRMSG_FILE} MATCHES "ERRMSG_FILE-NOTFOUND") + 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=") + else() + message(STATUS "Using errmsg.sys found at: ${ERRMSG_FILE}") + endif() + set(ERRMSG ${ERRMSG_FILE} CACHE FILEPATH "Path to the errmsg.sys file." FORCE) + set(ERRMSG_FILE "" INTERNAL) + + # Find the embedded mysql library + if(STATIC_EMBEDDED) + + set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + if (DEFINED EMBEDDED_LIB) + if(DEBUG_OUTPUT) + 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) + else() + find_library(EMBEDDED_LIB_STATIC libmysqld.a PATH_SUFFIXES mysql mariadb) + endif() + if(DEBUG_OUTPUT) + message(STATUS "Search returned: ${EMBEDDED_LIB_STATIC}") + endif() + set(EMBEDDED_LIB ${EMBEDDED_LIB_STATIC} CACHE FILEPATH "Path to libmysqld" FORCE) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) + set(OLD_SUFFIXES "" INTERNAL) + + else() + if (DEFINED EMBEDDED_LIB) + if(DEBUG_OUTPUT) + 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) + else() + find_library(EMBEDDED_LIB_DYNAMIC mysqld PATH_SUFFIXES mysql mariadb) + endif() + if(DEBUG_OUTPUT) + message(STATUS "Search returned: ${EMBEDDED_LIB_DYNAMIC}") + endif() + set(EMBEDDED_LIB ${EMBEDDED_LIB_DYNAMIC} CACHE FILEPATH "Path to libmysqld" FORCE) + + endif() + set(EMBEDDED_LIB_DYNAMIC "" INTERNAL) + set(EMBEDDED_LIB_STATIC "" INTERNAL) + + # Inform the user about the embedded library + if( (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_STATIC-NOTFOUND") OR (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_DYNAMIC-NOTFOUND")) + set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") + message(FATAL_ERROR "Library not found: libmysqld. If your install of MySQL is in a non-default location, please provide the location with -DEMBEDDED_LIB=") + else() + get_filename_component(EMBEDDED_LIB ${EMBEDDED_LIB} REALPATH) + message(STATUS "Using embedded library: ${EMBEDDED_LIB}") + endif() + + + # Check which init.d script to install + find_file(RPM_FNC functions PATHS /etc/rc.d/init.d) + if(${RPM_FNC} MATCHES "RPM_FNC-NOTFOUND") + find_file(DEB_FNC init-functions PATHS /lib/lsb) + if(${DEB_FNC} MATCHES "DEB_FNC-NOTFOUND") + set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") + message(FATAL_ERROR "Cannot find required init-functions in /lib/lsb/ or /etc/rc.d/init.d/, please confirm that your system files are OK.") + else() + set(DEB_BASED TRUE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.") + endif() + else() + set(DEB_BASED FALSE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.") + endif() + set(DEB_FNC "" INTERNAL) + set(RPM_FNC "" INTERNAL) + + #Check RabbitMQ headers and libraries + if(BUILD_RABBITMQ) + + if(DEFINED RABBITMQ_LIB) + find_library(RMQ_LIB rabbitmq PATHS ${RABBITMQ_LIB} NO_DEFAULT_PATH) + endif() + find_library(RMQ_LIB rabbitmq) + if(RMQ_LIB STREQUAL "RMQ_LIB-NOTFOUND") + set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") + message(FATAL_ERROR "Cannot find RabbitMQ libraries, please define the path to the libraries with -DRABBITMQ_LIB=") + else() + set(RABBITMQ_LIB ${RMQ_LIB} CACHE PATH "Path to RabbitMQ libraries" FORCE) + message(STATUS "Using RabbitMQ libraries found at: ${RABBITMQ_LIB}") + endif() + + if(DEFINED RABBITMQ_HEADERS) + find_file(RMQ_HEADERS amqp.h PATHS ${RABBITMQ_HEADERS} NO_DEFAULT_PATH) + endif() + find_file(RMQ_HEADERS amqp.h) + if(RMQ_HEADERS STREQUAL "RMQ_HEADERS-NOTFOUND") + set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.") + message(FATAL_ERROR "Cannot find RabbitMQ headers, please define the path to the headers with -DRABBITMQ_HEADERS=") + else() + set(RABBITMQ_HEADERS ${RMQ_HEADERS} CACHE PATH "Path to RabbitMQ headers" FORCE) + message(STATUS "Using RabbitMQ headers found at: ${RABBITMQ_HEADERS}") + endif() + + endif() + +endmacro() diff --git a/maxscale.conf.in b/maxscale.conf.in new file mode 100644 index 000000000..0283479f1 --- /dev/null +++ b/maxscale.conf.in @@ -0,0 +1,2 @@ +@INSTALL_DIR@/modules +@INSTALL_DIR@/lib diff --git a/query_classifier/CMakeLists.txt b/query_classifier/CMakeLists.txt new file mode 100644 index 000000000..8f8ab0186 --- /dev/null +++ b/query_classifier/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(query_classifier SHARED query_classifier.cc) +target_link_libraries(query_classifier ${EMBEDDED_LIB}) +install(TARGETS query_classifier DESTINATION lib) +if(BUILD_TESTS) + add_subdirectory(test) +endif() \ No newline at end of file diff --git a/query_classifier/query_classifier.cc b/query_classifier/query_classifier.cc index f034d770f..ecf305308 100644 --- a/query_classifier/query_classifier.cc +++ b/query_classifier/query_classifier.cc @@ -359,17 +359,37 @@ static bool create_parse_tree( Parser_state parser_state; bool failp = FALSE; const char* virtual_db = "skygw_virtual"; - +#if defined(SS_DEBUG_EXTRA) + LOGIF(LM, (skygw_log_write_flush( + LOGFILE_MESSAGE, + "[readwritesplit:create_parse_tree] 1."))); +#endif if (parser_state.init(thd, thd->query(), thd->query_length())) { failp = TRUE; goto return_here; } - mysql_reset_thd_for_next_command(thd); - - /** Set some database to thd so that parsing won't fail because of - * missing database. Then parse. */ - failp = thd->set_db(virtual_db, strlen(virtual_db)); +#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); +#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 + * missing database. Then parse. + */ + failp = thd->set_db(virtual_db, strlen(virtual_db)); +#if defined(SS_DEBUG_EXTRA) + LOGIF(LM, (skygw_log_write_flush( + LOGFILE_MESSAGE, + "[readwritesplit:create_parse_tree] 4."))); +#endif if (failp) { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, @@ -377,6 +397,11 @@ static bool create_parse_tree( } failp = parse_sql(thd, &parser_state, NULL); +#if defined(SS_DEBUG_EXTRA) + LOGIF(LM, (skygw_log_write_flush( + LOGFILE_MESSAGE, + "[readwritesplit:create_parse_tree] 5."))); +#endif if (failp) { LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, diff --git a/query_classifier/test/CMakeLists.txt b/query_classifier/test/CMakeLists.txt new file mode 100644 index 000000000..ceaad8110 --- /dev/null +++ b/query_classifier/test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(canonical_tests) \ No newline at end of file diff --git a/query_classifier/test/canonical_tests/CMakeLists.txt b/query_classifier/test/canonical_tests/CMakeLists.txt new file mode 100644 index 000000000..4777fad8d --- /dev/null +++ b/query_classifier/test/canonical_tests/CMakeLists.txt @@ -0,0 +1,12 @@ +file(COPY ${ERRMSG} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +if(${ERRMSG} MATCHES "ERRMSG-NOTFOUND") + message(FATAL_ERROR "The errmsg.sys file was not found, please define the path with -DERRMSG=") +endif() +add_executable(canonizer canonizer.c) +target_link_libraries(canonizer pthread query_classifier z dl ssl aio crypt crypto rt m ${EMBEDDED_LIB} fullcore stdc++) +add_test(NAME TestCanonicalQuery COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/canontest.sh + ${CMAKE_CURRENT_BINARY_DIR}/test.log + ${CMAKE_CURRENT_SOURCE_DIR}/input.sql + ${CMAKE_CURRENT_BINARY_DIR}/output.sql + ${CMAKE_CURRENT_SOURCE_DIR}/expected.sql + $) diff --git a/query_classifier/test/canonical_tests/canontest.sh b/query_classifier/test/canonical_tests/canontest.sh index 8382103c1..dd931504f 100755 --- a/query_classifier/test/canonical_tests/canontest.sh +++ b/query_classifier/test/canonical_tests/canontest.sh @@ -1,5 +1,5 @@ #! /bin/sh -if [[ $# -ne 4 ]] +if [[ $# -lt 4 ]] then echo "Usage: canontest.sh " exit 0 @@ -9,13 +9,29 @@ INPUT=$2 OUTPUT=$3 EXPECTED=$4 DIFFLOG=diff.out -$PWD/canonizer $INPUT $OUTPUT + +if [ $# -eq 5 ] +then + EXECUTABLE=$5 +else + EXECUTABLE=$PWD/canonizer +fi + +$EXECUTABLE $INPUT $OUTPUT diff $OUTPUT $EXPECTED > $DIFFLOG if [ $? -eq 0 ] then echo "PASSED" >> $TESTLOG + exval=0 else echo "FAILED" >> $TESTLOG echo "Diff output: " >> $TESTLOG cat $DIFFLOG >> $TESTLOG + exval=1 +fi + +if [ $# -eq 5 ] +then + cat $TESTLOG + exit $exval fi diff --git a/query_classifier/test/canonical_tests/expected.sql b/query_classifier/test/canonical_tests/expected.sql index fabb27dc7..1126f6016 100755 --- a/query_classifier/test/canonical_tests/expected.sql +++ b/query_classifier/test/canonical_tests/expected.sql @@ -1,7 +1,7 @@ -select md5(?) =?, sleep(?), rand(?); -select * from my1 where md5(?) =?; -select md5(?) =?; -select * from my1 where md5(?) =?; +select md5("?") =?, sleep(?), rand(?) +select * from my1 where md5("?") =? +select md5("?") =? +select * from my1 where md5("?") =? select sleep(?) select * from tst where lname='?' select ?,?,?,?,?,? from tst @@ -13,5 +13,5 @@ create table tst(fname varchar(30), lname varchar(30)) update tst set lname="?" where fname like '?' or lname like '?' delete from tst where lname like '?' and fname like '?' select ? from tst where fname='?' or lname like '?' -select ?,?,?,? from tst where 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 diff --git a/rabbitmq_consumer/CMakeLists.txt b/rabbitmq_consumer/CMakeLists.txt index 30d16d630..aee18a6da 100644 --- a/rabbitmq_consumer/CMakeLists.txt +++ b/rabbitmq_consumer/CMakeLists.txt @@ -1,44 +1,21 @@ -cmake_minimum_required (VERSION 2.6) +if (NOT ( DEFINED MYSQL_CLIENT_LIB ) ) + find_library(MYSQL_CLIENT_LIB NAMES mysqlclient PATHS /usr/lib /usr/lib64 PATH_SUFFIXES mysql mariadb) +endif() -set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 /usr/lib/mariadb /usr/lib64/mariadb) -set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /usr/include /usr/local/include /usr/include/mysql /usr/local/include/mysql /usr/include/mariadb /usr/local/include/mariadb) +if (NOT ( DEFINED MYSQL_CLIENT_HEADERS ) ) + find_path(MYSQL_CLIENT_HEADERS NAMES mysql.h PATH_SUFFIXES mysql mariadb) +endif() -include(InstallRequiredSystemLibraries) - -project (consumer) - -find_path(MYSQL_INCLUDE_DIRS mysql.h) -find_library(MYSQL_LIBRARIES NAMES mysqlclient) -find_library(RABBITMQ_C_LIBRARIES NAMES rabbitmq) - -include_directories(${MYSQL_INCLUDE_DIRS}) -include_directories(${RABBITMQ_C_INCLUDE_DIRS}) -include_directories(${CMAKE_SOURCE_DIR}/inih) - -add_subdirectory (inih) -link_directories(${CMAKE_SOURCE_DIR}/inih) - -if(RABBITMQ_C_LIBRARIES AND MYSQL_LIBRARIES AND MYSQL_INCLUDE_DIRS) - -add_executable (consumer consumer.c ${MYSQL_LIBRARIES} ${RABBITMQ_C_LIBRARIES}) -target_link_libraries(consumer mysqlclient) -target_link_libraries(consumer rabbitmq) -target_link_libraries(consumer inih) -install(TARGETS consumer DESTINATION bin) -install(FILES consumer.cnf DESTINATION share/consumer) +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) + target_link_libraries(consumer ${MYSQL_CLIENT_LIB} rabbitmq inih) + install(TARGETS consumer DESTINATION bin) + install(FILES consumer.cnf DESTINATION etc) -else(RABBITMQ_C_LIBRARIES AND MYSQL_LIBRARIES AND MYSQL_INCLUDE_DIRS) -message(FATAL_ERROR "Error: Can not find requred libraries: libmysqld, librabbitmq.") +else() -endif(RABBITMQ_C_LIBRARIES AND MYSQL_LIBRARIES AND MYSQL_INCLUDE_DIRS) + message(FATAL_ERROR "Error: Can not find requred libraries and headers: librabbitmq libmysqlclient") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "RabbitMQ Consumer Client") -set(CPACK_PACKAGE_NAME "RabbitMQ Consumer") -set(CPACK_GENERATOR "RPM") -set(CPACK_PACKAGE_VERSION_MAJOR "1") -set(CPACK_PACKAGE_VERSION_MINOR "0") -set(CPACK_RPM_PACKAGE_NAME "rabbitmq-consumer") -set(CPACK_RPM_PACKAGE_VENDOR "SkySQL Ab") -set(CPACK_RPM_PACKAGE_AUTOREQPROV " no") -include(CPack) \ No newline at end of file +endif() diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt new file mode 100644 index 000000000..a42c625ae --- /dev/null +++ b/server/CMakeLists.txt @@ -0,0 +1,6 @@ +add_subdirectory(core) +add_subdirectory(modules) +add_subdirectory(inih) +if(BUILD_TESTS) +add_subdirectory(test) +endif() \ No newline at end of file diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt new file mode 100644 index 000000000..2c7854de3 --- /dev/null +++ b/server/core/CMakeLists.txt @@ -0,0 +1,22 @@ +file(GLOB FULLCORE_SRC *.c) +add_library(fullcore STATIC ${FULLCORE_SRC}) +target_link_libraries(fullcore log_manager utils pthread ${EMBEDDED_LIB} ssl aio rt crypt dl crypto inih z m stdc++) + +add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c + gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c + poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c + monitor.c adminusers.c secrets.c filter.c modutil.c hint.c housekeeper.c) +target_link_libraries(maxscale ${EMBEDDED_LIB} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++) +install(TARGETS maxscale DESTINATION bin) + +add_executable(maxkeys maxkeys.c secrets.c utils.c) +target_link_libraries(maxkeys log_manager utils pthread crypt crypto) +install(TARGETS maxkeys DESTINATION bin) + +add_executable(maxpasswd maxpasswd.c secrets.c utils.c) +target_link_libraries(maxpasswd log_manager utils pthread crypt crypto) +install(TARGETS maxpasswd DESTINATION bin) + +if(BUILD_TESTS) +add_subdirectory(test) +endif() \ No newline at end of file diff --git a/server/core/config.c b/server/core/config.c index 1ba2bcbf4..995e0e0f4 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -1575,6 +1575,7 @@ static char *service_params[] = "use_sql_variables_in", /*< rwsplit only */ "version_string", "filters", + "weightby", NULL }; diff --git a/server/core/dcb.c b/server/core/dcb.c index 94fad72f6..f4d5a560c 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -123,12 +123,6 @@ DCB *rval; rval->dcb_errhandle_called = false; #endif rval->dcb_role = role; -#if 1 - simple_mutex_init(&rval->dcb_write_lock, "DCB write mutex"); - simple_mutex_init(&rval->dcb_read_lock, "DCB read mutex"); - rval->dcb_write_active = false; - rval->dcb_read_active = false; -#endif spinlock_init(&rval->dcb_initlock); spinlock_init(&rval->writeqlock); spinlock_init(&rval->delayqlock); @@ -225,43 +219,11 @@ dcb_add_to_zombieslist(DCB *dcb) spinlock_release(&zombiespin); return; } -#if 1 /*< * Add closing dcb to the top of the list. */ dcb->memdata.next = zombies; zombies = dcb; -#else - if (zombies == NULL) { - zombies = dcb; - } else { - DCB *ptr = zombies; - while (ptr->memdata.next) - { - ss_info_dassert( - ptr->memdata.next->state == DCB_STATE_ZOMBIE, - "Next zombie is not in DCB_STATE_ZOMBIE state"); - - ss_info_dassert( - ptr != dcb, - "Attempt to add DCB to zombies list although it " - "is already there."); - - if (ptr == dcb) - { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Attempt to add DCB to zombies " - "list when it is already in the list"))); - break; - } - ptr = ptr->memdata.next; - } - if (ptr != dcb) { - ptr->memdata.next = dcb; - } - } -#endif /*< * Set state which indicates that it has been added to zombies * list. @@ -396,8 +358,6 @@ DCB_CALLBACK *cb; spinlock_release(&dcb->cb_lock); bitmask_free(&dcb->memdata.bitmask); - simple_mutex_done(&dcb->dcb_read_lock); - simple_mutex_done(&dcb->dcb_write_lock); free(dcb); } @@ -411,15 +371,10 @@ DCB_CALLBACK *cb; * the memdata.bitmask then the DCB is no longer able to be * referenced and it can be finally removed. * - * The excluded DCB allows a thread to exclude a DCB from zombie processing. - * It is used when a thread calls dcb_process_zombies when there is - * a DCB that the caller knows it will continue processing with. - * * @param threadid The thread ID of the caller - * @param excluded The DCB the thread currently uses, NULL or valid DCB. */ DCB * -dcb_process_zombies(int threadid, DCB *excluded) +dcb_process_zombies(int threadid) { DCB *ptr, *lptr; DCB* dcb_list = NULL; @@ -453,10 +408,10 @@ bool succp = false; CHK_DCB(ptr); /* - * Skip processing of the excluded DCB or DCB's that are + * Skip processing of DCB's that are * in the event queue waiting to be processed. */ - if (ptr == excluded || ptr->evq.next || ptr->evq.prev) + if (ptr->evq.next || ptr->evq.prev) { lptr = ptr; ptr = ptr->memdata.next; diff --git a/server/core/gateway.c b/server/core/gateway.c index 7c674ad34..79c2585fe 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,17 @@ static bool libmysqld_started = FALSE; */ static bool daemon_mode = true; +const char *progname = NULL; +static struct option long_options[] = { + {"homedir", required_argument, 0, 'c'}, + {"config", required_argument, 0, 'f'}, + {"nodeamon", required_argument, 0, 'd'}, + {"log", required_argument, 0, 'l'}, + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, '?'}, + {0, 0, 0, 0} +}; + static void log_flush_shutdown(void); static void log_flush_cb(void* arg); static int write_pid_file(char *); /* write MaxScale pidfile */ @@ -878,15 +890,19 @@ return_cnf_file_buf: return cnf_file_buf; } - static void usage(void) { fprintf(stderr, - "*\n* Usage : maxscale [-h] | [-d] [-c ] [-f ]\n* where:\n* " - "-h help\n* -d enable running in terminal process (default:disabled)\n* " - "-c relative|absolute MaxScale home directory\n* " - "-f relative|absolute pathname of MaxScale configuration file (default:MAXSCALE_HOME/etc/MaxScale.cnf)\n*\n"); + "\nUsage : %s [-h] | [-d] [-c ] [-f ]\n\n" + " -d|--nodaemon enable running in terminal process (default:disabled)\n" + " -c|--homedir=... relative|absolute MaxScale home directory\n" + " -f|--config=... relative|absolute pathname of MaxScale configuration file\n" + " (default: $MAXSCALE_HOME/etc/MaxScale.cnf)\n" + " -l|--log=... log to file or shared memory\n" + " -lfile or -lshm - defaults to shared memory\n" + " -v|--version print version info and exit\n" + " -?|--help show this help\n" + , progname); } /** @@ -943,6 +959,8 @@ int main(int argc, char **argv) char* cnf_file_path = NULL; /*< conf file, to be freed */ char* cnf_file_arg = NULL; /*< conf filename from cmd-line arg */ void* log_flush_thr = NULL; + int option_index; + int logtofile = 0; /* Use shared memory or file */ ssize_t log_flush_timeout_ms = 0; sigset_t sigset; sigset_t sigpipe_mask; @@ -954,6 +972,8 @@ int main(int argc, char **argv) sigemptyset(&sigpipe_mask); sigaddset(&sigpipe_mask, SIGPIPE); + progname = *argv; + #if defined(SS_DEBUG) memset(conn_open, 0, sizeof(bool)*10240); memset(dcb_fake_write_errno, 0, sizeof(unsigned char)*10240); @@ -980,7 +1000,8 @@ int main(int argc, char **argv) goto return_main; } } - while ((opt = getopt(argc, argv, "dc:f:h")) != -1) + while ((opt = getopt_long(argc, argv, "dc:f:l:v?", + long_options, &option_index)) != -1) { bool succp = true; @@ -1061,9 +1082,36 @@ int main(int argc, char **argv) succp = false; } break; + + case 'v': + rc = EXIT_SUCCESS; + goto return_main; + + case 'l': + if (strncasecmp(optarg, "file") == 0) + logtofile = 1; + else if (strncasecmp(optarg, "shm") == 0) + logtofile = 0; + else + { + char* logerr = "Configuration file argument " + "identifier \'-l\' was specified but " + "the argument didn't specify\n a valid " + "configuration file or the argument " + "was missing."; + print_log_n_stderr(true, true, logerr, logerr, 0); + usage(); + succp = false; + } + break; + + case '?': + usage(); + rc = EXIT_SUCCESS; + goto return_main; default: - usage(); + usage(); succp = false; break; } @@ -1345,12 +1393,23 @@ int main(int argc, char **argv) argv[0] = "MaxScale"; argv[1] = "-j"; argv[2] = buf; - argv[3] = "-s"; /*< store to shared memory */ - argv[4] = "LOGFILE_DEBUG,LOGFILE_TRACE"; /*< ..these logs to shm */ - argv[5] = "-l"; /*< write to syslog */ - argv[6] = "LOGFILE_MESSAGE,LOGFILE_ERROR"; /*< ..these logs to syslog */ - argv[7] = NULL; - skygw_logmanager_init(7, argv); + if (logtofile) + { + argv[3] = "-l"; /*< write to syslog */ + argv[4] = "LOGFILE_MESSAGE,LOGFILE_ERROR" + "LOGFILE_DEBUG,LOGFILE_TRACE"; + argv[5] = NULL; + skygw_logmanager_init(5, argv); + } + else + { + argv[3] = "-s"; /*< store to shared memory */ + argv[4] = "LOGFILE_DEBUG,LOGFILE_TRACE"; /*< ..these logs to shm */ + argv[5] = "-l"; /*< write to syslog */ + argv[6] = "LOGFILE_MESSAGE,LOGFILE_ERROR"; /*< ..these logs to syslog */ + argv[7] = NULL; + skygw_logmanager_init(7, argv); + } } /*< @@ -1629,8 +1688,13 @@ static void log_flush_cb( static void unlink_pidfile(void) { if (strlen(pidfile)) { - if (unlink(pidfile)) { - fprintf(stderr, "MaxScale failed to remove pidfile %s: error %d, %s\n", pidfile, errno, strerror(errno)); + if (unlink(pidfile)) + { + fprintf(stderr, + "MaxScale failed to remove pidfile %s: error %d, %s\n", + pidfile, + errno, + strerror(errno)); } } } diff --git a/server/core/hint.c b/server/core/hint.c index 2a463585e..2d716771a 100644 --- a/server/core/hint.c +++ b/server/core/hint.c @@ -17,6 +17,7 @@ */ #include #include +#include #include /** diff --git a/server/core/modutil.c b/server/core/modutil.c index 7247f181d..ec7f8530b 100644 --- a/server/core/modutil.c +++ b/server/core/modutil.c @@ -76,7 +76,7 @@ unsigned char *ptr; ptr = GWBUF_DATA(buf); *length = *ptr++; *length += (*ptr++ << 8); - *length += (*ptr++ << 8); + *length += (*ptr++ << 16); ptr += 2; // Skip sequence id and COM_QUERY byte *length = *length - 1; *sql = (char *)ptr; @@ -111,7 +111,7 @@ unsigned char *ptr; ptr = GWBUF_DATA(buf); *residual = *ptr++; *residual += (*ptr++ << 8); - *residual += (*ptr++ << 8); + *residual += (*ptr++ << 16); ptr += 2; // Skip sequence id and COM_QUERY byte *residual = *residual - 1; *length = GWBUF_LENGTH(buf) - 5; @@ -143,7 +143,7 @@ GWBUF *addition; ptr = GWBUF_DATA(orig); length = *ptr++; length += (*ptr++ << 8); - length += (*ptr++ << 8); + length += (*ptr++ << 16); ptr += 2; // Skip sequence id and COM_QUERY byte newlength = strlen(sql); @@ -178,11 +178,11 @@ GWBUF *addition; * * @param buf GWBUF buffer including the query * - * @return Plaint text query if the packet type is COM_QUERY. Otherwise return + * @return Plain text query if the packet type is COM_QUERY. Otherwise return * a string including the packet type. */ -char* modutil_get_query( - GWBUF* buf) +char * +modutil_get_query(GWBUF *buf) { uint8_t* packet; mysql_server_cmd_t packet_type; diff --git a/server/core/monitor.c b/server/core/monitor.c index 6227afd5d..3504be917 100644 --- a/server/core/monitor.c +++ b/server/core/monitor.c @@ -60,8 +60,9 @@ MONITOR *mon; { return NULL; } - + mon->state = MONITOR_STATE_ALLOC; mon->name = strdup(name); + if ((mon->module = load_module(module, MODULE_MONITOR)) == NULL) { LOGIF(LE, (skygw_log_write_flush( @@ -73,7 +74,8 @@ MONITOR *mon; return NULL; } mon->handle = (*mon->module->startMonitor)(NULL); - mon->state |= MONITOR_STATE_RUNNING; + mon->state = MONITOR_STATE_RUNNING; + spinlock_acquire(&monLock); mon->next = allMonitors; allMonitors = mon; @@ -94,7 +96,7 @@ monitor_free(MONITOR *mon) MONITOR *ptr; mon->module->stopMonitor(mon->handle); - mon->state &= ~MONITOR_STATE_RUNNING; + mon->state = MONITOR_STATE_FREED; spinlock_acquire(&monLock); if (allMonitors == mon) allMonitors = mon->next; @@ -121,7 +123,7 @@ void monitorStart(MONITOR *monitor) { monitor->handle = (*monitor->module->startMonitor)(monitor->handle); - monitor->state |= MONITOR_STATE_RUNNING; + monitor->state = MONITOR_STATE_RUNNING; } /** @@ -132,8 +134,9 @@ monitorStart(MONITOR *monitor) void monitorStop(MONITOR *monitor) { + monitor->state = MONITOR_STATE_STOPPING; monitor->module->stopMonitor(monitor->handle); - monitor->state &= ~MONITOR_STATE_RUNNING; + monitor->state = MONITOR_STATE_STOPPED; } /** diff --git a/server/core/poll.c b/server/core/poll.c index 3d396a76d..fa2be4928 100644 --- a/server/core/poll.c +++ b/server/core/poll.c @@ -51,6 +51,13 @@ extern int lm_enabled_logfiles_bitmask; * zombie management * 29/08/14 Mark Riddoch Addition of thread status data, load average * etc. + * 23/09/14 Mark Riddoch Make use of RDHUP conditional to allow CentOS 5 + * builds. + * 24/09/14 Mark Riddoch Introduction of the event queue for processing the + * incoming events rather than processing them immediately + * in the loop after the epoll_wait. This allows for better + * thread utilisaiton and fairer scheduling of the event + * processing. * * @endverbatim */ @@ -204,8 +211,12 @@ poll_add_dcb(DCB *dcb) struct epoll_event ev; CHK_DCB(dcb); - + +#ifdef EPOLLRDHUP ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLHUP | EPOLLET; +#else + ev.events = EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLET; +#endif ev.data.ptr = dcb; /*< @@ -380,7 +391,11 @@ DCB *zombies = NULL; { /* Process of the queue of waiting requests */ while (process_pollq(thread_id)) - zombies = dcb_process_zombies(thread_id, NULL); + { + if (thread_data) + thread_data[thread_id].state = THREAD_ZPROCESSING; + zombies = dcb_process_zombies(thread_id); + } atomic_add(&n_waiting, 1); #if BLOCKINGPOLL @@ -494,15 +509,13 @@ DCB *zombies = NULL; } spinlock_release(&pollqlock); } - - /*< for */ } if (thread_data) { thread_data[thread_id].state = THREAD_ZPROCESSING; } - zombies = dcb_process_zombies(thread_id, NULL); + zombies = dcb_process_zombies(thread_id); if (do_shutdown) { @@ -515,6 +528,8 @@ DCB *zombies = NULL; thread_data[thread_id].state = THREAD_STOPPED; } bitmask_clear(&poll_mask, thread_id); + /** Release mysql thread context */ + mysql_thread_end(); return; } if (thread_data) @@ -522,8 +537,6 @@ DCB *zombies = NULL; thread_data[thread_id].state = THREAD_IDLE; } } /*< while(1) */ - /** Release mysql thread context */ - mysql_thread_end(); } /** @@ -762,6 +775,7 @@ uint32_t ev; spinlock_release(&dcb->dcb_initlock); } +#ifdef EPOLLRDHUP if (ev & EPOLLRDHUP) { int eno = 0; @@ -788,6 +802,7 @@ uint32_t ev; else spinlock_release(&dcb->dcb_initlock); } +#endif spinlock_acquire(&pollqlock); if (dcb->evq.pending_events == 0) @@ -932,12 +947,14 @@ char *str; strcat(str, "|"); strcat(str, "HUP"); } +#ifdef EPOLLRDHUP if (event & EPOLLRDHUP) { if (*str) strcat(str, "|"); strcat(str, "RDHUP"); } +#endif return str; } diff --git a/server/core/test/CMakeLists.txt b/server/core/test/CMakeLists.txt new file mode 100644 index 000000000..914fe277e --- /dev/null +++ b/server/core/test/CMakeLists.txt @@ -0,0 +1,13 @@ +add_executable(test_hash testhash.c) +add_executable(test_spinlock testspinlock.c) +add_executable(test_filter testfilter.c) +add_executable(test_adminusers testadminusers.c) +target_link_libraries(test_hash fullcore) +target_link_libraries(test_spinlock fullcore) +target_link_libraries(test_filter fullcore) +target_link_libraries(test_adminusers fullcore) +add_test(TestHash test_hash) +add_test(TestSpinlock test_spinlock) +add_test(TestFilter test_filter) +add_test(TestAdminUsers test_adminusers) + diff --git a/server/include/dcb.h b/server/include/dcb.h index 5e14fc235..72686b7b7 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -210,12 +210,6 @@ typedef struct dcb { dcb_role_t dcb_role; SPINLOCK dcb_initlock; DCBEVENTQ evq; /**< The event queue for this DCB */ -#if 1 - simple_mutex_t dcb_read_lock; - simple_mutex_t dcb_write_lock; - bool dcb_read_active; - bool dcb_write_active; -#endif int fd; /**< The descriptor */ dcb_state_t state; /**< Current descriptor state */ int flags; /**< DCB flags */ @@ -295,7 +289,7 @@ DCB *dcb_clone(DCB *); int dcb_read(DCB *, GWBUF **); int dcb_drain_writeq(DCB *); void dcb_close(DCB *); -DCB *dcb_process_zombies(int, DCB*); /* Process Zombies except the one behind the pointer */ +DCB *dcb_process_zombies(int); /* Process Zombies except the one behind the pointer */ void printAllDCBs(); /* Debug to print all DCB in the system */ void printDCB(DCB *); /* Debug print routine */ void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */ diff --git a/server/include/monitor.h b/server/include/monitor.h index 5d018c16f..04337d761 100644 --- a/server/include/monitor.h +++ b/server/include/monitor.h @@ -69,7 +69,7 @@ typedef struct { void (*unregisterServer)(void *, SERVER *); void (*defaultUser)(void *, char *, char *); void (*diagnostics)(DCB *, void *); - void (*setInterval)(void *, unsigned long); + void (*setInterval)(void *, size_t); void (*defaultId)(void *, unsigned long); void (*replicationHeartbeat)(void *, int); void (*detectStaleMaster)(void *, int); @@ -81,21 +81,30 @@ typedef struct { */ #define MONITOR_VERSION {1, 0, 0} +/** Monitor's poll frequency */ +#define MON_BASE_INTERVAL_MS 100 + /** * Monitor state bit mask values */ -#define MONITOR_STATE_RUNNING 0x0001 - +typedef enum +{ + MONITOR_STATE_ALLOC = 0x00, + MONITOR_STATE_RUNNING = 0x01, + MONITOR_STATE_STOPPING = 0x02, + MONITOR_STATE_STOPPED = 0x04, + MONITOR_STATE_FREED = 0x08 +} monitor_state_t; /** * Representation of the running monitor. */ typedef struct monitor { char *name; /**< The name of the monitor module */ - unsigned int state; /**< The monitor status */ + monitor_state_t state; /**< The state of the monitor */ MONITOR_OBJECT *module; /**< The "monitor object" */ void *handle; /**< Handle returned from startMonitor */ - int interval; /**< The monitor interval */ + size_t interval; /**< The monitor interval */ struct monitor *next; /**< Next monitor in the linked list */ } MONITOR; diff --git a/server/include/version.h.in b/server/include/version.h.in new file mode 100644 index 000000000..5aced69a5 --- /dev/null +++ b/server/include/version.h.in @@ -0,0 +1 @@ +#define MAXSCALE_VERSION "@MAXSCALE_VERSION@" diff --git a/server/inih/CMakeLists.txt b/server/inih/CMakeLists.txt new file mode 100644 index 000000000..24393e05d --- /dev/null +++ b/server/inih/CMakeLists.txt @@ -0,0 +1 @@ +add_library(inih ini.c) \ No newline at end of file diff --git a/server/modules/CMakeLists.txt b/server/modules/CMakeLists.txt new file mode 100644 index 000000000..f2d746ded --- /dev/null +++ b/server/modules/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(monitor) +add_subdirectory(routing) +add_subdirectory(protocol) +add_subdirectory(monitor) +add_subdirectory(filter) \ No newline at end of file diff --git a/server/modules/filter/CMakeLists.txt b/server/modules/filter/CMakeLists.txt new file mode 100644 index 000000000..f9dea236d --- /dev/null +++ b/server/modules/filter/CMakeLists.txt @@ -0,0 +1,27 @@ +if(BUILD_RABBITMQ) + add_library(mqfilter SHARED mqfilter.c) + target_link_libraries(mqfilter query_classifier log_manager utils rabbitmq) + install(TARGETS mqfilter DESTINATION modules) +endif() + +add_library(regexfilter SHARED regexfilter.c) +target_link_libraries(regexfilter log_manager utils) +install(TARGETS regexfilter DESTINATION modules) + +add_library(testfilter SHARED testfilter.c) +target_link_libraries(testfilter log_manager utils) +install(TARGETS testfilter DESTINATION modules) + +add_library(qlafilter SHARED qlafilter.c) +target_link_libraries(qlafilter log_manager utils) +install(TARGETS qlafilter DESTINATION modules) + +add_library(tee SHARED tee.c) +target_link_libraries(tee log_manager utils) +install(TARGETS tee DESTINATION modules) + +add_library(topfilter SHARED topfilter.c) +target_link_libraries(topfilter log_manager utils) +install(TARGETS topfilter DESTINATION modules) + +add_subdirectory(hint) \ No newline at end of file diff --git a/server/modules/filter/hint/CMakeLists.txt b/server/modules/filter/hint/CMakeLists.txt new file mode 100644 index 000000000..f47cb637e --- /dev/null +++ b/server/modules/filter/hint/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(hintfilter SHARED hintfilter.c hintparser.c) +set_target_properties(hintfilter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib) +target_link_libraries(hintfilter ssl log_manager utils) +install(TARGETS hintfilter DESTINATION modules) \ No newline at end of file diff --git a/server/modules/include/maxscaled.h b/server/modules/include/maxscaled.h index 3733772d8..fd4e6439e 100644 --- a/server/modules/include/maxscaled.h +++ b/server/modules/include/maxscaled.h @@ -30,13 +30,15 @@ * @endverbatim */ #include +#include /** * The telnetd specific protocol structure to put in the DCB. */ typedef struct maxscaled { - int state; /**< The connection state */ - char *username; /**< The login name of the user */ + SPINLOCK lock; /**< Protocol structure lock */ + int state; /**< The connection state */ + char *username; /**< The login name of the user */ } MAXSCALED; #define MAXSCALED_STATE_LOGIN 1 /**< Issued login prompt */ diff --git a/server/modules/monitor/CMakeLists.txt b/server/modules/monitor/CMakeLists.txt new file mode 100644 index 000000000..d94312682 --- /dev/null +++ b/server/modules/monitor/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(mysqlmon SHARED mysql_mon.c) +target_link_libraries(mysqlmon log_manager utils ${EMBEDDED_LIB}) +install(TARGETS mysqlmon DESTINATION modules) + +add_library(galeramon SHARED galera_mon.c) +target_link_libraries(galeramon log_manager utils ${EMBEDDED_LIB}) +install(TARGETS galeramon DESTINATION modules) + +add_library(ndbclustermon SHARED ndbcluster_mon.c) +target_link_libraries(ndbclustermon log_manager utils ${EMBEDDED_LIB}) +install(TARGETS ndbclustermon DESTINATION modules) \ No newline at end of file diff --git a/server/modules/monitor/galera_mon.c b/server/modules/monitor/galera_mon.c index 211407f86..bbde5ca49 100644 --- a/server/modules/monitor/galera_mon.c +++ b/server/modules/monitor/galera_mon.c @@ -67,9 +67,20 @@ static void registerServer(void *, SERVER *); static void unregisterServer(void *, SERVER *); static void defaultUsers(void *, char *, char *); static void diagnostics(DCB *, void *); -static void setInterval(void *, unsigned long); +static void setInterval(void *, size_t); -static MONITOR_OBJECT MyObject = { startMonitor, stopMonitor, registerServer, unregisterServer, defaultUsers, diagnostics, setInterval, NULL, NULL, NULL }; +static MONITOR_OBJECT MyObject = { + startMonitor, + stopMonitor, + registerServer, + unregisterServer, + defaultUsers, + diagnostics, + setInterval, + NULL, + NULL, + NULL, +}; /** * Implementation of the mandatory version entry point @@ -413,6 +424,7 @@ monitorMain(void *arg) MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; MONITOR_SERVERS *ptr; long master_id; +size_t nrounds = 0; if (mysql_thread_init()) { @@ -423,10 +435,9 @@ long master_id; return; } handle->status = MONITOR_RUNNING; + while (1) { - master_id = -1; - if (handle->shutdown) { handle->status = MONITOR_STOPPING; @@ -434,7 +445,23 @@ long master_id; handle->status = MONITOR_STOPPED; return; } - + /** Wait base interval */ + thread_millisleep(MON_BASE_INTERVAL_MS); + /** + * Calculate how far away the monitor interval is from its full + * cycle and if monitor interval time further than the base + * interval, then skip monitoring checks. Excluding the first + * round. + */ + if (nrounds != 0 && + ((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) > + MON_BASE_INTERVAL_MS) + { + nrounds += 1; + continue; + } + nrounds += 1; + master_id = -1; ptr = handle->databases; while (ptr) @@ -491,7 +518,6 @@ long master_id; ptr = ptr->next; } - thread_millisleep(handle->interval); } } @@ -502,7 +528,7 @@ long master_id; * @param interval The interval to set in monitor struct, in milliseconds */ static void -setInterval(void *arg, unsigned long interval) +setInterval(void *arg, size_t interval) { MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; memcpy(&handle->interval, &interval, sizeof(unsigned long)); diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 976aa315d..c4cea23ee 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -80,7 +80,7 @@ static void registerServer(void *, SERVER *); static void unregisterServer(void *, SERVER *); static void defaultUser(void *, char *, char *); static void diagnostics(DCB *, void *); -static void setInterval(void *, unsigned long); +static void setInterval(void *, size_t); static void defaultId(void *, unsigned long); static void replicationHeartbeat(void *, int); static void detectStaleMaster(void *, int); @@ -95,7 +95,18 @@ static int add_slave_to_master(long *, int, long); static void monitor_set_pending_status(MONITOR_SERVERS *, int); static void monitor_clear_pending_status(MONITOR_SERVERS *, int); -static MONITOR_OBJECT MyObject = { startMonitor, stopMonitor, registerServer, unregisterServer, defaultUser, diagnostics, setInterval, defaultId, replicationHeartbeat, detectStaleMaster }; +static MONITOR_OBJECT MyObject = { + startMonitor, + stopMonitor, + registerServer, + unregisterServer, + defaultUser, + diagnostics, + setInterval, + defaultId, + replicationHeartbeat, + detectStaleMaster +}; /** * Implementation of the mandatory version entry point @@ -577,6 +588,7 @@ int replication_heartbeat = handle->replicationHeartbeat; int detect_stale_master = handle->detectStaleMaster; int num_servers=0; MONITOR_SERVERS *root_master; +size_t nrounds = 0; if (mysql_thread_init()) { @@ -586,8 +598,8 @@ MONITOR_SERVERS *root_master; "module. Exiting.\n"))); return; } - handle->status = MONITOR_RUNNING; + while (1) { if (handle->shutdown) @@ -597,6 +609,22 @@ MONITOR_SERVERS *root_master; handle->status = MONITOR_STOPPED; return; } + /** Wait base interval */ + thread_millisleep(MON_BASE_INTERVAL_MS); + /** + * Calculate how far away the monitor interval is from its full + * cycle and if monitor interval time further than the base + * interval, then skip monitoring checks. Excluding the first + * round. + */ + if (nrounds != 0 && + ((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) > + MON_BASE_INTERVAL_MS) + { + nrounds += 1; + continue; + } + nrounds += 1; /* reset num_servers */ num_servers = 0; @@ -686,10 +714,7 @@ MONITOR_SERVERS *root_master; ptr = ptr->next; } } - - /* wait for the configured interval */ - thread_millisleep(handle->interval); - } + } /*< while (1) */ } /** @@ -704,7 +729,7 @@ defaultId(void *arg, unsigned long id) MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; memcpy(&handle->id, &id, sizeof(unsigned long)); } - + /** * Set the monitor sampling interval. * @@ -712,7 +737,7 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; * @param interval The interval to set in monitor struct, in milliseconds */ static void -setInterval(void *arg, unsigned long interval) +setInterval(void *arg, size_t interval) { MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; memcpy(&handle->interval, &interval, sizeof(unsigned long)); diff --git a/server/modules/monitor/ndbcluster_mon.c b/server/modules/monitor/ndbcluster_mon.c index 840e30691..b35af4fe2 100644 --- a/server/modules/monitor/ndbcluster_mon.c +++ b/server/modules/monitor/ndbcluster_mon.c @@ -61,9 +61,20 @@ static void registerServer(void *, SERVER *); static void unregisterServer(void *, SERVER *); static void defaultUsers(void *, char *, char *); static void diagnostics(DCB *, void *); -static void setInterval(void *, unsigned long); +static void setInterval(void *, size_t); -static MONITOR_OBJECT MyObject = { startMonitor, stopMonitor, registerServer, unregisterServer, defaultUsers, diagnostics, setInterval, NULL, NULL, NULL }; +static MONITOR_OBJECT MyObject = { + startMonitor, + stopMonitor, + registerServer, + unregisterServer, + defaultUsers, + diagnostics, + setInterval, + NULL, + NULL, + NULL +}; /** * Implementation of the mandatory version entry point @@ -410,6 +421,7 @@ monitorMain(void *arg) MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; MONITOR_SERVERS *ptr; long master_id; +size_t nrounds = 0; if (mysql_thread_init()) { @@ -420,10 +432,9 @@ long master_id; return; } handle->status = MONITOR_RUNNING; + while (1) { - master_id = -1; - if (handle->shutdown) { handle->status = MONITOR_STOPPING; @@ -432,6 +443,23 @@ long master_id; return; } + /** Wait base interval */ + thread_millisleep(MON_BASE_INTERVAL_MS); + /** + * Calculate how far away the monitor interval is from its full + * cycle and if monitor interval time further than the base + * interval, then skip monitoring checks. Excluding the first + * round. + */ + if (nrounds != 0 && + ((nrounds*MON_BASE_INTERVAL_MS)%handle->interval) > + MON_BASE_INTERVAL_MS) + { + nrounds += 1; + continue; + } + nrounds += 1; + master_id = -1; ptr = handle->databases; while (ptr) @@ -452,8 +480,6 @@ long master_id; ptr = ptr->next; } - - thread_millisleep(handle->interval); } } @@ -464,7 +490,7 @@ long master_id; * @param interval The interval to set in monitor struct, in milliseconds */ static void -setInterval(void *arg, unsigned long interval) +setInterval(void *arg, size_t interval) { MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; memcpy(&handle->interval, &interval, sizeof(unsigned long)); diff --git a/server/modules/protocol/CMakeLists.txt b/server/modules/protocol/CMakeLists.txt new file mode 100644 index 000000000..e51ff1495 --- /dev/null +++ b/server/modules/protocol/CMakeLists.txt @@ -0,0 +1,24 @@ +add_library(MySQLClient SHARED mysql_client.c mysql_common.c) +target_link_libraries(MySQLClient log_manager utils) +install(TARGETS MySQLClient DESTINATION modules) + +add_library(MySQLBackend SHARED mysql_backend.c mysql_common.c) +target_link_libraries(MySQLBackend log_manager utils) +install(TARGETS MySQLBackend DESTINATION modules) + +add_library(telnetd SHARED telnetd.c) +target_link_libraries(telnetd log_manager utils) +install(TARGETS telnetd DESTINATION modules) + +add_library(HTTPD SHARED httpd.c) +target_link_libraries(HTTPD log_manager utils) +install(TARGETS HTTPD DESTINATION modules) + +add_library(maxscaled SHARED maxscaled.c) +target_link_libraries(maxscaled log_manager utils) +install(TARGETS maxscaled DESTINATION modules) + + + + + diff --git a/server/modules/protocol/maxscaled.c b/server/modules/protocol/maxscaled.c index f580764f8..268b33b52 100644 --- a/server/modules/protocol/maxscaled.c +++ b/server/modules/protocol/maxscaled.c @@ -166,7 +166,6 @@ char *password; { dcb_printf(dcb, "FAILED"); maxscaled->state = MAXSCALED_STATE_LOGIN; - free(maxscaled->username); } gwbuf_consume(head, GWBUF_LENGTH(head)); free(password); @@ -276,16 +275,18 @@ int n_connect = 0; client_dcb->fd = so; client_dcb->remote = strdup(inet_ntoa(addr.sin_addr)); memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); - client_dcb->session = - session_alloc(dcb->session->service, client_dcb); - maxscaled_pr = (MAXSCALED *)malloc(sizeof(MAXSCALED)); - client_dcb->protocol = (void *)maxscaled_pr; - - if (maxscaled_pr == NULL) - { + if ((maxscaled_pr = (MAXSCALED *)malloc(sizeof(MAXSCALED))) == NULL) + { + client_dcb->protocol = NULL; dcb_add_to_zombieslist(client_dcb); return n_connect; } + maxscaled_pr->username = NULL; + spinlock_init(&maxscaled_pr->lock); + client_dcb->protocol = (void *)maxscaled_pr; + + client_dcb->session = + session_alloc(dcb->session->service, client_dcb); if (poll_add_dcb(client_dcb) == -1) { @@ -294,7 +295,6 @@ int n_connect = 0; } n_connect++; maxscaled_pr->state = MAXSCALED_STATE_LOGIN; - maxscaled_pr->username = NULL; dcb_printf(client_dcb, "USER"); } } @@ -313,11 +313,16 @@ maxscaled_close(DCB *dcb) { MAXSCALED *maxscaled = dcb->protocol; - if (maxscaled && maxscaled->username) + if (!maxscaled) + return 0; + + spinlock_acquire(&maxscaled->lock); + if (maxscaled->username) { free(maxscaled->username); maxscaled->username = NULL; } + spinlock_release(&maxscaled->lock); return 0; } diff --git a/server/modules/routing/CMakeLists.txt b/server/modules/routing/CMakeLists.txt new file mode 100644 index 000000000..595a216c8 --- /dev/null +++ b/server/modules/routing/CMakeLists.txt @@ -0,0 +1,18 @@ +add_library(testroute SHARED testroute.c) +target_link_libraries(testroute log_manager utils) +install(TARGETS testroute DESTINATION modules) + +add_library(readconnroute SHARED readconnroute.c) +target_link_libraries(readconnroute log_manager utils) +install(TARGETS readconnroute DESTINATION modules) + +add_library(debugcli SHARED debugcli.c debugcmd.c) +target_link_libraries(debugcli log_manager utils) +install(TARGETS debugcli DESTINATION modules) + +add_library(cli SHARED cli.c debugcmd.c) +target_link_libraries(cli log_manager utils) +install(TARGETS cli DESTINATION modules) + +add_subdirectory(readwritesplit) +add_subdirectory(binlog) \ No newline at end of file diff --git a/server/modules/routing/binlog/CMakeLists.txt b/server/modules/routing/binlog/CMakeLists.txt new file mode 100644 index 000000000..071901b70 --- /dev/null +++ b/server/modules/routing/binlog/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(binlogrouter SHARED blr.c blr_master.c blr_cache.c blr_slave.c blr_file.c) +set_target_properties(binlogrouter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib) +target_link_libraries(binlogrouter ssl pthread log_manager ${EMBEDDED_LIB}) +install(TARGETS binlogrouter DESTINATION modules) diff --git a/server/modules/routing/readwritesplit/CMakeLists.txt b/server/modules/routing/readwritesplit/CMakeLists.txt new file mode 100644 index 000000000..2821ca3ed --- /dev/null +++ b/server/modules/routing/readwritesplit/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(readwritesplit SHARED readwritesplit.c) +target_link_libraries(readwritesplit ssl pthread log_manager utils query_classifier ${EMBEDDED_LIB}) +install(TARGETS readwritesplit DESTINATION modules) +if(BUILD_TESTS) +add_subdirectory(test) +endif() \ No newline at end of file diff --git a/server/modules/routing/readwritesplit/test/CMakeLists.txt b/server/modules/routing/readwritesplit/test/CMakeLists.txt new file mode 100644 index 000000000..b2012e789 --- /dev/null +++ b/server/modules/routing/readwritesplit/test/CMakeLists.txt @@ -0,0 +1,3 @@ +add_test(NAME ReadWriteSplitTest COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/rwsplit.sh testrwsplit.log ${TEST_HOST} ${TEST_PORT_RW} ${TEST_MASTER_ID} ${TEST_USER} ${TEST_PASSWORD} ${CMAKE_CURRENT_SOURCE_DIR}) +set_tests_properties(ReadWriteSplitTest PROPERTIES DEPENDS RunExecutable) +add_subdirectory(test_hints) \ No newline at end of file diff --git a/server/modules/routing/readwritesplit/test/rwsplit.sh b/server/modules/routing/readwritesplit/test/rwsplit.sh index 6fefd8801..fcca4ac37 100755 --- a/server/modules/routing/readwritesplit/test/rwsplit.sh +++ b/server/modules/routing/readwritesplit/test/rwsplit.sh @@ -1,5 +1,5 @@ #!/bin/sh -NARGS=6 +NARGS=7 TLOG=$1 THOST=$2 TPORT=$3 @@ -7,10 +7,10 @@ TMASTER_ID=$4 TUSER=$5 TPWD=$6 -if [ $# != $NARGS ] ; +if [ $# -lt $(( NARGS - 1 )) ] ; then echo"" -echo "Wrong number of arguments, gave "$#" but "$NARGS" is required" +echo "Wrong number of arguments, gave "$#" but "$(( NARGS - 1 ))" is required" echo "" echo "Usage :" echo " rwsplit.sh " @@ -18,12 +18,20 @@ echo "" exit 1 fi +if [ "$#" == "$NARGS" ] +then + echo "CTest mode" + TDIR=$7 #this is only used by CMake + echo "Test directory is: $TDIR" +else + TDIR=. +fi RUNCMD=mysql\ --host=$THOST\ -P$TPORT\ -u$TUSER\ -p$TPWD\ --unbuffered=true\ --disable-reconnect\ --silent TINPUT=test_transaction_routing2.sql TRETVAL=0 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -32,7 +40,7 @@ fi TINPUT=test_transaction_routing2b.sql TRETVAL=0 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -41,7 +49,7 @@ fi TINPUT=test_transaction_routing3.sql TRETVAL=2 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TMASTER_ID" ]; then echo "$TINPUT FAILED, return value $a when one of the slave IDs was expected">>$TLOG; else @@ -50,7 +58,7 @@ fi TINPUT=test_transaction_routing3b.sql TRETVAL=2 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TMASTER_ID" ]; then echo "$TINPUT FAILED, return value $a when one of the slave IDs was expected">>$TLOG; else @@ -60,7 +68,7 @@ fi # test implicit transaction, that is, not started explicitly, autocommit=0 TINPUT=test_transaction_routing4.sql TRETVAL=0 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -69,7 +77,7 @@ fi TINPUT=test_transaction_routing4b.sql TRETVAL=0 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -80,7 +88,7 @@ fi TINPUT=select_for_var_set.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -90,7 +98,7 @@ fi TINPUT=test_implicit_commit1.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when it was not accetable">>$TLOG; else @@ -99,7 +107,7 @@ fi TINPUT=test_implicit_commit2.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when it was not accetable">>$TLOG; else @@ -108,7 +116,7 @@ fi TINPUT=test_implicit_commit3.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when it was not accetable">>$TLOG; else @@ -117,7 +125,7 @@ fi TINPUT=test_implicit_commit4.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -126,7 +134,7 @@ fi TINPUT=test_implicit_commit5.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when it was not accetable">>$TLOG; else @@ -135,7 +143,7 @@ fi TINPUT=test_implicit_commit6.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when it was not accetable">>$TLOG; else @@ -144,7 +152,7 @@ fi TINPUT=test_implicit_commit7.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when it was not accetable">>$TLOG; else @@ -153,7 +161,7 @@ fi TINPUT=test_autocommit_disabled1.sql TRETVAL=1 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -162,7 +170,7 @@ fi TINPUT=test_autocommit_disabled1b.sql TRETVAL=1 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -173,7 +181,7 @@ fi # it is again enabled. TINPUT=test_autocommit_disabled2.sql TRETVAL=1 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -181,10 +189,10 @@ else fi TINPUT=set_autocommit_disabled.sql -`$RUNCMD < ./$TINPUT` +`$RUNCMD < $TDIR/$TINPUT` TINPUT=test_after_autocommit_disabled.sql TRETVAL=$TMASTER_ID -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" = "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when it was not accetable">>$TLOG; else @@ -194,37 +202,37 @@ fi TINPUT=test_sescmd.sql TRETVAL=2 -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else echo "$TINPUT PASSED">>$TLOG ; fi -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else echo "$TINPUT PASSED">>$TLOG ; fi -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else echo "$TINPUT PASSED">>$TLOG ; fi -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else echo "$TINPUT PASSED">>$TLOG ; fi -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else echo "$TINPUT PASSED">>$TLOG ; fi -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; else @@ -232,7 +240,7 @@ else fi TINPUT=test_temporary_table.sql -a=`$RUNCMD < ./$TINPUT` +a=`$RUNCMD < $TDIR/$TINPUT` TRETVAL=1 if [ "$a" != "$TRETVAL" ]; then echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; @@ -252,7 +260,7 @@ do then printf "." fi - a=`$RUNCMD < $TINPUT 2>&1` + a=`$RUNCMD < $TDIR/$TINPUT 2>&1` if [[ "`echo "$a"|grep -i 'error'`" != "" ]] then err=`echo "$a" | grep -i error` @@ -278,7 +286,7 @@ do then printf "." fi - b=`$RUNCMD < $TINPUT 2>&1` + b=`$RUNCMD < $TDIR/$TINPUT 2>&1` if [[ "`echo "$b"|grep -i 'null\|error'`" != "" ]] then err=`echo "$b" | grep -i null\|error` @@ -292,3 +300,8 @@ else echo "Test FAILED at iteration $((j+1))" >> $TLOG fi echo "" >> $TLOG + +if [ $# -eq $NARGS ] +then + cat $TLOG +fi diff --git a/server/modules/routing/readwritesplit/test/test_hints/CMakeLists.txt b/server/modules/routing/readwritesplit/test/test_hints/CMakeLists.txt new file mode 100644 index 000000000..ed804382b --- /dev/null +++ b/server/modules/routing/readwritesplit/test/test_hints/CMakeLists.txt @@ -0,0 +1,3 @@ +add_test(NAME SimpleHintTest COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/rwsplit_hints.sh hints.log ${TEST_HOST} ${TEST_PORT_RW_HINT} ${TEST_MASTER_ID} ${TEST_USER} ${TEST_PASSWORD} simple_tests ${CMAKE_CURRENT_SOURCE_DIR}) +add_test(NAME ComplexHintTest COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/rwsplit_hints.sh hints.log ${TEST_HOST} ${TEST_PORT_RW_HINT} ${TEST_MASTER_ID} ${TEST_USER} ${TEST_PASSWORD} complex_tests ${CMAKE_CURRENT_SOURCE_DIR}) +add_test(NAME StackHintTest COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/rwsplit_hints.sh hints.log ${TEST_HOST} ${TEST_PORT_RW_HINT} ${TEST_MASTER_ID} ${TEST_USER} ${TEST_PASSWORD} stack_tests ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/server/modules/routing/readwritesplit/test/test_hints/rwsplit_hints.sh b/server/modules/routing/readwritesplit/test/test_hints/rwsplit_hints.sh index cdbfb335b..1f751861f 100755 --- a/server/modules/routing/readwritesplit/test/test_hints/rwsplit_hints.sh +++ b/server/modules/routing/readwritesplit/test/test_hints/rwsplit_hints.sh @@ -1,5 +1,5 @@ #!/bin/bash -NARGS=7 +NARGS=8 TLOG=$1 THOST=$2 TPORT=$3 @@ -8,10 +8,10 @@ TUSER=$5 TPWD=$6 TESTINPUT=$7 -if [ $# != $NARGS ] ; +if [ $# -lt $(( NARGS - 1 )) ] ; then echo"" -echo "Wrong number of arguments, gave "$#" but "$NARGS" is required" +echo "Wrong number of arguments, gave "$#" but "$(( NARGS - 1 ))" is required" echo "" echo "Usage :" echo " rwsplit_hints.sh " @@ -19,6 +19,14 @@ echo "" exit 1 fi +if [ $# -eq $NARGS ] +then + TDIR=$8 +else + TDIR=. +fi + +TESTINPUT=$TDIR/$TESTINPUT RUNCMD=mysql\ --host=$THOST\ -P$TPORT\ -u$TUSER\ -p$TPWD\ --unbuffered=true\ --disable-reconnect\ --silent\ --comment i=0 @@ -63,3 +71,8 @@ then else echo "Test set: FAILED">>$TLOG; fi + +if [ $# -eq $NARGS ] +then + cat $TLOG +fi diff --git a/server/test/CMakeLists.txt b/server/test/CMakeLists.txt new file mode 100644 index 000000000..22e4c1b4d --- /dev/null +++ b/server/test/CMakeLists.txt @@ -0,0 +1,7 @@ +file(COPY MaxScale_test.cnf DESTINATION ${CMAKE_BINARY_DIR}/etc) +file(RENAME ${CMAKE_BINARY_DIR}/etc/MaxScale_test.cnf ${CMAKE_BINARY_DIR}/etc/MaxScale.cnf) +#add_test(NAME RunExecutable COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/startmaxscale.sh "${CMAKE_BINARY_DIR}/bin/" "-c ${CMAKE_BINARY_DIR}") +#set_tests_properties(RunExecutable PROPERTIES TIMEOUT 2) + +#add_test(NAME KillExecutable COMMAND killall -KILL maxscale) +#set_tests_properties(KillExecutable PROPERTIES DEPENDS StackHintTest ) #this needs to be the last test that requires a running maxscale diff --git a/server/test/startmaxscale.sh b/server/test/startmaxscale.sh new file mode 100755 index 000000000..979034476 --- /dev/null +++ b/server/test/startmaxscale.sh @@ -0,0 +1,5 @@ +#!/bin/sh +killall -KILL maxscale +sleep 1 +setsid $1/maxscale $2 +exit 0 diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 000000000..8a2cfddb6 --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(utils skygw_utils.cc) +target_link_libraries(utils stdc++) \ No newline at end of file