Merge branch 'develop' into MAX-324

This commit is contained in:
Markus Makela 2015-02-16 14:58:35 +02:00
commit a2bff1dcea
38 changed files with 32195 additions and 1388 deletions

View File

@ -21,17 +21,27 @@ check_dirs()
find_package(Valgrind)
find_package(MySQLClient)
find_package(MySQL)
find_package(Pandoc)
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/modules)
# Make sure the release notes for this release are present if it is a stable one
if(${MAXSCALE_VERSION} MATCHES "-stable")
file(GLOB ${CMAKE_SOURCE_DIR}/Documentation/Release-Notes RELEASE_NOTES *${MAXSCALE_VERSION_NUMERIC}*.md)
list(LENGTH RELEASE_NOTES HAVE_NOTES)
if( NOT HAVE_NOTES EQUAL 1)
message(FATAL_ERROR "Could not find the release notes for this stable release: ${MAXSCALE_VERSION_NUMERIC}")
endif()
endif()
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/server/include)
configure_file(${CMAKE_SOURCE_DIR}/server/include/version.h.in ${CMAKE_BINARY_DIR}/server/include/version.h)
configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.h.in ${CMAKE_BINARY_DIR}/server/include/maxscale_test.h)
configure_file(${CMAKE_SOURCE_DIR}/etc/postinst.in ${CMAKE_BINARY_DIR}/postinst)
configure_file(${CMAKE_SOURCE_DIR}/etc/postrm.in ${CMAKE_BINARY_DIR}/postrm)
set(CMAKE_C_FLAGS "-Wall -fPIC")
set(CMAKE_CXX_FLAGS "-Wall -fPIC")
set(CMAKE_C_FLAGS "-Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -fPIC")
set(CMAKE_CXX_FLAGS "-Wall -Wno-unused-variable -Wno-unused-but-set-variable -fPIC")
set(DEBUG_FLAGS "-ggdb -pthread -pipe -Wformat -fstack-protector --param=ssp-buffer-size=4")
if(CMAKE_VERSION VERSION_GREATER 2.6)
@ -102,12 +112,11 @@ if(NOT WITHOUT_MAXADMIN)
add_subdirectory(client)
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)
install(FILES ${CMAKE_SOURCE_DIR}/COPYRIGHT DESTINATION .)
install(FILES ${CMAKE_SOURCE_DIR}/README DESTINATION .)
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .)
@ -230,3 +239,20 @@ add_custom_target(testall-valgrind
COMMENT "Running full test suite with Valgrind..." VERBATIM)
endif()
add_custom_target(generate_pdf
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Documentation ${CMAKE_BINARY_DIR}/Documentation
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/Documentation ${CMAKE_COMMAND}
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
-P generate-pdf.cmake
COMMENT "Generating PDF files" VERBATIM)
add_custom_target(generate_html
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Documentation ${CMAKE_BINARY_DIR}/Documentation
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/Documentation ${CMAKE_COMMAND}
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
-P generate-html.cmake
COMMENT "Generating HTML files" VERBATIM)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
[Search page for MaxScale Documentation]((http://mariadb-corporation.github.io/MaxScale/Search/)
[Search page for MaxScale Documentation](http://mariadb-corporation.github.io/MaxScale/Search/)
# Contents

View File

@ -518,7 +518,7 @@ Connection based routing is a mechanism by which MaxScale will, for each incomin
## Statement Based Routing
Statement based routing is somewhat different, the routing modules examine every statement the client sends and determines, on a per statement basis, which of the set of backend servers in the service is best to execute the statement. This gives better dynamic balancing of the load within the cluster but comes at a cost. The query router must understand the statement that is being routing and may have to parse the statement in order to achieve this.
Statement based routing is somewhat different, the routing modules examine every statement the client sends and determines, on a per statement basis, which of the set of backend servers in the service is best to execute the statement. This gives better dynamic balancing of the load within the cluster but comes at a cost. The query router must understand the statement that is being routed and may have to parse the statement in order to achieve this.
Parsing within the router adds overhead to the cost of routing and makes this type of router best suitable for loads in which the gains outweigh this added cost. The added cost from statement parsing also gives the possibility to create and use new type of filters which are based on statement processing. In contrast to the added processing cost, statement-based routing may increase the performance of the cluster by offloading statements away from the master when possible.

View File

@ -44,93 +44,82 @@ Alternatively you may download the MaxScale source and build your own binaries.
First clone the GitHub project to your machine either via the web interface, your favorite graphical interface or the git command line
$ git clone https://github.com/mariadb-corporation/MaxScale
Cloning into 'MaxScale'...
remote: Counting objects: 16228, done.
...
$ git clone https://github.com/mariadb-corporation/MaxScale
Cloning into 'MaxScale'...
remote: Counting objects: 16228, done.
...
Change directory to the MaxScale directory, create a build directory and change directory to that build directory
$ cd MaxScale
$ mkdir build
$ cd build
The next step is to run the cmake command to build the Makefile you need to compile Maxscale. There are a number of options you may give to configure cmake and point it to the various packages it requires. These are documented in the MaxScale README file, in this example we will assume the MariaDB developer packages have been installed in a non-standard location and set all the options required to locate these, along with options to build the unit tests and configure the installation target directory.
$ cmake -DMYSQL\_DIR=/usr/mariadb-5.5.41-linux-x86_64/include/mysql \
-DEMBEDDED\_LIB=/usr/mariadb-5.5.41-linux-x86\_64/lib/libmysqld.a \
-DMYSQLCLIENT\_LIBRARIES=/usr/mariadb-5.5.41-linux-x86_64/lib/libmysqlclient.so \
-DERRMSG=/usr/mariadb-5.5.41-linux-x86\_64/share/english/errmsg.sys \
-DINSTALL\_DIR=/home/maxscale/MaxScale -DBUILD_TESTS=Y \
-DINSTALL\_SYSTEM\_FILES=N \
-DBUILD_BINLOG=Y ../
-- CMake version: 2.8.12.2
-- The C compiler identification is GNU 4.4.7
-- The CXX compiler identification is GNU 4.4.7
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Library was found at: /lib64/libaio.so
-- Library was found at: /usr/lib64/libssl.so
-- Library was found at: /usr/lib64/libcrypt.so
-- Library was found at: /usr/lib64/libcrypto.so
-- Library was found at: /usr/lib64/libz.so
-- Library was found at: /usr/lib64/libm.so
-- Library was found at: /usr/lib64/libdl.so
-- Library was found at: /usr/lib64/librt.so
-- Library was found at: /usr/lib64/libpthread.so
-- Using errmsg.sys found at: /home/maxscale/usr/share/mysql/english/errmsg.sys
-- Using embedded library: /home/mpinto/usr/lib64/libmysqld.a
-- Valgrind found: /usr/bin/valgrind
-- Found dynamic MySQL client library: /home/maxscale/usr/lib64/libmysqlclient.so
-- Found static MySQL client library: /usr/lib/libmysqlclient.a
-- C Compiler supports: -Werror=format-security
-- Linking against: /home/mpinto/usr/lib64/libmysqlclient.so
-- Installing MaxScale to: /usr/local/maxscale/
-- Generating RPM packages
-- Found Doxygen: /usr/bin/doxygen (found version "1.6.1")
-- Configuring done
-- Generating done
-- Build files have been written to: /home/maxscale/develop/build
-bash-4.1$ make depend
-bash-4.1$ make
$ cd MaxScale
$ mkdir build
$ cd build
The next step is to run the cmake command to build the Makefile you need to compile Maxscale. There are a number of options you may give to configure cmake and point it to the various packages it requires. These are documented in the MaxScale README file, in this example we will assume the MariaDB developer packages have been installed in a non-standard location and set all the options required to locate these, along with options to build the unit tests and configure the installation target directory.
$ cmake -DMYSQL\_DIR=/usr/mariadb-5.5.41-linux-x86_64/include/mysql \
-DEMBEDDED\_LIB=/usr/mariadb-5.5.41-linux-x86\_64/lib/libmysqld.a \
-DMYSQLCLIENT\_LIBRARIES=/usr/mariadb-5.5.41-linux-x86_64/lib/libmysqlclient.so \
-DERRMSG=/usr/mariadb-5.5.41-linux-x86\_64/share/english/errmsg.sys \
-DINSTALL\_DIR=/home/maxscale/MaxScale -DBUILD_TESTS=Y \
-DINSTALL\_SYSTEM\_FILES=N \
-DBUILD_BINLOG=Y ../
-- CMake version: 2.8.12.2
-- The C compiler identification is GNU 4.4.7
-- The CXX compiler identification is GNU 4.4.7
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Library was found at: /lib64/libaio.so
-- Library was found at: /usr/lib64/libssl.so
-- Library was found at: /usr/lib64/libcrypt.so
-- Library was found at: /usr/lib64/libcrypto.so
-- Library was found at: /usr/lib64/libz.so
-- Library was found at: /usr/lib64/libm.so
-- Library was found at: /usr/lib64/libdl.so
-- Library was found at: /usr/lib64/librt.so
-- Library was found at: /usr/lib64/libpthread.so
-- Using errmsg.sys found at: /home/maxscale/usr/share/mysql/english/errmsg.sys
-- Using embedded library: /home/mpinto/usr/lib64/libmysqld.a
-- Valgrind found: /usr/bin/valgrind
-- Found dynamic MySQL client library: /home/maxscale/usr/lib64/libmysqlclient.so
-- Found static MySQL client library: /usr/lib/libmysqlclient.a
-- C Compiler supports: -Werror=format-security
-- Linking against: /home/mpinto/usr/lib64/libmysqlclient.so
-- Installing MaxScale to: /usr/local/maxscale/
-- Generating RPM packages
-- Found Doxygen: /usr/bin/doxygen (found version "1.6.1")
-- Configuring done
-- Generating done
-- Build files have been written to: /home/maxscale/develop/build
-bash-4.1$ make depend
-bash-4.1$ make
Once the cmake command is complete simply run make to build the MaxScale binaries.
$ make
**Scanning dependencies of target utils**
[ 1%] Building CXX object utils/CMakeFiles/utils.dir/skygw_utils.cc.o
**Linking CXX static library libutils.a**
[ 1%] Built target utils
**Scanning dependencies of target log_manager**
[ 2%] Building CXX object log_manager/CMakeFiles/log_manager.dir/log_manager.cc.o
...
$ make
**Scanning dependencies of target utils**
[ 1%] Building CXX object utils/CMakeFiles/utils.dir/skygw_utils.cc.o
**Linking CXX static library libutils.a**
[ 1%] Built target utils
**Scanning dependencies of target log_manager**
[ 2%] Building CXX object log_manager/CMakeFiles/log_manager.dir/log_manager.cc.o
...
After the completion of the make process the installation can be achieved by running the make install target.
$ make install
...
$ make install
...
This will result in an installation being created which is identical to that which would be achieved by installing the binary package.
@ -162,3 +151,4 @@ As well as the four major configuration choices outlined above there are also ot
There are various administration tasks that may be done with MaxScale, a client command, maxadmin, is available that will interact with a running MaxScale and allow the status of MaxScale to be monitored and give some control of the MaxScale functionality. There is a separate reference guide for the maxadmin utility and also a short administration tutorial that covers the common administration tasks that need to be done with MaxScale.

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,7 @@ MaxScale has added the ability to bind a listener for a service to a network add
The server version reported when connected to a database via MaxScale has now been altered. This now shows the MaxScale name and version together with the backend server name. An example of this can be seen below for the 0.5 release.
-bash-4.1$ mysql -h 127.0.0.1 -P 4006 -uxxxx -pxxxx Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 22320 Server version: MaxScale 0.5.0 MariaDB Server Copyright (c) 2000, 2012, Oracle, Monty Program Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> \s -------------- mysql Ver 15.1 Distrib 5.5.28a-MariaDB, for Linux (i686) using readline 5.1 ... Server: MySQL Server version: MaxScale 0.5.0 MariaDB Server ... -------------- MySQL [(none)]>
-bash-4.1$ mysql -h 127.0.0.1 -P 4006 -uxxxx -pxxxx Welcome to the MariaDB monitor. Commands end with ; or \\g. Your MySQL connection id is 22320 Server version: MaxScale 0.5.0 MariaDB Server Copyright (c) 2000, 2012, Oracle, Monty Program Ab and others. Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement. MySQL [(none)]> \\ys -------------- mysql Ver 15.1 Distrib 5.5.28a-MariaDB, for Linux (i686) using readline 5.1 ... Server: MySQL Server version: MaxScale 0.5.0 MariaDB Server ... -------------- MySQL [(none)]>
# Bug Fixes

View File

@ -0,0 +1,18 @@
# The BUILD_DIR variable is set at runtime
cmake_minimum_required(VERSION 2.8.12)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/")
find_package(Pandoc)
if(PANDOC_FOUND AND BUILD_DIR)
file(MAKE_DIRECTORY ${BUILD_DIR}/html)
file(GLOB_RECURSE MARKDOWN *.md)
foreach(VAR ${MARKDOWN})
string(REPLACE ".md" ".html" OUTPUT ${VAR})
get_filename_component(DIR ${VAR} DIRECTORY)
string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}" "${BUILD_DIR}/html" FILE ${OUTPUT})
execute_process(COMMAND ${CMAKE_COMMAND} -E chdir ${DIR} ${PANDOC_EXECUTABLE} ${VAR} -o ${OUTPUT})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${OUTPUT} ${FILE})
endforeach()
endif()

View File

@ -0,0 +1,18 @@
# The BUILD_DIR variable is set at runtime
cmake_minimum_required(VERSION 2.8.12)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/")
find_package(Pandoc)
if(PANDOC_FOUND AND BUILD_DIR)
file(MAKE_DIRECTORY ${BUILD_DIR}/pdf)
file(GLOB_RECURSE MARKDOWN *.md)
foreach(VAR ${MARKDOWN})
string(REPLACE ".md" ".pdf" OUTPUT ${VAR})
get_filename_component(DIR ${VAR} DIRECTORY)
string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}" "${BUILD_DIR}/pdf" FILE ${OUTPUT})
execute_process(COMMAND ${CMAKE_COMMAND} -E chdir ${DIR} ${PANDOC_EXECUTABLE} ${VAR} -o ${OUTPUT})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${OUTPUT} ${FILE})
endforeach()
endif()

13
cmake/FindPandoc.cmake Normal file
View File

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

View File

@ -167,7 +167,7 @@ struct logfile_st {
size_t lf_file_size;
/** list of block-sized log buffers */
mlist_t lf_blockbuf_list;
int lf_buf_size;
size_t lf_buf_size;
bool lf_flushflag;
bool lf_rotateflag;
int lf_spinlock; /**< lf_flushflag & lf_rotateflag */
@ -633,7 +633,7 @@ static int logmanager_write_log(
int err = 0;
blockbuf_t* bb;
blockbuf_t* bb_c;
int timestamp_len;
size_t timestamp_len;
int i;
CHK_LOGMANAGER(lm);
@ -680,9 +680,9 @@ static int logmanager_write_log(
else
{
/** Length of string that will be written, limited by bufsize */
int safe_str_len;
size_t safe_str_len;
/** Length of session id */
int sesid_str_len;
size_t sesid_str_len;
/**
* 2 braces, 2 spaces and terminating char
@ -2335,7 +2335,6 @@ static bool check_file_and_path(
bool* writable,
bool do_log)
{
int fd;
bool exists;
if (filename == NULL)
@ -2349,112 +2348,54 @@ static bool check_file_and_path(
}
else
{
fd = open(filename, O_CREAT|O_EXCL, S_IRWXU);
if (fd == -1)
{
/** File exists, check permission to read/write */
if (errno == EEXIST)
{
/** Open file and write a byte for test */
fd = open(filename, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG);
if (fd == -1)
{
if (do_log && file_is_symlink(filename))
{
fprintf(stderr,
"*\n* Error : Can't access "
"file pointed to by %s due "
"to %s.\n",
filename,
strerror(errno));
}
else if (do_log)
{
fprintf(stderr,
"*\n* Error : Can't access %s due "
"to %s.\n",
filename,
strerror(errno));
}
if (writable)
{
*writable = false;
}
}
else
{
if (writable)
{
char c = ' ';
if (write(fd, &c, 1) == 1)
{
*writable = true;
}
else
{
if (do_log &&
file_is_symlink(filename))
{
fprintf(stderr,
"*\n* Error : Can't write to "
"file pointed to by %s due to "
"%s.\n",
filename,
strerror(errno));
}
else if (do_log)
{
fprintf(stderr,
"*\n* Error : Can't write to "
"%s due to %s.\n",
filename,
strerror(errno));
}
*writable = false;
}
}
close(fd);
}
exists = true;
}
else
{
if (do_log && file_is_symlink(filename))
{
fprintf(stderr,
"*\n* Error : Can't access the file "
"pointed to by %s due to %s.\n",
filename,
strerror(errno));
}
else if (do_log)
{
fprintf(stderr,
"*\n* Error : Can't access %s due to %s.\n",
filename,
strerror(errno));
}
exists = false;
if (writable)
{
*writable = false;
}
}
}
else
{
close(fd);
unlink(filename);
exists = false;
if (writable)
{
*writable = true;
}
}
if(access(filename,F_OK) == 0)
{
exists = true;
if(access(filename,W_OK) == 0)
{
if(writable)
{
*writable = true;
}
}
else
{
if (do_log && file_is_symlink(filename))
{
fprintf(stderr,
"*\n* Error : Can't access "
"file pointed to by %s due "
"to %s.\n",
filename,
strerror(errno));
}
else if (do_log)
{
fprintf(stderr,
"*\n* Error : Can't access %s due "
"to %s.\n",
filename,
strerror(errno));
}
if(writable)
{
*writable = false;
}
}
}
else
{
exists = false;
if(writable)
{
*writable = true;
}
}
}
return exists;
}

View File

@ -89,7 +89,7 @@ int main(int argc, char* argv[])
goto return_err;
}
thr = (thread_t*)calloc(1, nthr*sizeof(thread_t*));
thr = (thread_t **)calloc(1, nthr*sizeof(thread_t*));
if (thr == NULL)
{
@ -585,7 +585,6 @@ static void* thr_run_morelog(
void* data)
{
thread_t* td = (thread_t *)data;
char* logstr;
int err;
int i;
int nmsg;

View File

@ -1,3 +1,4 @@
function(debugmsg MSG)
if(DEBUG_OUTPUT)
message(STATUS "DEBUG: ${MSG}")
@ -9,7 +10,7 @@ macro(set_maxscale_version)
#MaxScale version number
set(MAXSCALE_VERSION_MAJOR "1")
set(MAXSCALE_VERSION_MINOR "0")
set(MAXSCALE_VERSION_PATCH "5")
set(MAXSCALE_VERSION_PATCH "6")
set(MAXSCALE_VERSION_NUMERIC "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")
set(MAXSCALE_VERSION "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}-unstable")

View File

@ -1253,7 +1253,7 @@ char* skygw_get_affected_fields(GWBUF* buf)
List_iterator<Item> ilist(lex->current_select->item_list);
item = (Item*)ilist.next();
for (item; item != NULL; item=(Item*)ilist.next())
for (; item != NULL; item=(Item*)ilist.next())
{
itype = item->type();
@ -1627,7 +1627,7 @@ retblock:
skygw_query_op_t query_classifier_get_operation(GWBUF* querybuf)
{
LEX* lex = get_lex(querybuf);
skygw_query_op_t operation;
skygw_query_op_t operation = QUERY_OP_UNDEFINED;
if(lex){
switch(lex->sql_command){
case SQLCOM_SELECT:

View File

@ -158,6 +158,7 @@ int sendMessage(MYSQL* server, amqp_message_t* msg)
(int)((msg->properties.correlation_id.len + 1)*2+1) +
strlen(DB_INSERT),
rval = 0;
char* saved;
char *qstr = calloc(buffsz,sizeof(char)),
*rawmsg = calloc((msg->body.len + 1),sizeof(char)),
*clnmsg = calloc(((msg->body.len + 1)*2+1),sizeof(char)),
@ -170,9 +171,9 @@ int sendMessage(MYSQL* server, amqp_message_t* msg)
sprintf(qstr,"%.*s",(int)msg->body.len,(char *)msg->body.bytes);
fprintf(out_fd,"Received: %s\n",qstr);
char *ptr = strtok(qstr,"|");
char *ptr = strtok_r(qstr,"|",&saved);
sprintf(rawdate,"%s",ptr);
ptr = strtok(NULL,"\n\0");
ptr = strtok_r(NULL,"\n\0",&saved);
if(ptr == NULL){
fprintf(out_fd,"Message content not valid.\n");
rval = 1;

View File

@ -385,7 +385,7 @@ getDatabases(SERVICE *service, MYSQL *con)
"%s: Unable to load database grant information, MaxScale "
"authentication will proceed without including database "
"permissions. To correct this GRANT select permission "
"on msql.db to the user %s.",
"on mysql.db to the user %s.",
service->name, service_user)));
}

View File

@ -991,7 +991,7 @@ static void usage(void)
" -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"
" -lfile or -lshm - defaults to file\n"
" -v|--version print version info and exit\n"
" -?|--help show this help\n"
, progname);
@ -1039,6 +1039,7 @@ int main(int argc, char **argv)
int l;
int i;
int n;
intptr_t thread_id;
int n_threads; /*< number of epoll listener threads */
int n_services;
int eno = 0; /*< local variable for errno */
@ -1052,7 +1053,7 @@ int main(int argc, char **argv)
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 */
int logtofile = 1; /* Use shared memory or file */
ssize_t log_flush_timeout_ms = 0;
sigset_t sigset;
sigset_t sigpipe_mask;
@ -1788,9 +1789,9 @@ int main(int argc, char **argv)
/*<
* Start server threads.
*/
for (n = 0; n < n_threads - 1; n++)
for (thread_id = 0; thread_id < n_threads - 1; thread_id++)
{
threads[n] = thread_start(poll_waitevents, (void *)(n + 1));
threads[thread_id] = thread_start(poll_waitevents, (void *)(thread_id + 1));
}
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
"MaxScale started with %d server threads.",
@ -1803,9 +1804,9 @@ int main(int argc, char **argv)
/*<
* Wait server threads' completion.
*/
for (n = 0; n < n_threads - 1; n++)
for (thread_id = 0; thread_id < n_threads - 1; thread_id++)
{
thread_wait(threads[n]);
thread_wait(threads[thread_id]);
}
/*<
* Wait the flush thread.

View File

@ -678,12 +678,14 @@ void *key, *value;
if (!(*keywrite)(fd, key))
{
close(fd);
hashtable_iterator_free(iter);
return -1;
}
if ((value = hashtable_fetch(table, key)) == NULL ||
(*valuewrite)(fd, value) == 0)
{
close(fd);
hashtable_iterator_free(iter);
return -1;
}
rval++;
@ -691,10 +693,13 @@ void *key, *value;
}
/* Now go back and write the count of entries */
lseek(fd, 7L, SEEK_SET);
write(fd, &rval, sizeof(rval));
if(lseek(fd, 7L, SEEK_SET) != -1)
{
write(fd, &rval, sizeof(rval));
}
close(fd);
hashtable_iterator_free(iter);
return rval;
}

View File

@ -30,7 +30,7 @@
#include <stdio.h>
#include <secrets.h>
main(int argc, char **argv)
int main(int argc, char **argv)
{
if (argc != 2)
{

View File

@ -28,10 +28,12 @@
* @endverbatim
*/
#include <memlog.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static MEMLOG *memlogs = NULL;
static SPINLOCK *memlock = SPINLOCK_INIT;
static SPINLOCK memlock = SPINLOCK_INIT;
/**
* Create a new instance of a memory logger.

View File

@ -206,6 +206,10 @@ GWBUF *addition;
/* New SQL is shorter */
memcpy(ptr, sql, newlength);
GWBUF_RTRIM(orig, (length - 1) - newlength);
ptr = GWBUF_DATA(orig);
*ptr++ = (newlength + 1) & 0xff;
*ptr++ = ((newlength + 1) >> 8) & 0xff;
*ptr++ = ((newlength + 1) >> 16) & 0xff;
}
else
{
@ -237,7 +241,7 @@ char *
modutil_get_SQL(GWBUF *buf)
{
unsigned int len, length;
unsigned char *ptr, *dptr, *rval = NULL;
char *ptr, *dptr, *rval = NULL;
if (!modutil_is_SQL(buf))
return rval;

View File

@ -15,7 +15,6 @@
*
* Copyright MariaDB Corporation Ab 2013-2014
*/
#include <my_config.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -438,7 +437,7 @@ poll_waitevents(void *arg)
{
struct epoll_event events[MAX_EVENTS];
int i, nfds, timeout_bias = 1;
int thread_id = (int)arg;
intptr_t thread_id = (intptr_t)arg;
DCB *zombies = NULL;
int poll_spins = 0;

View File

@ -221,7 +221,7 @@ GWPROTOCOL *funcs;
{
/* Try loading authentication data from file cache */
char *ptr, path[4096];
char *ptr, path[4097];
strcpy(path, "/usr/local/skysql/MaxScale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
@ -251,6 +251,7 @@ GWPROTOCOL *funcs;
{
/* Save authentication data to file cache */
char *ptr, path[4096];
int mkdir_rval = 0;
strcpy(path, "/usr/local/skysql/MaxScale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
@ -259,10 +260,33 @@ GWPROTOCOL *funcs;
strncat(path, "/", 4096);
strncat(path, service->name, 4096);
if (access(path, R_OK) == -1)
mkdir(path, 0777);
{
mkdir_rval = mkdir(path, 0777);
}
if(mkdir_rval)
{
skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
path,
errno,
strerror(errno));
mkdir_rval = 0;
}
strncat(path, "/.cache", 4096);
if (access(path, R_OK) == -1)
mkdir(path, 0777);
{
mkdir_rval = mkdir(path, 0777);
}
if(mkdir_rval)
{
skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
path,
errno,
strerror(errno));
mkdir_rval = 0;
}
strncat(path, "/dbusers", 4096);
dbusers_save(service->users, path);
}

View File

@ -18,39 +18,48 @@
/**
* @file fwfilter.c
* Firewall Filter
* @author Markus Mäkelä
* @date 13.2.2015
* @version 1.0.0
* @copyright GPLv2
* @section secDesc Firewall Filter
*
* A filter that acts as a firewall, denying queries that do not meet a set of rules.
*
* Filter configuration parameters:
*
*@code{.unparsed}
* rules=<path to file> Location of the rule file
*
*@endcode
* Rules are defined in a separate rule file that lists all the rules and the users to whom the rules are applied.
* Rules follow a simple syntax that denies the queries that meet the requirements of the rules.
* For example, to define a rule denying users from accessing the column 'salary' between
* the times 15:00 and 17:00, the following rule is to be configured into the configuration file:
*
*@code{.unparsed}
* rule block_salary deny columns salary at_times 15:00:00-17:00:00
*
*@endcode
* The users are matched by username and network address. Wildcard values can be provided by using the '%' character.
* For example, to apply this rule to users John, connecting from any address
* that starts with the octets 198.168.%, and Jane, connecting from the address 192.168.0.1:
*
*@code{.unparsed}
* users John@192.168.% Jane@192.168.0.1 match any rules block_salary
*@endcode
*
*
* The 'match' keyword controls the way rules are matched. If it is set to 'any' the first active rule that is triggered will cause the query to be denied.
* The 'match' keyword controls the way rules are matched. If it is set to
* 'any' the first active rule that is triggered will cause the query to be denied.
* If it is set to 'all' all the active rules need to match before the query is denied.
*
* Rule syntax
*
* @subsection secRule Rule syntax
* This is the syntax used when defining rules.
*@code{.unparsed}
* rule NAME deny [wildcard | columns VALUE ... | regex REGEX | limit_queries COUNT TIMEPERIOD HOLDOFF | no_where_clause] [at_times VALUE...] [on_queries [select|update|insert|delete]]
*
* User syntax
*
*@endcode
* @subsection secUser User syntax
* This is the syntax used when linking users to rules. It takes one or more
* combinations of username and network, either the value any or all,
* depending on how you want to match the rules, and one or more rule names.
*@code{.unparsed}
* users NAME ... match [any|all] rules RULE ...
*
*@endcode
*/
#include <my_config.h>
#include <stdint.h>
@ -109,13 +118,13 @@ static FILTER_OBJECT MyObject = {
* Rule types
*/
typedef enum {
RT_UNDEFINED = 0x00,
RT_COLUMN,
RT_THROTTLE,
RT_PERMISSION,
RT_WILDCARD,
RT_REGEX,
RT_CLAUSE
RT_UNDEFINED = 0x00, /*< Undefined rule */
RT_COLUMN, /*< Column name rule*/
RT_THROTTLE, /*< Query speed rule */
RT_PERMISSION, /*< Simple denying rule */
RT_WILDCARD, /*< Wildcard denial rule */
RT_REGEX, /*< Regex matching rule */
RT_CLAUSE /*< WHERE-clause requirement rule */
}ruletype_t;
const char* rule_names[] = {
@ -133,25 +142,31 @@ const char* rule_names[] = {
* Linked list of strings.
*/
typedef struct strlink_t{
struct strlink_t *next;
char* value;
struct strlink_t *next; /*< Next node in the list */
char* value; /*< Value of the current node */
}STRLINK;
/**
* A structure defining a range of time
*/
typedef struct timerange_t{
struct timerange_t* next;
struct tm start;
struct tm end;
struct timerange_t* next; /*< Next node in the list */
struct tm start; /*< Start of the time range */
struct tm end; /*< End of the time range */
}TIMERANGE;
/**
* Query speed measurement and limitation structure
*/
typedef struct queryspeed_t{
time_t first_query;
time_t triggered;
double period;
double cooldown;
int count;
int limit;
long id;
struct queryspeed_t* next;
time_t first_query; /*< Time when the first query occurred */
time_t triggered; /*< Time when the limit was exceeded */
double period; /*< Measurement interval in seconds */
double cooldown;/*< Time the user is denied access for */
int count; /*< Number of queries done */
int limit; /*< Maximum number of queries */
long id; /*< Unique id of the rule */
struct queryspeed_t* next; /*< Next node in the list */
}QUERYSPEED;
@ -162,65 +177,70 @@ typedef struct queryspeed_t{
* This allows to match an arbitrary set of rules against a user.
*/
typedef struct rule_t{
void* data;
char* name;
ruletype_t type;
skygw_query_op_t on_queries;
bool allow;
int times_matched;
TIMERANGE* active;
void* data; /*< Actual implementation of the rule */
char* name; /*< Name of the rule */
ruletype_t type;/*< Type of the rule */
skygw_query_op_t on_queries;/*< Types of queries to inspect */
bool allow;/*< Allow or deny the query if this rule matches */
int times_matched;/*< Number of times this rule has been matched */
TIMERANGE* active;/*< List of times when this rule is active */
}RULE;
/**
* Linked list of pointers to a global pool of RULE structs
*/
typedef struct rulelist_t{
RULE* rule;
struct rulelist_t* next;
RULE* rule; /*< The rule structure */
struct rulelist_t* next;/*< Next node in the list */
}RULELIST;
typedef struct user_t{
char* name;
SPINLOCK* lock;
QUERYSPEED* qs_limit;
RULELIST* rules_or;
RULELIST* rules_and;
char* name;/*< Name of the user */
SPINLOCK* lock;/*< User spinlock */
QUERYSPEED* qs_limit;/*< The query speed structure unique to this user */
RULELIST* rules_or;/*< If any of these rules match the action is triggered */
RULELIST* rules_and;/*< All of these rules must match for the action to trigger */
}USER;
/**
* Linked list of IP adresses and subnet masks
*/
typedef struct iprange_t{
struct iprange_t* next;
uint32_t ip;
uint32_t mask;
struct iprange_t* next;/*< Next node in the list */
uint32_t ip;/*< IP address */
uint32_t mask;/*< Network mask */
}IPRANGE;
/**
* The Firewall filter instance.
*/
typedef struct {
HASHTABLE* htable;
RULELIST* rules;
STRLINK* userstrings;
bool def_op;
SPINLOCK* lock;
long idgen; /**UID generator*/
HASHTABLE* htable; /*< User hashtable */
RULELIST* rules;/*< List of all the rules */
STRLINK* userstrings;/*< Temporary list of raw strings of users */
bool def_op;/*< Default operation mode, defaults to deny */
SPINLOCK* lock;/*< Instance spinlock */
long idgen; /*< UID generator */
} FW_INSTANCE;
/**
* The session structure for Firewall filter.
*/
typedef struct {
SESSION* session;
char* errmsg;
DOWNSTREAM down;
UPSTREAM up;
SESSION* session;/*< Client session structure */
char* errmsg;/*< Rule specific error message */
DOWNSTREAM down;/*< Next object in the downstream chain */
UPSTREAM up;/*< Next object in the upstream chain */
} FW_SESSION;
static int hashkeyfun(void* key);
static int hashcmpfun (void *, void *);
/**
* Hashtable key hashing function. Uses a simple string hashing algorithm.
* @param key Key to hash
* @return The hash value of the key
*/
static int hashkeyfun(
void* key)
{
@ -232,9 +252,16 @@ static int hashkeyfun(
while((c = *ptr++)){
hash = c + (hash << 6) + (hash << 16) - hash;
}
return (int)hash > 0 ? hash : -hash;
return hash;
}
/**
* Hashtable entry comparison function. Does a string matching operation on the
* two keys. This function assumes the values are pointers to null-terminated
* character arrays.
* @param v1 The first key
* @param v2 The second key
* @return Zero if the values are equal. Non-zero in other cases.
*/
static int hashcmpfun(
void* v1,
void* v2)
@ -245,19 +272,6 @@ static int hashcmpfun(
return strcmp(i1,i2);
}
static void* hstrdup(void* fval)
{
char* str = (char*)fval;
return strdup(str);
}
static void* hstrfree(void* fval)
{
free (fval);
return NULL;
}
void* rlistdup(void* fval)
{
@ -588,7 +602,7 @@ RULE* find_rule(char* tok, FW_INSTANCE* instance)
}
rlist = rlist->next;
}
skygw_log_write(LOGFILE_ERROR, "fwfilter: Rule not found: %s",tok);
skygw_log_write(LOGFILE_ERROR, "Error : Rule not found: %s",tok);
return NULL;
}
@ -602,6 +616,10 @@ void add_users(char* rule, FW_INSTANCE* instance)
assert(rule != NULL && instance != NULL);
STRLINK* link = calloc(1,sizeof(STRLINK));
if(link == NULL){
skygw_log_write(LOGFILE_ERROR,"Error : Memory allocation failed");
return;
}
link->next = instance->userstrings;
link->value = strdup(rule);
instance->userstrings = link;
@ -619,8 +637,9 @@ void link_rules(char* rule, FW_INSTANCE* instance)
/**Apply rules to users*/
bool match_any;
bool match_any = true;
char *tok, *ruleptr, *userptr, *modeptr;
char *saveptr = NULL;
RULELIST* rulelist = NULL;
userptr = strstr(rule,"users ");
@ -635,10 +654,10 @@ void link_rules(char* rule, FW_INSTANCE* instance)
*modeptr++ = '\0';
*ruleptr++ = '\0';
tok = strtok(modeptr," ");
if(strcmp(tok,"match") == 0){
tok = strtok(NULL," ");
tok = strtok_r(modeptr," ",&saveptr);
if(tok && strcmp(tok,"match") == 0){
tok = strtok_r(NULL," ",&saveptr);
if(strcmp(tok,"any") == 0){
match_any = true;
}else if(strcmp(tok,"all") == 0){
@ -649,8 +668,8 @@ void link_rules(char* rule, FW_INSTANCE* instance)
}
}
tok = strtok(ruleptr," ");
tok = strtok(NULL," ");
tok = strtok_r(ruleptr," ",&saveptr);
tok = strtok_r(NULL," ",&saveptr);
while(tok)
{
@ -664,7 +683,7 @@ void link_rules(char* rule, FW_INSTANCE* instance)
rulelist = tmp_rl;
}
tok = strtok(NULL," ");
tok = strtok_r(NULL," ",&saveptr);
}
/**
@ -672,8 +691,8 @@ void link_rules(char* rule, FW_INSTANCE* instance)
*/
*(ruleptr) = '\0';
userptr = strtok(rule," ");
userptr = strtok(NULL," ");
userptr = strtok_r(rule," ",&saveptr);
userptr = strtok_r(NULL," ",&saveptr);
while(userptr)
{
@ -720,10 +739,16 @@ void link_rules(char* rule, FW_INSTANCE* instance)
(void *)userptr,
(void *)user);
userptr = strtok(NULL," ");
userptr = strtok_r(NULL," ",&saveptr);
}
while(rulelist)
{
RULELIST *tmp = rulelist;
rulelist = rulelist->next;
free(tmp);
}
}
@ -737,7 +762,8 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
ss_dassert(rule != NULL && instance != NULL);
char *rulecpy = strdup(rule);
char *tok = strtok(rulecpy," ,");
char *saveptr = NULL;
char *tok = strtok_r(rulecpy," ,",&saveptr);
bool allow,deny,mode;
RULE* ruledef = NULL;
@ -745,7 +771,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
if(strcmp("rule",tok) == 0){ /**Define a new rule*/
tok = strtok(NULL," ,");
tok = strtok_r(NULL," ,",&saveptr);
if(tok == NULL) goto retblock;
@ -780,8 +806,13 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
add_users(rule, instance);
goto retblock;
}
else
{
skygw_log_write(LOGFILE_ERROR,"Error : Unknown token in rule file: %s",tok);
goto retblock;
}
tok = strtok(NULL, " ,");
tok = strtok_r(NULL, " ,",&saveptr);
if((allow = (strcmp(tok,"allow") == 0)) ||
@ -790,7 +821,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
mode = allow ? true:false;
ruledef->allow = mode;
ruledef->type = RT_PERMISSION;
tok = strtok(NULL, " ,");
tok = strtok_r(NULL, " ,",&saveptr);
while(tok){
@ -802,13 +833,13 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
{
STRLINK *tail = NULL,*current;
ruledef->type = RT_COLUMN;
tok = strtok(NULL, " ,");
tok = strtok_r(NULL, " ,",&saveptr);
while(tok && strcmp(tok,"at_times") != 0){
current = malloc(sizeof(STRLINK));
current->value = strdup(tok);
current->next = tail;
tail = current;
tok = strtok(NULL, " ,");
tok = strtok_r(NULL, " ,",&saveptr);
}
ruledef->data = (void*)tail;
@ -818,7 +849,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
else if(strcmp(tok,"at_times") == 0)
{
tok = strtok(NULL, " ,");
tok = strtok_r(NULL, " ,",&saveptr);
TIMERANGE *tr = NULL;
while(tok){
TIMERANGE *tmp = parse_time(tok,instance);
@ -828,7 +859,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
}
tmp->next = tr;
tr = tmp;
tok = strtok(NULL, " ,");
tok = strtok_r(NULL, " ,",&saveptr);
}
ruledef->active = tr;
}
@ -837,21 +868,22 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
bool escaped = false;
regex_t *re;
char* start, *str;
tok = strtok(NULL," ");
tok = strtok_r(NULL," ",&saveptr);
char delim = '\'';
while(*tok == '\'' || *tok == '"'){
delim = *tok;
tok++;
}
start = tok;
while(isspace(*tok) || *tok == '\'' || *tok == '"'){
while(isspace(*tok) || *tok == delim){
tok++;
}
while(true){
if((*tok == '\'' || *tok == '"') && !escaped){
if((*tok == delim) && !escaped){
break;
}
escaped = (*tok == '\\');
@ -895,12 +927,24 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
qs->id = ++instance->idgen;
spinlock_release(instance->lock);
tok = strtok(NULL," ");
tok = strtok_r(NULL," ",&saveptr);
if(tok == NULL){
free(qs);
goto retblock;
}
qs->limit = atoi(tok);
tok = strtok(NULL," ");
tok = strtok_r(NULL," ",&saveptr);
if(tok == NULL){
free(qs);
goto retblock;
}
qs->period = atof(tok);
tok = strtok(NULL," ");
tok = strtok_r(NULL," ",&saveptr);
if(tok == NULL){
free(qs);
goto retblock;
}
qs->cooldown = atof(tok);
ruledef->type = RT_THROTTLE;
ruledef->data = (void*)qs;
@ -912,7 +956,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
}
else if(strcmp(tok,"on_operations") == 0)
{
tok = strtok(NULL," ");
tok = strtok_r(NULL," ",&saveptr);
if(!parse_querytypes(tok,ruledef)){
skygw_log_write(LOGFILE_ERROR,
"fwfilter: Invalid query type"
@ -920,7 +964,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
,tok);
}
}
tok = strtok(NULL," ,");
tok = strtok_r(NULL," ,",&saveptr);
}
goto retblock;
@ -958,13 +1002,13 @@ createInstance(char **options, FILTER_PARAMETER **params)
spinlock_init(my_instance->lock);
if((ht = hashtable_alloc(7, hashkeyfun, hashcmpfun)) == NULL){
if((ht = hashtable_alloc(100, hashkeyfun, hashcmpfun)) == NULL){
skygw_log_write(LOGFILE_ERROR, "Unable to allocate hashtable.");
free(my_instance);
return NULL;
}
hashtable_memory_fns(ht,hstrdup,NULL,hstrfree,hrulefree);
hashtable_memory_fns(ht,(HASHMEMORYFN)strdup,NULL,(HASHMEMORYFN)free,hrulefree);
my_instance->htable = ht;
my_instance->def_op = true;
@ -979,18 +1023,22 @@ createInstance(char **options, FILTER_PARAMETER **params)
}
}
if(filename == NULL)
{
skygw_log_write(LOGFILE_ERROR, "Unable to find rule file for firewall filter.");
skygw_log_write(LOGFILE_ERROR, "Unable to find rule file for firewall filter. Please provide the path with"
" rules=<path to file>");
hashtable_free(my_instance->htable);
free(my_instance);
return NULL;
}
if((file = fopen(filename,"rb")) == NULL ){
skygw_log_write(LOGFILE_ERROR, "Error while opening rule file for firewall filter.");
free(my_instance);
free(filename);
return NULL;
hashtable_free(my_instance->htable);
free(my_instance);
free(filename);
return NULL;
}
free(filename);
@ -1002,6 +1050,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
if(ferror(file)){
skygw_log_write(LOGFILE_ERROR, "Error while reading rule file for firewall filter.");
fclose(file);
hashtable_free(my_instance->htable);
free(my_instance);
return NULL;
}
@ -1037,9 +1086,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
/**
* Associate a new session with this instance of the filter and opens
* a connection to the server and prepares the exchange and the queue for use.
*
* Associate a new session with this instance of the filter.
*
* @param instance The filter instance data
* @param session The session itself
@ -1370,15 +1417,17 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
spinlock_acquire(user->lock);
queryspeed = user->qs_limit;
spinlock_release(user->lock);
while(queryspeed){
if(queryspeed->id == rule_qs->id){
break;
}
queryspeed = queryspeed->next;
}
if(queryspeed == NULL){
/**No match found*/
@ -1427,7 +1476,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
{
queryspeed->first_query = time_now;
}
spinlock_release(user->lock);
break;
case RT_CLAUSE:

View File

@ -11,6 +11,7 @@ add_executable(harness harness_util.c harness_common.c ${CORE})
target_link_libraries(harness_ui fullcore log_manager utils)
target_link_libraries(harness fullcore)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${ERRMSG} ${CMAKE_CURRENT_BINARY_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/harness.cnf ${CMAKE_CURRENT_BINARY_DIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testdriver.sh ${CMAKE_CURRENT_BINARY_DIR}/testdriver.sh @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hintfilter/hint_testing.cnf ${CMAKE_CURRENT_BINARY_DIR}/hintfilter/hint_testing.cnf)

View File

@ -141,6 +141,7 @@ FILTER_PARAMETER** read_params(int* paramc)
{
char buffer[256];
char* token;
char* saveptr;
char* names[64];
char* values[64];
int pc = 0, do_read = 1, val_len = 0;
@ -157,14 +158,14 @@ FILTER_PARAMETER** read_params(int* paramc)
if(strcmp("done\n",buffer) == 0){
do_read = 0;
}else{
token = strtok(buffer,"=\n");
token = strtok_r(buffer,"=\n",&saveptr);
if(token!=NULL){
val_len = strcspn(token," \n\0");
if((names[pc] = calloc((val_len + 1),sizeof(char))) != NULL){
memcpy(names[pc],token,val_len);
}
}
token = strtok(NULL,"=\n");
token = strtok_r(NULL,"=\n",&saveptr);
if(token!=NULL){
val_len = strcspn(token," \n\0");
if((values[pc] = calloc((val_len + 1),sizeof(char))) != NULL){
@ -997,6 +998,7 @@ int process_opts(int argc, char** argv)
int fd, buffsize = 1024;
int rd,rdsz, rval = 0, error = 0;
size_t fsize;
char* saveptr;
char *buff = calloc(buffsize,sizeof(char)), *tok = NULL;
/**Parse 'harness.cnf' file*/
@ -1027,16 +1029,16 @@ int process_opts(int argc, char** argv)
instance.session_count = 1;
rdsz = read(fd,buff,fsize);
buff[rdsz] = '\0';
tok = strtok(buff,"=");
tok = strtok_r(buff,"=",&saveptr);
while(tok){
if(!strcmp(tok,"threads")){
tok = strtok(NULL,"\n\0");
tok = strtok_r(NULL,"\n\0",&saveptr);
instance.thrcount = strtol(tok,0,0);
}else if(!strcmp(tok,"sessions")){
tok = strtok(NULL,"\n\0");
tok = strtok_r(NULL,"\n\0",&saveptr);
instance.session_count = strtol(tok,0,0);
}
tok = strtok(NULL,"=");
tok = strtok_r(NULL,"=",&saveptr);
}

View File

@ -20,7 +20,6 @@ int main(int argc, char** argv){
printf("\n\n\tFilter Test Harness\n\n");
}
while(instance.running){
printf("Harness> ");
memset(buffer,0,256);

View File

@ -488,8 +488,11 @@ char *ptr;
}
static int
cmp_topn(TOPNQ **a, TOPNQ **b)
cmp_topn(const void *va, const void *vb)
{
TOPNQ **a = (TOPNQ **)va;
TOPNQ **b = (TOPNQ **)vb;
if ((*b)->duration.tv_sec == (*a)->duration.tv_sec)
return (*b)->duration.tv_usec - (*a)->duration.tv_usec;
return (*b)->duration.tv_sec - (*a)->duration.tv_sec;

View File

@ -172,6 +172,7 @@ typedef struct router_slave {
int overrun;
uint32_t rank; /*< Replication rank */
uint8_t seqno; /*< Replication dump sequence no */
uint32_t lastEventTimestamp;/*< Last event timestamp sent */
SPINLOCK catch_lock; /*< Event catchup lock */
unsigned int cstate; /*< Catch up state */
SPINLOCK rses_lock; /*< Protects rses_deleted */
@ -257,6 +258,7 @@ typedef struct router_instance {
SESSION *session; /*< Fake session for master connection */
unsigned int master_state; /*< State of the master FSM */
uint8_t lastEventReceived;
uint32_t lastEventTimestamp; /*< Timestamp from last event */
GWBUF *residual; /*< Any residual binlog event */
MASTER_RESPONSES saved_master; /*< Saved master responses */
char *binlogdir; /*< The directory with the binlog files */

View File

@ -569,7 +569,7 @@ int gw_read_client_event(
int rc = 0;
int nbytes_read = 0;
uint8_t cap = 0;
bool stmt_input; /*< router input type */
bool stmt_input = false; /*< router input type */
CHK_DCB(dcb);
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);

View File

@ -367,6 +367,7 @@ unsigned char *defuuid;
inst->residual = NULL;
inst->slaves = NULL;
inst->next = NULL;
inst->lastEventTimestamp = 0;
/*
* Read any cached response messages
@ -486,6 +487,7 @@ ROUTER_SLAVE *slave;
slave->file = NULL;
strcpy(slave->binlogfile, "unassigned");
slave->connect_time = time(0);
slave->lastEventTimestamp = 0;
/**
* Add this session to the list of active sessions.
@ -777,11 +779,18 @@ struct tm tm;
buf);
dcb_printf(dcb, "\t (%d seconds ago)\n",
time(0) - router_inst->stats.lastReply);
dcb_printf(dcb, "\tLast event from master: 0x%x (%s)\n",
dcb_printf(dcb, "\tLast event from master: 0x%x, %s",
router_inst->lastEventReceived,
(router_inst->lastEventReceived >= 0 &&
router_inst->lastEventReceived < 0x24) ?
event_names[router_inst->lastEventReceived] : "unknown");
if (router_inst->lastEventTimestamp)
{
localtime_r(&router_inst->lastEventTimestamp, &tm);
asctime_r(&tm, buf);
dcb_printf(dcb, "\tLast binlog event timestamp: %ld (%s)\n",
router_inst->lastEventTimestamp, buf);
}
if (router_inst->active_logs)
dcb_printf(dcb, "\tRouter processing binlog records\n");
if (router_inst->reconnect_pending)
@ -865,6 +874,9 @@ struct tm tm;
dcb_printf(dcb,
"\t\tNo. events sent: %u\n",
session->stats.n_events);
dcb_printf(dcb,
"\t\tNo. bytes sent: %u\n",
session->stats.n_bytes);
dcb_printf(dcb,
"\t\tNo. bursts sent: %u\n",
session->stats.n_bursts);
@ -890,6 +902,14 @@ struct tm tm;
dcb_printf(dcb, "\t\tNo. of distribute action 2 %u\n", session->stats.n_actions[1]);
dcb_printf(dcb, "\t\tNo. of distribute action 3 %u\n", session->stats.n_actions[2]);
#endif
if (session->lastEventTimestamp
&& router_inst->lastEventTimestamp)
{
localtime_r(&session->lastEventTimestamp, &tm);
asctime_r(&tm, buf);
dcb_printf(dcb, "\t\tLast binlog event timestamp %u, %s", session->lastEventTimestamp, buf);
dcb_printf(dcb, "\t\tSeconds behind master %u\n", router_inst->lastEventTimestamp - session->lastEventTimestamp);
}
if ((session->cstate & CS_UPTODATE) == 0)
{
@ -1151,6 +1171,13 @@ int len;
return slave->dcb->func.write(slave->dcb, ret);
}
/**
* Respond to a COM_PING command
*
* @param router The router instance
* @param slave The "slave" connection that requested the ping
* @param queue The ping request
*/
int
blr_ping(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue)
{

View File

@ -456,7 +456,7 @@ char query[128];
break;
case BLRM_MUUID:
{
char *val = blr_extract_column(buf, 1);
char *val = blr_extract_column(buf, 2);
router->master_uuid = val;
// Response to the SERVER_UUID, should be stored
@ -925,6 +925,7 @@ static REP_HEADER phdr;
}
router->stats.n_binlogs++;
router->lastEventReceived = hdr.event_type;
router->lastEventTimestamp = hdr.timestamp;
// #define SHOW_EVENTS
#ifdef SHOW_EVENTS
@ -1291,6 +1292,7 @@ int action;
* this is a rotate event. Send the event directly from
* memory to the slave.
*/
slave->lastEventTimestamp = hdr->timestamp;
pkt = gwbuf_alloc(hdr->event_size + 5);
buf = GWBUF_DATA(pkt);
encode_value(buf, hdr->event_size + 1, 24);
@ -1303,6 +1305,7 @@ int action;
blr_slave_rotate(router, slave, ptr);
}
slave->stats.n_bytes += gwbuf_length(pkt);
slave->stats.n_events++;
slave->dcb->func.write(slave->dcb, pkt);
if (hdr->event_type != ROTATE_EVENT)
{

View File

@ -68,6 +68,7 @@ int blr_slave_callback(DCB *dcb, DCB_REASON reason, void *data);
static int blr_slave_fake_rotate(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
static void blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
static int blr_slave_send_maxscale_version(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
static int blr_slave_send_server_id(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
static int blr_slave_send_maxscale_variables(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
static int blr_slave_send_master_status(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
static int blr_slave_send_slave_status(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
@ -164,6 +165,7 @@ blr_slave_request(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue)
* SELECT @@hostname
* SELECT @@max_allowed_packet
* SELECT @@maxscale_version
* SELECT @@server_id
*
* Five show commands are supported:
* SHOW VARIABLES LIKE 'SERVER_ID'
@ -265,6 +267,11 @@ int query_len;
free(query_text);
return blr_slave_send_maxscale_version(router, slave);
}
else if (strcasecmp(word, "@@server_id") == 0)
{
free(query_text);
return blr_slave_send_server_id(router, slave);
}
}
else if (strcasecmp(word, "SHOW") == 0)
{
@ -544,6 +551,41 @@ int len, vers_len;
return blr_slave_send_eof(router, slave, 5);
}
/**
* Send a response the the SQL command SELECT @@server_id
*
* @param router The binlog router instance
* @param slave The slave server to which we are sending the response
* @return Non-zero if data was sent
*/
static int
blr_slave_send_server_id(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
{
GWBUF *pkt;
char server_id[40];
uint8_t *ptr;
int len, id_len;
sprintf(server_id, "%d", router->masterid);
id_len = strlen(server_id);
blr_slave_send_fieldcount(router, slave, 1);
blr_slave_send_columndef(router, slave, "SERVER_ID", 0xf, id_len, 2);
blr_slave_send_eof(router, slave, 3);
len = 5 + id_len;
if ((pkt = gwbuf_alloc(len)) == NULL)
return 0;
ptr = GWBUF_DATA(pkt);
encode_value(ptr, id_len + 1, 24); // Add length of data packet
ptr += 3;
*ptr++ = 0x04; // Sequence number in response
*ptr++ = id_len; // Length of result string
strncpy((char *)ptr, server_id, id_len); // Result string
ptr += id_len;
slave->dcb->func.write(slave->dcb, pkt);
return blr_slave_send_eof(router, slave, 5);
}
/**
* Send the response to the SQL command "SHOW VARIABLES LIKE 'MAXSCALE%'
@ -647,8 +689,8 @@ static char *slave_status_columns[] = {
"Last_Errno", "Last_Error", "Skip_Counter", "Exec_Master_Log_Pos", "Relay_Log_Space",
"Until_Condition", "Until_Log_File", "Until_Log_Pos", "Master_SSL_Allowed",
"Master_SSL_CA_File", "Master_SSL_CA_Path", "Master_SSL_Cert", "Master_SSL_Cipher",
"Master_SSL_Key",
"Seconds_Behind_Master", "Last_IO_Errno", "Last_IO_Error", "Last_SQL_Errno",
"Master_SSL_Key", "Seconds_Behind_Master",
"Master_SSL_Verify_Server_Cert", "Last_IO_Errno", "Last_IO_Error", "Last_SQL_Errno",
"Last_SQL_Error", "Replicate_Ignore_Server_Ids", "Master_Server_Id", "Master_UUID",
"Master_Info_File", "SQL_Delay", "SQL_Remaining_Delay", "Slave_SQL_Running_State",
"Master_Retry_Count", "Master_Bind", "Last_IO_Error_TimeStamp",
@ -856,9 +898,15 @@ int len, actual_len, col_len, seqno, ncols, i;
ptr += col_len;
*ptr++ = 0;
*ptr++ = 0;
/* Master_Server_Id */
sprintf(column, "%d", router->masterid);
col_len = strlen(column);
*ptr++ = col_len; // Length of result string
strncpy((char *)ptr, column, col_len); // Result string
ptr += col_len;
sprintf(column, "%s", router->master_uuid ?
router->master_uuid : router->uuid);
col_len = strlen(column);
@ -1343,6 +1391,7 @@ uint8_t *ptr;
*ptr++ = slave->seqno++;
*ptr++ = 0; // OK
head = gwbuf_append(head, record);
slave->lastEventTimestamp = hdr.timestamp;
if (hdr.event_type == ROTATE_EVENT)
{
unsigned long beat1 = hkheartbeat;