Merge branch 'cmake_build' into query_classifier_test

This commit is contained in:
Markus Makela
2014-09-22 14:39:02 +03:00
18 changed files with 368 additions and 231 deletions

View File

@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.6)
include(macros.cmake) include(macros.cmake)
enable_testing() enable_testing()
set_variables() set_variables()
set_maxscale_version() set_maxscale_version()

37
README
View File

@ -157,7 +157,7 @@ Please check errmsg.sys is found in the MaxScale install_dir DEST/MaxScale/mysql
You can also build MaxScale with CMake which makes the build process a bit more simple. 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 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 or newer if you wish to generate packages. 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 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 explicitly state the locations you can pass additional options to CMake by using the -D flag. To confirm the variable
@ -166,16 +166,19 @@ values, you can run CMake in interactive mode by using the -i flag or use a CMak
It is highly recommended to make a separate build directory to build into. This keeps the source and build trees clean and 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. makes it easy to get rid of everything you built.
By default, MaxScale installs to /usr/local/skysql and places init.d scripts and ldconfig files into their folders. Change the INSTALL_DIR To build MaxScale using CMake:
variable to your desired installation directory and set INSTALL_SYSTEM_FILES=N to prevent the init.d script and ldconfig file installation.
To build and install MaxScale using CMake with a custom install location and a separate build directory: cd <path to MaxScale source>
cmake -D_INSTALL_DIR=<install destination> <path to MaxScale source> mkdir build
make cd build
make install cmake ..
make
make install
This generates the required makefiles in the current directory, compiles and links all the programs and installs 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. all the required files in their right places.
@ -184,19 +187,33 @@ To build MaxScale using the ccmake GUI:
ccmake <path to MaxScale source> ccmake <path to MaxScale source>
If you have your headers and libraries in non-standard locations, you can define those locations at configuration time as such:
cmake -D<variable>=<value>
By default, MaxScale installs to '/usr/local/skysql/maxscale' and places init.d scripts and ldconfig files into their folders. Change the INSTALL_DIR
variable to your desired installation directory and set INSTALL_SYSTEM_FILES=N to prevent the init.d script and ldconfig file installation.
All the parameters affecting CMake can be found in 'macros.cmake'. This file also has the parameters CMake uses for testing. All the parameters affecting CMake can be found in 'macros.cmake'. This file also has the parameters CMake uses for testing.
Variables controlling the CMake build process: All the variables that control the CMake build process:
INSTALL_DIR=<path> Installation directory INSTALL_DIR=<path> Installation directory
BUILD_TYPE=[None|Debug|Release] Type of the build, defaults to Release (optimized) 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 INSTALL_SYSTEM_FILES=[Y|N] Install startup scripts and ld configuration files
EMBEDDED_LIB=<path> Path to the embedded library, filename included EMBEDDED_LIB=<path> Path to the embedded library, filename included
MYSQL_DIR=<path> Path to MySQL headers MYSQL_DIR=<path> Path to MySQL headers
ERRMSG=<path> Path to errmsg.sys file
STATIC_EMBEDDED=[Y|N] Link the static or the dynamic verson of the library STATIC_EMBEDDED=[Y|N] Link the static or the dynamic verson of the library
GCOV=[Y|N] Generate gcov output GCOV=[Y|N] Generate gcov output
BUILD_TESTS=[Y|N] Build tests 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 DEBUG_OUTPUT=[Y|N] Produce debugging output when configuring CMake
RABBITMQ_LIB=<path> Path to RabbitMQ-C libraries
RABBITMQ_HEADERS=<path> Path to RabbitMQ-C headers
MYSQL_CLIENT_LIB=<path> Path to MySQL client libraries
MYSQL_CLIENT_HEADERS=<path> Path to MySQL client headers
\section Running Running MaxScale \section Running Running MaxScale

View File

@ -33,7 +33,7 @@ endif
CC=cc CC=cc
CFLAGS=-c -Wall -g $(HISTFLAG) CFLAGS=-c -Wall -g $(HISTFLAG) -I ../server/include
SRCS= maxadmin.c SRCS= maxadmin.c

View File

@ -47,6 +47,9 @@
#include <dirent.h> #include <dirent.h>
#include <locale.h> #include <locale.h>
#include <errno.h> #include <errno.h>
#include <getopt.h>
#include <version.h>
#ifdef HISTORY #ifdef HISTORY
#include <histedit.h> #include <histedit.h>
@ -59,6 +62,7 @@ static int sendCommand(int so, char *cmd);
static void DoSource(int so, char *cmd); static void DoSource(int so, char *cmd);
static void DoUsage(); static void DoUsage();
static int isquit(char *buf); static int isquit(char *buf);
static void PrintVersion(const char *progname);
#ifdef HISTORY #ifdef HISTORY
static char * static char *
@ -70,6 +74,16 @@ prompt(EditLine *el __attribute__((__unused__)))
} }
#endif #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 * The main for the maxadmin client
* *
@ -79,7 +93,7 @@ prompt(EditLine *el __attribute__((__unused__)))
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int i, num, rv, fatal = 0; int i, num, rv;
#ifdef HISTORY #ifdef HISTORY
char *buf; char *buf;
EditLine *el = NULL; EditLine *el = NULL;
@ -96,107 +110,39 @@ char *user = "admin";
char *passwd = NULL; char *passwd = NULL;
int so, cmdlen; int so, cmdlen;
char *cmd; char *cmd;
int argno = 0; int option_index = 0;
char c;
cmd = malloc(1); cmd = malloc(1);
*cmd = 0; *cmd = 0;
cmdlen = 1; cmdlen = 1;
for (i = 1; i < argc; i++) while ((c = getopt_long(argc, argv, "h:p:P:u:v?",
{ long_options, &option_index))
if (argv[i][0] == '-') >= 0)
{ {
switch (argv[i][1]) switch (c) {
{ case 'h':
case 'u': /* User */ hostname = strdup(optarg);
if (argv[i][2]) break;
user = &(argv[i][2]); case 'p':
else if (i + 1 < argc) passwd = strdup(optarg);
user = argv[++i]; break;
else case 'P':
{ port = strdup(optarg);
fprintf(stderr, "Missing username" break;
"in -u option.\n"); case 'u':
fatal = 1; user = strdup(optarg);
} break;
break; case 'v':
case 'p': /* Password */ PrintVersion(*argv);
if (argv[i][2]) exit(EXIT_SUCCESS);
passwd = &(argv[i][2]); case '?':
else if (i + 1 < argc) DoUsage(*argv);
passwd = argv[++i]; exit(optopt ? EXIT_FAILURE : EXIT_SUCCESS);
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, " ");
}
}
} }
if (fatal)
exit(1);
if (passwd == NULL) if (passwd == NULL)
{ {
struct termios tty_attr; struct termios tty_attr;
@ -533,23 +479,34 @@ FILE *fp;
return; return;
} }
/**
* Print version information
*/
static void
PrintVersion(const char *progname)
{
printf("%s Version %s\n", progname, MAXSCALE_VERSION);
}
/** /**
* Display the --help text. * Display the --help text.
*/ */
static void static void
DoUsage() DoUsage(const char *progname)
{ {
printf("maxadmin: The MaxScale administrative and monitor client.\n\n"); PrintVersion(progname);
printf("Usage: maxadmin [-u user] [-p password] [-h hostname] [-P port] [<command file> | <command>]\n\n"); printf("The MaxScale administrative and monitor client.\n\n");
printf(" -u user The user name to use for the connection, default\n"); printf("Usage: %s [-u user] [-p password] [-h hostname] [-P port] [<command file> | <command>]\n\n", progname);
printf(" -u|--user=... The user name to use for the connection, default\n");
printf(" is admin.\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(" 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(" 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(" 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("Any remaining arguments are treated as MaxScale commands or a file\n");
printf("containing commands to execute.\n"); printf("containing commands to execute.\n");
} }

View File

@ -255,7 +255,7 @@ static int logmanager_write_log(
bool use_valist, bool use_valist,
bool spread_down, bool spread_down,
size_t len, size_t len,
char* str, const char* str,
va_list valist); va_list valist);
static blockbuf_t* blockbuf_init(logfile_id_t id); static blockbuf_t* blockbuf_init(logfile_id_t id);
@ -609,7 +609,7 @@ static int logmanager_write_log(
bool use_valist, bool use_valist,
bool spread_down, bool spread_down,
size_t str_len, size_t str_len,
char* str, const char* str,
va_list valist) va_list valist)
{ {
logfile_t* lf; logfile_t* lf;
@ -623,7 +623,7 @@ static int logmanager_write_log(
CHK_LOGMANAGER(lm); CHK_LOGMANAGER(lm);
if (id < LOGFILE_FIRST || id > LOGFILE_LAST) { 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. * invalid id, since we don't have logfile yet.
*/ */
@ -1181,7 +1181,7 @@ static bool logfile_set_enabled(
CHK_LOGMANAGER(lm); CHK_LOGMANAGER(lm);
if (id < LOGFILE_FIRST || id > LOGFILE_LAST) { 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. * invalid id, since we don't have logfile yet.
*/ */
@ -1235,7 +1235,7 @@ return_succp:
int skygw_log_write_flush( int skygw_log_write_flush(
logfile_id_t id, logfile_id_t id,
char* str, const char* str,
...) ...)
{ {
int err = 0; int err = 0;
@ -1291,7 +1291,7 @@ return_err:
int skygw_log_write( int skygw_log_write(
logfile_id_t id, logfile_id_t id,
char* str, const char* str,
...) ...)
{ {
int err = 0; int err = 0;

View File

@ -72,9 +72,9 @@ void skygw_logmanager_exit(void);
* free private write buffer list * free private write buffer list
*/ */
void skygw_log_done(void); 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_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_enable(logfile_id_t id);
int skygw_log_disable(logfile_id_t id); int skygw_log_disable(logfile_id_t id);

View File

@ -70,6 +70,7 @@ macro(check_deps)
if(DEPS_ERROR) if(DEPS_ERROR)
message(FATAL_ERROR "Cannot find dependencies: ${FAILED_DEPS}") message(FATAL_ERROR "Cannot find dependencies: ${FAILED_DEPS}")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
endif() endif()
endmacro() endmacro()
@ -86,19 +87,23 @@ macro(check_dirs)
set(MYSQL_DIR ${MYSQL_DIR_LOC} CACHE PATH "Path to MySQL headers" FORCE) set(MYSQL_DIR ${MYSQL_DIR_LOC} CACHE PATH "Path to MySQL headers" FORCE)
if(${MYSQL_DIR} STREQUAL "MYSQL_DIR-NOTFOUND") if(${MYSQL_DIR} STREQUAL "MYSQL_DIR-NOTFOUND")
message(FATAL_ERROR "Fatal Error: MySQL headers were not found.") message(FATAL_ERROR "Fatal Error: MySQL headers were not found.")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
else() else()
message(STATUS "Using MySQL headers found at: ${MYSQL_DIR}") message(STATUS "Using MySQL headers found at: ${MYSQL_DIR}")
endif() endif()
# Find the errmsg.sys file if it was not defied # Find the errmsg.sys file if it was not defied
if( NOT ( DEFINED ERRMSG ) ) if( DEFINED ERRMSG )
find_file(ERRMSG errmsg.sys PATHS /usr/share/mysql /usr/local/share/mysql ${CUSTOM_ERRMSG} PATH_SUFFIXES english) find_file(ERRMSG_FILE errmsg.sys PATHS ${ERRMSG} NO_DEFAULT_PATH)
if(${ERRMSG} STREQUAL "ERRMSG-NOTFOUND")
message(FATAL_ERROR "Fatal Error: The errmsg.sys file was not found.")
elseif(DEBUG_OUTPUT)
message(STATUS "Using errmsg.sys found at: ${ERRMSG}")
endif()
endif() 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")
message(FATAL_ERROR "Fatal Error: The errmsg.sys file was not found, please define the path to it by using -DERRMSG=<path>")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
else()
message(STATUS "Using errmsg.sys found at: ${ERRMSG_FILE}")
endif()
set(ERRMSG ${ERRMSG_FILE} CACHE FILEPATH "Path to the errmsg.sys file." FORCE)
# Find the embedded mysql library # Find the embedded mysql library
if(STATIC_EMBEDDED) if(STATIC_EMBEDDED)
@ -132,6 +137,7 @@ macro(check_dirs)
# Inform the user about the embedded library # Inform the user about the embedded library
if( (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_STATIC-NOTFOUND") OR (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_DYNAMIC-NOTFOUND")) if( (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_STATIC-NOTFOUND") OR (${EMBEDDED_LIB} STREQUAL "EMBEDDED_LIB_DYNAMIC-NOTFOUND"))
message(FATAL_ERROR "Library not found: libmysqld. If your install of MySQL is in a non-default location, please provide the location with -DEMBEDDED_LIB=<path to library>") message(FATAL_ERROR "Library not found: libmysqld. If your install of MySQL is in a non-default location, please provide the location with -DEMBEDDED_LIB=<path to library>")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
else() else()
get_filename_component(EMBEDDED_LIB ${EMBEDDED_LIB} REALPATH) get_filename_component(EMBEDDED_LIB ${EMBEDDED_LIB} REALPATH)
message(STATUS "Using embedded library: ${EMBEDDED_LIB}") message(STATUS "Using embedded library: ${EMBEDDED_LIB}")
@ -144,13 +150,42 @@ macro(check_dirs)
find_file(DEB_FNC init-functions PATHS /lib/lsb) find_file(DEB_FNC init-functions PATHS /lib/lsb)
if(${DEB_FNC} MATCHES "DEB_FNC-NOTFOUND") if(${DEB_FNC} MATCHES "DEB_FNC-NOTFOUND")
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.") 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.")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
else() else()
set(DEB_BASED TRUE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.") set(DEB_BASED TRUE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.")
endif() endif()
else() else()
set(DEB_BASED FALSE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.") set(DEB_BASED FALSE CACHE BOOL "If init.d script uses /lib/lsb/init-functions instead of /etc/rc.d/init.d/functions.")
endif() endif()
#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")
message(FATAL_ERROR "Cannot find RabbitMQ libraries, please define the path to the libraries with -DRABBITMQ_LIB=<path>")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
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")
message(FATAL_ERROR "Cannot find RabbitMQ headers, please define the path to the headers with -DRABBITMQ_HEADERS=<path>")
set(DEPS_OK FALSE CACHE BOOL "If all the dependencies were found.")
else()
set(RABBITMQ_HEADERS ${RMQ_HEADERS} CACHE PATH "Path to RabbitMQ headers" FORCE)
message(STATUS "Using RabbitMQ headers found at: ${RABBITMQ_HEADERS}")
endif()
endif()
set(DEPS_OK TRUE CACHE BOOL "If all the dependencies were found.") set(DEPS_OK TRUE CACHE BOOL "If all the dependencies were found.")

View File

@ -1 +1,3 @@
add_subdirectory(canonical_tests) add_subdirectory(canonical_tests)
add_executable(classify classify.c)
target_link_libraries(classify fullcore)

View File

@ -1,4 +1,7 @@
file(COPY ${ERRMSG} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 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=<path>")
endif()
add_executable(canonizer canonizer.c) add_executable(canonizer canonizer.c)
target_link_libraries(canonizer pthread query_classifier z dl ssl aio crypt crypto rt m ${EMBEDDED_LIB} fullcore stdc++) target_link_libraries(canonizer pthread query_classifier z dl ssl aio crypt crypto rt m ${EMBEDDED_LIB} fullcore stdc++)
add_test(NAME TestCanonicalQuery COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/canontest.sh add_test(NAME TestCanonicalQuery COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/canontest.sh

View File

@ -1,7 +1,13 @@
find_library(MYSQL_CLIENT_LIB NAMES mysqlclient PATHS /usr/lib /usr/lib64 PATH_SUFFIXES mysql mariadb) if (NOT ( DEFINED MYSQL_CLIENT_LIB ) )
find_library(MYSQL_CLIENT_LIB NAMES mysqlclient PATHS /usr/lib /usr/lib64 PATH_SUFFIXES mysql mariadb)
endif()
if( ( RABBITMQ_LIB AND RABBITMQ_HEADERS ) AND ( NOT ( ${MYSQL_CLIENT_LIB} STREQUAL "MYSQL_CLIENT_LIB-NOTFOUND" ) ) ) if (NOT ( DEFINED MYSQL_CLIENT_HEADERS ) )
find_path(MYSQL_CLIENT_HEADERS NAMES mysql.h PATH_SUFFIXES mysql mariadb)
endif()
if( ( RABBITMQ_LIB AND RABBITMQ_HEADERS ) AND ( NOT ( ${MYSQL_CLIENT_LIB} STREQUAL "MYSQL_CLIENT_LIB-NOTFOUND" ) ) AND ( NOT ( ${MYSQL_CLIENT_HEADERS} STREQUAL "MYSQL_CLIENT_HEADERS-NOTFOUND" ) ) )
include_directories(${MYSQL_CLIENT_HEADERS})
add_executable (consumer consumer.c) add_executable (consumer consumer.c)
target_link_libraries(consumer ${MYSQL_CLIENT_LIB} rabbitmq inih) target_link_libraries(consumer ${MYSQL_CLIENT_LIB} rabbitmq inih)
install(TARGETS consumer DESTINATION bin) install(TARGETS consumer DESTINATION bin)

View File

@ -1575,6 +1575,7 @@ static char *service_params[] =
"use_sql_variables_in", /*< rwsplit only */ "use_sql_variables_in", /*< rwsplit only */
"version_string", "version_string",
"filters", "filters",
"weightby",
NULL NULL
}; };

View File

@ -403,13 +403,16 @@ DCB_CALLBACK *cb;
* operation of clearing this bit means that no bits are set in * operation of clearing this bit means that no bits are set in
* the memdata.bitmask then the DCB is no longer able to be * the memdata.bitmask then the DCB is no longer able to be
* referenced and it can be finally removed. * referenced and it can be finally removed.
* Thread won't clear its bit from bitmask of the DCB it is still using. *
* 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 threadid The thread ID of the caller
* @param dcb_in_use The DCB the thread currently uses, NULL or valid DCB. * @param excluded The DCB the thread currently uses, NULL or valid DCB.
*/ */
DCB * DCB *
dcb_process_zombies(int threadid, DCB *dcb_in_use) dcb_process_zombies(int threadid, DCB *excluded)
{ {
DCB *ptr, *lptr; DCB *ptr, *lptr;
DCB* dcb_list = NULL; DCB* dcb_list = NULL;
@ -426,78 +429,100 @@ bool succp = false;
if (!zombies) if (!zombies)
return NULL; return NULL;
/*
* Process the zombie queue and create a list of DCB's that can be
* finally freed. This processing is down under a spinlock that
* will prevent new entries being added to the zombie queue. Therefore
* we do not want to do any expensive operations under this spinlock
* as it will block other threads. The expensive operations will be
* performed on the victim queue within holding the zombie queue
* spinlock.
*/
spinlock_acquire(&zombiespin); spinlock_acquire(&zombiespin);
ptr = zombies; ptr = zombies;
lptr = NULL; lptr = NULL;
while (ptr) while (ptr)
{ {
CHK_DCB(ptr); CHK_DCB(ptr);
/** Don't clear the bit from DCB the user currently uses */
if (dcb_in_use == NULL || ptr != dcb_in_use) /*
{ * Skip processing of the excluded DCB
bitmask_clear(&ptr->memdata.bitmask, threadid); */
} if (ptr == excluded)
if (ptr == dcb_in_use)
ss_dassert(!bitmask_isallclear(&ptr->memdata.bitmask));
if (bitmask_isallclear(&ptr->memdata.bitmask))
{
/**
* Remove the DCB from the zombie queue
* and call the final free routine for the
* DCB
*
* ptr is the DCB we are processing
* lptr is the previous DCB on the zombie queue
* or NULL if the DCB is at the head of the queue
* tptr is the DCB after the one we are processing
* on the zombie queue
*/
DCB *tptr = ptr->memdata.next;
if (lptr == NULL)
zombies = tptr;
else
lptr->memdata.next = tptr;
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
"%lu [dcb_process_zombies] Remove dcb %p fd %d "
"in state %s from zombies list.",
pthread_self(),
ptr,
ptr->fd,
STRDCBSTATE(ptr->state))));
ss_info_dassert(ptr->state == DCB_STATE_ZOMBIE,
"dcb not in DCB_STATE_ZOMBIE state.");
/*<
* Move dcb to linked list of victim dcbs.
*/
if (dcb_list == NULL) {
dcb_list = ptr;
dcb = dcb_list;
} else {
dcb->memdata.next = ptr;
dcb = dcb->memdata.next;
}
dcb->memdata.next = NULL;
ptr = tptr;
}
else
{ {
lptr = ptr; lptr = ptr;
ptr = ptr->memdata.next; ptr = ptr->memdata.next;
} }
else
{
bitmask_clear(&ptr->memdata.bitmask, threadid);
if (bitmask_isallclear(&ptr->memdata.bitmask))
{
/**
* Remove the DCB from the zombie queue
* and call the final free routine for the
* DCB
*
* ptr is the DCB we are processing
* lptr is the previous DCB on the zombie queue
* or NULL if the DCB is at the head of the
* queue tptr is the DCB after the one we are
* processing on the zombie queue
*/
DCB *tptr = ptr->memdata.next;
if (lptr == NULL)
zombies = tptr;
else
lptr->memdata.next = tptr;
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
"%lu [dcb_process_zombies] Remove dcb "
"%p fd %d " "in state %s from the "
"list of zombies.",
pthread_self(),
ptr,
ptr->fd,
STRDCBSTATE(ptr->state))));
ss_info_dassert(ptr->state == DCB_STATE_ZOMBIE,
"dcb not in DCB_STATE_ZOMBIE state.");
/*<
* Move dcb to linked list of victim dcbs.
*/
if (dcb_list == NULL) {
dcb_list = ptr;
dcb = dcb_list;
} else {
dcb->memdata.next = ptr;
dcb = dcb->memdata.next;
}
dcb->memdata.next = NULL;
ptr = tptr;
}
else
{
lptr = ptr;
ptr = ptr->memdata.next;
}
}
} }
spinlock_release(&zombiespin); spinlock_release(&zombiespin);
/*
* Process the victim queue. These are DCBs that are not in
* use by any thread.
* The corresponding file descriptor is closed, the DCB marked
* as disconnected and the DCB itself is fianlly freed.
*/
dcb = dcb_list; dcb = dcb_list;
/** Close, and set DISCONNECTED victims */
while (dcb != NULL) { while (dcb != NULL) {
DCB* dcb_next = NULL; DCB* dcb_next = NULL;
int rc = 0; int rc = 0;
/*< /*<
* Close file descriptor and move to clean-up phase. * Close file descriptor and move to clean-up phase.
*/ */
ss_dassert(dcb_in_use != dcb); ss_dassert(excluded != dcb);
rc = close(dcb->fd); rc = close(dcb->fd);
if (rc < 0) { if (rc < 0) {
@ -1119,8 +1144,8 @@ int above_water;
/** /**
* Removes dcb from poll set, and adds it to zombies list. As a consequense, * Removes dcb from poll set, and adds it to zombies list. As a consequense,
* dcb first moves to DCB_STATE_NOPOLLING, and then to DCB_STATE_ZOMBIE state. * dcb first moves to DCB_STATE_NOPOLLING, and then to DCB_STATE_ZOMBIE state.
* At the end of the function state may not be DCB_STATE_ZOMBIE because once dcb_initlock * At the end of the function state may not be DCB_STATE_ZOMBIE because once
* is released parallel threads may change the state. * dcb_initlock is released parallel threads may change the state.
* *
* Parameters: * Parameters:
* @param dcb The DCB to close * @param dcb The DCB to close
@ -1943,9 +1968,11 @@ int rval = 0;
* to return immediately and and process other events. * to return immediately and and process other events.
* *
* @param dcb The DCB that has data available * @param dcb The DCB that has data available
* @param thread_id The ID of the calling thread
* @param nozombies If non-zero then do not do zombie processing
*/ */
void void
dcb_pollin(DCB *dcb, int thread_id) dcb_pollin(DCB *dcb, int thread_id, int nozombies)
{ {
spinlock_acquire(&dcb->pollinlock); spinlock_acquire(&dcb->pollinlock);
@ -1956,7 +1983,8 @@ dcb_pollin(DCB *dcb, int thread_id)
if (dcb->readcheck) if (dcb->readcheck)
{ {
dcb->stats.n_readrechecks++; dcb->stats.n_readrechecks++;
dcb_process_zombies(thread_id, dcb); if (!nozombies)
dcb_process_zombies(thread_id, dcb);
} }
dcb->readcheck = 0; dcb->readcheck = 0;
spinlock_release(&dcb->pollinlock); spinlock_release(&dcb->pollinlock);
@ -1987,9 +2015,11 @@ dcb_pollin(DCB *dcb, int thread_id)
* to return immediately and and process other events. * to return immediately and and process other events.
* *
* @param dcb The DCB thats available for writes * @param dcb The DCB thats available for writes
* @param thread_id The ID of the calling thread
* @param nozombies If non-zero then do not do zombie processing
*/ */
void void
dcb_pollout(DCB *dcb, int thread_id) dcb_pollout(DCB *dcb, int thread_id, int nozombies)
{ {
spinlock_acquire(&dcb->polloutlock); spinlock_acquire(&dcb->polloutlock);
@ -1999,7 +2029,8 @@ dcb_pollout(DCB *dcb, int thread_id)
do { do {
if (dcb->writecheck) if (dcb->writecheck)
{ {
dcb_process_zombies(thread_id, dcb); if (!nozombies)
dcb_process_zombies(thread_id, dcb);
dcb->stats.n_writerechecks++; dcb->stats.n_writerechecks++;
} }
dcb->writecheck = 0; dcb->writecheck = 0;

View File

@ -44,6 +44,7 @@
#include <string.h> #include <string.h>
#include <gw.h> #include <gw.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h>
#include <service.h> #include <service.h>
#include <server.h> #include <server.h>
#include <dcb.h> #include <dcb.h>
@ -131,6 +132,17 @@ static bool libmysqld_started = FALSE;
*/ */
static bool daemon_mode = true; 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_shutdown(void);
static void log_flush_cb(void* arg); static void log_flush_cb(void* arg);
static int write_pid_file(char *); /* write MaxScale pidfile */ static int write_pid_file(char *); /* write MaxScale pidfile */
@ -878,15 +890,19 @@ return_cnf_file_buf:
return cnf_file_buf; return cnf_file_buf;
} }
static void usage(void) static void usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"*\n* Usage : maxscale [-h] | [-d] [-c <home " "\nUsage : %s [-h] | [-d] [-c <home directory>] [-f <config file name>]\n\n"
"directory>] [-f <config file name>]\n* where:\n* " " -d|--nodaemon enable running in terminal process (default:disabled)\n"
"-h help\n* -d enable running in terminal process (default:disabled)\n* " " -c|--homedir=... relative|absolute MaxScale home directory\n"
"-c relative|absolute MaxScale home directory\n* " " -f|--config=... relative|absolute pathname of MaxScale configuration file\n"
"-f relative|absolute pathname of MaxScale configuration file (default:MAXSCALE_HOME/etc/MaxScale.cnf)\n*\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_path = NULL; /*< conf file, to be freed */
char* cnf_file_arg = NULL; /*< conf filename from cmd-line arg */ char* cnf_file_arg = NULL; /*< conf filename from cmd-line arg */
void* log_flush_thr = NULL; void* log_flush_thr = NULL;
int option_index;
int logtofile = 0; /* Use shared memory or file */
ssize_t log_flush_timeout_ms = 0; ssize_t log_flush_timeout_ms = 0;
sigset_t sigset; sigset_t sigset;
sigset_t sigpipe_mask; sigset_t sigpipe_mask;
@ -954,6 +972,8 @@ int main(int argc, char **argv)
sigemptyset(&sigpipe_mask); sigemptyset(&sigpipe_mask);
sigaddset(&sigpipe_mask, SIGPIPE); sigaddset(&sigpipe_mask, SIGPIPE);
progname = *argv;
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
memset(conn_open, 0, sizeof(bool)*10240); memset(conn_open, 0, sizeof(bool)*10240);
memset(dcb_fake_write_errno, 0, sizeof(unsigned char)*10240); memset(dcb_fake_write_errno, 0, sizeof(unsigned char)*10240);
@ -980,7 +1000,8 @@ int main(int argc, char **argv)
goto return_main; 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; bool succp = true;
@ -1061,9 +1082,36 @@ int main(int argc, char **argv)
succp = false; succp = false;
} }
break; 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: default:
usage(); usage();
succp = false; succp = false;
break; break;
} }
@ -1345,12 +1393,23 @@ int main(int argc, char **argv)
argv[0] = "MaxScale"; argv[0] = "MaxScale";
argv[1] = "-j"; argv[1] = "-j";
argv[2] = buf; argv[2] = buf;
argv[3] = "-s"; /*< store to shared memory */ if (logtofile)
argv[4] = "LOGFILE_DEBUG,LOGFILE_TRACE"; /*< ..these logs to shm */ {
argv[5] = "-l"; /*< write to syslog */ argv[3] = "-l"; /*< write to syslog */
argv[6] = "LOGFILE_MESSAGE,LOGFILE_ERROR"; /*< ..these logs to syslog */ argv[4] = "LOGFILE_MESSAGE,LOGFILE_ERROR"
argv[7] = NULL; "LOGFILE_DEBUG,LOGFILE_TRACE";
skygw_logmanager_init(7, argv); 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);
}
} }
/*< /*<

View File

@ -16,6 +16,7 @@
* Copyright SkySQL Ab 2014 * Copyright SkySQL Ab 2014
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <housekeeper.h> #include <housekeeper.h>
#include <thread.h> #include <thread.h>
#include <spinlock.h> #include <spinlock.h>

View File

@ -125,7 +125,7 @@ unsigned char *ptr;
/** /**
* Replace the contents of a GWBUF with the new SQL statement passed as a text string. * Replace the contents of a GWBUF with the new SQL statement passed as a text string.
* The routine takes care of the modification needed to the MySQL packet, * The routine takes care of the modification needed to the MySQL packet,
* returning a GWBUF chian that cna be used to send the data to a MySQL server * returning a GWBUF chain that can be used to send the data to a MySQL server
* *
* @param orig The original request in a GWBUF * @param orig The original request in a GWBUF
* @param sql The SQL text to replace in the packet * @param sql The SQL text to replace in the packet
@ -225,4 +225,4 @@ char* modutil_get_query(
} /*< switch */ } /*< switch */
retblock: retblock:
return query_str; return query_str;
} }

View File

@ -49,10 +49,19 @@ extern int lm_enabled_logfiles_bitmask;
* @endverbatim * @endverbatim
*/ */
/**
* Control the use of mutexes for the epoll_wait call. Setting to 1 will
* cause the epoll_wait calls to be moved under a mutex. This may be useful
* for debuggign purposes but should be avoided in general use.
*/
#define MUTEX_EPOLL 0
static int epoll_fd = -1; /*< The epoll file descriptor */ static int epoll_fd = -1; /*< The epoll file descriptor */
static int do_shutdown = 0; /*< Flag the shutdown of the poll subsystem */ static int do_shutdown = 0; /*< Flag the shutdown of the poll subsystem */
static GWBITMASK poll_mask; static GWBITMASK poll_mask;
#if MUTEX_EPOLL
static simple_mutex_t epoll_wait_mutex; /*< serializes calls to epoll_wait */ static simple_mutex_t epoll_wait_mutex; /*< serializes calls to epoll_wait */
#endif
static int n_waiting = 0; /*< No. of threads in epoll_wait */ static int n_waiting = 0; /*< No. of threads in epoll_wait */
/** /**
@ -154,7 +163,9 @@ int i;
thread_data[i].state = THREAD_STOPPED; thread_data[i].state = THREAD_STOPPED;
} }
} }
#if MUTEX_EPOLL
simple_mutex_init(&epoll_wait_mutex, "epoll_wait_mutex"); simple_mutex_init(&epoll_wait_mutex, "epoll_wait_mutex");
#endif
hktask_add("Load Average", poll_loadav, NULL, POLL_LOAD_FREQ); hktask_add("Load Average", poll_loadav, NULL, POLL_LOAD_FREQ);
n_avg_samples = 15 * 60 / POLL_LOAD_FREQ; n_avg_samples = 15 * 60 / POLL_LOAD_FREQ;
@ -359,7 +370,7 @@ DCB *zombies = NULL;
thread_id))); thread_id)));
no_op = TRUE; no_op = TRUE;
} }
#if 0 #if MUTEX_EPOLL
simple_mutex_lock(&epoll_wait_mutex, TRUE); simple_mutex_lock(&epoll_wait_mutex, TRUE);
#endif #endif
if (thread_data) if (thread_data)
@ -385,7 +396,7 @@ DCB *zombies = NULL;
{ {
atomic_add(&n_waiting, -1); atomic_add(&n_waiting, -1);
if (process_zombies_only) { if (process_zombies_only) {
#if 0 #if MUTEX_EPOLL
simple_mutex_unlock(&epoll_wait_mutex); simple_mutex_unlock(&epoll_wait_mutex);
#endif #endif
goto process_zombies; goto process_zombies;
@ -413,7 +424,7 @@ DCB *zombies = NULL;
if (n_waiting == 0) if (n_waiting == 0)
atomic_add(&pollStats.n_nothreads, 1); atomic_add(&pollStats.n_nothreads, 1);
#if 0 #if MUTEX_EPOLL
simple_mutex_unlock(&epoll_wait_mutex); simple_mutex_unlock(&epoll_wait_mutex);
#endif #endif
#endif /* BLOCKINGPOLL */ #endif /* BLOCKINGPOLL */
@ -442,7 +453,7 @@ DCB *zombies = NULL;
for (i = 0; i < nfds; i++) for (i = 0; i < nfds; i++)
{ {
DCB *dcb = (DCB *)events[i].data.ptr; DCB *dcb = (DCB *)events[i].data.ptr;
__uint32_t ev = events[i].events; __uint32_t ev = events[i].events;
CHK_DCB(dcb); CHK_DCB(dcb);
@ -504,7 +515,7 @@ DCB *zombies = NULL;
#else #else
atomic_add(&pollStats.n_write, atomic_add(&pollStats.n_write,
1); 1);
dcb_pollout(dcb, thread_id); dcb_pollout(dcb, thread_id, nfds);
#endif #endif
} else { } else {
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
@ -554,7 +565,7 @@ DCB *zombies = NULL;
#if MUTEX_BLOCK #if MUTEX_BLOCK
dcb->func.read(dcb); dcb->func.read(dcb);
#else #else
dcb_pollin(dcb, thread_id); dcb_pollin(dcb, thread_id, nfds);
#endif #endif
} }
#if MUTEX_BLOCK #if MUTEX_BLOCK
@ -609,7 +620,15 @@ DCB *zombies = NULL;
eno, eno,
strerror(eno)))); strerror(eno))));
atomic_add(&pollStats.n_hup, 1); atomic_add(&pollStats.n_hup, 1);
dcb->func.hangup(dcb); spinlock_acquire(&dcb->dcb_initlock);
if ((dcb->flags & DCBF_HUNG) == 0)
{
dcb->flags |= DCBF_HUNG;
spinlock_release(&dcb->dcb_initlock);
dcb->func.hangup(dcb);
}
else
spinlock_release(&dcb->dcb_initlock);
} }
if (ev & EPOLLRDHUP) if (ev & EPOLLRDHUP)
@ -628,7 +647,15 @@ DCB *zombies = NULL;
eno, eno,
strerror(eno)))); strerror(eno))));
atomic_add(&pollStats.n_hup, 1); atomic_add(&pollStats.n_hup, 1);
dcb->func.hangup(dcb); spinlock_acquire(&dcb->dcb_initlock);
if ((dcb->flags & DCBF_HUNG) == 0)
{
dcb->flags |= DCBF_HUNG;
spinlock_release(&dcb->dcb_initlock);
dcb->func.hangup(dcb);
}
else
spinlock_release(&dcb->dcb_initlock);
} }
} /*< for */ } /*< for */
no_op = FALSE; no_op = FALSE;

View File

@ -271,8 +271,8 @@ int fail_accept_errno;
#define DCB_BELOW_LOW_WATER(x) ((x)->low_water && (x)->writeqlen < (x)->low_water) #define DCB_BELOW_LOW_WATER(x) ((x)->low_water && (x)->writeqlen < (x)->low_water)
#define DCB_ABOVE_HIGH_WATER(x) ((x)->high_water && (x)->writeqlen > (x)->high_water) #define DCB_ABOVE_HIGH_WATER(x) ((x)->high_water && (x)->writeqlen > (x)->high_water)
void dcb_pollin(DCB *, int); void dcb_pollin(DCB *, int, int);
void dcb_pollout(DCB *, int); void dcb_pollout(DCB *, int, int);
DCB *dcb_get_zombies(void); DCB *dcb_get_zombies(void);
int gw_write( int gw_write(
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
@ -317,6 +317,9 @@ void dcb_call_foreach (DCB_REASON reason);
void dcb_call_foreach ( void dcb_call_foreach (
DCB_REASON reason); DCB_REASON reason);
/* DCB flags values */ /**
#define DCBF_CLONE 0x0001 /* DCB is a clone */ * DCB flags values
*/
#define DCBF_CLONE 0x0001 /*< DCB is a clone */
#define DCBF_HUNG 0x0002 /*< Hangup has been dispatched */
#endif /* _DCB_H */ #endif /* _DCB_H */

View File

@ -1,11 +1,7 @@
if(BUILD_RABBITMQ) if(BUILD_RABBITMQ)
if(RABBITMQ_LIB AND RABBITMQ_HEADERS) add_library(mqfilter SHARED mqfilter.c)
add_library(mqfilter SHARED mqfilter.c) target_link_libraries(mqfilter query_classifier log_manager utils rabbitmq)
target_link_libraries(mqfilter query_classifier log_manager utils rabbitmq) install(TARGETS mqfilter DESTINATION modules)
install(TARGETS mqfilter DESTINATION modules)
else()
message(ERROR "Error: Cannot find the required librabbitmq-c locations, please check that you have them configured correctly.")
endif()
endif() endif()
add_library(regexfilter SHARED regexfilter.c) add_library(regexfilter SHARED regexfilter.c)