Merge branch 'develop' into firewall
Conflicts: server/modules/filter/test/harness_common.c
This commit is contained in:
@ -10,11 +10,13 @@ set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR}" CACHE INTERNAL "Prefix prepended to in
|
||||
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/")
|
||||
find_package(Valgrind)
|
||||
|
||||
project(MaxScale)
|
||||
|
||||
check_deps()
|
||||
check_dirs()
|
||||
find_package(Valgrind)
|
||||
find_package(MySQLClient)
|
||||
|
||||
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/modules)
|
||||
|
||||
@ -93,7 +95,10 @@ add_subdirectory(log_manager)
|
||||
add_subdirectory(query_classifier)
|
||||
add_subdirectory(server)
|
||||
add_subdirectory(client)
|
||||
|
||||
if(BUILD_RABBITMQ)
|
||||
find_package(RabbitMQ)
|
||||
add_subdirectory(rabbitmq_consumer)
|
||||
endif()
|
||||
|
||||
# Install startup scripts and ldconfig files
|
||||
if( NOT ( (DEFINED INSTALL_SYSTEM_FILES) AND ( NOT ( INSTALL_SYSTEM_FILES ) ) ) )
|
||||
|
||||
33
FindMySQLClient.cmake
Normal file
33
FindMySQLClient.cmake
Normal file
@ -0,0 +1,33 @@
|
||||
# This CMake file tries to find the the MySQL client library
|
||||
# The following variables are set:
|
||||
# MYSQLCLIENT_FOUND - System has MySQL client
|
||||
# MYSQLCLIENT_STATIC_FOUND - System has statically linked MySQL client
|
||||
# MYSQLCLIENT_LIBRARIES - The MySQL client library
|
||||
# MYSQLCLIENT_STATIC_LIBRARIES - The static MySQL client library
|
||||
# MYSQLCLIENT_HEADERS - The MySQL client headers
|
||||
|
||||
find_library(MYSQLCLIENT_LIBRARIES NAMES mysqlclient PATH_SUFFIXES mysql mariadb)
|
||||
if(${MYSQLCLIENT_LIBRARIES} MATCHES "NOTFOUND")
|
||||
set(MYSQLCLIENT_FOUND FALSE CACHE INTERNAL "")
|
||||
message(STATUS "Dynamic MySQL client library not found.")
|
||||
unset(MYSQLCLIENT_LIBRARIES)
|
||||
else()
|
||||
set(MYSQLCLIENT_FOUND TRUE CACHE INTERNAL "")
|
||||
message(STATUS "Found dynamic MySQL client library: ${MYSQLCLIENT_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
set(OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
find_library(MYSQLCLIENT_STATIC_LIBRARIES NAMES mysqlclient PATH_SUFFIXES mysql mariadb)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES})
|
||||
|
||||
if(${MYSQLCLIENT_STATIC_LIBRARIES} MATCHES "NOTFOUND")
|
||||
set(MYSQLCLIENT_STATIC_FOUND FALSE CACHE INTERNAL "")
|
||||
message(STATUS "Static MySQL client library not found.")
|
||||
unset(MYSQLCLIENT_STATIC_LIBRARIES)
|
||||
else()
|
||||
set(MYSQLCLIENT_STATIC_FOUND TRUE CACHE INTERNAL "")
|
||||
message(STATUS "Found statc MySQL client library: ${MYSQLCLIENT_STATIC_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
find_path(MYSQLCLIENT_HEADERS mysql.h PATH_SUFFIXES mysql mariadb)
|
||||
23
FindRabbitMQ.cmake
Normal file
23
FindRabbitMQ.cmake
Normal file
@ -0,0 +1,23 @@
|
||||
# This CMake file tries to find the the RabbitMQ library
|
||||
# The following variables are set:
|
||||
# RABBITMQ_FOUND - System has RabbitMQ client
|
||||
# RABBITMQ_LIBRARIES - The RabbitMQ client library
|
||||
# RABBITMQ_HEADERS - The RabbitMQ client headers
|
||||
include(CheckCSourceCompiles)
|
||||
find_library(RABBITMQ_LIBRARIES NAMES rabbitmq)
|
||||
find_path(RABBITMQ_HEADERS amqp.h PATH_SUFFIXES mysql mariadb)
|
||||
|
||||
if(${RABBITMQ_LIBRARIES} MATCHES "NOTFOUND")
|
||||
set(RABBITMQ_FOUND FALSE CACHE INTERNAL "")
|
||||
message(STATUS "RabbitMQ library not found.")
|
||||
unset(RABBITMQ_LIBRARIES)
|
||||
else()
|
||||
set(RABBITMQ_FOUND TRUE CACHE INTERNAL "")
|
||||
message(STATUS "Found RabbitMQ library: ${RABBITMQ_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${RABBITMQ_HEADERS})
|
||||
check_c_source_compiles("#include <amqp.h>\n int main(){if(AMQP_DELIVERY_PERSISTENT){return 0;}return 1;}" HAVE_RABBITMQ50)
|
||||
if(NOT HAVE_RABBITMQ50)
|
||||
message(FATAL_ERROR "Old version of RabbitMQ-C library found. Version 0.5 or newer is required.")
|
||||
endif()
|
||||
6
README
6
README
@ -219,10 +219,10 @@ OLEVEL=<0-3> Level of optimization
|
||||
BUILD_TESTS=[Y|N] Build tests
|
||||
DEPS_OK=[Y|N] Check dependencies, use N when you want to force a recheck of values
|
||||
DEBUG_OUTPUT=[Y|N] Produce debugging output when configuring CMake
|
||||
RABBITMQ_LIB=<path> Path to RabbitMQ-C libraries
|
||||
RABBITMQ_LIBRARIES=<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
|
||||
MYSQLCLIENT_LIBRARIES=<path> Path to MySQL client libraries
|
||||
MYSQLCLIENT_HEADERS=<path> Path to MySQL client headers
|
||||
|
||||
\section Running Running MaxScale
|
||||
|
||||
|
||||
@ -183,12 +183,22 @@ char c;
|
||||
len += strlen(argv[i]) + 1;
|
||||
}
|
||||
|
||||
cmd = malloc(len);
|
||||
int arglen;
|
||||
memcpy(cmd, argv[optind], (arglen = strlen(argv[optind])) < 8192 ? arglen : 8192);
|
||||
for (i = optind +1; i < argc; i++) {
|
||||
cmd = malloc(len + (2 * argc)); // Allow for quotes
|
||||
strncpy(cmd, argv[optind],len + (2 * argc));
|
||||
for (i = optind +1; i < argc; i++)
|
||||
{
|
||||
strcat(cmd, " ");
|
||||
strcat(cmd, argv[i]);
|
||||
/* Arguments after the seconf are quoted to allow for names
|
||||
* that contain white space
|
||||
*/
|
||||
if (i - optind > 1)
|
||||
{
|
||||
strcat(cmd, "\"");
|
||||
strcat(cmd, argv[i]);
|
||||
strcat(cmd, "\"");
|
||||
}
|
||||
else
|
||||
strcat(cmd, argv[i]);
|
||||
}
|
||||
|
||||
if (access(cmd, R_OK) == 0)
|
||||
|
||||
@ -57,10 +57,18 @@ static simple_mutex_t msg_mutex;
|
||||
* actual library calls such as skygw_log_write.
|
||||
*/
|
||||
int lm_enabled_logfiles_bitmask = 0;
|
||||
|
||||
/**
|
||||
* Thread-specific variable for session id which is used in trace logging.
|
||||
* Thread-specific struct variable for storing current session id and currently
|
||||
* enabled log files for the session.
|
||||
*/
|
||||
__thread size_t tls_sesid = 0;
|
||||
__thread log_info_t tls_log_info = {0, 0};
|
||||
|
||||
/**
|
||||
* Global counter for each log file type. It indicates for how many sessions
|
||||
* each log type is currently enabled.
|
||||
*/
|
||||
ssize_t log_ses_count[LOGFILE_LAST] = {0};
|
||||
|
||||
/**
|
||||
* BUFSIZ comes from the system. It equals with block size or
|
||||
@ -68,13 +76,6 @@ __thread size_t tls_sesid = 0;
|
||||
*/
|
||||
#define MAX_LOGSTRLEN BUFSIZ
|
||||
|
||||
#if defined(SS_PROF)
|
||||
/**
|
||||
* These counters may be inaccurate but give some idea of how
|
||||
* things are going.
|
||||
*/
|
||||
|
||||
#endif
|
||||
/**
|
||||
* Path to directory in which all files are stored to shared memory
|
||||
* by the OS.
|
||||
@ -240,7 +241,7 @@ static void logfile_flush(logfile_t* lf);
|
||||
static void logfile_rotate(logfile_t* lf);
|
||||
static bool logfile_create(logfile_t* lf);
|
||||
static bool logfile_open_file(filewriter_t* fw, logfile_t* lf);
|
||||
static char* form_full_file_name(strpart_t* parts, int seqno, int seqnoidx);
|
||||
static char* form_full_file_name(strpart_t* parts, logfile_t* lf, int seqnoidx);
|
||||
|
||||
static bool filewriter_init(
|
||||
logmanager_t* logmanager,
|
||||
@ -289,6 +290,7 @@ static bool check_file_and_path(
|
||||
|
||||
static bool file_is_symlink(char* filename);
|
||||
static int skygw_log_disable_raw(logfile_id_t id, bool emergency); /*< no locking */
|
||||
static int find_last_seqno(strpart_t* parts, int seqno, int seqnoidx);
|
||||
|
||||
|
||||
const char* get_suffix_default(void)
|
||||
@ -726,27 +728,26 @@ static int logmanager_write_log(
|
||||
int safe_str_len;
|
||||
/** Length of session id */
|
||||
int sesid_str_len;
|
||||
|
||||
|
||||
/** 2 braces and 2 spaces */
|
||||
if (id == LOGFILE_TRACE && tls_sesid > 0)
|
||||
if (id == LOGFILE_TRACE && tls_log_info.li_sesid != 0)
|
||||
{
|
||||
sesid_str_len = 2+2+get_decimal_len(tls_sesid);
|
||||
sesid_str_len = 2+2+get_decimal_len(tls_log_info.li_sesid);
|
||||
}
|
||||
else
|
||||
{
|
||||
sesid_str_len = 0;
|
||||
}
|
||||
|
||||
}
|
||||
timestamp_len = get_timestamp_len();
|
||||
|
||||
/** Findout how much can be safely written with current block size */
|
||||
if (timestamp_len-1+sesid_str_len-1+str_len > lf->lf_buf_size)
|
||||
/** Find out how much can be safely written with current block size */
|
||||
if (timestamp_len-1+sesid_str_len+str_len > lf->lf_buf_size)
|
||||
{
|
||||
safe_str_len = lf->lf_buf_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
safe_str_len = timestamp_len-1+sesid_str_len-1+str_len;
|
||||
safe_str_len = timestamp_len-1+sesid_str_len+str_len;
|
||||
}
|
||||
/**
|
||||
* Seek write position and register to block buffer.
|
||||
@ -799,13 +800,15 @@ static int logmanager_write_log(
|
||||
*/
|
||||
timestamp_len = snprint_timestamp(wp, timestamp_len);
|
||||
|
||||
if (id == LOGFILE_TRACE)
|
||||
if (sesid_str_len != 0)
|
||||
{
|
||||
/**
|
||||
* Write session id
|
||||
*/
|
||||
snprintf(wp+timestamp_len, sesid_str_len, "[%lu] ", tls_sesid);
|
||||
sesid_str_len -= 1; /*< remove terminating char */
|
||||
snprintf(wp+timestamp_len,
|
||||
sesid_str_len,
|
||||
"[%lu] ",
|
||||
tls_log_info.li_sesid);
|
||||
}
|
||||
/**
|
||||
* Write next string to overwrite terminating null character
|
||||
@ -1234,10 +1237,10 @@ int skygw_log_enable(
|
||||
{
|
||||
bool err = 0;
|
||||
|
||||
if (!logmanager_register(true)) {
|
||||
//fprintf(stderr, "ERROR: Can't register to logmanager\n");
|
||||
err = -1;
|
||||
goto return_err;
|
||||
if (!logmanager_register(true))
|
||||
{
|
||||
err = -1;
|
||||
goto return_err;
|
||||
}
|
||||
CHK_LOGMANAGER(lm);
|
||||
|
||||
@ -1369,19 +1372,21 @@ int skygw_log_write_flush(
|
||||
va_list valist;
|
||||
size_t len;
|
||||
|
||||
if (!logmanager_register(true)) {
|
||||
//fprintf(stderr, "ERROR: Can't register to logmanager\n");
|
||||
err = -1;
|
||||
goto return_err;
|
||||
if (!logmanager_register(true))
|
||||
{
|
||||
err = -1;
|
||||
goto return_err;
|
||||
}
|
||||
CHK_LOGMANAGER(lm);
|
||||
|
||||
/**
|
||||
* If particular log is disabled only unregister and return.
|
||||
*/
|
||||
if (!(lm->lm_enabled_logfiles & id)) {
|
||||
err = 1;
|
||||
goto return_unregister;
|
||||
/**
|
||||
* If particular log is disabled in general and it is not enabled for
|
||||
* the current session, then unregister and return.
|
||||
*/
|
||||
if (!LOG_IS_ENABLED(id))
|
||||
{
|
||||
err = 1;
|
||||
goto return_unregister;
|
||||
}
|
||||
/**
|
||||
* Find out the length of log string (to be formatted str).
|
||||
@ -1422,17 +1427,19 @@ int skygw_log_write(
|
||||
va_list valist;
|
||||
size_t len;
|
||||
|
||||
if (!logmanager_register(true)) {
|
||||
//fprintf(stderr, "ERROR: Can't register to logmanager\n");
|
||||
err = -1;
|
||||
goto return_err;
|
||||
if (!logmanager_register(true))
|
||||
{
|
||||
err = -1;
|
||||
goto return_err;
|
||||
}
|
||||
CHK_LOGMANAGER(lm);
|
||||
|
||||
/**
|
||||
* If particular log is disabled only unregister and return.
|
||||
* If particular log is disabled in general and it is not enabled for
|
||||
* the current session, then unregister and return.
|
||||
*/
|
||||
if (!(lm->lm_enabled_logfiles & id)) {
|
||||
if (!LOG_IS_ENABLED(id))
|
||||
{
|
||||
err = 1;
|
||||
goto return_unregister;
|
||||
}
|
||||
@ -1981,6 +1988,11 @@ static void logfile_rotate(
|
||||
* @param lf logfile pointer
|
||||
*
|
||||
* @return true if succeed, false if failed
|
||||
*
|
||||
* @note Log file openings are not TOCTOU-safe. It is not likely that
|
||||
* multiple copies of same files are opened in parallel but it is possible by
|
||||
* using log manager in parallel with multiple processes and by configuring
|
||||
* log manager to use same directories among those processes.
|
||||
*/
|
||||
static bool logfile_create(
|
||||
logfile_t* lf)
|
||||
@ -2015,7 +2027,7 @@ static bool logfile_create(
|
||||
* suffix (index == 2)
|
||||
*/
|
||||
lf->lf_full_file_name =
|
||||
form_full_file_name(spart, lf->lf_name_seqno, 2);
|
||||
form_full_file_name(spart, lf, 2);
|
||||
|
||||
if (store_shmem)
|
||||
{
|
||||
@ -2023,10 +2035,7 @@ static bool logfile_create(
|
||||
/**
|
||||
* Create name for link file
|
||||
*/
|
||||
lf->lf_full_link_name = form_full_file_name(
|
||||
spart,
|
||||
lf->lf_name_seqno,
|
||||
2);
|
||||
lf->lf_full_link_name = form_full_file_name(spart,lf,2);
|
||||
}
|
||||
/**
|
||||
* At least one of the files couldn't be created. Increase
|
||||
@ -2194,38 +2203,37 @@ return_succp:
|
||||
* @node Combine all name parts from left to right.
|
||||
*
|
||||
* Parameters:
|
||||
* @param parts - <usage>
|
||||
* <description>
|
||||
* @param parts
|
||||
*
|
||||
* @param seqno - in, use
|
||||
* specifies the the sequence number which will be added as a part
|
||||
* of full file name.
|
||||
* seqno == -1 indicates that sequence number won't be used.
|
||||
* @param seqno specifies the the sequence number which will be added as a part
|
||||
* of full file name. seqno == -1 indicates that sequence number won't be used.
|
||||
*
|
||||
* @param seqnoidx - in, use
|
||||
* Specifies the seqno position in the 'array' of name parts.
|
||||
* If seqno == -1 seqnoidx will be set -1 as well.
|
||||
* @param seqnoidx Specifies the seqno position in the 'array' of name parts.
|
||||
* If seqno == -1 seqnoidx will be set -1 as well.
|
||||
*
|
||||
* @return Pointer to filename, of NULL if failed.
|
||||
*
|
||||
*
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
static char* form_full_file_name(
|
||||
strpart_t* parts,
|
||||
int seqno,
|
||||
logfile_t* lf,
|
||||
int seqnoidx)
|
||||
{
|
||||
int i;
|
||||
int seqno;
|
||||
size_t s;
|
||||
size_t fnlen;
|
||||
char* filename = NULL;
|
||||
char* seqnostr = NULL;
|
||||
strpart_t* p;
|
||||
|
||||
if (seqno != -1)
|
||||
|
||||
if (lf->lf_name_seqno != -1)
|
||||
{
|
||||
lf->lf_name_seqno = find_last_seqno(parts,
|
||||
lf->lf_name_seqno,
|
||||
seqnoidx);
|
||||
seqno = lf->lf_name_seqno;
|
||||
s = UINTLEN(seqno);
|
||||
seqnostr = (char *)malloc((int)s+1);
|
||||
}
|
||||
@ -2237,6 +2245,7 @@ static char* form_full_file_name(
|
||||
*/
|
||||
s = 0;
|
||||
seqnoidx = -1;
|
||||
seqno = lf->lf_name_seqno;
|
||||
}
|
||||
|
||||
if (parts == NULL || parts->sp_string == NULL) {
|
||||
@ -2259,8 +2268,9 @@ static char* form_full_file_name(
|
||||
}
|
||||
p = p->sp_next;
|
||||
}
|
||||
|
||||
if (fnlen > NAME_MAX) {
|
||||
|
||||
if (fnlen > NAME_MAX)
|
||||
{
|
||||
fprintf(stderr, "Error : Too long file name= %d.\n", (int)fnlen);
|
||||
goto return_filename;
|
||||
}
|
||||
@ -2327,11 +2337,10 @@ static char* add_slash(
|
||||
* check if they are accessible and writable.
|
||||
*
|
||||
* Parameters:
|
||||
* @param filename - <usage>
|
||||
* <description>
|
||||
* @param filename file to be checked
|
||||
*
|
||||
* @param writable - <usage>
|
||||
* <description>
|
||||
* @param writable flag indicating whether file was found writable or not
|
||||
* if writable is NULL, check is skipped.
|
||||
*
|
||||
* @return true & writable if file exists and it is writable,
|
||||
* true & not writable if file exists but it can't be written,
|
||||
@ -2352,7 +2361,11 @@ static bool check_file_and_path(
|
||||
if (filename == NULL)
|
||||
{
|
||||
exists = false;
|
||||
*writable = false;
|
||||
|
||||
if (writable)
|
||||
{
|
||||
*writable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2373,24 +2386,30 @@ static bool check_file_and_path(
|
||||
"to %s.\n",
|
||||
filename,
|
||||
strerror(errno));
|
||||
*writable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
char c = ' ';
|
||||
if (write(fd, &c, 1) == 1)
|
||||
{
|
||||
*writable = true;
|
||||
}
|
||||
else
|
||||
if (writable)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"*\n* Error : Can't write to "
|
||||
"%s due to %s.\n",
|
||||
filename,
|
||||
strerror(errno));
|
||||
*writable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (writable)
|
||||
{
|
||||
char c = ' ';
|
||||
if (write(fd, &c, 1) == 1)
|
||||
{
|
||||
*writable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"*\n* Error : Can't write to "
|
||||
"%s due to %s.\n",
|
||||
filename,
|
||||
strerror(errno));
|
||||
*writable = false;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
exists = true;
|
||||
@ -2402,7 +2421,11 @@ static bool check_file_and_path(
|
||||
filename,
|
||||
strerror(errno));
|
||||
exists = false;
|
||||
*writable = false;
|
||||
|
||||
if (writable)
|
||||
{
|
||||
*writable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -2410,7 +2433,11 @@ static bool check_file_and_path(
|
||||
close(fd);
|
||||
unlink(filename);
|
||||
exists = false;
|
||||
*writable = true;
|
||||
|
||||
if (writable)
|
||||
{
|
||||
*writable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return exists;
|
||||
@ -2457,8 +2484,6 @@ static bool file_is_symlink(
|
||||
*
|
||||
* @return true if succeed, false otherwise
|
||||
*
|
||||
*
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
static bool logfile_init(
|
||||
@ -2546,6 +2571,7 @@ static bool logfile_init(
|
||||
logfile_free_memory(logfile);
|
||||
goto return_with_succp;
|
||||
}
|
||||
#if defined(SS_DEBUG)
|
||||
if (store_shmem)
|
||||
{
|
||||
fprintf(stderr, "%s\t: %s->%s\n",
|
||||
@ -2559,6 +2585,7 @@ static bool logfile_init(
|
||||
STRLOGNAME(logfile_id),
|
||||
logfile->lf_full_file_name);
|
||||
}
|
||||
#endif
|
||||
succp = true;
|
||||
logfile->lf_state = RUN;
|
||||
CHK_LOGFILE(logfile);
|
||||
@ -2985,3 +3012,64 @@ static void fnames_conf_free_memory(
|
||||
if (fn->fn_err_suffix != NULL) free(fn->fn_err_suffix);
|
||||
if (fn->fn_logpath != NULL) free(fn->fn_logpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the file with biggest sequence number from given directory and return
|
||||
* the sequence number.
|
||||
*
|
||||
* @param parts string parts of which the file name is composed of
|
||||
* @param seqno the sequence number to start with, if seqno is -1 just return
|
||||
*
|
||||
* @return the biggest sequence number used
|
||||
*/
|
||||
static int find_last_seqno(
|
||||
strpart_t* parts,
|
||||
int seqno,
|
||||
int seqnoidx)
|
||||
{
|
||||
strpart_t* p;
|
||||
char* snstr;
|
||||
int snstrlen;
|
||||
|
||||
if (seqno == -1)
|
||||
{
|
||||
return seqno;
|
||||
}
|
||||
snstrlen = UINTLEN(INT_MAX);
|
||||
snstr = (char *)calloc(1, snstrlen);
|
||||
p = parts;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int i;
|
||||
char filename[NAME_MAX] = {0};
|
||||
/** Form name with next seqno */
|
||||
snprintf(snstr, snstrlen, "%d", seqno+1);
|
||||
|
||||
for (i=0, p=parts; p->sp_string != NULL; i++, p=p->sp_next)
|
||||
{
|
||||
if (snstr != NULL && i == seqnoidx && strnlen(snstr,NAME_MAX) < NAME_MAX)
|
||||
{
|
||||
strcat(filename, snstr); /*< add sequence number */
|
||||
}
|
||||
strcat(filename, p->sp_string);
|
||||
|
||||
if (p->sp_next == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_file_and_path(filename, NULL))
|
||||
{
|
||||
seqno++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(snstr);
|
||||
|
||||
return seqno;
|
||||
}
|
||||
|
||||
@ -42,17 +42,55 @@ typedef enum {
|
||||
typedef enum { FILEWRITER_INIT, FILEWRITER_RUN, FILEWRITER_DONE }
|
||||
filewriter_state_t;
|
||||
|
||||
/**
|
||||
* Thread-specific logging information.
|
||||
*/
|
||||
typedef struct log_info_st
|
||||
{
|
||||
size_t li_sesid;
|
||||
int li_enabled_logs;
|
||||
} log_info_t;
|
||||
|
||||
#define LE LOGFILE_ERROR
|
||||
#define LM LOGFILE_MESSAGE
|
||||
#define LT LOGFILE_TRACE
|
||||
#define LD LOGFILE_DEBUG
|
||||
|
||||
/**
|
||||
* Check if specified log type is enabled in general or if it is enabled
|
||||
* for the current session.
|
||||
*/
|
||||
#define LOG_IS_ENABLED(id) (((lm_enabled_logfiles_bitmask & id) || \
|
||||
(log_ses_count[id] > 0 && \
|
||||
tls_log_info.li_enabled_logs & id)) ? true : false)
|
||||
|
||||
|
||||
#define LOG_MAY_BE_ENABLED(id) (((lm_enabled_logfiles_bitmask & id) || \
|
||||
log_ses_count[id] > 0) ? true : false)
|
||||
/**
|
||||
* Execute the given command if specified log is enabled in general or
|
||||
* if there is at least one session for whom the log is enabled.
|
||||
*/
|
||||
#define LOGIF_MAYBE(id,cmd) if (LOG_MAY_BE_ENABLED(id)) \
|
||||
{ \
|
||||
cmd; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given command if specified log is enabled in general or
|
||||
* if the log is enabled for the current session.
|
||||
*/
|
||||
#define LOGIF(id,cmd) if (LOG_IS_ENABLED(id)) \
|
||||
{ \
|
||||
cmd; \
|
||||
}
|
||||
|
||||
#if !defined(LOGIF)
|
||||
#define LOGIF(id,cmd) if (lm_enabled_logfiles_bitmask & id) \
|
||||
{ \
|
||||
cmd; \
|
||||
} \
|
||||
|
||||
#define LOG_IS_ENABLED(id) ((lm_enabled_logfiles_bitmask & id) ? true : false)
|
||||
{ \
|
||||
cmd; \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* UNINIT means zeroed memory buffer allocated for the struct.
|
||||
|
||||
106
macros.cmake
106
macros.cmake
@ -115,14 +115,24 @@ debugmsg("Search returned: ${MYSQL_DIR_LOC}")
|
||||
# Find the errmsg.sys file if it was not defied
|
||||
if( DEFINED ERRMSG )
|
||||
debugmsg("Looking for errmsg.sys at: ${ERRMSG}")
|
||||
if(NOT(IS_DIRECTORY ${ERRMSG}))
|
||||
get_filename_component(ERRMSG ${ERRMSG} PATH)
|
||||
debugmsg("Path to file is: ${ERRMSG}")
|
||||
endif()
|
||||
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=<path>")
|
||||
if(${ERRMSG_FILE} MATCHES "NOTFOUND")
|
||||
message(FATAL_ERROR "Fatal Error: The errmsg.sys file was not found at ${ERRMSG}")
|
||||
else()
|
||||
message(STATUS "Using custom errmsg.sys found at: ${ERRMSG_FILE}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Using errmsg.sys found at: ${ERRMSG_FILE}")
|
||||
find_file(ERRMSG_FILE errmsg.sys PATHS /usr/share/mysql /usr/local/share/mysql PATH_SUFFIXES english)
|
||||
if(${ERRMSG_FILE} MATCHES "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=<path>")
|
||||
else()
|
||||
message(STATUS "Using errmsg.sys found at: ${ERRMSG_FILE}")
|
||||
endif()
|
||||
endif()
|
||||
set(ERRMSG ${ERRMSG_FILE} CACHE FILEPATH "Path to the errmsg.sys file." FORCE)
|
||||
unset(ERRMSG_FILE)
|
||||
@ -206,50 +216,52 @@ debugmsg("Search returned: ${MYSQL_DIR_LOC}")
|
||||
unset(RPM_FNC)
|
||||
|
||||
#Find the MySQL client library
|
||||
find_library(MYSQLCLIENT_LIBRARIES NAMES mysqlclient PATH_SUFFIXES mysql mariadb)
|
||||
if(${MYSQLCLIENT_LIBRARIES} MATCHES "NOTFOUND")
|
||||
set(MYSQLCLIENT_FOUND FALSE CACHE INTERNAL "")
|
||||
message(STATUS "Cannot find MySQL client library: Login tests disabled.")
|
||||
else()
|
||||
set(MYSQLCLIENT_FOUND TRUE CACHE INTERNAL "")
|
||||
message(STATUS "Found MySQL client library: ${MYSQLCLIENT_LIBRARIES}")
|
||||
endif()
|
||||
# find_library(MYSQLCLIENT_LIBRARIES NAMES mysqlclient PATH_SUFFIXES mysql mariadb)
|
||||
# if(${MYSQLCLIENT_LIBRARIES} MATCHES "NOTFOUND")
|
||||
# set(MYSQLCLIENT_FOUND FALSE CACHE INTERNAL "")
|
||||
# message(STATUS "Cannot find MySQL client library: Login tests disabled.")
|
||||
# else()
|
||||
# set(MYSQLCLIENT_FOUND TRUE CACHE INTERNAL "")
|
||||
# message(STATUS "Found MySQL client library: ${MYSQLCLIENT_LIBRARIES}")
|
||||
# endif()
|
||||
|
||||
#Check RabbitMQ headers and libraries
|
||||
if(BUILD_RABBITMQ)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
if(DEFINED RABBITMQ_LIB)
|
||||
find_library(RMQ_LIB rabbitmq PATHS ${RABBITMQ_LIB} NO_DEFAULT_PATH)
|
||||
else()
|
||||
find_library(RMQ_LIB rabbitmq)
|
||||
endif()
|
||||
if(RMQ_LIB MATCHES "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=<path>")
|
||||
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)
|
||||
else()
|
||||
find_file(RMQ_HEADERS amqp.h)
|
||||
endif()
|
||||
if(RMQ_HEADERS MATCHES "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=<path>")
|
||||
else()
|
||||
set(RABBITMQ_HEADERS ${RMQ_HEADERS} CACHE PATH "Path to RabbitMQ headers" FORCE)
|
||||
message(STATUS "Using RabbitMQ headers found at: ${RABBITMQ_HEADERS}")
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_INCLUDES ${RABBITMQ_HEADERS})
|
||||
check_c_source_compiles("#include <amqp.h>\n int main(){if(AMQP_DELIVERY_PERSISTENT){return 0;}return 1;}" HAVE_RMQ50)
|
||||
if(NOT HAVE_RMQ50)
|
||||
message(FATAL_ERROR "Old version of RabbitMQ-C library found. Version 0.5 or newer is required.")
|
||||
endif()
|
||||
|
||||
find_package(RabbitMQ)
|
||||
# include(CheckCSourceCompiles)
|
||||
#
|
||||
# if(DEFINED RABBITMQ_LIB)
|
||||
# find_library(RMQ_LIB rabbitmq PATHS ${RABBITMQ_LIB} NO_DEFAULT_PATH)
|
||||
# else()
|
||||
# find_library(RMQ_LIB rabbitmq)
|
||||
# endif()
|
||||
# if(RMQ_LIB MATCHES "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=<path>")
|
||||
# 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)
|
||||
# else()
|
||||
# find_file(RMQ_HEADERS amqp.h)
|
||||
# endif()
|
||||
# if(RMQ_HEADERS MATCHES "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=<path>")
|
||||
# else()
|
||||
# set(RABBITMQ_HEADERS ${RMQ_HEADERS} CACHE PATH "Path to RabbitMQ headers" FORCE)
|
||||
# message(STATUS "Using RabbitMQ headers found at: ${RABBITMQ_HEADERS}")
|
||||
# endif()
|
||||
#
|
||||
# set(CMAKE_REQUIRED_INCLUDES ${RABBITMQ_HEADERS})
|
||||
# check_c_source_compiles("#include <amqp.h>\n int main(){if(AMQP_DELIVERY_PERSISTENT){return 0;}return 1;}" HAVE_RMQ50)
|
||||
# if(NOT HAVE_RMQ50)
|
||||
# message(FATAL_ERROR "Old version of RabbitMQ-C library found. Version 0.5 or newer is required.")
|
||||
# endif()
|
||||
#
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
||||
@ -61,7 +61,9 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
#define QTYPE_LESS_RESTRICTIVE_THAN_WRITE(t) (t<QUERY_TYPE_WRITE ? true : false)
|
||||
|
||||
|
||||
@ -1,19 +1,17 @@
|
||||
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_FOUND AND MYSQLCLIENT_FOUND)
|
||||
|
||||
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})
|
||||
include_directories(${MYSQLCLIENT_HEADERS})
|
||||
add_executable (consumer consumer.c)
|
||||
target_link_libraries(consumer ${MYSQL_CLIENT_LIB} rabbitmq inih)
|
||||
|
||||
if(MYSQLCLIENT_FOUND)
|
||||
target_link_libraries(consumer ${MYSQLCLIENT_LIBRARIES} rabbitmq inih)
|
||||
elseif(MYSQLCLIENT_STATIC_FOUND)
|
||||
target_link_libraries(consumer ${MYSQLCLIENT_STATIC_LIBRARIES} rabbitmq inih)
|
||||
endif()
|
||||
|
||||
install(TARGETS consumer DESTINATION bin)
|
||||
install(FILES consumer.cnf DESTINATION etc)
|
||||
|
||||
|
||||
else()
|
||||
|
||||
message(FATAL_ERROR "Error: Can not find requred libraries and headers: librabbitmq libmysqlclient")
|
||||
|
||||
@ -143,7 +143,7 @@ int connectToServer(MYSQL* server)
|
||||
}
|
||||
|
||||
memset(qstr,0,bsz);
|
||||
sprintf(qstr,DB_TABLE);
|
||||
sprintf(qstr,"%s",DB_TABLE);
|
||||
if(mysql_query(server,qstr)){
|
||||
fprintf(stderr,"Error: Could not send query MySQL server: %s\n",mysql_error(server));
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,9 +4,10 @@ if(BUILD_TESTS)
|
||||
target_link_libraries(fullcore log_manager utils pthread ${EMBEDDED_LIB} ssl aio rt crypt dl crypto inih z m stdc++)
|
||||
endif()
|
||||
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)
|
||||
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c
|
||||
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c
|
||||
monitor.c adminusers.c secrets.c filter.c modutil.c hint.c
|
||||
housekeeper.c memlog.c)
|
||||
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)
|
||||
|
||||
@ -20,4 +21,4 @@ install(TARGETS maxpasswd DESTINATION bin)
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -65,7 +65,8 @@ include ../../makefile.inc
|
||||
SRCS= 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
|
||||
monitor.c adminusers.c secrets.c filter.c modutil.c hint.c \
|
||||
housekeeper.c memlog.c
|
||||
|
||||
HDRS= ../include/atomic.h ../include/buffer.h ../include/dcb.h \
|
||||
../include/gw.h ../modules/include/mysql_client_server_protocol.h \
|
||||
@ -73,7 +74,8 @@ HDRS= ../include/atomic.h ../include/buffer.h ../include/dcb.h \
|
||||
../include/modules.h ../include/poll.h ../include/config.h \
|
||||
../include/users.h ../include/hashtable.h ../include/gwbitmask.h \
|
||||
../include/adminusers.h ../include/version.h ../include/maxscale.h \
|
||||
../include/filter.h ../include/modutil.h ../hint.h ../include/housekeeper.h
|
||||
../include/filter.h ../include/modutil.h ../hint.h \
|
||||
../include/housekeeper.h ../include/memlog.h
|
||||
|
||||
OBJ=$(SRCS:.c=.o)
|
||||
|
||||
|
||||
@ -27,7 +27,10 @@
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/**
|
||||
* @file adminusers.c - Administration user account management
|
||||
|
||||
@ -47,7 +47,10 @@
|
||||
#include <log_manager.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
static buffer_object_t* gwbuf_remove_buffer_object(
|
||||
GWBUF* buf,
|
||||
|
||||
@ -58,7 +58,10 @@
|
||||
#include <log_manager.h>
|
||||
#include <mysql.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
extern int setipaddress(struct in_addr *, char *);
|
||||
static int process_config_context(CONFIG_CONTEXT *);
|
||||
@ -1147,6 +1150,31 @@ config_threadcount()
|
||||
return gateway.n_threads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of non-blocking polls to be done before a blocking poll
|
||||
* is issued.
|
||||
*
|
||||
* @return The number of blocking poll calls to make before a blocking call
|
||||
*/
|
||||
unsigned int
|
||||
config_nbpolls()
|
||||
{
|
||||
return gateway.n_nbpoll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured number of milliseconds for which we wait when we do
|
||||
* a blocking poll call.
|
||||
*
|
||||
* @return The number of milliseconds to sleep in a blocking poll call
|
||||
*/
|
||||
unsigned int
|
||||
config_pollsleep()
|
||||
{
|
||||
return gateway.pollsleep;
|
||||
}
|
||||
|
||||
|
||||
static struct {
|
||||
char *logname;
|
||||
logfile_id_t logfile;
|
||||
@ -1167,9 +1195,20 @@ static int
|
||||
handle_global_item(const char *name, const char *value)
|
||||
{
|
||||
int i;
|
||||
if (strcmp(name, "threads") == 0) {
|
||||
if (strcmp(name, "threads") == 0)
|
||||
{
|
||||
gateway.n_threads = atoi(value);
|
||||
} else {
|
||||
}
|
||||
else if (strcmp(name, "non_blocking_polls") == 0)
|
||||
{
|
||||
gateway.n_nbpoll = atoi(value);
|
||||
}
|
||||
else if (strcmp(name, "poll_sleep") == 0)
|
||||
{
|
||||
gateway.pollsleep = atoi(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; lognames[i].logname; i++)
|
||||
{
|
||||
if (strcasecmp(name, lognames[i].logname) == 0)
|
||||
@ -1191,6 +1230,8 @@ static void
|
||||
global_defaults()
|
||||
{
|
||||
gateway.n_threads = 1;
|
||||
gateway.n_nbpoll = DEFAULT_NBPOLLS;
|
||||
gateway.pollsleep = DEFAULT_POLLSLEEP;
|
||||
if (version_string != NULL)
|
||||
gateway.version_string = strdup(version_string);
|
||||
else
|
||||
|
||||
@ -63,7 +63,10 @@
|
||||
|
||||
#define LOAD_MYSQL_DATABASE_NAMES "SELECT * FROM ( (SELECT COUNT(1) AS ndbs FROM INFORMATION_SCHEMA.SCHEMATA) AS tbl1, (SELECT GRANTEE,PRIVILEGE_TYPE from INFORMATION_SCHEMA.USER_PRIVILEGES WHERE privilege_type='SHOW DATABASES' AND REPLACE(GRANTEE, \"\'\",\"\")=CURRENT_USER()) AS tbl2)"
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
static int getUsers(SERVICE *service, USERS *users);
|
||||
static int uh_cmpfun( void* v1, void* v2);
|
||||
@ -749,19 +752,19 @@ getUsers(SERVICE *service, USERS *users)
|
||||
/* Log the user being added with its db grants */
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [mysql_users_add()] Added user %s@%s with DB grants on [%s]",
|
||||
pthread_self(),
|
||||
"Added user %s@%s with DB grants on [%s], for service [%s]",
|
||||
row[0],
|
||||
row[1],
|
||||
dbgrant)));
|
||||
dbgrant,
|
||||
service->name)));
|
||||
} else {
|
||||
/* Log the user being added (without db grants) */
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [mysql_users_add()] Added user %s@%s",
|
||||
pthread_self(),
|
||||
"Added user %s@%s for service [%s]",
|
||||
row[0],
|
||||
row[1])));
|
||||
row[1],
|
||||
service->name)));
|
||||
}
|
||||
|
||||
/* Append data in the memory area for SHA1 digest */
|
||||
@ -771,8 +774,7 @@ getUsers(SERVICE *service, USERS *users)
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [mysql_users_add()] Failed adding user %s@%s for service [%s]",
|
||||
pthread_self(),
|
||||
"Warning: Failed adding user %s@%s for service [%s]",
|
||||
row[0],
|
||||
row[1],
|
||||
service->name)));
|
||||
|
||||
@ -71,7 +71,10 @@
|
||||
#include <log_manager.h>
|
||||
#include <hashtable.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
static DCB *allDCBs = NULL; /* Diagnostics need a list of DCBs */
|
||||
static DCB *zombies = NULL;
|
||||
@ -85,10 +88,10 @@ static bool dcb_set_state_nomutex(
|
||||
dcb_state_t* old_state);
|
||||
static void dcb_call_callback(DCB *dcb, DCB_REASON reason);
|
||||
static DCB* dcb_get_next (DCB* dcb);
|
||||
static int dcb_null_write(DCB *dcb, GWBUF *buf);
|
||||
static int dcb_null_close(DCB *dcb);
|
||||
static int dcb_null_auth(DCB *dcb, SERVER *server, SESSION *session, GWBUF *buf);
|
||||
static int dcb_isvalid_nolock(DCB *dcb);
|
||||
static int dcb_null_write(DCB *dcb, GWBUF *buf);
|
||||
static int dcb_null_close(DCB *dcb);
|
||||
static int dcb_null_auth(DCB *dcb, SERVER *server, SESSION *session, GWBUF *buf);
|
||||
static int dcb_isvalid_nolock(DCB *dcb);
|
||||
|
||||
size_t dcb_get_session_id(
|
||||
DCB* dcb)
|
||||
@ -105,8 +108,45 @@ size_t dcb_get_session_id(
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pointer to the lsit of zombie DCB's
|
||||
* Read log info from session through DCB and store values to memory locations
|
||||
* passed as parameters.
|
||||
*
|
||||
* @param dcb DCB
|
||||
* @param sesid location where session id is to be copied
|
||||
* @param enabled_logs bit field indicating which log types are enabled for the
|
||||
* session
|
||||
*
|
||||
*@return true if call arguments included memory addresses, false if any of the
|
||||
*parameters was NULL.
|
||||
*/
|
||||
bool dcb_get_ses_log_info(
|
||||
DCB* dcb,
|
||||
size_t* sesid,
|
||||
int* enabled_logs)
|
||||
{
|
||||
bool succp;
|
||||
|
||||
if (dcb == NULL ||
|
||||
dcb->session == NULL ||
|
||||
sesid == NULL ||
|
||||
enabled_logs == NULL)
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sesid = dcb->session->ses_id;
|
||||
*enabled_logs = dcb->session->ses_enabled_logs;
|
||||
succp = true;
|
||||
}
|
||||
|
||||
return succp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pointer to the list of zombie DCB's
|
||||
*
|
||||
* @return Zombies DCB list
|
||||
*/
|
||||
@ -166,6 +206,7 @@ DCB *rval;
|
||||
rval->low_water = 0;
|
||||
rval->next = NULL;
|
||||
rval->callbacks = NULL;
|
||||
rval->data = NULL;
|
||||
|
||||
rval->remote = NULL;
|
||||
rval->user = NULL;
|
||||
@ -200,7 +241,7 @@ dcb_free(DCB *dcb)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Attempt to free a DCB via dcb_fee "
|
||||
"Error : Attempt to free a DCB via dcb_free "
|
||||
"that has been associated with a descriptor.")));
|
||||
}
|
||||
}
|
||||
@ -302,6 +343,15 @@ DCB_CALLBACK *cb;
|
||||
dcb->state == DCB_STATE_ALLOC,
|
||||
"dcb not in DCB_STATE_DISCONNECTED not in DCB_STATE_ALLOC state.");
|
||||
|
||||
if (DCB_POLL_BUSY(dcb))
|
||||
{
|
||||
/* Check if DCB has outstanding poll events */
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"dcb_final_free: DCB %p has outstanding events",
|
||||
dcb)));
|
||||
}
|
||||
|
||||
/*< First remove this DCB from the chain */
|
||||
spinlock_acquire(&dcbspin);
|
||||
if (allDCBs == dcb)
|
||||
@ -373,6 +423,7 @@ DCB_CALLBACK *cb;
|
||||
}
|
||||
spinlock_release(&dcb->cb_lock);
|
||||
|
||||
|
||||
bitmask_free(&dcb->memdata.bitmask);
|
||||
free(dcb);
|
||||
}
|
||||
@ -455,6 +506,7 @@ bool succp = false;
|
||||
zombies = tptr;
|
||||
else
|
||||
lptr->memdata.next = tptr;
|
||||
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_process_zombies] Remove dcb "
|
||||
@ -498,6 +550,7 @@ bool succp = false;
|
||||
while (dcb != NULL) {
|
||||
DCB* dcb_next = NULL;
|
||||
int rc = 0;
|
||||
|
||||
/*<
|
||||
* Close file descriptor and move to clean-up phase.
|
||||
*/
|
||||
@ -532,12 +585,20 @@ bool succp = false;
|
||||
ss_debug(dcb->fd = -1;)
|
||||
}
|
||||
#endif /* SS_DEBUG */
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
|
||||
succp = dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL);
|
||||
ss_dassert(succp);
|
||||
dcb_next = dcb->memdata.next;
|
||||
dcb_final_free(dcb);
|
||||
dcb = dcb_next;
|
||||
}
|
||||
/** Reset threads session data */
|
||||
LOGIF(LT, tls_log_info.li_sesid = 0);
|
||||
|
||||
return zombies;
|
||||
}
|
||||
|
||||
@ -893,11 +954,7 @@ int below_water;
|
||||
#endif /* FAKE_CODE */
|
||||
qlen = GWBUF_LENGTH(queue);
|
||||
GW_NOINTR_CALL(
|
||||
w = gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
dcb,
|
||||
#endif
|
||||
dcb->fd, GWBUF_DATA(queue), qlen);
|
||||
w = gw_write(dcb, GWBUF_DATA(queue), qlen);
|
||||
dcb->stats.n_writes++;
|
||||
);
|
||||
|
||||
@ -1049,13 +1106,7 @@ int above_water;
|
||||
while (dcb->writeq != NULL)
|
||||
{
|
||||
len = GWBUF_LENGTH(dcb->writeq);
|
||||
GW_NOINTR_CALL(w = gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
dcb,
|
||||
#endif
|
||||
dcb->fd,
|
||||
GWBUF_DATA(dcb->writeq),
|
||||
len););
|
||||
GW_NOINTR_CALL(w = gw_write(dcb, GWBUF_DATA(dcb->writeq), len););
|
||||
saved_errno = errno;
|
||||
errno = 0;
|
||||
|
||||
@ -1130,7 +1181,7 @@ int above_water;
|
||||
void
|
||||
dcb_close(DCB *dcb)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
|
||||
@ -1158,46 +1209,49 @@ dcb_close(DCB *dcb)
|
||||
*/
|
||||
if (dcb->state == DCB_STATE_POLLING)
|
||||
{
|
||||
rc = poll_remove_dcb(dcb);
|
||||
|
||||
if (rc == 0) {
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_close] Removed dcb %p in state %s from "
|
||||
"poll set.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Removing DCB fd == %d in state %s from "
|
||||
"poll set failed.",
|
||||
dcb->fd,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
if (dcb->fd != -1)
|
||||
{
|
||||
/**
|
||||
* close protocol and router session
|
||||
*/
|
||||
if (dcb->func.close != NULL)
|
||||
{
|
||||
dcb->func.close(dcb);
|
||||
rc = poll_remove_dcb(dcb);
|
||||
|
||||
if (rc == 0) {
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_close] Removed dcb %p in state %s from "
|
||||
"poll set.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Removing DCB fd == %d in state %s from "
|
||||
"poll set failed.",
|
||||
dcb->fd,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
dcb_call_callback(dcb, DCB_REASON_CLOSE);
|
||||
|
||||
|
||||
if (dcb->state == DCB_STATE_NOPOLLING)
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
dcb_add_to_zombieslist(dcb);
|
||||
/**
|
||||
* close protocol and router session
|
||||
*/
|
||||
if (dcb->func.close != NULL)
|
||||
{
|
||||
dcb->func.close(dcb);
|
||||
}
|
||||
dcb_call_callback(dcb, DCB_REASON_CLOSE);
|
||||
|
||||
|
||||
if (dcb->state == DCB_STATE_NOPOLLING)
|
||||
{
|
||||
dcb_add_to_zombieslist(dcb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ss_dassert(dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE);
|
||||
}
|
||||
ss_dassert(dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1226,9 +1280,9 @@ printDCB(DCB *dcb)
|
||||
dcb->stats.n_buffered);
|
||||
printf("\t\tNo. of Accepts: %d\n",
|
||||
dcb->stats.n_accepts);
|
||||
printf("\t\tNo. of High Water Events: %d\n",
|
||||
printf("\t\tNo. of High Water Events: %d\n",
|
||||
dcb->stats.n_high_water);
|
||||
printf("\t\tNo. of Low Water Events: %d\n",
|
||||
printf("\t\tNo. of Low Water Events: %d\n",
|
||||
dcb->stats.n_low_water);
|
||||
}
|
||||
/**
|
||||
@ -1413,6 +1467,12 @@ dprintDCB(DCB *pdcb, DCB *dcb)
|
||||
dcb->stats.n_high_water);
|
||||
dcb_printf(pdcb, "\t\tNo. of Low Water Events: %d\n",
|
||||
dcb->stats.n_low_water);
|
||||
if (DCB_POLL_BUSY(dcb))
|
||||
{
|
||||
dcb_printf(pdcb, "\t\tPending events in the queue: %x %s\n",
|
||||
dcb->evq.pending_events, dcb->evq.processing ? "(processing)" : "");
|
||||
|
||||
}
|
||||
if (dcb->flags & DCBF_CLONE)
|
||||
dcb_printf(pdcb, "\t\tDCB is a clone.\n");
|
||||
#if SPINLOCK_PROFILE
|
||||
@ -1691,15 +1751,18 @@ static bool dcb_set_state_nomutex(
|
||||
return succp;
|
||||
}
|
||||
|
||||
int gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
DCB* dcb,
|
||||
#endif
|
||||
int fd,
|
||||
const void* buf,
|
||||
size_t nbytes)
|
||||
/**
|
||||
* Write data to a DCB
|
||||
*
|
||||
* @param dcb The DCB to write buffer
|
||||
* @param buf Buffer to write
|
||||
* @param nbytes Number of bytes to write
|
||||
*/
|
||||
int
|
||||
gw_write(DCB *dcb, const void *buf, size_t nbytes)
|
||||
{
|
||||
int w;
|
||||
int fd = dcb->fd;
|
||||
#if defined(FAKE_CODE)
|
||||
if (dcb_fake_write_errno[fd] != 0) {
|
||||
ss_dassert(dcb_fake_write_ev[fd] != 0);
|
||||
|
||||
@ -38,7 +38,10 @@
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
static SPINLOCK filter_spin = SPINLOCK_INIT; /**< Protects the list of all filters */
|
||||
static FILTER_DEF *allFilters = NULL; /**< The list of all filters */
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
#include <config.h>
|
||||
#include <poll.h>
|
||||
#include <housekeeper.h>
|
||||
#include <memlog.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -85,7 +86,10 @@ extern char *program_invocation_short_name;
|
||||
* Used from log users to check enabled logs prior calling
|
||||
* actual library calls such as skygw_log_write.
|
||||
*/
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/*
|
||||
* Server options are passed to the mysql_server_init. Each gateway must have a unique
|
||||
@ -191,6 +195,21 @@ static void sighup_handler (int i)
|
||||
config_reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for SIGUSR1 signal. A SIGUSR1 signal will cause
|
||||
* maxscale to rotate all log files.
|
||||
*/
|
||||
static void sigusr1_handler (int i)
|
||||
{
|
||||
LOGIF(LM, (skygw_log_write(
|
||||
LOGFILE_MESSAGE,
|
||||
"Log file flush following reception of SIGUSR1\n")));
|
||||
skygw_log_rotate(LOGFILE_ERROR);
|
||||
skygw_log_rotate(LOGFILE_MESSAGE);
|
||||
skygw_log_rotate(LOGFILE_TRACE);
|
||||
skygw_log_rotate(LOGFILE_DEBUG);
|
||||
}
|
||||
|
||||
static void sigterm_handler (int i) {
|
||||
extern void shutdown_server();
|
||||
|
||||
@ -387,7 +406,11 @@ static bool file_write_header(
|
||||
ts1.tv_sec = 0;
|
||||
ts1.tv_nsec = DISKWRITE_LATENCY*1000000;
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(SS_DEBUG)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if ((t = (time_t *)malloc(sizeof(time_t))) == NULL) {
|
||||
goto return_succp;
|
||||
}
|
||||
@ -1182,8 +1205,12 @@ int main(int argc, char **argv)
|
||||
if (!daemon_mode)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Info : MaxScale will be run in the terminal process.\n See "
|
||||
"Info : MaxScale will be run in the terminal process.\n");
|
||||
#if defined(SS_DEBUG)
|
||||
fprintf(stderr,
|
||||
"\tSee "
|
||||
"the log from the following log files : \n\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1195,11 +1222,11 @@ int main(int argc, char **argv)
|
||||
int eno = 0;
|
||||
char* fprerr = "Failed to initialize set the signal "
|
||||
"set for MaxScale. Exiting.";
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
fprintf(stderr,
|
||||
"Info : MaxScale will be run in a daemon process.\n\tSee "
|
||||
"the log from the following log files : \n\n");
|
||||
|
||||
#endif
|
||||
r = sigfillset(&sigset);
|
||||
|
||||
if (r != 0)
|
||||
@ -1222,6 +1249,18 @@ int main(int argc, char **argv)
|
||||
rc = MAXSCALE_INTERNALERROR;
|
||||
goto return_main;
|
||||
}
|
||||
r = sigdelset(&sigset, SIGUSR1);
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
char* logerr = "Failed to delete signal SIGUSR1 from the "
|
||||
"signal set of MaxScale. Exiting.";
|
||||
eno = errno;
|
||||
errno = 0;
|
||||
print_log_n_stderr(true, true, fprerr, logerr, eno);
|
||||
rc = MAXSCALE_INTERNALERROR;
|
||||
goto return_main;
|
||||
}
|
||||
r = sigdelset(&sigset, SIGTERM);
|
||||
|
||||
if (r != 0)
|
||||
@ -1323,6 +1362,14 @@ int main(int argc, char **argv)
|
||||
"SIGHUP. Exiting.");
|
||||
goto sigset_err;
|
||||
}
|
||||
l = signal_set(SIGUSR1, sigusr1_handler);
|
||||
|
||||
if (l != 0)
|
||||
{
|
||||
logerr = strdup("Failed to set signal handler for "
|
||||
"SIGUSR1. Exiting.");
|
||||
goto sigset_err;
|
||||
}
|
||||
l = signal_set(SIGTERM, sigterm_handler);
|
||||
|
||||
if (l != 0)
|
||||
@ -1481,11 +1528,11 @@ int main(int argc, char **argv)
|
||||
{
|
||||
char buf[1024];
|
||||
char *argv[8];
|
||||
bool succp;
|
||||
|
||||
bool succp;
|
||||
|
||||
sprintf(buf, "%s/log", home_dir);
|
||||
if(mkdir(buf, 0777) != 0){
|
||||
|
||||
|
||||
if(errno != EEXIST){
|
||||
fprintf(stderr,
|
||||
"Error: Cannot create log directory: %s\n",buf);
|
||||
@ -1537,12 +1584,26 @@ int main(int argc, char **argv)
|
||||
* instances of the gateway are beign run on the same
|
||||
* machine.
|
||||
*/
|
||||
sprintf(datadir, "%s/data%d", home_dir, getpid());
|
||||
if(mkdir(datadir, 0777) != 0){
|
||||
LOGIF(LE,(skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Directory creation failed due to %s.",
|
||||
strerror(errno))));
|
||||
sprintf(datadir, "%s/data", home_dir);
|
||||
|
||||
if(mkdir(datadir, 0777) != 0){
|
||||
|
||||
if(errno != EEXIST){
|
||||
fprintf(stderr,
|
||||
"Error: Cannot create data directory: %s\n",datadir);
|
||||
goto return_main;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(datadir, "%s/data/data%d", home_dir, getpid());
|
||||
|
||||
if(mkdir(datadir, 0777) != 0){
|
||||
|
||||
if(errno != EEXIST){
|
||||
fprintf(stderr,
|
||||
"Error: Cannot create data directory: %s\n",datadir);
|
||||
goto return_main;
|
||||
}
|
||||
}
|
||||
|
||||
if (!daemon_mode)
|
||||
@ -1550,9 +1611,11 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr,
|
||||
"Home directory : %s"
|
||||
"\nConfiguration file : %s"
|
||||
"\nLog directory : %s/log"
|
||||
"\nData directory : %s\n\n",
|
||||
home_dir,
|
||||
cnf_file_path,
|
||||
home_dir,
|
||||
datadir);
|
||||
}
|
||||
LOGIF(LM, (skygw_log_write_flush(
|
||||
@ -1563,6 +1626,10 @@ int main(int argc, char **argv)
|
||||
LOGFILE_MESSAGE,
|
||||
"Data directory : %s",
|
||||
datadir)));
|
||||
LOGIF(LM, (skygw_log_write_flush(
|
||||
LOGFILE_MESSAGE,
|
||||
"Log directory : %s/log",
|
||||
home_dir)));
|
||||
LOGIF(LM, (skygw_log_write_flush(
|
||||
LOGFILE_MESSAGE,
|
||||
"Configuration file : %s",
|
||||
@ -1741,6 +1808,7 @@ int main(int argc, char **argv)
|
||||
LOGFILE_MESSAGE,
|
||||
"MaxScale shutdown completed.")));
|
||||
|
||||
unload_all_modules();
|
||||
/* Remove Pidfile */
|
||||
unlink_pidfile();
|
||||
|
||||
@ -1759,10 +1827,11 @@ return_main:
|
||||
* Shutdown MaxScale server
|
||||
*/
|
||||
void
|
||||
shutdown_server()
|
||||
shutdown_server()
|
||||
{
|
||||
poll_shutdown();
|
||||
hkshutdown();
|
||||
memlog_flush_all();
|
||||
log_flush_shutdown();
|
||||
}
|
||||
|
||||
|
||||
@ -48,7 +48,10 @@
|
||||
|
||||
SPINLOCK tmplock = SPINLOCK_INIT;
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/*
|
||||
* Set IP address in socket structure in_addr
|
||||
|
||||
@ -24,11 +24,21 @@
|
||||
/**
|
||||
* @file housekeeper.c Provide a mechanism to run periodic tasks
|
||||
*
|
||||
* The housekeeper provides a mechanism to allow for tasks, function
|
||||
* calls basically, to be run on a tiem basis. A task may be run
|
||||
* repeatedly, with a given frequency (in seconds), or may be a one
|
||||
* shot task that will only be run once after a specified number of
|
||||
* seconds.
|
||||
*
|
||||
* The housekeeper also maintains a global variable, hkheartbeat, that
|
||||
* is incremented every 100ms.
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 29/08/14 Mark Riddoch Initial implementation
|
||||
* 22/10/14 Mark Riddoch Addition of one-shot tasks
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -43,6 +53,7 @@ static HKTASK *tasks = NULL;
|
||||
static SPINLOCK tasklock = SPINLOCK_INIT;
|
||||
|
||||
static int do_shutdown = 0;
|
||||
unsigned long hkheartbeat = 0;
|
||||
|
||||
static void hkthread(void *);
|
||||
|
||||
@ -69,7 +80,7 @@ hkinit()
|
||||
* @param taskfn The function to call for the task
|
||||
* @param data Data to pass to the task function
|
||||
* @param frequency How often to run the task, expressed in seconds
|
||||
* @return Return the tiem in seconds when the task will be first run if the task was added, otherwise 0
|
||||
* @return Return the time in seconds when the task will be first run if the task was added, otherwise 0
|
||||
*/
|
||||
int
|
||||
hktask_add(char *name, void (*taskfn)(void *), void *data, int frequency)
|
||||
@ -88,6 +99,7 @@ HKTASK *task, *ptr;
|
||||
task->task = taskfn;
|
||||
task->data = data;
|
||||
task->frequency = frequency;
|
||||
task->type = HK_REPEATED;
|
||||
task->nextdue = time(0) + frequency;
|
||||
task->next = NULL;
|
||||
spinlock_acquire(&tasklock);
|
||||
@ -112,6 +124,61 @@ HKTASK *task, *ptr;
|
||||
return task->nextdue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a one-shot task to the housekeeper task list
|
||||
*
|
||||
* Task names must be unique.
|
||||
*
|
||||
* @param name The unique name for this housekeeper task
|
||||
* @param taskfn The function to call for the task
|
||||
* @param data Data to pass to the task function
|
||||
* @param when How many second until the task is executed
|
||||
* @return Return the time in seconds when the task will be first run if the task was added, otherwise 0
|
||||
*
|
||||
*/
|
||||
int
|
||||
hktask_oneshot(char *name, void (*taskfn)(void *), void *data, int when)
|
||||
{
|
||||
HKTASK *task, *ptr;
|
||||
|
||||
if ((task = (HKTASK *)malloc(sizeof(HKTASK))) == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((task->name = strdup(name)) == NULL)
|
||||
{
|
||||
free(task);
|
||||
return 0;
|
||||
}
|
||||
task->task = taskfn;
|
||||
task->data = data;
|
||||
task->frequency = 0;
|
||||
task->type = HK_ONESHOT;
|
||||
task->nextdue = time(0) + when;
|
||||
task->next = NULL;
|
||||
spinlock_acquire(&tasklock);
|
||||
ptr = tasks;
|
||||
while (ptr && ptr->next)
|
||||
{
|
||||
if (strcmp(ptr->name, name) == 0)
|
||||
{
|
||||
spinlock_release(&tasklock);
|
||||
free(task->name);
|
||||
free(task);
|
||||
return 0;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
if (ptr)
|
||||
ptr->next = task;
|
||||
else
|
||||
tasks = task;
|
||||
spinlock_release(&tasklock);
|
||||
|
||||
return task->nextdue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a named task from the housekeepers task list
|
||||
*
|
||||
@ -171,12 +238,17 @@ HKTASK *ptr;
|
||||
time_t now;
|
||||
void (*taskfn)(void *);
|
||||
void *taskdata;
|
||||
int i;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (do_shutdown)
|
||||
return;
|
||||
thread_millisleep(1000);
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
if (do_shutdown)
|
||||
return;
|
||||
thread_millisleep(100);
|
||||
hkheartbeat++;
|
||||
}
|
||||
now = time(0);
|
||||
spinlock_acquire(&tasklock);
|
||||
ptr = tasks;
|
||||
@ -189,6 +261,8 @@ void *taskdata;
|
||||
taskdata = ptr->data;
|
||||
spinlock_release(&tasklock);
|
||||
(*taskfn)(taskdata);
|
||||
if (ptr->type == HK_ONESHOT)
|
||||
hktask_remove(ptr->name);
|
||||
spinlock_acquire(&tasklock);
|
||||
ptr = tasks;
|
||||
}
|
||||
@ -208,3 +282,33 @@ hkshutdown()
|
||||
{
|
||||
do_shutdown = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the tasks that are scheduled for the house keeper
|
||||
*
|
||||
* @param pdcb The DCB to send to output
|
||||
*/
|
||||
void
|
||||
hkshow_tasks(DCB *pdcb)
|
||||
{
|
||||
HKTASK *ptr;
|
||||
struct tm tm;
|
||||
char buf[40];
|
||||
|
||||
dcb_printf(pdcb, "%-25s | Type | Frequency | Next Due\n", "Name");
|
||||
dcb_printf(pdcb, "--------------------------+----------+-----------+-------------------------\n");
|
||||
spinlock_acquire(&tasklock);
|
||||
ptr = tasks;
|
||||
while (ptr)
|
||||
{
|
||||
localtime_r(&ptr->nextdue, &tm);
|
||||
asctime_r(&tm, buf);
|
||||
dcb_printf(pdcb, "%-25s | %-8s | %-9d | %s",
|
||||
ptr->name,
|
||||
ptr->type == HK_REPEATED ? "Repeated" : "One-Shot",
|
||||
ptr->frequency,
|
||||
buf);
|
||||
ptr = ptr->next;
|
||||
}
|
||||
spinlock_release(&tasklock);
|
||||
}
|
||||
|
||||
@ -43,7 +43,10 @@
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
static MODULES *registered = NULL;
|
||||
|
||||
@ -327,12 +330,28 @@ MODULES *ptr;
|
||||
* The module is now not in the linked list and all
|
||||
* memory related to it can be freed
|
||||
*/
|
||||
dlclose(mod->handle);
|
||||
free(mod->module);
|
||||
free(mod->type);
|
||||
free(mod->version);
|
||||
free(mod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unload all modules
|
||||
*
|
||||
* Remove all the modules from the system, called during shutdown
|
||||
* to allow termination hooks to be called.
|
||||
*/
|
||||
void
|
||||
unload_all_modules()
|
||||
{
|
||||
while (registered)
|
||||
{
|
||||
unregister_module(registered->module);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print Modules
|
||||
*
|
||||
|
||||
254
server/core/memlog.c
Normal file
254
server/core/memlog.c
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* This file is distributed as part of the MariaDB MaxScale. It is free
|
||||
* software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation,
|
||||
* version 2.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright MariaDB Ab 2014
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file memlog.c - Implementation of memory logging mechanism for debug purposes
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 26/09/14 Mark Riddoch Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
#include <memlog.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static MEMLOG *memlogs = NULL;
|
||||
static SPINLOCK *memlock = SPINLOCK_INIT;
|
||||
|
||||
/**
|
||||
* Create a new instance of a memory logger.
|
||||
*
|
||||
* @param name The name of the memory log
|
||||
* @param type The type of item being logged
|
||||
* @param size The number of items to store in memory before flushign to disk
|
||||
*
|
||||
* @return MEMLOG* A memory log handle
|
||||
*/
|
||||
MEMLOG *
|
||||
memlog_create(char *name, MEMLOGTYPE type, int size)
|
||||
{
|
||||
MEMLOG *log;
|
||||
|
||||
if ((log = (MEMLOG *)malloc(sizeof(MEMLOG))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log->name = strdup(name);
|
||||
spinlock_init(&log->lock);
|
||||
log->type = type;
|
||||
log->offset = 0;
|
||||
log->size = size;
|
||||
log->flags = 0;
|
||||
switch (type)
|
||||
{
|
||||
case ML_INT:
|
||||
log->values = malloc(sizeof(int) * size);
|
||||
break;
|
||||
case ML_LONG:
|
||||
log->values = malloc(sizeof(long) * size);
|
||||
break;
|
||||
case ML_LONGLONG:
|
||||
log->values = malloc(sizeof(long long) * size);
|
||||
break;
|
||||
case ML_STRING:
|
||||
log->values = malloc(sizeof(char *) * size);
|
||||
break;
|
||||
}
|
||||
if (log->values == NULL)
|
||||
{
|
||||
free(log);
|
||||
return NULL;
|
||||
}
|
||||
spinlock_acquire(&memlock);
|
||||
log->next = memlogs;
|
||||
memlogs = log;
|
||||
spinlock_release(&memlock);
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a memory logger any unwritten data will be flushed to disk
|
||||
*
|
||||
* @param log The memory log to destroy
|
||||
*/
|
||||
void
|
||||
memlog_destroy(MEMLOG *log)
|
||||
{
|
||||
MEMLOG *ptr;
|
||||
|
||||
if ((log->flags & MLNOAUTOFLUSH) == 0)
|
||||
memlog_flush(log);
|
||||
free(log->values);
|
||||
|
||||
spinlock_acquire(&memlock);
|
||||
if (memlogs == log)
|
||||
memlogs = log->next;
|
||||
else
|
||||
{
|
||||
ptr = memlogs;
|
||||
while (ptr && ptr->next != log)
|
||||
ptr = ptr->next;
|
||||
if (ptr)
|
||||
ptr->next = log->next;
|
||||
}
|
||||
spinlock_release(&memlock);
|
||||
free(log->name);
|
||||
free(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a data item to the memory logger
|
||||
*
|
||||
* @param log The memory logger
|
||||
* @param value The value to log
|
||||
*/
|
||||
void
|
||||
memlog_log(MEMLOG *log, void *value)
|
||||
{
|
||||
if (!log)
|
||||
return;
|
||||
spinlock_acquire(&log->lock);
|
||||
switch (log->type)
|
||||
{
|
||||
case ML_INT:
|
||||
((int *)(log->values))[log->offset] = (int)value;
|
||||
break;
|
||||
case ML_LONG:
|
||||
((long *)(log->values))[log->offset] = (long)value;
|
||||
break;
|
||||
case ML_LONGLONG:
|
||||
((long long *)(log->values))[log->offset] = (long long)value;
|
||||
break;
|
||||
case ML_STRING:
|
||||
((char **)(log->values))[log->offset] = (char *)value;
|
||||
break;
|
||||
}
|
||||
log->offset++;
|
||||
if (log->offset == log->size)
|
||||
{
|
||||
if ((log->flags & MLNOAUTOFLUSH) == 0)
|
||||
memlog_flush(log);
|
||||
log->offset = 0;
|
||||
log->iflags = MLWRAPPED;
|
||||
}
|
||||
spinlock_release(&log->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all memlogs to disk, called during shutdown
|
||||
*
|
||||
*/
|
||||
void
|
||||
memlog_flush_all()
|
||||
{
|
||||
MEMLOG *log;
|
||||
|
||||
spinlock_acquire(&memlock);
|
||||
log = memlogs;
|
||||
while (log)
|
||||
{
|
||||
spinlock_acquire(&log->lock);
|
||||
memlog_flush(log);
|
||||
spinlock_release(&log->lock);
|
||||
log = log->next;
|
||||
}
|
||||
spinlock_release(&memlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flags for a memlog
|
||||
*
|
||||
* @param log The memlog to set the flags for
|
||||
* @param flags The new flags values
|
||||
*/
|
||||
void
|
||||
memlog_set(MEMLOG *log, unsigned int flags)
|
||||
{
|
||||
log->flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush a memory log to disk
|
||||
*
|
||||
* Assumes the the log->lock has been acquired by the caller
|
||||
*
|
||||
* @param log The memory log to flush
|
||||
*/
|
||||
void
|
||||
memlog_flush(MEMLOG *log)
|
||||
{
|
||||
FILE *fp;
|
||||
int i;
|
||||
|
||||
if ((fp = fopen(log->name, "a")) == NULL)
|
||||
return;
|
||||
if ((log->flags & MLNOAUTOFLUSH) && (log->iflags & MLWRAPPED))
|
||||
{
|
||||
for (i = 0; i < log->size; i++)
|
||||
{
|
||||
int ind = (i + log->offset) % log->size;
|
||||
switch (log->type)
|
||||
{
|
||||
case ML_INT:
|
||||
fprintf(fp, "%d\n",
|
||||
((int *)(log->values))[ind]);
|
||||
break;
|
||||
case ML_LONG:
|
||||
fprintf(fp, "%ld\n",
|
||||
((long *)(log->values))[ind]);
|
||||
break;
|
||||
case ML_LONGLONG:
|
||||
fprintf(fp, "%lld\n",
|
||||
((long long *)(log->values))[ind]);
|
||||
break;
|
||||
case ML_STRING:
|
||||
fprintf(fp, "%s\n",
|
||||
((char **)(log->values))[ind]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < log->offset; i++)
|
||||
{
|
||||
switch (log->type)
|
||||
{
|
||||
case ML_INT:
|
||||
fprintf(fp, "%d\n", ((int *)(log->values))[i]);
|
||||
break;
|
||||
case ML_LONG:
|
||||
fprintf(fp, "%ld\n", ((long *)(log->values))[i]);
|
||||
break;
|
||||
case ML_LONGLONG:
|
||||
fprintf(fp, "%lld\n", ((long long *)(log->values))[i]);
|
||||
break;
|
||||
case ML_STRING:
|
||||
fprintf(fp, "%s\n", ((char **)(log->values))[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
log->offset = 0;
|
||||
fclose(fp);
|
||||
}
|
||||
@ -40,7 +40,10 @@
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
static MONITOR *allMonitors = NULL;
|
||||
static SPINLOCK monLock = SPINLOCK_INIT;
|
||||
|
||||
@ -33,15 +33,23 @@
|
||||
#include <housekeeper.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#define PROFILE_POLL 1
|
||||
#define PROFILE_POLL 0
|
||||
|
||||
#if PROFILE_POLL
|
||||
#include <rdtsc.h>
|
||||
#include <memlog.h>
|
||||
|
||||
extern unsigned long hkheartbeat;
|
||||
MEMLOG *plog;
|
||||
#endif
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
extern __thread size_t tls_sesid;
|
||||
int number_poll_spins;
|
||||
int max_poll_sleep;
|
||||
|
||||
/**
|
||||
* @file poll.c - Abstraction of the epoll functionality
|
||||
@ -69,7 +77,7 @@ extern __thread size_t tls_sesid;
|
||||
/**
|
||||
* 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.
|
||||
* for debugging purposes but should be avoided in general use.
|
||||
*/
|
||||
#define MUTEX_EPOLL 0
|
||||
|
||||
@ -96,6 +104,7 @@ static int load_samples = 0;
|
||||
static int load_nfds = 0;
|
||||
static double current_avg = 0.0;
|
||||
static double *avg_samples = NULL;
|
||||
static int *evqp_samples = NULL;
|
||||
static int next_sample = 0;
|
||||
static int n_avg_samples;
|
||||
|
||||
@ -143,13 +152,29 @@ static struct {
|
||||
int n_hup; /*< Number of hangup events */
|
||||
int n_accept; /*< Number of accept events */
|
||||
int n_polls; /*< Number of poll cycles */
|
||||
int n_pollev; /*< Number of polls returnign events */
|
||||
int n_nbpollev; /*< Number of polls returnign events */
|
||||
int n_nothreads; /*< Number of times no threads are polling */
|
||||
int n_fds[MAXNFDS]; /*< Number of wakeups with particular
|
||||
n_fds value */
|
||||
int evq_length; /*< Event queue length */
|
||||
int evq_pending; /*< Number of pending descriptors in event queue */
|
||||
int evq_max; /*< Maximum event queue length */
|
||||
int wake_evqpending;/*< Woken from epoll_wait with pending events in queue */
|
||||
int blockingpolls; /*< Number of epoll_waits with a timeout specified */
|
||||
} pollStats;
|
||||
|
||||
#define N_QUEUE_TIMES 30
|
||||
/**
|
||||
* The event queue statistics
|
||||
*/
|
||||
static struct {
|
||||
unsigned int qtimes[N_QUEUE_TIMES+1];
|
||||
unsigned int exectimes[N_QUEUE_TIMES+1];
|
||||
unsigned long maxqtime;
|
||||
unsigned long maxexectime;
|
||||
} queueStats;
|
||||
|
||||
/**
|
||||
* How frequently to call the poll_loadav function used to monitor the load
|
||||
* average of the poll subsystem.
|
||||
@ -178,6 +203,7 @@ int i;
|
||||
exit(-1);
|
||||
}
|
||||
memset(&pollStats, 0, sizeof(pollStats));
|
||||
memset(&queueStats, 0, sizeof(queueStats));
|
||||
bitmask_init(&poll_mask);
|
||||
n_threads = config_threadcount();
|
||||
if ((thread_data =
|
||||
@ -194,10 +220,19 @@ int i;
|
||||
|
||||
hktask_add("Load Average", poll_loadav, NULL, POLL_LOAD_FREQ);
|
||||
n_avg_samples = 15 * 60 / POLL_LOAD_FREQ;
|
||||
avg_samples = (double *)malloc(sizeof(double *) * n_avg_samples);
|
||||
avg_samples = (double *)malloc(sizeof(double) * n_avg_samples);
|
||||
for (i = 0; i < n_avg_samples; i++)
|
||||
avg_samples[i] = 0.0;
|
||||
evqp_samples = (int *)malloc(sizeof(int) * n_avg_samples);
|
||||
for (i = 0; i < n_avg_samples; i++)
|
||||
evqp_samples[i] = 0.0;
|
||||
|
||||
number_poll_spins = config_nbpolls();
|
||||
max_poll_sleep = config_pollsleep();
|
||||
|
||||
#if PROFILE_POLL
|
||||
plog = memlog_create("EventQueueWaitTime", ML_LONG, 10000);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -361,7 +396,7 @@ return_rc:
|
||||
* deschedule a process if a timeout is included, but will not do this if a 0 timeout
|
||||
* value is given. this improves performance when the gateway is under heavy load.
|
||||
*
|
||||
* In order to provide a fairer means of sharign the threads between the different
|
||||
* In order to provide a fairer means of sharing the threads between the different
|
||||
* DCB's the poll mechanism has been decoupled from the processing of the events.
|
||||
* The events are now recieved via the epoll_wait call, a queue of DCB's that have
|
||||
* events pending is maintained and as new events arrive the DCB is added to the end
|
||||
@ -372,15 +407,33 @@ return_rc:
|
||||
* events at a high rate will not block the execution of events for other DCB's and
|
||||
* should result in a fairer polling strategy.
|
||||
*
|
||||
* The introduction of the ability to inject "fake" write events into the event queue meant
|
||||
* that there was a possibility to "starve" new events sicne the polling loop would
|
||||
* consume the event queue before looking for new events. If the DCB that inject
|
||||
* the fake event then injected another fake event as a result of the first it meant
|
||||
* that new events did not get added to the queue. The strategy has been updated to
|
||||
* not consume the entire event queue, but process one event before doing a non-blocking
|
||||
* call to add any new events before processing any more events. A blocking call to
|
||||
* collect events is only made if there are no pending events to be processed on the
|
||||
* event queue.
|
||||
*
|
||||
* Also introduced a "timeout bias" mechanism. This mechansim control the length of
|
||||
* of timeout passed to epoll_wait in blocking calls based on previous behaviour.
|
||||
* The initial call will block for 10% of the define timeout peroid, this will be
|
||||
* increased in increments of 10% until the full timeout value is used. If at any
|
||||
* point there is an event to be processed then the value will be reduced to 10% again
|
||||
* for the next blocking call.
|
||||
*
|
||||
* @param arg The thread ID passed as a void * to satisfy the threading package
|
||||
*/
|
||||
void
|
||||
poll_waitevents(void *arg)
|
||||
{
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
int i, nfds;
|
||||
int i, nfds, timeout_bias = 1;
|
||||
int thread_id = (int)arg;
|
||||
DCB *zombies = NULL;
|
||||
int poll_spins = 0;
|
||||
|
||||
/** Add this thread to the bitmask of running polling threads */
|
||||
bitmask_set(&poll_mask, thread_id);
|
||||
@ -394,12 +447,9 @@ DCB *zombies = NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Process of the queue of waiting requests */
|
||||
while (do_shutdown == 0 && process_pollq(thread_id))
|
||||
if (pollStats.evq_pending == 0 && timeout_bias < 10)
|
||||
{
|
||||
if (thread_data)
|
||||
thread_data[thread_id].state = THREAD_ZPROCESSING;
|
||||
zombies = dcb_process_zombies(thread_id);
|
||||
timeout_bias++;
|
||||
}
|
||||
|
||||
atomic_add(&n_waiting, 1);
|
||||
@ -415,6 +465,7 @@ DCB *zombies = NULL;
|
||||
thread_data[thread_id].state = THREAD_POLLING;
|
||||
}
|
||||
|
||||
atomic_add(&pollStats.n_polls, 1);
|
||||
if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 0)) == -1)
|
||||
{
|
||||
atomic_add(&n_waiting, -1);
|
||||
@ -427,19 +478,28 @@ DCB *zombies = NULL;
|
||||
pthread_self(),
|
||||
nfds,
|
||||
eno)));
|
||||
atomic_add(&n_waiting, -1);
|
||||
}
|
||||
/*
|
||||
* If there are no new descriptors from the non-blocking call
|
||||
* and nothing to proces on the event queue then for do a
|
||||
* and nothing to process on the event queue then for do a
|
||||
* blocking call to epoll_wait.
|
||||
*
|
||||
* We calculate a timeout bias to alter the length of the blocking
|
||||
* call based on the time since we last received an event to process
|
||||
*/
|
||||
else if (nfds == 0 && process_pollq(thread_id) == 0)
|
||||
else if (nfds == 0 && pollStats.evq_pending == 0 && poll_spins++ > number_poll_spins)
|
||||
{
|
||||
atomic_add(&n_waiting, 1);
|
||||
atomic_add(&pollStats.blockingpolls, 1);
|
||||
nfds = epoll_wait(epoll_fd,
|
||||
events,
|
||||
MAX_EVENTS,
|
||||
EPOLL_TIMEOUT);
|
||||
(max_poll_sleep * timeout_bias) / 10);
|
||||
if (nfds == 0 && pollStats.evq_pending)
|
||||
{
|
||||
atomic_add(&pollStats.wake_evqpending, 1);
|
||||
poll_spins = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -454,12 +514,16 @@ DCB *zombies = NULL;
|
||||
#endif /* BLOCKINGPOLL */
|
||||
if (nfds > 0)
|
||||
{
|
||||
timeout_bias = 1;
|
||||
if (poll_spins <= number_poll_spins + 1)
|
||||
atomic_add(&pollStats.n_nbpollev, 1);
|
||||
poll_spins = 0;
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [poll_waitevents] epoll_wait found %d fds",
|
||||
pthread_self(),
|
||||
nfds)));
|
||||
atomic_add(&pollStats.n_polls, 1);
|
||||
atomic_add(&pollStats.n_pollev, 1);
|
||||
if (thread_data)
|
||||
{
|
||||
thread_data[thread_id].n_fds = nfds;
|
||||
@ -478,7 +542,7 @@ DCB *zombies = NULL;
|
||||
/*
|
||||
* Process every DCB that has a new event and add
|
||||
* it to the poll queue.
|
||||
* If the DCB is currently beign processed then we
|
||||
* If the DCB is currently being processed then we
|
||||
* or in the new eent bits to the pending event bits
|
||||
* and leave it in the queue.
|
||||
* If the DCB was not already in the queue then it was
|
||||
@ -493,6 +557,11 @@ DCB *zombies = NULL;
|
||||
spinlock_acquire(&pollqlock);
|
||||
if (DCB_POLL_BUSY(dcb))
|
||||
{
|
||||
if (dcb->evq.pending_events == 0)
|
||||
{
|
||||
pollStats.evq_pending++;
|
||||
dcb->evq.inserted = hkheartbeat;
|
||||
}
|
||||
dcb->evq.pending_events |= ev;
|
||||
}
|
||||
else
|
||||
@ -512,6 +581,8 @@ DCB *zombies = NULL;
|
||||
dcb->evq.next = dcb;
|
||||
}
|
||||
pollStats.evq_length++;
|
||||
pollStats.evq_pending++;
|
||||
dcb->evq.inserted = hkheartbeat;
|
||||
if (pollStats.evq_length > pollStats.evq_max)
|
||||
{
|
||||
pollStats.evq_max = pollStats.evq_length;
|
||||
@ -522,17 +593,20 @@ DCB *zombies = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was nothing to process then process the zombie queue
|
||||
* Process of the queue of waiting requests
|
||||
* This is done without checking the evq_pending count as a
|
||||
* precautionary measure to avoid issues if the house keeping
|
||||
* of the count goes wrong.
|
||||
*/
|
||||
if (process_pollq(thread_id) == 0)
|
||||
{
|
||||
if (thread_data)
|
||||
{
|
||||
thread_data[thread_id].state = THREAD_ZPROCESSING;
|
||||
}
|
||||
zombies = dcb_process_zombies(thread_id);
|
||||
}
|
||||
|
||||
if (process_pollq(thread_id))
|
||||
timeout_bias = 1;
|
||||
|
||||
if (thread_data)
|
||||
thread_data[thread_id].state = THREAD_ZPROCESSING;
|
||||
zombies = dcb_process_zombies(thread_id);
|
||||
if (thread_data)
|
||||
thread_data[thread_id].state = THREAD_IDLE;
|
||||
|
||||
if (do_shutdown)
|
||||
{
|
||||
/*<
|
||||
@ -555,6 +629,34 @@ DCB *zombies = NULL;
|
||||
} /*< while(1) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of non-blocking poll cycles that will be done before
|
||||
* a blocking poll will take place. Whenever an event arrives on a thread
|
||||
* or the thread sees a pending event to execute it will reset it's
|
||||
* poll_spin coutn to zero and will then poll with a 0 timeout until the
|
||||
* poll_spin value is greater than the value set here.
|
||||
*
|
||||
* @param nbpolls Number of non-block polls to perform before blocking
|
||||
*/
|
||||
void
|
||||
poll_set_nonblocking_polls(unsigned int nbpolls)
|
||||
{
|
||||
number_poll_spins = nbpolls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum amount of time, in milliseconds, the polling thread
|
||||
* will block before it will wake and check the event queue for work
|
||||
* that may have been added by another thread.
|
||||
*
|
||||
* @param maxwait Maximum wait time in milliseconds
|
||||
*/
|
||||
void
|
||||
poll_set_maxwait(unsigned int maxwait)
|
||||
{
|
||||
max_poll_sleep = maxwait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process of the queue of DCB's that have outstanding events
|
||||
*
|
||||
@ -575,6 +677,7 @@ process_pollq(int thread_id)
|
||||
DCB *dcb;
|
||||
int found = 0;
|
||||
uint32_t ev;
|
||||
unsigned long qtime;
|
||||
|
||||
spinlock_acquire(&pollqlock);
|
||||
if (eventq == NULL)
|
||||
@ -611,13 +714,28 @@ uint32_t ev;
|
||||
if (found)
|
||||
{
|
||||
ev = dcb->evq.pending_events;
|
||||
dcb->evq.processing_events = ev;
|
||||
dcb->evq.pending_events = 0;
|
||||
pollStats.evq_pending--;
|
||||
}
|
||||
spinlock_release(&pollqlock);
|
||||
|
||||
if (found == 0)
|
||||
return 0;
|
||||
|
||||
#if PROFILE_POLL
|
||||
memlog_log(plog, hkheartbeat - dcb->evq.inserted);
|
||||
#endif
|
||||
qtime = hkheartbeat - dcb->evq.inserted;
|
||||
dcb->evq.started = hkheartbeat;
|
||||
|
||||
if (qtime > N_QUEUE_TIMES)
|
||||
queueStats.qtimes[N_QUEUE_TIMES]++;
|
||||
else
|
||||
queueStats.qtimes[qtime]++;
|
||||
if (qtime > queueStats.maxqtime)
|
||||
queueStats.maxqtime = qtime;
|
||||
|
||||
|
||||
CHK_DCB(dcb);
|
||||
if (thread_data)
|
||||
@ -662,24 +780,21 @@ uint32_t ev;
|
||||
|
||||
if (eno == 0) {
|
||||
#if MUTEX_BLOCK
|
||||
simple_mutex_lock(
|
||||
&dcb->dcb_write_lock,
|
||||
true);
|
||||
ss_info_dassert(
|
||||
!dcb->dcb_write_active,
|
||||
"Write already active");
|
||||
simple_mutex_lock(&dcb->dcb_write_lock, true);
|
||||
ss_info_dassert(!dcb->dcb_write_active,
|
||||
"Write already active");
|
||||
dcb->dcb_write_active = TRUE;
|
||||
atomic_add(
|
||||
&pollStats.n_write,
|
||||
1);
|
||||
atomic_add(&pollStats.n_write, 1);
|
||||
dcb->func.write_ready(dcb);
|
||||
dcb->dcb_write_active = FALSE;
|
||||
simple_mutex_unlock(
|
||||
&dcb->dcb_write_lock);
|
||||
simple_mutex_unlock(&dcb->dcb_write_lock);
|
||||
#else
|
||||
atomic_add(&pollStats.n_write,
|
||||
1);
|
||||
LOGIF(LT, (tls_sesid = dcb_get_session_id(dcb)));
|
||||
atomic_add(&pollStats.n_write, 1);
|
||||
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
dcb->func.write_ready(dcb);
|
||||
#endif
|
||||
} else {
|
||||
@ -698,10 +813,8 @@ uint32_t ev;
|
||||
if (ev & EPOLLIN)
|
||||
{
|
||||
#if MUTEX_BLOCK
|
||||
simple_mutex_lock(&dcb->dcb_read_lock,
|
||||
true);
|
||||
ss_info_dassert(!dcb->dcb_read_active,
|
||||
"Read already active");
|
||||
simple_mutex_lock(&dcb->dcb_read_lock, true);
|
||||
ss_info_dassert(!dcb->dcb_read_active, "Read already active");
|
||||
dcb->dcb_read_active = TRUE;
|
||||
#endif
|
||||
|
||||
@ -715,7 +828,10 @@ uint32_t ev;
|
||||
dcb->fd)));
|
||||
atomic_add(
|
||||
&pollStats.n_accept, 1);
|
||||
LOGIF(LT, (tls_sesid = dcb_get_session_id(dcb)));
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
dcb->func.accept(dcb);
|
||||
}
|
||||
else
|
||||
@ -728,7 +844,10 @@ uint32_t ev;
|
||||
dcb,
|
||||
dcb->fd)));
|
||||
atomic_add(&pollStats.n_read, 1);
|
||||
LOGIF(LT, (tls_sesid = dcb_get_session_id(dcb)));
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
dcb->func.read(dcb);
|
||||
}
|
||||
#if MUTEX_BLOCK
|
||||
@ -764,7 +883,10 @@ uint32_t ev;
|
||||
strerror(eno))));
|
||||
}
|
||||
atomic_add(&pollStats.n_error, 1);
|
||||
LOGIF(LT, (tls_sesid = dcb_get_session_id(dcb)));
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
dcb->func.error(dcb);
|
||||
}
|
||||
|
||||
@ -789,7 +911,10 @@ uint32_t ev;
|
||||
{
|
||||
dcb->flags |= DCBF_HUNG;
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
LOGIF(LT, (tls_sesid = dcb_get_session_id(dcb)));
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
dcb->func.hangup(dcb);
|
||||
}
|
||||
else
|
||||
@ -818,16 +943,28 @@ uint32_t ev;
|
||||
{
|
||||
dcb->flags |= DCBF_HUNG;
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
LOGIF(LT, (tls_sesid = dcb_get_session_id(dcb)));
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
dcb->func.hangup(dcb);
|
||||
}
|
||||
else
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
}
|
||||
#endif
|
||||
LOGIF(LT, tls_sesid = 0);
|
||||
qtime = hkheartbeat - dcb->evq.started;
|
||||
|
||||
if (qtime > N_QUEUE_TIMES)
|
||||
queueStats.exectimes[N_QUEUE_TIMES]++;
|
||||
else
|
||||
queueStats.exectimes[qtime % N_QUEUE_TIMES]++;
|
||||
if (qtime > queueStats.maxexectime)
|
||||
queueStats.maxexectime = qtime;
|
||||
|
||||
spinlock_acquire(&pollqlock);
|
||||
dcb->evq.processing_events = 0;
|
||||
|
||||
if (dcb->evq.pending_events == 0)
|
||||
{
|
||||
/* No pending events so remove from the queue */
|
||||
@ -871,6 +1008,7 @@ uint32_t ev;
|
||||
}
|
||||
}
|
||||
dcb->evq.processing = 0;
|
||||
LOGIF(LT, tls_log_info.li_sesid = 0);
|
||||
spinlock_release(&pollqlock);
|
||||
|
||||
return 1;
|
||||
@ -920,24 +1058,35 @@ dprintPollStats(DCB *dcb)
|
||||
{
|
||||
int i;
|
||||
|
||||
dcb_printf(dcb, "Number of epoll cycles: %d\n",
|
||||
dcb_printf(dcb, "\nPoll Statistics.\n\n");
|
||||
dcb_printf(dcb, "No. of epoll cycles: %d\n",
|
||||
pollStats.n_polls);
|
||||
dcb_printf(dcb, "Number of read events: %d\n",
|
||||
dcb_printf(dcb, "No. of epoll cycles with wait: %d\n",
|
||||
pollStats.blockingpolls);
|
||||
dcb_printf(dcb, "No. of epoll calls returning events: %d\n",
|
||||
pollStats.n_pollev);
|
||||
dcb_printf(dcb, "No. of non-blocking calls returning events: %d\n",
|
||||
pollStats.n_nbpollev);
|
||||
dcb_printf(dcb, "No. of read events: %d\n",
|
||||
pollStats.n_read);
|
||||
dcb_printf(dcb, "Number of write events: %d\n",
|
||||
dcb_printf(dcb, "No. of write events: %d\n",
|
||||
pollStats.n_write);
|
||||
dcb_printf(dcb, "Number of error events: %d\n",
|
||||
dcb_printf(dcb, "No. of error events: %d\n",
|
||||
pollStats.n_error);
|
||||
dcb_printf(dcb, "Number of hangup events: %d\n",
|
||||
dcb_printf(dcb, "No. of hangup events: %d\n",
|
||||
pollStats.n_hup);
|
||||
dcb_printf(dcb, "Number of accept events: %d\n",
|
||||
dcb_printf(dcb, "No. of accept events: %d\n",
|
||||
pollStats.n_accept);
|
||||
dcb_printf(dcb, "Number of times no threads polling: %d\n",
|
||||
dcb_printf(dcb, "No. of times no threads polling: %d\n",
|
||||
pollStats.n_nothreads);
|
||||
dcb_printf(dcb, "Current event queue length: %d\n",
|
||||
dcb_printf(dcb, "Current event queue length: %d\n",
|
||||
pollStats.evq_length);
|
||||
dcb_printf(dcb, "Maximum event queue length: %d\n",
|
||||
dcb_printf(dcb, "Maximum event queue length: %d\n",
|
||||
pollStats.evq_max);
|
||||
dcb_printf(dcb, "No. of DCBs with pending events: %d\n",
|
||||
pollStats.evq_pending);
|
||||
dcb_printf(dcb, "No. of wakeups with pending queue: %d\n",
|
||||
pollStats.wake_evqpending);
|
||||
|
||||
dcb_printf(dcb, "No of poll completions with descriptors\n");
|
||||
dcb_printf(dcb, "\tNo. of descriptors\tNo. of poll completions.\n");
|
||||
@ -1014,6 +1163,7 @@ dShowThreads(DCB *dcb)
|
||||
int i, j, n;
|
||||
char *state;
|
||||
double avg1 = 0.0, avg5 = 0.0, avg15 = 0.0;
|
||||
double qavg1 = 0.0, qavg5 = 0.0, qavg15 = 0.0;
|
||||
|
||||
|
||||
dcb_printf(dcb, "Polling Threads.\n\n");
|
||||
@ -1022,8 +1172,12 @@ double avg1 = 0.0, avg5 = 0.0, avg15 = 0.0;
|
||||
|
||||
/* Average all the samples to get the 15 minute average */
|
||||
for (i = 0; i < n_avg_samples; i++)
|
||||
{
|
||||
avg15 += avg_samples[i];
|
||||
qavg15 += evqp_samples[i];
|
||||
}
|
||||
avg15 = avg15 / n_avg_samples;
|
||||
qavg15 = qavg15 / n_avg_samples;
|
||||
|
||||
/* Average the last third of the samples to get the 5 minute average */
|
||||
n = 5 * 60 / POLL_LOAD_FREQ;
|
||||
@ -1031,8 +1185,12 @@ double avg1 = 0.0, avg5 = 0.0, avg15 = 0.0;
|
||||
if (i < 0)
|
||||
i += n_avg_samples;
|
||||
for (j = i; j < i + n; j++)
|
||||
{
|
||||
avg5 += avg_samples[j % n_avg_samples];
|
||||
qavg5 += evqp_samples[j % n_avg_samples];
|
||||
}
|
||||
avg5 = (3 * avg5) / (n_avg_samples);
|
||||
qavg5 = (3 * qavg5) / (n_avg_samples);
|
||||
|
||||
/* Average the last 15th of the samples to get the 1 minute average */
|
||||
n = 60 / POLL_LOAD_FREQ;
|
||||
@ -1040,16 +1198,23 @@ double avg1 = 0.0, avg5 = 0.0, avg15 = 0.0;
|
||||
if (i < 0)
|
||||
i += n_avg_samples;
|
||||
for (j = i; j < i + n; j++)
|
||||
{
|
||||
avg1 += avg_samples[j % n_avg_samples];
|
||||
qavg1 += evqp_samples[j % n_avg_samples];
|
||||
}
|
||||
avg1 = (15 * avg1) / (n_avg_samples);
|
||||
qavg1 = (15 * qavg1) / (n_avg_samples);
|
||||
|
||||
dcb_printf(dcb, "15 Minute Average: %.2f, 5 Minute Average: %.2f, "
|
||||
"1 Minute Average: %.2f\n\n", avg15, avg5, avg1);
|
||||
dcb_printf(dcb, "Pending event queue length averages:\n");
|
||||
dcb_printf(dcb, "15 Minute Average: %.2f, 5 Minute Average: %.2f, "
|
||||
"1 Minute Average: %.2f\n\n", qavg15, qavg5, qavg1);
|
||||
|
||||
if (thread_data == NULL)
|
||||
return;
|
||||
dcb_printf(dcb, " ID | State | # fds | Descriptor | Event\n");
|
||||
dcb_printf(dcb, "----+------------+--------+------------------+---------------\n");
|
||||
dcb_printf(dcb, " ID | State | # fds | Descriptor | Running | Event\n");
|
||||
dcb_printf(dcb, "----+------------+--------+------------------+----------+---------------\n");
|
||||
for (i = 0; i < n_threads; i++)
|
||||
{
|
||||
switch (thread_data[i].state)
|
||||
@ -1072,11 +1237,11 @@ double avg1 = 0.0, avg5 = 0.0, avg15 = 0.0;
|
||||
}
|
||||
if (thread_data[i].state != THREAD_PROCESSING)
|
||||
dcb_printf(dcb,
|
||||
" %2d | %-10s | | |\n",
|
||||
" %2d | %-10s | | | |\n",
|
||||
i, state);
|
||||
else if (thread_data[i].cur_dcb == NULL)
|
||||
dcb_printf(dcb,
|
||||
" %2d | %-10s | %6d | |\n",
|
||||
" %2d | %-10s | %6d | | |\n",
|
||||
i, state, thread_data[i].n_fds);
|
||||
else
|
||||
{
|
||||
@ -1094,9 +1259,10 @@ double avg1 = 0.0, avg5 = 0.0, avg15 = 0.0;
|
||||
from_heap = true;
|
||||
}
|
||||
dcb_printf(dcb,
|
||||
" %2d | %-10s | %6d | %-16p | %s\n",
|
||||
" %2d | %-10s | %6d | %-16p | <%3d00ms | %s\n",
|
||||
i, state, thread_data[i].n_fds,
|
||||
thread_data[i].cur_dcb, event_string);
|
||||
thread_data[i].cur_dcb, 1 + hkheartbeat - dcb->evq.started,
|
||||
event_string);
|
||||
|
||||
if (from_heap)
|
||||
{
|
||||
@ -1129,6 +1295,7 @@ int new_samples, new_nfds;
|
||||
else
|
||||
current_avg = 0.0;
|
||||
avg_samples[next_sample] = current_avg;
|
||||
evqp_samples[next_sample] = pollStats.evq_pending;
|
||||
next_sample++;
|
||||
if (next_sample >= n_avg_samples)
|
||||
next_sample = 0;
|
||||
@ -1197,4 +1364,139 @@ static void poll_add_event_to_dcb(
|
||||
}
|
||||
}
|
||||
spinlock_release(&pollqlock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a fake write completion event for a DCB into the polling
|
||||
* queue.
|
||||
*
|
||||
* This is used to trigger transmission activity on another DCB from
|
||||
* within the event processing routine of a DCB. or to allow a DCB
|
||||
* to defer some further output processing, to allow for other DCBs
|
||||
* to receive a slice of the processing time. Fake events are added
|
||||
* to the tail of the event queue, in the same way that real events
|
||||
* are, so maintain the "fairness" of processing.
|
||||
*
|
||||
* @param dcb DCB to emulate an EPOLLOUT event for
|
||||
*/
|
||||
void
|
||||
poll_fake_write_event(DCB *dcb)
|
||||
{
|
||||
uint32_t ev = EPOLLOUT;
|
||||
|
||||
spinlock_acquire(&pollqlock);
|
||||
/*
|
||||
* If the DCB is already on the queue, there are no pending events and
|
||||
* there are other events on the queue, then
|
||||
* take it off the queue. This stops the DCB hogging the threads.
|
||||
*/
|
||||
if (DCB_POLL_BUSY(dcb) && dcb->evq.pending_events == 0 && dcb->evq.prev != dcb)
|
||||
{
|
||||
dcb->evq.prev->evq.next = dcb->evq.next;
|
||||
dcb->evq.next->evq.prev = dcb->evq.prev;
|
||||
if (eventq == dcb)
|
||||
eventq = dcb->evq.next;
|
||||
dcb->evq.next = NULL;
|
||||
dcb->evq.prev = NULL;
|
||||
pollStats.evq_length--;
|
||||
}
|
||||
|
||||
if (DCB_POLL_BUSY(dcb))
|
||||
{
|
||||
if (dcb->evq.pending_events == 0)
|
||||
pollStats.evq_pending++;
|
||||
dcb->evq.pending_events |= ev;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb->evq.pending_events = ev;
|
||||
dcb->evq.inserted = hkheartbeat;
|
||||
if (eventq)
|
||||
{
|
||||
dcb->evq.prev = eventq->evq.prev;
|
||||
eventq->evq.prev->evq.next = dcb;
|
||||
eventq->evq.prev = dcb;
|
||||
dcb->evq.next = eventq;
|
||||
}
|
||||
else
|
||||
{
|
||||
eventq = dcb;
|
||||
dcb->evq.prev = dcb;
|
||||
dcb->evq.next = dcb;
|
||||
}
|
||||
pollStats.evq_length++;
|
||||
pollStats.evq_pending++;
|
||||
dcb->evq.inserted = hkheartbeat;
|
||||
if (pollStats.evq_length > pollStats.evq_max)
|
||||
{
|
||||
pollStats.evq_max = pollStats.evq_length;
|
||||
}
|
||||
}
|
||||
spinlock_release(&pollqlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the event queue contents
|
||||
*
|
||||
* @param pdcb The DCB to print the event queue to
|
||||
*/
|
||||
void
|
||||
dShowEventQ(DCB *pdcb)
|
||||
{
|
||||
DCB *dcb;
|
||||
char *tmp1, *tmp2;
|
||||
|
||||
spinlock_acquire(&pollqlock);
|
||||
if (eventq == NULL)
|
||||
{
|
||||
/* Nothing to process */
|
||||
spinlock_release(&pollqlock);
|
||||
return;
|
||||
}
|
||||
dcb = eventq;
|
||||
dcb_printf(pdcb, "\nEvent Queue.\n");
|
||||
dcb_printf(pdcb, "%-16s | %-10s | %-18s | %s\n", "DCB", "Status", "Processing Events",
|
||||
"Pending Events");
|
||||
dcb_printf(pdcb, "-----------------+------------+--------------------+-------------------\n");
|
||||
do {
|
||||
dcb_printf(pdcb, "%-16p | %-10s | %-18s | %-18s\n", dcb,
|
||||
dcb->evq.processing ? "Processing" : "Pending",
|
||||
(tmp1 = event_to_string(dcb->evq.processing_events)),
|
||||
(tmp2 = event_to_string(dcb->evq.pending_events)));
|
||||
free(tmp1);
|
||||
free(tmp2);
|
||||
dcb = dcb->evq.next;
|
||||
} while (dcb != eventq);
|
||||
spinlock_release(&pollqlock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print the event queue statistics
|
||||
*
|
||||
* @param pdcb The DCB to print the event queue to
|
||||
*/
|
||||
void
|
||||
dShowEventStats(DCB *pdcb)
|
||||
{
|
||||
int i;
|
||||
|
||||
dcb_printf(pdcb, "\nEvent statistics.\n");
|
||||
dcb_printf(pdcb, "Maximum queue time: %3d00ms\n", queueStats.maxqtime);
|
||||
dcb_printf(pdcb, "Maximum execution time: %3d00ms\n", queueStats.maxexectime);
|
||||
dcb_printf(pdcb, "Maximum event queue length: %3d\n", pollStats.evq_max);
|
||||
dcb_printf(pdcb, "Current event queue length: %3d\n", pollStats.evq_length);
|
||||
dcb_printf(pdcb, "\n");
|
||||
dcb_printf(pdcb, " | Number of events\n");
|
||||
dcb_printf(pdcb, "Duration | Queued | Executed\n");
|
||||
dcb_printf(pdcb, "---------------+------------+-----------\n");
|
||||
dcb_printf(pdcb, " < 100ms | %-10d | %-10d\n",
|
||||
queueStats.qtimes[0], queueStats.exectimes[0]);
|
||||
for (i = 1; i < N_QUEUE_TIMES; i++)
|
||||
{
|
||||
dcb_printf(pdcb, " %2d00 - %2d00ms | %-10d | %-10d\n", i, i + 1,
|
||||
queueStats.qtimes[i], queueStats.exectimes[i]);
|
||||
}
|
||||
dcb_printf(pdcb, " > %2d00ms | %-10d | %-10d\n", N_QUEUE_TIMES,
|
||||
queueStats.qtimes[N_QUEUE_TIMES], queueStats.exectimes[N_QUEUE_TIMES]);
|
||||
}
|
||||
|
||||
@ -23,7 +23,10 @@
|
||||
#include <ctype.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
/**
|
||||
* Generate a random printable character
|
||||
*
|
||||
@ -224,8 +227,9 @@ static int reported = 0;
|
||||
*/
|
||||
int secrets_writeKeys(char *secret_file)
|
||||
{
|
||||
int fd;
|
||||
MAXKEYS key;
|
||||
int fd,randfd;
|
||||
unsigned int randval;
|
||||
MAXKEYS key;
|
||||
|
||||
/* Open for writing | Create | Truncate the file for writing */
|
||||
if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0)
|
||||
@ -240,7 +244,28 @@ MAXKEYS key;
|
||||
return 1;
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
/* Open for writing | Create | Truncate the file for writing */
|
||||
if ((randfd = open("/dev/random", O_RDONLY)) < 0)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed opening /dev/random. Error %d, %s.",
|
||||
errno,
|
||||
strerror(errno))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(read(randfd,(void*)&randval,sizeof(unsigned int)) < 1)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to read /dev/random.")));
|
||||
close(randfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(randfd);
|
||||
srand(randval);
|
||||
secrets_random_str(key.enckey, MAXSCALE_KEYLEN);
|
||||
secrets_random_str(key.initvector, MAXSCALE_IV_LEN);
|
||||
|
||||
@ -360,7 +385,7 @@ unsigned char encrypted[80];
|
||||
return NULL;
|
||||
|
||||
memset(padded_passwd, 0, 80);
|
||||
strcpy((char *)padded_passwd, password);
|
||||
strncpy((char *)padded_passwd, password, 79);
|
||||
padded_len = ((strlen(password) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
|
||||
|
||||
AES_set_encrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
|
||||
|
||||
@ -45,7 +45,10 @@
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
static SPINLOCK server_spin = SPINLOCK_INIT;
|
||||
static SERVER *allServers = NULL;
|
||||
|
||||
@ -55,7 +55,10 @@
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/** To be used with configuration type checks */
|
||||
typedef struct typelib_st {
|
||||
|
||||
@ -44,7 +44,10 @@
|
||||
#include <log_manager.h>
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/** Global session id; updated safely by holding session_spin */
|
||||
static size_t session_id;
|
||||
|
||||
@ -74,15 +77,14 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
ss_info_dassert(session != NULL,
|
||||
"Allocating memory for session failed.");
|
||||
|
||||
if (session == NULL) {
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
if (session == NULL)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Failed to allocate memory for "
|
||||
"session object due error %d, %s.",
|
||||
eno,
|
||||
strerror(eno))));
|
||||
errno,
|
||||
strerror(errno))));
|
||||
goto return_session;
|
||||
}
|
||||
#if defined(SS_DEBUG)
|
||||
@ -219,7 +221,8 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
session->state = SESSION_STATE_ROUTER_READY;
|
||||
spinlock_release(&session->ses_lock);
|
||||
spinlock_acquire(&session_spin);
|
||||
session->ses_id = ++session_id; /*< assign an id and increase */
|
||||
/** Assign a session id and increase */
|
||||
session->ses_id = ++session_id;
|
||||
session->next = allSessions;
|
||||
allSessions = session;
|
||||
spinlock_release(&session_spin);
|
||||
@ -250,6 +253,41 @@ return_session:
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable specified logging for the current session and increase logger
|
||||
* counter.
|
||||
* Generic logging setting has precedence over session-specific setting.
|
||||
*
|
||||
* @param ses session
|
||||
* @param id logfile identifier
|
||||
*/
|
||||
void session_enable_log(
|
||||
SESSION* ses,
|
||||
logfile_id_t id)
|
||||
{
|
||||
ses->ses_enabled_logs |= id;
|
||||
atomic_add((int *)&log_ses_count[id], 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable specified logging for the current session and decrease logger
|
||||
* counter.
|
||||
* Generic logging setting has precedence over session-specific setting.
|
||||
*
|
||||
* @param ses session
|
||||
* @param id logfile identifier
|
||||
*/
|
||||
void session_disable_log(
|
||||
SESSION* ses,
|
||||
logfile_id_t id)
|
||||
{
|
||||
if (ses->ses_enabled_logs & id)
|
||||
{
|
||||
ses->ses_enabled_logs &= ~id;
|
||||
atomic_add((int *)&log_ses_count[id], -1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Link a session to a DCB.
|
||||
*
|
||||
@ -381,6 +419,9 @@ bool session_free(
|
||||
session->service->name,
|
||||
session->ses_id)));
|
||||
|
||||
/** Disable trace and decrease trace logger counter */
|
||||
session_disable_log(session, LT);
|
||||
|
||||
free(session);
|
||||
succp = true;
|
||||
|
||||
@ -531,7 +572,7 @@ SESSION *ptr;
|
||||
ptr = allSessions;
|
||||
while (ptr)
|
||||
{
|
||||
dcb_printf(dcb, "Session %p\n", ptr);
|
||||
dcb_printf(dcb, "Session %d (%p)\n",ptr->ses_id, ptr);
|
||||
dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state));
|
||||
dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service);
|
||||
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
|
||||
@ -557,7 +598,7 @@ dprintSession(DCB *dcb, SESSION *ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
dcb_printf(dcb, "Session %p\n", ptr);
|
||||
dcb_printf(dcb, "Session %d (%p)\n",ptr->ses_id, ptr);
|
||||
dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state));
|
||||
dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service);
|
||||
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
|
||||
@ -812,3 +853,11 @@ session_getUser(SESSION *session)
|
||||
{
|
||||
return (session && session->client) ? session->client->user : NULL;
|
||||
}
|
||||
/**
|
||||
* Return the pointer to the list of all sessions.
|
||||
* @return Pointer to the list of all sessions.
|
||||
*/
|
||||
SESSION *get_all_sessions()
|
||||
{
|
||||
return allSessions;
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ add_executable(test_service testservice.c)
|
||||
add_executable(test_server testserver.c)
|
||||
add_executable(test_users testusers.c)
|
||||
add_executable(test_adminusers testadminusers.c)
|
||||
add_executable(testmemlog testmemlog.c)
|
||||
target_link_libraries(test_mysql_users MySQLClient fullcore)
|
||||
target_link_libraries(test_hash fullcore)
|
||||
target_link_libraries(test_hint fullcore)
|
||||
@ -25,6 +26,7 @@ target_link_libraries(test_server fullcore)
|
||||
target_link_libraries(test_users fullcore)
|
||||
target_link_libraries(test_adminusers fullcore)
|
||||
add_test(testMySQLUsers test_mysql_users)
|
||||
target_link_libraries(testmemlog fullcore)
|
||||
add_test(TestHash test_hash)
|
||||
add_test(TestHint test_hint)
|
||||
add_test(TestSpinlock test_spinlock)
|
||||
@ -37,3 +39,4 @@ add_test(TestService test_service)
|
||||
add_test(TestServer test_server)
|
||||
add_test(TestUsers test_users)
|
||||
add_test(TestAdminUsers test_adminusers)
|
||||
add_test(TestMemlog testmemlog)
|
||||
|
||||
@ -22,7 +22,7 @@ LIBS= -L$(EMBEDDED_LIB) -lmysqld \
|
||||
-lz -lm -lcrypt -lcrypto -ldl -laio -lrt -pthread -llog_manager \
|
||||
-L../../inih/extra -linih -lssl -lstdc++
|
||||
|
||||
TESTS=testhash testspinlock testbuffer testmodutil testpoll testservice testdcb testfilter testadminusers
|
||||
TESTS=testhash testspinlock testbuffer testmodutil testpoll testservice testdcb testfilter testadminusers testmemlog
|
||||
|
||||
cleantests:
|
||||
- $(DEL) *.o
|
||||
@ -100,6 +100,13 @@ testadminusers: testadminusers.c libcore.a
|
||||
-I$(ROOT_PATH)/utils \
|
||||
testadminusers.c libcore.a $(UTILSPATH)/skygw_utils.o $(LIBS) -o testadminusers
|
||||
|
||||
testmemlog: testmemlog.c libcore.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) \
|
||||
-I$(ROOT_PATH)/server/include \
|
||||
-I$(ROOT_PATH)/utils \
|
||||
testmemlog.c libcore.a $(UTILSPATH)/skygw_utils.o $(LIBS) -o testmemlog
|
||||
|
||||
|
||||
libcore.a: ../*.o
|
||||
ar rv libcore.a ../*.o
|
||||
|
||||
|
||||
404
server/core/test/testmemlog.c
Normal file
404
server/core/test/testmemlog.c
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* This file is distributed as part of MaxScale from MariaDB. It is free
|
||||
* software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation,
|
||||
* version 2.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright MariaDB Corporation 2014
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 30/09/2014 Mark Riddoch Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <memlog.h>
|
||||
|
||||
/**
|
||||
* Count the number of lines in a file
|
||||
*
|
||||
* @param file The name of the file
|
||||
* @return -1 if the file could not be opened or the numebr of lines
|
||||
*/
|
||||
int
|
||||
linecount(char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
int i = 0;
|
||||
char buffer[180];
|
||||
|
||||
if ((fp = fopen(file, "r")) == NULL)
|
||||
return -1;
|
||||
while (fgets(buffer, 180, fp) != NULL)
|
||||
i++;
|
||||
fclose(fp);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Some strings to log */
|
||||
char *strings[] = {
|
||||
"First log entry",
|
||||
"Second entry",
|
||||
"Third",
|
||||
"The fourth thing to log",
|
||||
"Add a final 5th item"
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
MEMLOG *log, *log2;
|
||||
int i;
|
||||
long j;
|
||||
long long k;
|
||||
int failures = 0;
|
||||
|
||||
unlink("memlog1");
|
||||
if ((log = memlog_create("memlog1", ML_INT, 100)) == NULL)
|
||||
{
|
||||
printf("Memlog Creation: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Memlog Creation: Passed\n");
|
||||
if (access("memlog1",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 1: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 1: Passed\n");
|
||||
for (i = 0; i < 50; i++)
|
||||
memlog_log(log, (void *)i);
|
||||
if (access("memlog1",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 2: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 2: Passed\n");
|
||||
for (i = 0; i < 50; i++)
|
||||
memlog_log(log, (void *)i);
|
||||
if (access("memlog1",R_OK) != 0)
|
||||
{
|
||||
printf("File existance 3: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 3: Passed\n");
|
||||
if (linecount("memlog1") != 100)
|
||||
{
|
||||
printf("Incorrect entry count: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Incorrect entry count: Passed\n");
|
||||
for (i = 0; i < 50; i++)
|
||||
memlog_log(log, (void *)i);
|
||||
if (linecount("memlog1") != 100)
|
||||
{
|
||||
printf("Premature Flushing: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Premature Flushing: Passed\n");
|
||||
memlog_destroy(log);
|
||||
if (linecount("memlog1") != 150)
|
||||
{
|
||||
printf("Flush on destroy: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Flush on destroy: Passed\n");
|
||||
}
|
||||
|
||||
unlink("memlog2");
|
||||
if ((log = memlog_create("memlog2", ML_LONG, 100)) == NULL)
|
||||
{
|
||||
printf("Memlog Creation: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Memlog Creation: Passed\n");
|
||||
if (access("memlog2",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 1: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 1: Passed\n");
|
||||
for (j = 0; j < 50; j++)
|
||||
memlog_log(log, (void *)j);
|
||||
if (access("memlog2",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 2: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 2: Passed\n");
|
||||
for (j = 0; j < 50; j++)
|
||||
memlog_log(log, (void *)j);
|
||||
if (access("memlog2",R_OK) != 0)
|
||||
{
|
||||
printf("File existance 3: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 3: Passed\n");
|
||||
if (linecount("memlog2") != 100)
|
||||
{
|
||||
printf("Incorrect entry count: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Incorrect entry count: Passed\n");
|
||||
for (j = 0; j < 50; j++)
|
||||
memlog_log(log, (void *)j);
|
||||
if (linecount("memlog2") != 100)
|
||||
{
|
||||
printf("Premature Flushing: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Premature Flushing: Passed\n");
|
||||
memlog_destroy(log);
|
||||
if (linecount("memlog2") != 150)
|
||||
{
|
||||
printf("Flush on destroy: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Flush on destroy: Passed\n");
|
||||
}
|
||||
|
||||
unlink("memlog3");
|
||||
if ((log = memlog_create("memlog3", ML_LONGLONG, 100)) == NULL)
|
||||
{
|
||||
printf("Memlog Creation: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Memlog Creation: Passed\n");
|
||||
if (access("memlog3",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 1: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 1: Passed\n");
|
||||
for (k = 0; k < 50; k++)
|
||||
memlog_log(log, (void *)k);
|
||||
if (access("memlog3",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 2: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 2: Passed\n");
|
||||
for (k = 0; k < 50; k++)
|
||||
memlog_log(log, (void *)k);
|
||||
if (access("memlog3",R_OK) != 0)
|
||||
{
|
||||
printf("File existance 3: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 3: Passed\n");
|
||||
if (linecount("memlog3") != 100)
|
||||
{
|
||||
printf("Incorrect entry count: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Incorrect entry count: Passed\n");
|
||||
for (k = 0; k < 50; k++)
|
||||
memlog_log(log, (void *)k);
|
||||
if (linecount("memlog3") != 100)
|
||||
{
|
||||
printf("Premature Flushing: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Premature Flushing: Passed\n");
|
||||
memlog_destroy(log);
|
||||
if (linecount("memlog3") != 150)
|
||||
{
|
||||
printf("Flush on destroy: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Flush on destroy: Passed\n");
|
||||
}
|
||||
|
||||
unlink("memlog4");
|
||||
if ((log = memlog_create("memlog4", ML_STRING, 100)) == NULL)
|
||||
{
|
||||
printf("Memlog Creation: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Memlog Creation: Passed\n");
|
||||
if (access("memlog4",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 1: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 1: Passed\n");
|
||||
for (i = 0; i < 50; i++)
|
||||
memlog_log(log, strings[i%5]);
|
||||
if (access("memlog4",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 2: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 2: Passed\n");
|
||||
for (i = 0; i < 50; i++)
|
||||
memlog_log(log, strings[i%5]);
|
||||
if (access("memlog4",R_OK) != 0)
|
||||
{
|
||||
printf("File existance 3: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 3: Passed\n");
|
||||
if (linecount("memlog4") != 100)
|
||||
{
|
||||
printf("Incorrect entry count: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Incorrect entry count: Passed\n");
|
||||
for (i = 0; i < 50; i++)
|
||||
memlog_log(log, strings[i%5]);
|
||||
if (linecount("memlog4") != 100)
|
||||
{
|
||||
printf("Premature Flushing: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Premature Flushing: Passed\n");
|
||||
memlog_destroy(log);
|
||||
if (linecount("memlog4") != 150)
|
||||
{
|
||||
printf("Flush on destroy: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Flush on destroy: Passed\n");
|
||||
}
|
||||
|
||||
unlink("memlog5");
|
||||
unlink("memlog6");
|
||||
if ((log = memlog_create("memlog5", ML_INT, 100)) == NULL)
|
||||
{
|
||||
printf("Memlog Creation: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Memlog Creation: Passed\n");
|
||||
if ((log2 = memlog_create("memlog6", ML_INT, 100)) == NULL)
|
||||
{
|
||||
printf("Memlog Creation: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Memlog Creation: Passed\n");
|
||||
for (i = 0; i < 40; i++)
|
||||
memlog_log(log, (void *)i);
|
||||
for (i = 0; i < 30; i++)
|
||||
memlog_log(log2, (void *)i);
|
||||
memlog_flush_all();
|
||||
if (linecount("memlog5") != 40 ||
|
||||
linecount("memlog6") != 30)
|
||||
{
|
||||
printf(
|
||||
"Memlog flush all: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf(
|
||||
"Memlog flush all: Passed\n");
|
||||
}
|
||||
}
|
||||
|
||||
unlink("memlog7");
|
||||
if ((log = memlog_create("memlog7", ML_INT, 100)) == NULL)
|
||||
{
|
||||
printf("Memlog Creation: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Memlog Creation: Passed\n");
|
||||
if (access("memlog7",R_OK) == 0)
|
||||
{
|
||||
printf("File existance 1: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 1: Passed\n");
|
||||
for (i = 0; i < 5050; i++)
|
||||
memlog_log(log, (void *)i);
|
||||
if (access("memlog7",R_OK) != 0)
|
||||
{
|
||||
printf("File existance 3: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("File existance 3: Passed\n");
|
||||
if (linecount("memlog7") != 5000)
|
||||
{
|
||||
printf("Incorrect entry count: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Incorrect entry count: Passed\n");
|
||||
for (i = 0; i < 50; i++)
|
||||
memlog_log(log, (void *)i);
|
||||
if (linecount("memlog7") != 5100)
|
||||
{
|
||||
printf("Residual flushing: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Premature Flushing: Passed\n");
|
||||
for (i = 0; i < 10120; i++)
|
||||
memlog_log(log, (void *)i);
|
||||
memlog_destroy(log);
|
||||
if (linecount("memlog7") != 15220)
|
||||
{
|
||||
printf("Flush on destroy: Failed\n");
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("Flush on destroy: Passed\n");
|
||||
}
|
||||
exit(failures);
|
||||
}
|
||||
@ -43,7 +43,10 @@
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/* used in the hex2bin function */
|
||||
#define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\
|
||||
|
||||
@ -29,10 +29,13 @@
|
||||
* 21/06/13 Mark Riddoch Initial implementation
|
||||
* 07/05/14 Massimiliano Pinto Added version_string to global configuration
|
||||
* 23/05/14 Massimiliano Pinto Added id to global configuration
|
||||
* 17/10/14 Mark Riddoch Added poll tuning configuration parameters
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#define DEFAULT_NBPOLLS 3 /**< Default number of non block polls before we block */
|
||||
#define DEFAULT_POLLSLEEP 1000 /**< Default poll wait time (milliseconds) */
|
||||
/**
|
||||
* Maximum length for configuration parameter value.
|
||||
*/
|
||||
@ -92,11 +95,15 @@ typedef struct {
|
||||
int n_threads; /**< Number of polling threads */
|
||||
char *version_string; /**< The version string of embedded database library */
|
||||
unsigned long id; /**< MaxScale ID */
|
||||
unsigned int n_nbpoll; /**< Tune number of non-blocking polls */
|
||||
unsigned int pollsleep; /**< Wait time in blocking polls */
|
||||
} GATEWAY_CONF;
|
||||
|
||||
extern int config_load(char *);
|
||||
extern int config_reload();
|
||||
extern int config_threadcount();
|
||||
extern unsigned int config_nbpolls();
|
||||
extern unsigned int config_pollsleep();
|
||||
CONFIG_PARAMETER* config_get_param(CONFIG_PARAMETER* params, const char* name);
|
||||
config_param_type_t config_get_paramtype(CONFIG_PARAMETER* param);
|
||||
CONFIG_PARAMETER* config_clone_param(CONFIG_PARAMETER* param);
|
||||
|
||||
@ -98,12 +98,28 @@ typedef struct gw_protocol {
|
||||
int (*session)(struct dcb *, void *);
|
||||
} GWPROTOCOL;
|
||||
|
||||
/**
|
||||
* The event queue structure used in the polling loop to maintain a queue
|
||||
* of events that need to be processed for the DCB.
|
||||
*
|
||||
* next The next DCB in the event queue
|
||||
* prev The previous DCB in the event queue
|
||||
* pending_events The events that are pending processing
|
||||
* processing_events The evets currently being processed
|
||||
* processing Flag to indicate the processing status of the DCB
|
||||
* eventqlock Spinlock to protect this structure
|
||||
* inserted Insertion time for logging purposes
|
||||
* started Time that the processign started
|
||||
*/
|
||||
typedef struct {
|
||||
struct dcb *next;
|
||||
struct dcb *prev;
|
||||
uint32_t pending_events;
|
||||
uint32_t processing_events;
|
||||
int processing;
|
||||
SPINLOCK eventqlock;
|
||||
unsigned long inserted;
|
||||
unsigned long started;
|
||||
} DCBEVENTQ;
|
||||
|
||||
/**
|
||||
@ -274,13 +290,7 @@ int fail_accept_errno;
|
||||
#define DCB_POLL_BUSY(x) ((x)->evq.next != NULL)
|
||||
|
||||
DCB *dcb_get_zombies(void);
|
||||
int gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
DCB* dcb,
|
||||
#endif
|
||||
int fd,
|
||||
const void* buf,
|
||||
size_t nbytes);
|
||||
int gw_write(DCB *, const void *, size_t);
|
||||
int dcb_write(DCB *, GWBUF *);
|
||||
DCB *dcb_alloc(dcb_role_t);
|
||||
void dcb_free(DCB *);
|
||||
@ -309,7 +319,9 @@ int dcb_isvalid(DCB *); /* Check the DCB is in the linked list */
|
||||
|
||||
bool dcb_set_state(DCB* dcb, dcb_state_t new_state, dcb_state_t* old_state);
|
||||
void dcb_call_foreach (DCB_REASON reason);
|
||||
size_t dcb_get_session_id(DCB* dcb);;
|
||||
size_t dcb_get_session_id(DCB* dcb);
|
||||
bool dcb_get_ses_log_info(DCB* dcb, size_t* sesid, int* enabled_logs);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -61,13 +61,7 @@ int do_read_dcb(DCB *dcb);
|
||||
int do_read_10(DCB *dcb, uint8_t *buffer);
|
||||
int MySQLWrite(DCB *dcb, GWBUF *queue);
|
||||
int setnonblocking(int fd);
|
||||
int gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
DCB* dcb,
|
||||
#endif
|
||||
int fd,
|
||||
const void* buf,
|
||||
size_t nbytes);
|
||||
int gw_write(DCB *dcb, const void *buf, size_t nbytes);
|
||||
int gw_getsockerrno(int fd);
|
||||
int parse_bindconfig(char *, unsigned short, struct sockaddr_in *);
|
||||
int setipaddress(struct in_addr *, char *);
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
* Copyright MariaDB Corporation Ab 2014
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <dcb.h>
|
||||
|
||||
/**
|
||||
* @file housekeeper.h A mechanism to have task run periodically
|
||||
@ -31,6 +32,11 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
HK_REPEATED = 1,
|
||||
HK_ONESHOT
|
||||
} HKTASK_TYPE;
|
||||
|
||||
/**
|
||||
* The housekeeper task list
|
||||
*/
|
||||
@ -40,12 +46,22 @@ typedef struct hktask {
|
||||
void *data; /*< Data to pass the task */
|
||||
int frequency; /*< How often to call the tasks (seconds) */
|
||||
time_t nextdue; /*< When the task should be next run */
|
||||
HKTASK_TYPE
|
||||
type; /*< The task type */
|
||||
struct hktask
|
||||
*next; /*< Next task in the list */
|
||||
} HKTASK;
|
||||
|
||||
/**
|
||||
* The global housekeeper heartbeat value. This value is increamente
|
||||
* every 100ms and may be used for crude timing etc.
|
||||
*/
|
||||
extern unsigned long hkheartbeat;
|
||||
|
||||
extern void hkinit();
|
||||
extern int hktask_add(char *name, void (*task)(void *), void *data, int frequency);
|
||||
extern int hktask_oneshot(char *name, void (*task)(void *), void *data, int when);
|
||||
extern int hktask_remove(char *name);
|
||||
extern void hkshutdown();
|
||||
extern void hkshow_tasks(DCB *pdcb);
|
||||
#endif
|
||||
|
||||
65
server/include/memlog.h
Normal file
65
server/include/memlog.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef _MEMLOG_H
|
||||
#define _MEMLOG_H
|
||||
/*
|
||||
* This file is distributed as part of MariaDB MaxScale. It is free
|
||||
* software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation,
|
||||
* version 2.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright MariaDB Ab 2014
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file memlog.h The memory logging mechanism
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 26/09/14 Mark Riddoch Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
#include <spinlock.h>
|
||||
|
||||
typedef enum { ML_INT, ML_LONG, ML_LONGLONG, ML_STRING } MEMLOGTYPE;
|
||||
|
||||
typedef struct memlog {
|
||||
char *name;
|
||||
SPINLOCK lock;
|
||||
void *values;
|
||||
int offset;
|
||||
int size;
|
||||
MEMLOGTYPE type;
|
||||
unsigned int flags;
|
||||
unsigned int iflags;
|
||||
struct memlog *next;
|
||||
} MEMLOG;
|
||||
|
||||
/*
|
||||
* MEMLOG flag bits
|
||||
*/
|
||||
#define MLNOAUTOFLUSH 0x0001
|
||||
|
||||
/*
|
||||
* MEMLOG internal flags
|
||||
*/
|
||||
#define MLWRAPPED 0x0001
|
||||
|
||||
|
||||
extern MEMLOG *memlog_create(char *, MEMLOGTYPE, int);
|
||||
extern void memlog_destroy(MEMLOG *);
|
||||
extern void memlog_set(MEMLOG *, unsigned int);
|
||||
extern void memlog_log(MEMLOG *, void *);
|
||||
extern void memlog_flush_all();
|
||||
extern void memlog_flush(MEMLOG *);
|
||||
#endif
|
||||
@ -32,6 +32,8 @@
|
||||
* 13/06/13 Mark Riddoch Initial implementation
|
||||
* 08/07/13 Mark Riddoch Addition of monitor modules
|
||||
* 29/05/14 Mark Riddoch Addition of filter modules
|
||||
* 01/10/14 Mark Riddoch Addition of call to unload all modules on
|
||||
* shutdown
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
@ -58,6 +60,7 @@ typedef struct modules {
|
||||
|
||||
extern void *load_module(const char *module, const char *type);
|
||||
extern void unload_module(const char *module);
|
||||
extern void unload_all_modules();
|
||||
extern void printModules();
|
||||
extern void dprintAllModules(DCB *);
|
||||
char* get_maxscale_home(void);
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
#define MAX_EVENTS 1000
|
||||
#define EPOLL_TIMEOUT 1000 /**< The epoll timeout in milliseconds */
|
||||
|
||||
extern void poll_init();
|
||||
extern int poll_add_dcb(DCB *);
|
||||
@ -40,8 +39,11 @@ extern int poll_remove_dcb(DCB *);
|
||||
extern void poll_waitevents(void *);
|
||||
extern void poll_shutdown();
|
||||
extern GWBITMASK *poll_bitmask();
|
||||
extern void poll_set_maxwait(unsigned int);
|
||||
extern void poll_set_nonblocking_polls(unsigned int);
|
||||
extern void dprintPollStats(DCB *);
|
||||
extern void dShowThreads(DCB *dcb);
|
||||
void poll_add_epollin_event_to_dcb(DCB* dcb, GWBUF* buf);
|
||||
|
||||
extern void dShowEventQ(DCB *dcb);
|
||||
extern void dShowEventStats(DCB *dcb);
|
||||
#endif
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include <buffer.h>
|
||||
#include <spinlock.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
struct dcb;
|
||||
struct service;
|
||||
@ -109,19 +110,20 @@ typedef struct session {
|
||||
skygw_chk_t ses_chk_top;
|
||||
#endif
|
||||
SPINLOCK ses_lock;
|
||||
session_state_t state; /**< Current descriptor state */
|
||||
size_t ses_id; /**< unique session identifier */
|
||||
struct dcb *client; /**< The client connection */
|
||||
void *data; /**< The session data */
|
||||
void *router_session;/**< The router instance data */
|
||||
SESSION_STATS stats; /**< Session statistics */
|
||||
struct service *service; /**< The service this session is using */
|
||||
int n_filters; /**< Number of filter sessions */
|
||||
SESSION_FILTER *filters; /**< The filters in use within this session */
|
||||
DOWNSTREAM head; /**< Head of the filter chain */
|
||||
UPSTREAM tail; /**< The tail of the filter chain */
|
||||
struct session *next; /**< Linked list of all sessions */
|
||||
int refcount; /**< Reference count on the session */
|
||||
session_state_t state; /*< Current descriptor state */
|
||||
size_t ses_id; /*< Unique session identifier */
|
||||
int ses_enabled_logs; /*< Bitfield of enabled logs */
|
||||
struct dcb *client; /*< The client connection */
|
||||
void *data; /*< The session data */
|
||||
void *router_session; /*< The router instance data */
|
||||
SESSION_STATS stats; /*< Session statistics */
|
||||
struct service *service; /*< The service this session is using */
|
||||
int n_filters; /*< Number of filter sessions */
|
||||
SESSION_FILTER *filters; /*< The filters in use within this session */
|
||||
DOWNSTREAM head; /*< Head of the filter chain */
|
||||
UPSTREAM tail; /*< The tail of the filter chain */
|
||||
struct session *next; /*< Linked list of all sessions */
|
||||
int refcount; /*< Reference count on the session */
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t ses_chk_tail;
|
||||
#endif
|
||||
@ -146,6 +148,7 @@ typedef struct session {
|
||||
((sess)->tail.clientReply)((sess)->tail.instance, \
|
||||
(sess)->tail.session, (buf))
|
||||
|
||||
SESSION *get_all_sessions();
|
||||
SESSION *session_alloc(struct service *, struct dcb *);
|
||||
bool session_free(SESSION *);
|
||||
int session_isvalid(SESSION *);
|
||||
@ -160,4 +163,7 @@ void dListSessions(struct dcb *);
|
||||
char *session_state(int);
|
||||
bool session_link_dcb(SESSION *, struct dcb *);
|
||||
SESSION* get_session_by_router_ses(void* rses);
|
||||
void session_enable_log(SESSION* ses, logfile_id_t id);
|
||||
void session_disable_log(SESSION* ses, logfile_id_t id);
|
||||
|
||||
#endif
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -25,7 +25,10 @@
|
||||
#include <modutil.h>
|
||||
#include <mysqlhint.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
/**
|
||||
* hintparser.c - Find any comment in the SQL packet and look for MAXSCALE
|
||||
|
||||
@ -51,7 +51,10 @@
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
MODULE_INFO info = {
|
||||
MODULE_API_FILTER,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user