MXS-2005: Remove unused code
Removed skygw_utils and relate files along with the old log manager code. Also removed file flushing due to it being redundant; messages are written to the file immediately. Adjusted tests to accommodate this change.
This commit is contained in:
@ -28,12 +28,12 @@ MXS_BEGIN_DECLS
|
|||||||
const char *debug_expr = #exp; /** The MXS_ERROR marco doesn't seem to like stringification */ \
|
const char *debug_expr = #exp; /** The MXS_ERROR marco doesn't seem to like stringification */ \
|
||||||
MXS_ERROR("debug assert at %s:%d failed: %s\n", (char*)__FILE__, __LINE__, debug_expr); \
|
MXS_ERROR("debug assert at %s:%d failed: %s\n", (char*)__FILE__, __LINE__, debug_expr); \
|
||||||
fprintf(stderr, "debug assert at %s:%d failed: %s\n", (char*)__FILE__, __LINE__, debug_expr); \
|
fprintf(stderr, "debug assert at %s:%d failed: %s\n", (char*)__FILE__, __LINE__, debug_expr); \
|
||||||
mxs_log_flush_sync(); raise(SIGABRT);} } while (false)
|
raise(SIGABRT);} } while (false)
|
||||||
#define ss_info_dassert(exp,info) do { if(!(exp)){\
|
#define ss_info_dassert(exp,info) do { if(!(exp)){\
|
||||||
const char *debug_expr = #exp; \
|
const char *debug_expr = #exp; \
|
||||||
MXS_ERROR("debug assert at %s:%d failed: %s (%s)\n", (char*)__FILE__, __LINE__, info, debug_expr); \
|
MXS_ERROR("debug assert at %s:%d failed: %s (%s)\n", (char*)__FILE__, __LINE__, info, debug_expr); \
|
||||||
fprintf(stderr, "debug assert at %s:%d failed: %s (%s)\n", (char*)__FILE__, __LINE__, info, debug_expr); \
|
fprintf(stderr, "debug assert at %s:%d failed: %s (%s)\n", (char*)__FILE__, __LINE__, info, debug_expr); \
|
||||||
mxs_log_flush_sync();raise(SIGABRT);} } while (false)
|
raise(SIGABRT);} } while (false)
|
||||||
# define ss_debug(exp) exp
|
# define ss_debug(exp) exp
|
||||||
# define ss_dfprintf fprintf
|
# define ss_dfprintf fprintf
|
||||||
# define ss_dfflush fflush
|
# define ss_dfflush fflush
|
||||||
|
|||||||
@ -94,23 +94,7 @@ typedef struct mxs_log_throttling
|
|||||||
|
|
||||||
bool mxs_log_init(const char* ident, const char* logdir, mxs_log_target_t target);
|
bool mxs_log_init(const char* ident, const char* logdir, mxs_log_target_t target);
|
||||||
void mxs_log_finish(void);
|
void mxs_log_finish(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* Start log flushing thread
|
|
||||||
*
|
|
||||||
* @return True if log flusher thread was started
|
|
||||||
*/
|
|
||||||
bool mxs_log_start_flush_thr();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop log flushing thread
|
|
||||||
*/
|
|
||||||
void mxs_log_stop_flush_thr();
|
|
||||||
|
|
||||||
int mxs_log_flush();
|
|
||||||
int mxs_log_flush_sync();
|
|
||||||
bool mxs_log_rotate();
|
bool mxs_log_rotate();
|
||||||
|
|
||||||
int mxs_log_set_priority_enabled(int priority, bool enabled);
|
int mxs_log_set_priority_enabled(int priority, bool enabled);
|
||||||
void mxs_log_set_syslog_enabled(bool enabled);
|
void mxs_log_set_syslog_enabled(bool enabled);
|
||||||
void mxs_log_set_maxlog_enabled(bool enabled);
|
void mxs_log_set_maxlog_enabled(bool enabled);
|
||||||
|
|||||||
@ -1,556 +0,0 @@
|
|||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <mysql.h>
|
|
||||||
|
|
||||||
#include "../../utils/skygw_utils.h"
|
|
||||||
#include "../query_classifier.h"
|
|
||||||
|
|
||||||
static char datadir[1024] = "";
|
|
||||||
static char mysqldir[1024] = "";
|
|
||||||
|
|
||||||
static char* server_options[] =
|
|
||||||
{
|
|
||||||
"MariaDB Corporation MaxScale",
|
|
||||||
"--datadir=",
|
|
||||||
"--default-storage-engine=myisam",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
const int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
|
|
||||||
|
|
||||||
static char* server_groups[] =
|
|
||||||
{
|
|
||||||
"embedded",
|
|
||||||
"server",
|
|
||||||
"server",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
static void slcursor_add_case(
|
|
||||||
slist_cursor_t* c,
|
|
||||||
void* data)
|
|
||||||
{
|
|
||||||
slcursor_add_data(c, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct query_test_st query_test_t;
|
|
||||||
|
|
||||||
struct query_test_st
|
|
||||||
{
|
|
||||||
skygw_chk_t qt_chk_top;
|
|
||||||
const char* qt_query_str;
|
|
||||||
skygw_query_type_t qt_query_type;
|
|
||||||
skygw_query_type_t qt_result_type;
|
|
||||||
bool qt_should_fail;
|
|
||||||
bool qt_exec_also_in_server;
|
|
||||||
skygw_chk_t qt_chk_tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static query_test_t* query_test_init(
|
|
||||||
const char* query_str,
|
|
||||||
skygw_query_type_t query_type,
|
|
||||||
bool case_should_fail,
|
|
||||||
bool exec_also_in_server)
|
|
||||||
{
|
|
||||||
query_test_t* qtest;
|
|
||||||
|
|
||||||
qtest = (query_test_t *)calloc(1, sizeof(query_test_t));
|
|
||||||
ss_dassert(qtest != NULL);
|
|
||||||
qtest->qt_chk_top = CHK_NUM_QUERY_TEST;
|
|
||||||
qtest->qt_chk_tail = CHK_NUM_QUERY_TEST;
|
|
||||||
qtest->qt_query_str = query_str;
|
|
||||||
qtest->qt_query_type = query_type;
|
|
||||||
qtest->qt_should_fail = case_should_fail;
|
|
||||||
qtest->qt_exec_also_in_server = exec_also_in_server;
|
|
||||||
return qtest;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* query_test_get_querystr(
|
|
||||||
query_test_t* qt)
|
|
||||||
{
|
|
||||||
CHK_QUERY_TEST(qt);
|
|
||||||
return qt->qt_query_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static skygw_query_type_t query_test_get_query_type(
|
|
||||||
query_test_t* qt)
|
|
||||||
{
|
|
||||||
CHK_QUERY_TEST(qt);
|
|
||||||
return qt->qt_query_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static skygw_query_type_t query_test_get_result_type(
|
|
||||||
query_test_t* qt)
|
|
||||||
{
|
|
||||||
CHK_QUERY_TEST(qt);
|
|
||||||
return qt->qt_result_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool query_test_types_match(
|
|
||||||
query_test_t* qt)
|
|
||||||
{
|
|
||||||
CHK_QUERY_TEST(qt);
|
|
||||||
return (qt->qt_query_type == qt->qt_result_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool query_test_exec_also_in_server(
|
|
||||||
query_test_t* qt)
|
|
||||||
{
|
|
||||||
CHK_QUERY_TEST(qt);
|
|
||||||
return (qt->qt_exec_also_in_server);
|
|
||||||
}
|
|
||||||
|
|
||||||
static query_test_t* slcursor_get_case(
|
|
||||||
slist_cursor_t* c)
|
|
||||||
{
|
|
||||||
return (query_test_t*)slcursor_get_data(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
slist_cursor_t* c;
|
|
||||||
const char* q;
|
|
||||||
query_test_t* qtest;
|
|
||||||
bool succp;
|
|
||||||
bool failp = true;
|
|
||||||
unsigned int f = 0;
|
|
||||||
int nsucc = 0;
|
|
||||||
int nfail = 0;
|
|
||||||
int rc = 0;
|
|
||||||
MYSQL* mysql;
|
|
||||||
char* workingdir;
|
|
||||||
char ddoption[1024];
|
|
||||||
|
|
||||||
ss_dfprintf(stderr, ">> testmain\n");
|
|
||||||
c = slist_init();
|
|
||||||
|
|
||||||
/** Test some functions */
|
|
||||||
q = "SELECT MY_UDF('Hello')";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
/** This could be QUERY_TYPE_LOCAL_READ */
|
|
||||||
q = "SELECT repeat('a', 1024)";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_READ, false, true));
|
|
||||||
|
|
||||||
/** This could be QUERY_TYPE_LOCAL_READ */
|
|
||||||
q = "SELECT soundex('Hello')";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_READ, false, true));
|
|
||||||
|
|
||||||
q = "SELECT ssoundexx('Hello')";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
/** This could be QUERY_TYPE_LOCAL_READ */
|
|
||||||
q = "SELECT now()";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_READ, false, true));
|
|
||||||
|
|
||||||
/** This could be QUERY_TYPE_LOCAL_READ */
|
|
||||||
q = "SELECT rand()";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_READ, false, true));
|
|
||||||
|
|
||||||
q = "SELECT rand(234), MY_UDF('Hello'), soundex('Hello')";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
|
|
||||||
/** Read-only SELECTs */
|
|
||||||
q = "SELECT user from mysql.user";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_READ, false, true));
|
|
||||||
|
|
||||||
q = "select tt1.id, tt2.id from t1 tt1, t2 tt2 where tt1.name is "
|
|
||||||
"not null and tt2.name is not null";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_READ, false, false));
|
|
||||||
|
|
||||||
/** SELECT ..INTO clauses > session updates */
|
|
||||||
q = "SELECT user from mysql.user INTO DUMPFILE '/tmp/dump1'";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "SELECT user INTO DUMPFILE '/tmp/dump2 ' from mysql.user";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "SELECT user from mysql.user INTO OUTFILE '/tmp/out1'";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
/** Database and table name must be separated by a dot */
|
|
||||||
q = "SELECT user INTO OUTFILE '/tmp/out2 ' from mysql-user";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, true, false));
|
|
||||||
|
|
||||||
/** Database and table name must be separated by a dot */
|
|
||||||
q = "SELECT user INTO OUTFILE '/tmp/out2 ' from mysql_foo_user";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "SELECT user FROM mysql.user limit 1 INTO @local_variable";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "SELECT user INTO @local_variable FROM mysql.user limit 1";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "SELECT non_existent_attr INTO @d FROM non_existent_table";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "select * from table1 "
|
|
||||||
"where table1.field IN "
|
|
||||||
"(select * from table1a union select * from table1b) union "
|
|
||||||
"select * from table2 where table2.field = "
|
|
||||||
"(select (select f1 from table2a where table2a.f2 = table2b.f3) "
|
|
||||||
"from table2b where table2b.f1 = table2.f2) union "
|
|
||||||
"select * from table3";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_READ, false, true));
|
|
||||||
|
|
||||||
/** RENAME TABLEs */
|
|
||||||
q = "RENAME TABLE T1 to T2";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, false));
|
|
||||||
|
|
||||||
|
|
||||||
/** INSERTs */
|
|
||||||
q = "INSERT INTO T1 (SELECT * FROM T2)";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "INSERT INTO T1 VALUES(2, 'foo', 'toomanyattributes')";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "INSERT INTO T2 VALUES(1, 'sthrgey')";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "INSERT INTO T2 VALUES(8, 'ergstrhe')";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "INSERT INTO T2 VALUES(9, NULL)";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, false));
|
|
||||||
|
|
||||||
|
|
||||||
/** Ok, delimeter is client-side parameter which shouldn't be handled
|
|
||||||
* on server side.
|
|
||||||
*/
|
|
||||||
q = "delimiter //";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, true, true));
|
|
||||||
|
|
||||||
/** SETs, USEs > Session updates */
|
|
||||||
q = "SET @a=1";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "USE TEST";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, false));
|
|
||||||
|
|
||||||
|
|
||||||
/** Object creation statements */
|
|
||||||
q = "create procedure si (out param1 int) \nbegin select count(*) "
|
|
||||||
"into param1 from t1; \nend";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "CREATE TABLE T1 (id integer primary key, name varchar(10))";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "DROP TABLE T1";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "ALTER TABLE T1 ADD COLUMN WHYME INTEGER NOT NULL";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "TRUNCATE TABLE T1";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, false));
|
|
||||||
|
|
||||||
q = "DROP SERVER IF EXISTS VICTIMSRV";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "CREATE USER FOO IDENTIFIED BY 'BAR'";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "OPTIMIZE NO_WRITE_TO_BINLOG TABLE T1";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
q = "SELECT NOW();CREATE TABLE T1 (ID INTEGER);"
|
|
||||||
"SET sql_log_bin=0;CREATE TABLE T2 (ID INTEGER)";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_WRITE, false, true));
|
|
||||||
|
|
||||||
|
|
||||||
/** Setting database makes this SESSION_WRITE */
|
|
||||||
q = "USE TEST;CREATE TABLE T1 (ID INTEGER);"
|
|
||||||
"SET sql_log_bin=0;CREATE TABLE T2 (ID INTEGER)";
|
|
||||||
slcursor_add_case(
|
|
||||||
c,
|
|
||||||
query_test_init(q, QUERY_TYPE_SESSION_WRITE, false, true));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init libmysqld.
|
|
||||||
*/
|
|
||||||
workingdir = getenv("PWD");
|
|
||||||
|
|
||||||
if (workingdir == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"Failed to resolve the working directory, $PWD is not "
|
|
||||||
"set.\n");
|
|
||||||
ss_dassert(workingdir != NULL);
|
|
||||||
}
|
|
||||||
else if (access(workingdir, R_OK) != 0)
|
|
||||||
{
|
|
||||||
char errbuf[STRERROR_BUFLEN];
|
|
||||||
fprintf(stderr,
|
|
||||||
"Failed to access the working directory due %d, %s\n",
|
|
||||||
errno,
|
|
||||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
|
||||||
ss_dassert(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char** so = server_options;
|
|
||||||
snprintf(datadir, 1023, "%s/data", workingdir);
|
|
||||||
mkdir(datadir, 0777);
|
|
||||||
snprintf(ddoption, 1023, "--datadir=%s", datadir);
|
|
||||||
|
|
||||||
while (strncmp(*so++, "--datadir=", 10) != 0) ;
|
|
||||||
|
|
||||||
if (*so == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Failed to find datadir option.\n");
|
|
||||||
ss_dassert(*so != NULL);
|
|
||||||
}
|
|
||||||
*so = ddoption;
|
|
||||||
|
|
||||||
snprintf(mysqldir, 1023, "%s/mysql", workingdir);
|
|
||||||
setenv("MYSQL_HOME", mysqldir, 1);
|
|
||||||
}
|
|
||||||
failp = mysql_library_init(num_elements, server_options, server_groups);
|
|
||||||
|
|
||||||
if (failp)
|
|
||||||
{
|
|
||||||
MYSQL* mysql = mysql_init(NULL);
|
|
||||||
ss_dassert(mysql != NULL);
|
|
||||||
fprintf(stderr,
|
|
||||||
"mysql_init failed, %d : %s\n",
|
|
||||||
mysql_errno(mysql),
|
|
||||||
mysql_error(mysql));
|
|
||||||
ss_dassert(!failp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"\nExecuting selected cases in "
|
|
||||||
"skygw_query_classifier_get_type :\n\n");
|
|
||||||
/**
|
|
||||||
* Set cursor to the beginning, scan through the list and execute
|
|
||||||
* test cases.
|
|
||||||
*/
|
|
||||||
succp = slcursor_move_to_begin(c);
|
|
||||||
|
|
||||||
while (succp)
|
|
||||||
{
|
|
||||||
qtest = slcursor_get_case(c);
|
|
||||||
qtest->qt_result_type =
|
|
||||||
skygw_query_classifier_get_type(qtest->qt_query_str, f,
|
|
||||||
&mysql);
|
|
||||||
succp = slcursor_step_ahead(c);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Scan through test results and compare them against expected
|
|
||||||
* results.
|
|
||||||
*/
|
|
||||||
succp = slcursor_move_to_begin(c);
|
|
||||||
fprintf(stderr, "\nScanning through the results :\n\n");
|
|
||||||
|
|
||||||
while (succp)
|
|
||||||
{
|
|
||||||
qtest = slcursor_get_case(c);
|
|
||||||
|
|
||||||
if (!query_test_types_match(qtest))
|
|
||||||
{
|
|
||||||
nfail += 1;
|
|
||||||
ss_dfprintf(stderr,
|
|
||||||
"* Failed: \"%s\" -> %s (Expected %s)\n",
|
|
||||||
query_test_get_querystr(qtest),
|
|
||||||
STRQTYPE(query_test_get_result_type(qtest)),
|
|
||||||
STRQTYPE(query_test_get_query_type(qtest)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nsucc += 1;
|
|
||||||
ss_dfprintf(stderr,
|
|
||||||
"Succeed\t: \"%s\" -> %s\n",
|
|
||||||
query_test_get_querystr(qtest),
|
|
||||||
STRQTYPE(query_test_get_query_type(qtest)));
|
|
||||||
}
|
|
||||||
succp = slcursor_step_ahead(c);
|
|
||||||
}
|
|
||||||
fprintf(stderr,
|
|
||||||
"------------------------------------------\n"
|
|
||||||
"Tests in total %d, SUCCEED %d, FAILED %d\n",
|
|
||||||
nsucc + nfail,
|
|
||||||
nsucc,
|
|
||||||
nfail);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan test results and re-execute those which are marked to be
|
|
||||||
* executed also in the server. This serves mostly debugging purposes.
|
|
||||||
*/
|
|
||||||
succp = slcursor_move_to_begin(c);
|
|
||||||
mysql = mysql_init(NULL);
|
|
||||||
|
|
||||||
if (mysql == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "mysql_init failed\n");
|
|
||||||
ss_dassert(mysql != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_options(mysql,
|
|
||||||
MYSQL_READ_DEFAULT_GROUP,
|
|
||||||
"libmysqld_client");
|
|
||||||
mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
|
|
||||||
mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
|
|
||||||
|
|
||||||
mysql = mysql_real_connect(mysql,
|
|
||||||
NULL,
|
|
||||||
"skygw",
|
|
||||||
"skygw",
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
CLIENT_MULTI_STATEMENTS);
|
|
||||||
|
|
||||||
if (mysql == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "mysql_real_connect failed\n");
|
|
||||||
ss_dassert(mysql != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"\nRe-execution of selected cases in Embedded server :\n\n");
|
|
||||||
|
|
||||||
while (succp)
|
|
||||||
{
|
|
||||||
qtest = slcursor_get_case(c);
|
|
||||||
|
|
||||||
if (query_test_exec_also_in_server(qtest))
|
|
||||||
{
|
|
||||||
MYSQL_RES* results;
|
|
||||||
MYSQL_ROW record;
|
|
||||||
const char* query_str;
|
|
||||||
|
|
||||||
query_str = query_test_get_querystr(qtest);
|
|
||||||
failp = mysql_query(mysql, query_str);
|
|
||||||
|
|
||||||
if (failp)
|
|
||||||
{
|
|
||||||
ss_dfprintf(stderr,
|
|
||||||
"* Failed: \"%s\" -> %d : %s\n",
|
|
||||||
query_str,
|
|
||||||
mysql_errno(mysql),
|
|
||||||
mysql_error(mysql));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ss_dfprintf(stderr,
|
|
||||||
"Succeed\t: \"%s\"\n",
|
|
||||||
query_str);
|
|
||||||
results = mysql_store_result(mysql);
|
|
||||||
|
|
||||||
if (results != NULL)
|
|
||||||
{
|
|
||||||
|
|
||||||
while ((record = mysql_fetch_row(results)))
|
|
||||||
{
|
|
||||||
while (record != NULL && *record != NULL)
|
|
||||||
{
|
|
||||||
ss_dfprintf(stderr, "%s ", *record);
|
|
||||||
record++;
|
|
||||||
}
|
|
||||||
ss_dfprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
mysql_free_result(results);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
succp = slcursor_step_ahead(c);
|
|
||||||
|
|
||||||
}
|
|
||||||
slist_done(c);
|
|
||||||
fprintf(stderr, "------------------------------------------\n");
|
|
||||||
|
|
||||||
return_with_handle:
|
|
||||||
mysql_close(mysql);
|
|
||||||
mysql_thread_end();
|
|
||||||
mysql_library_end();
|
|
||||||
|
|
||||||
return_without_server:
|
|
||||||
ss_dfprintf(stderr, "\n<< testmain\n");
|
|
||||||
fflush(stderr);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
@ -26,7 +26,6 @@ add_library(maxscale-common SHARED
|
|||||||
mariadb.cc
|
mariadb.cc
|
||||||
maxscale_pcre2.cc
|
maxscale_pcre2.cc
|
||||||
misc.cc
|
misc.cc
|
||||||
mlist.cc
|
|
||||||
messagequeue.cc
|
messagequeue.cc
|
||||||
modulecmd.cc
|
modulecmd.cc
|
||||||
modutil.cc
|
modutil.cc
|
||||||
@ -48,7 +47,6 @@ add_library(maxscale-common SHARED
|
|||||||
service.cc
|
service.cc
|
||||||
session.cc
|
session.cc
|
||||||
session_command.cc
|
session_command.cc
|
||||||
skygw_utils.cc
|
|
||||||
spinlock.cc
|
spinlock.cc
|
||||||
ssl.cc
|
ssl.cc
|
||||||
statistics.cc
|
statistics.cc
|
||||||
|
|||||||
@ -411,8 +411,6 @@ sigfatal_handler(int i)
|
|||||||
|
|
||||||
mxb::dump_stacktrace(cb);
|
mxb::dump_stacktrace(cb);
|
||||||
|
|
||||||
mxs_log_flush_sync();
|
|
||||||
|
|
||||||
/* re-raise signal to enforce core dump */
|
/* re-raise signal to enforce core dump */
|
||||||
fprintf(stderr, "\n\nWriting core dump\n");
|
fprintf(stderr, "\n\nWriting core dump\n");
|
||||||
signal_set(i, SIG_DFL);
|
signal_set(i, SIG_DFL);
|
||||||
@ -2111,14 +2109,6 @@ int main(int argc, char **argv)
|
|||||||
goto return_main;
|
goto return_main;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mxs_log_start_flush_thr())
|
|
||||||
{
|
|
||||||
const char* logerr = "Failed to start log flushing thread.";
|
|
||||||
print_log_n_stderr(true, true, logerr, logerr, 0);
|
|
||||||
rc = MAXSCALE_INTERNALERROR;
|
|
||||||
goto return_main;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*<
|
/*<
|
||||||
* Start the routing workers running in their own thread.
|
* Start the routing workers running in their own thread.
|
||||||
*/
|
*/
|
||||||
@ -2206,8 +2196,6 @@ int main(int argc, char **argv)
|
|||||||
Worker::finish();
|
Worker::finish();
|
||||||
MessageQueue::finish();
|
MessageQueue::finish();
|
||||||
|
|
||||||
mxs_log_stop_flush_thr();
|
|
||||||
|
|
||||||
/*< Call finish on all modules. */
|
/*< Call finish on all modules. */
|
||||||
modules_process_finish();
|
modules_process_finish();
|
||||||
|
|
||||||
|
|||||||
@ -1,81 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _MAXSCALE_MLIST_H
|
|
||||||
#define _MAXSCALE_MLIST_H
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
||||||
*
|
|
||||||
* Change Date: 2022-01-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <maxscale/cdefs.h>
|
|
||||||
#include "skygw_utils.h"
|
|
||||||
|
|
||||||
MXS_BEGIN_DECLS
|
|
||||||
|
|
||||||
typedef struct mlist_node_st mlist_node_t;
|
|
||||||
|
|
||||||
typedef struct mlist_st
|
|
||||||
{
|
|
||||||
skygw_chk_t mlist_chk_top;
|
|
||||||
char* mlist_name;
|
|
||||||
void (*mlist_datadel)(void *); /**< clean-up function for data */
|
|
||||||
simple_mutex_t mlist_mutex; /**< protect node updates and clean-up */
|
|
||||||
bool mlist_uselock;
|
|
||||||
bool mlist_islocked;
|
|
||||||
bool mlist_deleted;
|
|
||||||
size_t mlist_nodecount;
|
|
||||||
size_t mlist_nodecount_max; /**< size limit. 0 == no limit */
|
|
||||||
volatile size_t mlist_versno;
|
|
||||||
bool mlist_flat;
|
|
||||||
mlist_node_t* mlist_first;
|
|
||||||
mlist_node_t* mlist_last;
|
|
||||||
skygw_chk_t mlist_chk_tail;
|
|
||||||
} mlist_t;
|
|
||||||
|
|
||||||
typedef struct mlist_cursor_st
|
|
||||||
{
|
|
||||||
skygw_chk_t mlcursor_chk_top;
|
|
||||||
mlist_t* mlcursor_list;
|
|
||||||
mlist_node_t* mlcursor_pos;
|
|
||||||
pthread_t* mlcursor_owner_thr;
|
|
||||||
skygw_chk_t mlcursor_chk_tail;
|
|
||||||
} mlist_cursor_t;
|
|
||||||
|
|
||||||
struct mlist_node_st
|
|
||||||
{
|
|
||||||
skygw_chk_t mlnode_chk_top;
|
|
||||||
mlist_t* mlnode_list;
|
|
||||||
mlist_node_t* mlnode_next;
|
|
||||||
void* mlnode_data;
|
|
||||||
bool mlnode_deleted;
|
|
||||||
skygw_chk_t mlnode_chk_tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
mlist_t* mlist_init(mlist_t* mlist,
|
|
||||||
mlist_cursor_t** cursor,
|
|
||||||
char* name,
|
|
||||||
void (*datadel)(void*),
|
|
||||||
int maxnodes);
|
|
||||||
void mlist_done(mlist_t* list);
|
|
||||||
bool mlist_add_data_nomutex(mlist_t* list, void* data);
|
|
||||||
bool mlist_add_node_nomutex(mlist_t* list, mlist_node_t* newnode);
|
|
||||||
mlist_node_t* mlist_detach_first(mlist_t* ml);
|
|
||||||
mlist_node_t* mlist_detach_nodes(mlist_t* ml);
|
|
||||||
void* mlist_node_get_data(mlist_node_t* node);
|
|
||||||
void mlist_node_done(mlist_node_t* n);
|
|
||||||
|
|
||||||
mlist_cursor_t* mlist_cursor_init(mlist_t* ml);
|
|
||||||
void* mlist_cursor_get_data_nomutex(mlist_cursor_t* c);
|
|
||||||
bool mlist_cursor_move_to_first(mlist_cursor_t* c);
|
|
||||||
|
|
||||||
MXS_END_DECLS
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,152 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _MAXSCALE_SKYGW_UTILS_H
|
|
||||||
#define _MAXSCALE_SKYGW_UTILS_H
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
||||||
*
|
|
||||||
* Change Date: 2022-01-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <maxscale/cdefs.h>
|
|
||||||
|
|
||||||
MXS_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define FSYNCLIMIT 10
|
|
||||||
|
|
||||||
#include <maxscale/debug.h>
|
|
||||||
|
|
||||||
#define DISKWRITE_LATENCY (5*MSEC_USEC)
|
|
||||||
|
|
||||||
typedef struct skygw_file_st skygw_file_t;
|
|
||||||
typedef struct skygw_thread_st skygw_thread_t;
|
|
||||||
typedef struct skygw_message_st skygw_message_t;
|
|
||||||
|
|
||||||
typedef struct simple_mutex_st
|
|
||||||
{
|
|
||||||
skygw_chk_t sm_chk_top;
|
|
||||||
pthread_mutex_t sm_mutex;
|
|
||||||
pthread_t sm_lock_thr;
|
|
||||||
bool sm_locked;
|
|
||||||
int sm_enabled; /**< defined as in to minimize mutexing */
|
|
||||||
bool sm_flat;
|
|
||||||
char* sm_name;
|
|
||||||
skygw_chk_t sm_chk_tail;
|
|
||||||
} simple_mutex_t;
|
|
||||||
|
|
||||||
typedef enum { THR_INIT, THR_RUNNING, THR_STOPPED, THR_DONE } skygw_thr_state_t;
|
|
||||||
typedef enum { MES_RC_FAIL, MES_RC_SUCCESS, MES_RC_TIMEOUT } skygw_mes_rc_t;
|
|
||||||
|
|
||||||
|
|
||||||
static const char* timestamp_formatstr = "%04d-%02d-%02d %02d:%02d:%02d ";
|
|
||||||
/** One for terminating '\0' */
|
|
||||||
static const size_t timestamp_len = (4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 3 + 1);
|
|
||||||
|
|
||||||
static const char* timestamp_formatstr_hp = "%04d-%02d-%02d %02d:%02d:%02d.%03d ";
|
|
||||||
/** One for terminating '\0' */
|
|
||||||
static const size_t timestamp_len_hp = (4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 3 + 3 + 1);
|
|
||||||
|
|
||||||
struct skygw_thread_st
|
|
||||||
{
|
|
||||||
skygw_chk_t sth_chk_top;
|
|
||||||
bool sth_must_exit;
|
|
||||||
simple_mutex_t* sth_mutex;
|
|
||||||
pthread_t sth_parent;
|
|
||||||
pthread_t sth_thr;
|
|
||||||
int sth_errno;
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
skygw_thr_state_t sth_state;
|
|
||||||
#endif
|
|
||||||
char* sth_name;
|
|
||||||
void* (*sth_thrfun)(void* data);
|
|
||||||
void* sth_data;
|
|
||||||
skygw_chk_t sth_chk_tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct skygw_message_st
|
|
||||||
{
|
|
||||||
skygw_chk_t mes_chk_top;
|
|
||||||
bool mes_sent;
|
|
||||||
pthread_mutex_t mes_mutex;
|
|
||||||
pthread_cond_t mes_cond;
|
|
||||||
skygw_chk_t mes_chk_tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct skygw_file_st
|
|
||||||
{
|
|
||||||
skygw_chk_t sf_chk_top;
|
|
||||||
char* sf_fname;
|
|
||||||
FILE* sf_file;
|
|
||||||
int sf_fd;
|
|
||||||
skygw_chk_t sf_chk_tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Skygw thread routines */
|
|
||||||
skygw_thread_t* skygw_thread_init(const char* name,
|
|
||||||
void* (*sth_thrfun)(void* data),
|
|
||||||
void* data);
|
|
||||||
void skygw_thread_done(skygw_thread_t* th);
|
|
||||||
int skygw_thread_start(skygw_thread_t* thr);
|
|
||||||
skygw_thr_state_t skygw_thread_get_state(skygw_thread_t* thr);
|
|
||||||
pthread_t skygw_thread_gettid(skygw_thread_t* thr);
|
|
||||||
|
|
||||||
size_t get_timestamp_len(void);
|
|
||||||
size_t get_timestamp_len_hp(void);
|
|
||||||
size_t snprint_timestamp(char* p_ts, size_t tslen);
|
|
||||||
size_t snprint_timestamp_hp(char* p_ts, size_t tslen);
|
|
||||||
|
|
||||||
void skygw_thread_set_state(skygw_thread_t* thr,
|
|
||||||
skygw_thr_state_t state);
|
|
||||||
void* skygw_thread_get_data(skygw_thread_t* thr);
|
|
||||||
bool skygw_thread_must_exit(skygw_thread_t* thr);
|
|
||||||
bool skygw_thread_set_exitflag(skygw_thread_t* thr,
|
|
||||||
skygw_message_t* sendmes,
|
|
||||||
skygw_message_t* recmes);
|
|
||||||
|
|
||||||
/** Skygw thread routines */
|
|
||||||
|
|
||||||
/** Skygw file routines */
|
|
||||||
typedef enum skygw_open_mode
|
|
||||||
{
|
|
||||||
SKYGW_OPEN_APPEND,
|
|
||||||
SKYGW_OPEN_TRUNCATE,
|
|
||||||
} skygw_open_mode_t;
|
|
||||||
|
|
||||||
skygw_file_t* skygw_file_alloc(const char* fname);
|
|
||||||
void skygw_file_free(skygw_file_t* file);
|
|
||||||
skygw_file_t* skygw_file_init(const char* fname,
|
|
||||||
const char* symlinkname,
|
|
||||||
skygw_open_mode_t mode);
|
|
||||||
void skygw_file_close(skygw_file_t* file);
|
|
||||||
int skygw_file_write(skygw_file_t* file,
|
|
||||||
void* data,
|
|
||||||
size_t nbytes,
|
|
||||||
bool flush);
|
|
||||||
/** Skygw file routines */
|
|
||||||
|
|
||||||
simple_mutex_t* simple_mutex_init(simple_mutex_t* mutexptr, const char* name);
|
|
||||||
int simple_mutex_done(simple_mutex_t* sm);
|
|
||||||
int simple_mutex_lock(simple_mutex_t* sm, bool block);
|
|
||||||
int simple_mutex_unlock(simple_mutex_t* sm);
|
|
||||||
|
|
||||||
/** Skygw message routines */
|
|
||||||
skygw_message_t* skygw_message_init(void);
|
|
||||||
void skygw_message_done(skygw_message_t* mes);
|
|
||||||
skygw_mes_rc_t skygw_message_send(skygw_message_t* mes);
|
|
||||||
void skygw_message_wait(skygw_message_t* mes);
|
|
||||||
skygw_mes_rc_t skygw_message_request(skygw_message_t* mes);
|
|
||||||
void skygw_message_reset(skygw_message_t* mes);
|
|
||||||
|
|
||||||
/** Skygw message routines */
|
|
||||||
|
|
||||||
size_t get_decimal_len(size_t s);
|
|
||||||
|
|
||||||
MXS_END_DECLS
|
|
||||||
|
|
||||||
#endif /* SKYGW_UTILS_H */
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,417 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
||||||
*
|
|
||||||
* Change Date: 2022-01-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "internal/mlist.h"
|
|
||||||
#include <maxscale/alloc.h>
|
|
||||||
|
|
||||||
static void mlist_free_memory(mlist_t* ml, char* name);
|
|
||||||
static mlist_node_t* mlist_node_init(void* data, mlist_cursor_t* cursor);
|
|
||||||
//static mlist_node_t* mlist_node_get_next(mlist_node_t* curr_node);
|
|
||||||
//static mlist_node_t* mlist_get_first(mlist_t* list);
|
|
||||||
//static mlist_cursor_t* mlist_get_cursor(mlist_t* list);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Cut off nodes of the list.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param ml - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return Pointer to the first of the detached nodes.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
mlist_node_t* mlist_detach_nodes(mlist_t* ml)
|
|
||||||
{
|
|
||||||
mlist_node_t* node;
|
|
||||||
CHK_MLIST(ml);
|
|
||||||
|
|
||||||
node = ml->mlist_first;
|
|
||||||
ml->mlist_first = NULL;
|
|
||||||
ml->mlist_last = NULL;
|
|
||||||
ml->mlist_nodecount = 0;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Create a list with rwlock and optional read-only cursor
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param listp - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param cursor - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param name - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return Address of mlist_t struct.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details Cursor must protect its reads with read lock, and after
|
|
||||||
* acquiring read lock reader must check whether the list is deleted
|
|
||||||
* (mlist_deleted).
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
mlist_t* mlist_init(mlist_t* listp, mlist_cursor_t** cursor, char* name,
|
|
||||||
void (*datadel)(void*), int maxnodes)
|
|
||||||
{
|
|
||||||
mlist_cursor_t* c;
|
|
||||||
mlist_t* list;
|
|
||||||
|
|
||||||
if (cursor != NULL)
|
|
||||||
{
|
|
||||||
ss_dassert(*cursor == NULL);
|
|
||||||
}
|
|
||||||
/** listp is not NULL if caller wants flat list */
|
|
||||||
if (listp == NULL)
|
|
||||||
{
|
|
||||||
list = (mlist_t*) MXS_CALLOC(1, sizeof (mlist_t));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/** Caller wants list flat, memory won't be freed */
|
|
||||||
list = listp;
|
|
||||||
list->mlist_flat = true;
|
|
||||||
}
|
|
||||||
ss_dassert(list != NULL);
|
|
||||||
|
|
||||||
if (list == NULL)
|
|
||||||
{
|
|
||||||
mlist_free_memory(list, name);
|
|
||||||
goto return_list;
|
|
||||||
}
|
|
||||||
list->mlist_chk_top = CHK_NUM_MLIST;
|
|
||||||
list->mlist_chk_tail = CHK_NUM_MLIST;
|
|
||||||
/** Set size limit for list. 0 means unlimited */
|
|
||||||
list->mlist_nodecount_max = maxnodes;
|
|
||||||
/** Set data deletion callback fun */
|
|
||||||
list->mlist_datadel = datadel;
|
|
||||||
|
|
||||||
if (name != NULL)
|
|
||||||
{
|
|
||||||
list->mlist_name = name;
|
|
||||||
}
|
|
||||||
/** Create mutex, return NULL if fails. */
|
|
||||||
if (simple_mutex_init(&list->mlist_mutex, "writebuf mutex") == NULL)
|
|
||||||
{
|
|
||||||
ss_dfprintf(stderr, "* Creating rwlock for mlist failed\n");
|
|
||||||
mlist_free_memory(list, name);
|
|
||||||
list = NULL;
|
|
||||||
goto return_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create cursor for reading the list */
|
|
||||||
if (cursor != NULL)
|
|
||||||
{
|
|
||||||
c = mlist_cursor_init(list);
|
|
||||||
|
|
||||||
if (c == NULL)
|
|
||||||
{
|
|
||||||
simple_mutex_done(&list->mlist_mutex);
|
|
||||||
mlist_free_memory(list, name);
|
|
||||||
list = NULL;
|
|
||||||
goto return_list;
|
|
||||||
}
|
|
||||||
CHK_MLIST_CURSOR(c);
|
|
||||||
*cursor = c;
|
|
||||||
}
|
|
||||||
list->mlist_versno = 2; /*< vresno != 0 means that list is initialized */
|
|
||||||
CHK_MLIST(list);
|
|
||||||
|
|
||||||
return_list:
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Free mlist memory allocations. name must be explicitly
|
|
||||||
* set if mlist has one.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param ml - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param name - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static void mlist_free_memory(mlist_t* ml, char* name)
|
|
||||||
{
|
|
||||||
mlist_node_t* node;
|
|
||||||
|
|
||||||
/** name */
|
|
||||||
if (name != NULL)
|
|
||||||
{
|
|
||||||
MXS_FREE(name);
|
|
||||||
}
|
|
||||||
if (ml != NULL)
|
|
||||||
{
|
|
||||||
/** list data */
|
|
||||||
while (ml->mlist_first != NULL)
|
|
||||||
{
|
|
||||||
/** Scan list and free nodes and data inside nodes */
|
|
||||||
node = ml->mlist_first->mlnode_next;
|
|
||||||
mlist_node_done(ml->mlist_first);
|
|
||||||
ml->mlist_first = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** list structure */
|
|
||||||
if (!ml->mlist_flat)
|
|
||||||
{
|
|
||||||
MXS_FREE(ml);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mlist_node_get_data(mlist_node_t* node)
|
|
||||||
{
|
|
||||||
CHK_MLIST_NODE(node);
|
|
||||||
return node->mlnode_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mlist_node_done(mlist_node_t* n)
|
|
||||||
{
|
|
||||||
CHK_MLIST_NODE(n);
|
|
||||||
if (n->mlnode_data != NULL)
|
|
||||||
{
|
|
||||||
if (n->mlnode_list->mlist_datadel != NULL)
|
|
||||||
{
|
|
||||||
(n->mlnode_list->mlist_datadel(n->mlnode_data));
|
|
||||||
}
|
|
||||||
MXS_FREE(n->mlnode_data);
|
|
||||||
}
|
|
||||||
MXS_FREE(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Mark list as deleted and free the memory.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param list - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void mlist_done(mlist_t* list)
|
|
||||||
{
|
|
||||||
CHK_MLIST(list);
|
|
||||||
simple_mutex_lock(&list->mlist_mutex, true);
|
|
||||||
list->mlist_deleted = true;
|
|
||||||
simple_mutex_unlock(&list->mlist_mutex);
|
|
||||||
simple_mutex_done(&list->mlist_mutex);
|
|
||||||
mlist_free_memory(list, list->mlist_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Adds data to list by allocating node for it. Checks list size limit.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param list - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param data - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return true, if succeed, false, if list had node limit and it is full.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
bool mlist_add_data_nomutex(mlist_t* list, void* data)
|
|
||||||
{
|
|
||||||
bool succp;
|
|
||||||
|
|
||||||
succp = mlist_add_node_nomutex(list, mlist_node_init(data, NULL));
|
|
||||||
|
|
||||||
return succp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static mlist_node_t* mlist_node_init(void* data, mlist_cursor_t* cursor)
|
|
||||||
{
|
|
||||||
mlist_node_t* node;
|
|
||||||
|
|
||||||
node = (mlist_node_t*) MXS_CALLOC(1, sizeof (mlist_node_t));
|
|
||||||
MXS_ABORT_IF_NULL(node);
|
|
||||||
node->mlnode_chk_top = CHK_NUM_MLIST_NODE;
|
|
||||||
node->mlnode_chk_tail = CHK_NUM_MLIST_NODE;
|
|
||||||
node->mlnode_data = data;
|
|
||||||
CHK_MLIST_NODE(node);
|
|
||||||
|
|
||||||
if (cursor != NULL)
|
|
||||||
{
|
|
||||||
cursor->mlcursor_pos = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
mlist_node_t* mlist_detach_first(mlist_t* ml)
|
|
||||||
{
|
|
||||||
mlist_node_t* node;
|
|
||||||
|
|
||||||
CHK_MLIST(ml);
|
|
||||||
node = ml->mlist_first;
|
|
||||||
CHK_MLIST_NODE(node);
|
|
||||||
ml->mlist_first = node->mlnode_next;
|
|
||||||
node->mlnode_next = NULL;
|
|
||||||
|
|
||||||
ml->mlist_nodecount -= 1;
|
|
||||||
if (ml->mlist_nodecount == 0)
|
|
||||||
{
|
|
||||||
ml->mlist_last = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CHK_MLIST_NODE(ml->mlist_first);
|
|
||||||
}
|
|
||||||
CHK_MLIST(ml);
|
|
||||||
|
|
||||||
return (node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Add new node to end of list if there is space for it.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param list - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param newnode - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param add_last - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return true, if succeede, false, if list size limit was exceeded.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
bool mlist_add_node_nomutex(mlist_t* list, mlist_node_t* newnode)
|
|
||||||
{
|
|
||||||
bool succp = false;
|
|
||||||
|
|
||||||
CHK_MLIST(list);
|
|
||||||
CHK_MLIST_NODE(newnode);
|
|
||||||
ss_dassert(!list->mlist_deleted);
|
|
||||||
|
|
||||||
/** List is full already. */
|
|
||||||
if (list->mlist_nodecount == list->mlist_nodecount_max)
|
|
||||||
{
|
|
||||||
goto return_succp;
|
|
||||||
}
|
|
||||||
/** Find location for new node */
|
|
||||||
if (list->mlist_last != NULL)
|
|
||||||
{
|
|
||||||
ss_dassert(!list->mlist_last->mlnode_deleted);
|
|
||||||
CHK_MLIST_NODE(list->mlist_last);
|
|
||||||
CHK_MLIST_NODE(list->mlist_first);
|
|
||||||
ss_dassert(list->mlist_last->mlnode_next == NULL);
|
|
||||||
list->mlist_last->mlnode_next = newnode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list->mlist_first = newnode;
|
|
||||||
}
|
|
||||||
list->mlist_last = newnode;
|
|
||||||
newnode->mlnode_list = list;
|
|
||||||
list->mlist_nodecount += 1;
|
|
||||||
succp = true;
|
|
||||||
return_succp:
|
|
||||||
CHK_MLIST(list);
|
|
||||||
return succp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mlist_cursor_t
|
|
||||||
*/
|
|
||||||
mlist_cursor_t* mlist_cursor_init(mlist_t* list)
|
|
||||||
{
|
|
||||||
CHK_MLIST(list);
|
|
||||||
mlist_cursor_t* c;
|
|
||||||
|
|
||||||
/** acquire shared lock to the list */
|
|
||||||
simple_mutex_lock(&list->mlist_mutex, true);
|
|
||||||
|
|
||||||
c = (mlist_cursor_t *) MXS_CALLOC(1, sizeof (mlist_cursor_t));
|
|
||||||
|
|
||||||
if (c == NULL)
|
|
||||||
{
|
|
||||||
simple_mutex_unlock(&list->mlist_mutex);
|
|
||||||
goto return_cursor;
|
|
||||||
}
|
|
||||||
c->mlcursor_chk_top = CHK_NUM_MLIST_CURSOR;
|
|
||||||
c->mlcursor_chk_tail = CHK_NUM_MLIST_CURSOR;
|
|
||||||
c->mlcursor_list = list;
|
|
||||||
|
|
||||||
/** Set cursor position if list is not empty */
|
|
||||||
if (list->mlist_first != NULL)
|
|
||||||
{
|
|
||||||
c->mlcursor_pos = list->mlist_first;
|
|
||||||
}
|
|
||||||
simple_mutex_unlock(&list->mlist_mutex);
|
|
||||||
|
|
||||||
CHK_MLIST_CURSOR(c);
|
|
||||||
|
|
||||||
return_cursor:
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mlist_cursor_get_data_nomutex(mlist_cursor_t* mc)
|
|
||||||
{
|
|
||||||
CHK_MLIST_CURSOR(mc);
|
|
||||||
return (mc->mlcursor_pos->mlnode_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mlist_cursor_move_to_first(mlist_cursor_t* mc)
|
|
||||||
{
|
|
||||||
bool succp = false;
|
|
||||||
mlist_t* list;
|
|
||||||
|
|
||||||
CHK_MLIST_CURSOR(mc);
|
|
||||||
list = mc->mlcursor_list;
|
|
||||||
CHK_MLIST(list);
|
|
||||||
simple_mutex_lock(&list->mlist_mutex, true);
|
|
||||||
|
|
||||||
if (mc->mlcursor_list->mlist_deleted)
|
|
||||||
{
|
|
||||||
simple_mutex_unlock(&list->mlist_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/** Set position point to first node */
|
|
||||||
mc->mlcursor_pos = list->mlist_first;
|
|
||||||
|
|
||||||
if (mc->mlcursor_pos != NULL)
|
|
||||||
{
|
|
||||||
CHK_MLIST_NODE(mc->mlcursor_pos);
|
|
||||||
succp = true;
|
|
||||||
}
|
|
||||||
simple_mutex_unlock(&list->mlist_mutex);
|
|
||||||
return succp;
|
|
||||||
}
|
|
||||||
@ -1,861 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
||||||
*
|
|
||||||
* Change Date: 2022-01-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PCRE2_CODE_UNIT_WIDTH
|
|
||||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <maxscale/debug.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include "internal/skygw_utils.h"
|
|
||||||
#include <maxscale/atomic.h>
|
|
||||||
#include <pcre2.h>
|
|
||||||
|
|
||||||
#if !defined(PATH_MAX)
|
|
||||||
# if defined(__USE_POSIX)
|
|
||||||
# define PATH_MAX _POSIX_PATH_MAX
|
|
||||||
# else
|
|
||||||
# define PATH_MAX 256
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void simple_mutex_free_memory(simple_mutex_t* sm);
|
|
||||||
static void thread_free_memory(skygw_thread_t* th, char* name);
|
|
||||||
/** End of static function declarations */
|
|
||||||
|
|
||||||
size_t get_timestamp_len(void)
|
|
||||||
{
|
|
||||||
return timestamp_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t get_timestamp_len_hp(void)
|
|
||||||
{
|
|
||||||
return timestamp_len_hp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Generate and write a timestamp to location passed as argument
|
|
||||||
* by using at most tslen characters.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param p_ts - in, use
|
|
||||||
* Write position in memory. Must be filled with at least
|
|
||||||
* <timestamp_len> zeroes
|
|
||||||
*
|
|
||||||
* @return Length of string written to p_ts. Length includes terminating '\0'.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
size_t snprint_timestamp(char* p_ts, size_t tslen)
|
|
||||||
{
|
|
||||||
time_t t;
|
|
||||||
struct tm tm;
|
|
||||||
size_t rval;
|
|
||||||
struct timeval tv;
|
|
||||||
if (p_ts == NULL)
|
|
||||||
{
|
|
||||||
rval = 0;
|
|
||||||
goto retblock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generate timestamp */
|
|
||||||
|
|
||||||
t = time(NULL);
|
|
||||||
localtime_r(&t, &tm);
|
|
||||||
snprintf(p_ts, tslen, timestamp_formatstr,
|
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
|
|
||||||
tm.tm_min, tm.tm_sec);
|
|
||||||
rval = strlen(p_ts) * sizeof (char);
|
|
||||||
retblock:
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Generate and write a timestamp to location passed as argument
|
|
||||||
* by using at most tslen characters. This will use millisecond precision.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param p_ts - in, use
|
|
||||||
* Write position in memory. Must be filled with at least
|
|
||||||
* <timestamp_len> zeroes
|
|
||||||
*
|
|
||||||
* @return Length of string written to p_ts. Length includes terminating '\0'.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
size_t snprint_timestamp_hp(char* p_ts, size_t tslen)
|
|
||||||
{
|
|
||||||
time_t t;
|
|
||||||
struct tm tm;
|
|
||||||
size_t rval;
|
|
||||||
struct timeval tv;
|
|
||||||
int usec;
|
|
||||||
if (p_ts == NULL)
|
|
||||||
{
|
|
||||||
rval = 0;
|
|
||||||
goto retblock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generate timestamp */
|
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
localtime_r(&tv.tv_sec, &tm);
|
|
||||||
usec = tv.tv_usec / 1000;
|
|
||||||
snprintf(p_ts, tslen, timestamp_formatstr_hp,
|
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec, usec);
|
|
||||||
rval = strlen(p_ts) * sizeof (char);
|
|
||||||
retblock:
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Initialize thread data structure
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param name copy is taken and stored to thread structure
|
|
||||||
*
|
|
||||||
* @param sth_thrfun - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param data thread data pointer
|
|
||||||
*
|
|
||||||
* @return thread pointer or NULL in case of failure
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
skygw_thread_t* skygw_thread_init(const char* name, void* (*sth_thrfun)(void* data),
|
|
||||||
void* data)
|
|
||||||
{
|
|
||||||
skygw_thread_t* th = (skygw_thread_t *) calloc(1, sizeof (skygw_thread_t));
|
|
||||||
|
|
||||||
if (th == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Memory allocation for thread failed\n");
|
|
||||||
goto return_th;
|
|
||||||
}
|
|
||||||
ss_dassert(th != NULL);
|
|
||||||
th->sth_chk_top = CHK_NUM_THREAD;
|
|
||||||
th->sth_chk_tail = CHK_NUM_THREAD;
|
|
||||||
th->sth_parent = pthread_self();
|
|
||||||
ss_debug(th->sth_state = THR_INIT);
|
|
||||||
th->sth_name = strndup(name, PATH_MAX);
|
|
||||||
th->sth_mutex = simple_mutex_init(NULL, name);
|
|
||||||
|
|
||||||
if (th->sth_mutex == NULL)
|
|
||||||
{
|
|
||||||
thread_free_memory(th, th->sth_name);
|
|
||||||
th = NULL;
|
|
||||||
goto return_th;
|
|
||||||
}
|
|
||||||
th->sth_thrfun = sth_thrfun;
|
|
||||||
th->sth_data = data;
|
|
||||||
CHK_THREAD(th);
|
|
||||||
|
|
||||||
return_th:
|
|
||||||
return th;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void thread_free_memory(skygw_thread_t* th, char* name)
|
|
||||||
{
|
|
||||||
free(name);
|
|
||||||
free(th);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Release skygw_thread data except filewriter.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param th - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details (write detailed description here)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void skygw_thread_done(skygw_thread_t* th)
|
|
||||||
{
|
|
||||||
if (th != NULL)
|
|
||||||
{
|
|
||||||
CHK_THREAD(th);
|
|
||||||
ss_dassert(th->sth_state == THR_STOPPED);
|
|
||||||
ss_debug(th->sth_state = THR_DONE);
|
|
||||||
simple_mutex_done(th->sth_mutex);
|
|
||||||
pthread_join(th->sth_thr, NULL);
|
|
||||||
thread_free_memory(th, th->sth_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_t skygw_thread_gettid(skygw_thread_t* thr)
|
|
||||||
{
|
|
||||||
CHK_THREAD(thr);
|
|
||||||
return thr->sth_thr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int skygw_thread_start(skygw_thread_t* thr)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
CHK_THREAD(thr);
|
|
||||||
err = pthread_create(&thr->sth_thr, NULL, thr->sth_thrfun, thr);
|
|
||||||
ss_dassert(err == 0);
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Starting file writer thread failed due error, %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
goto return_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return_err:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
|
|
||||||
skygw_thr_state_t skygw_thread_get_state(skygw_thread_t* thr)
|
|
||||||
{
|
|
||||||
CHK_THREAD(thr);
|
|
||||||
return thr->sth_state;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Update thread state
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param thr - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @param state - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details Thread must check state with mutex.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
|
|
||||||
void skygw_thread_set_state(skygw_thread_t* thr, skygw_thr_state_t state)
|
|
||||||
{
|
|
||||||
CHK_THREAD(thr);
|
|
||||||
simple_mutex_lock(thr->sth_mutex, true);
|
|
||||||
thr->sth_state = state;
|
|
||||||
simple_mutex_unlock(thr->sth_mutex);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Set exit flag for thread from other thread
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param thr - <usage>
|
|
||||||
* <description>
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details This call informs thread about exit flag and waits the response.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
bool skygw_thread_set_exitflag(skygw_thread_t* thr, skygw_message_t* sendmes,
|
|
||||||
skygw_message_t* recmes)
|
|
||||||
{
|
|
||||||
bool succp = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If thread struct pointer is NULL there's running thread
|
|
||||||
* neither.
|
|
||||||
*/
|
|
||||||
if (thr == NULL)
|
|
||||||
{
|
|
||||||
succp = true;
|
|
||||||
goto return_succp;
|
|
||||||
}
|
|
||||||
CHK_THREAD(thr);
|
|
||||||
CHK_MESSAGE(sendmes);
|
|
||||||
CHK_MESSAGE(recmes);
|
|
||||||
|
|
||||||
simple_mutex_lock(thr->sth_mutex, true);
|
|
||||||
succp = !thr->sth_must_exit;
|
|
||||||
thr->sth_must_exit = true;
|
|
||||||
simple_mutex_unlock(thr->sth_mutex);
|
|
||||||
|
|
||||||
/** Inform thread and wait for response */
|
|
||||||
if (succp)
|
|
||||||
{
|
|
||||||
skygw_message_send(sendmes);
|
|
||||||
skygw_message_wait(recmes);
|
|
||||||
}
|
|
||||||
|
|
||||||
ss_dassert(simple_mutex_lock(thr->sth_mutex, true) == 0);
|
|
||||||
ss_dassert(thr->sth_state == THR_STOPPED);
|
|
||||||
ss_dassert(simple_mutex_unlock(thr->sth_mutex) == 0);
|
|
||||||
|
|
||||||
return_succp:
|
|
||||||
return succp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* skygw_thread_get_data(skygw_thread_t* thr)
|
|
||||||
{
|
|
||||||
CHK_THREAD(thr);
|
|
||||||
return thr->sth_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool skygw_thread_must_exit(skygw_thread_t* thr)
|
|
||||||
{
|
|
||||||
CHK_THREAD(thr);
|
|
||||||
return thr->sth_must_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @node Create a simple_mutex structure which encapsulates pthread_mutex.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* @param mutexptr if mutex is initialized within caller's memory, this is
|
|
||||||
* the address for it. If mutex is flat, there is value, otherwise it is NULL.
|
|
||||||
*
|
|
||||||
* @param name name of mutex, passed argument is copied and pointer is stored
|
|
||||||
* to mutex struct.
|
|
||||||
*
|
|
||||||
* @return simple_mutex pointer or NULL in case of failure.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @details If mutex is flat, sm_enabled can be read if the memory is not freed.
|
|
||||||
* If flat mutex exists, sm_enabled is true.
|
|
||||||
* If mutex allocates its own memory, the pointer is NULL if mutex doesn't
|
|
||||||
* exist.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
simple_mutex_t* simple_mutex_init(simple_mutex_t* mutexptr, const char* name)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
simple_mutex_t* sm;
|
|
||||||
|
|
||||||
/** Copy pointer only if flat, allocate memory otherwise. */
|
|
||||||
if (mutexptr != NULL)
|
|
||||||
{
|
|
||||||
sm = mutexptr;
|
|
||||||
sm->sm_flat = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sm = (simple_mutex_t *) calloc(1, sizeof (simple_mutex_t));
|
|
||||||
}
|
|
||||||
ss_dassert(sm != NULL);
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
sm->sm_chk_top = CHK_NUM_SIMPLE_MUTEX;
|
|
||||||
sm->sm_chk_tail = CHK_NUM_SIMPLE_MUTEX;
|
|
||||||
#endif
|
|
||||||
sm->sm_name = strndup(name, PATH_MAX);
|
|
||||||
|
|
||||||
/** Create pthread mutex */
|
|
||||||
err = pthread_mutex_init(&sm->sm_mutex, NULL);
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Initializing simple mutex %s failed due error %d, %s\n",
|
|
||||||
name, err, mxs_strerror(errno));
|
|
||||||
perror("simple_mutex : ");
|
|
||||||
|
|
||||||
/** Write zeroes if flat, free otherwise. */
|
|
||||||
if (sm->sm_flat)
|
|
||||||
{
|
|
||||||
memset(sm, 0, sizeof (*sm));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
simple_mutex_free_memory(sm);
|
|
||||||
sm = NULL;
|
|
||||||
}
|
|
||||||
goto return_sm;
|
|
||||||
}
|
|
||||||
sm->sm_enabled = true;
|
|
||||||
CHK_SIMPLE_MUTEX(sm);
|
|
||||||
|
|
||||||
return_sm:
|
|
||||||
return sm;
|
|
||||||
}
|
|
||||||
|
|
||||||
int simple_mutex_done(simple_mutex_t* sm)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
CHK_SIMPLE_MUTEX(sm);
|
|
||||||
|
|
||||||
if (atomic_add(&sm->sm_enabled, -1) != 1)
|
|
||||||
{
|
|
||||||
atomic_add(&sm->sm_enabled, 1);
|
|
||||||
}
|
|
||||||
err = pthread_mutex_destroy(&sm->sm_mutex);
|
|
||||||
|
|
||||||
#if defined(NOT_USED)
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
perror("simple_mutex : ");
|
|
||||||
fprintf(stderr, "* Destroying simple mutex %s failed due %d, %s\n",
|
|
||||||
sm->sm_name, err, mxs_strerror(errno));
|
|
||||||
goto return_err;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
simple_mutex_free_memory(sm);
|
|
||||||
|
|
||||||
#if defined(NOT_USED)
|
|
||||||
return_err:
|
|
||||||
#endif
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void simple_mutex_free_memory(simple_mutex_t* sm)
|
|
||||||
{
|
|
||||||
if (sm->sm_name != NULL)
|
|
||||||
{
|
|
||||||
free(sm->sm_name);
|
|
||||||
}
|
|
||||||
if (!sm->sm_flat)
|
|
||||||
{
|
|
||||||
free(sm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int simple_mutex_lock(simple_mutex_t* sm, bool block)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Leaving the following serves as a reminder. It may assert
|
|
||||||
* any given time because sm_lock_thr is not protected.
|
|
||||||
*
|
|
||||||
* ss_dassert(sm->sm_lock_thr != pthread_self());
|
|
||||||
*/
|
|
||||||
if (block)
|
|
||||||
{
|
|
||||||
err = pthread_mutex_lock(&sm->sm_mutex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
err = pthread_mutex_trylock(&sm->sm_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Locking simple mutex %s failed due error, %d, %s\n",
|
|
||||||
sm->sm_name, err, mxs_strerror(errno));
|
|
||||||
perror("simple_mutex : ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Note that these updates are not protected.
|
|
||||||
*/
|
|
||||||
sm->sm_locked = true;
|
|
||||||
sm->sm_lock_thr = pthread_self();
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int simple_mutex_unlock(simple_mutex_t* sm)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
/**
|
|
||||||
* Leaving the following serves as a reminder. It may assert
|
|
||||||
* any given time because sm_lock_thr is not protected.
|
|
||||||
*
|
|
||||||
* ss_dassert(sm->sm_lock_thr == pthread_self());
|
|
||||||
*/
|
|
||||||
err = pthread_mutex_unlock(&sm->sm_mutex);
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Unlocking simple mutex %s failed due error %d, %s\n",
|
|
||||||
sm->sm_name, err, mxs_strerror(errno));
|
|
||||||
perror("simple_mutex : ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Note that these updates are not protected.
|
|
||||||
*/
|
|
||||||
sm->sm_locked = false;
|
|
||||||
sm->sm_lock_thr = 0;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
skygw_message_t* skygw_message_init(void)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
skygw_message_t* mes;
|
|
||||||
|
|
||||||
mes = (skygw_message_t*) calloc(1, sizeof (skygw_message_t));
|
|
||||||
|
|
||||||
if (mes == NULL)
|
|
||||||
{
|
|
||||||
err = 1;
|
|
||||||
goto return_mes;
|
|
||||||
}
|
|
||||||
mes->mes_chk_top = CHK_NUM_MESSAGE;
|
|
||||||
mes->mes_chk_tail = CHK_NUM_MESSAGE;
|
|
||||||
err = pthread_mutex_init(&(mes->mes_mutex), NULL);
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Initializing pthread mutex failed due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
free(mes);
|
|
||||||
mes = NULL;
|
|
||||||
goto return_mes;
|
|
||||||
}
|
|
||||||
err = pthread_cond_init(&(mes->mes_cond), NULL);
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Initializing pthread cond var failed, due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
pthread_mutex_destroy(&mes->mes_mutex);
|
|
||||||
free(mes);
|
|
||||||
mes = NULL;
|
|
||||||
goto return_mes;
|
|
||||||
}
|
|
||||||
CHK_MESSAGE(mes);
|
|
||||||
return_mes:
|
|
||||||
return mes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void skygw_message_done(skygw_message_t* mes)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If message struct pointer is NULL there's nothing to free.
|
|
||||||
*/
|
|
||||||
if (mes == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CHK_MESSAGE(mes);
|
|
||||||
err = pthread_cond_destroy(&(mes->mes_cond));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Destroying cond var failed due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
ss_dassert(err == 0);
|
|
||||||
err = pthread_mutex_destroy(&(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Destroying pthread mutex failed, due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
ss_dassert(err == 0);
|
|
||||||
free(mes);
|
|
||||||
}
|
|
||||||
|
|
||||||
skygw_mes_rc_t skygw_message_send(skygw_message_t* mes)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
skygw_mes_rc_t rc = MES_RC_FAIL;
|
|
||||||
|
|
||||||
CHK_MESSAGE(mes);
|
|
||||||
err = pthread_mutex_lock(&(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Locking pthread mutex failed, due to error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
goto return_mes_rc;
|
|
||||||
}
|
|
||||||
mes->mes_sent = true;
|
|
||||||
err = pthread_cond_signal(&(mes->mes_cond));
|
|
||||||
|
|
||||||
if (err == 0)
|
|
||||||
{
|
|
||||||
rc = MES_RC_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Signaling pthread cond var failed, due to error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
err = pthread_mutex_unlock(&(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Unlocking pthread mutex failed, due to error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
return_mes_rc:
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void skygw_message_wait(skygw_message_t* mes)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
CHK_MESSAGE(mes);
|
|
||||||
err = pthread_mutex_lock(&(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Locking pthread mutex failed, due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
ss_dassert(err == 0);
|
|
||||||
|
|
||||||
while (!mes->mes_sent)
|
|
||||||
{
|
|
||||||
err = pthread_cond_wait(&(mes->mes_cond), &(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Locking pthread cond wait failed, due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mes->mes_sent = false;
|
|
||||||
err = pthread_mutex_unlock(&(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Unlocking pthread mutex failed, due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
ss_dassert(err == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void skygw_message_reset(skygw_message_t* mes)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
CHK_MESSAGE(mes);
|
|
||||||
err = pthread_mutex_lock(&(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Locking pthread mutex failed, due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
goto return_mes_rc;
|
|
||||||
}
|
|
||||||
ss_dassert(err == 0);
|
|
||||||
mes->mes_sent = false;
|
|
||||||
err = pthread_mutex_unlock(&(mes->mes_mutex));
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Unlocking pthread mutex failed, due error %d, %s\n",
|
|
||||||
err, mxs_strerror(errno));
|
|
||||||
goto return_mes_rc;
|
|
||||||
}
|
|
||||||
return_mes_rc:
|
|
||||||
ss_dassert(err == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write data to a file.
|
|
||||||
*
|
|
||||||
* @param file write target
|
|
||||||
* @param data pointer to contiguous memory buffer
|
|
||||||
* @param nbytes amount of bytes to be written
|
|
||||||
* @param flush ensure that write is permanent
|
|
||||||
*
|
|
||||||
* @return 0 if succeed, errno if failed.
|
|
||||||
*/
|
|
||||||
int skygw_file_write(skygw_file_t* file, void* data, size_t nbytes, bool flush)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
size_t nwritten;
|
|
||||||
int fd;
|
|
||||||
static int writecount;
|
|
||||||
|
|
||||||
CHK_FILE(file);
|
|
||||||
|
|
||||||
nwritten = fwrite(data, nbytes, 1, file->sf_file);
|
|
||||||
|
|
||||||
if (nwritten != 1)
|
|
||||||
{
|
|
||||||
rc = errno;
|
|
||||||
perror("Logfile write.\n");
|
|
||||||
fprintf(stderr, "* Writing %ld bytes,\n%s\n to %s failed.\n",
|
|
||||||
nbytes, (char *) data, file->sf_fname);
|
|
||||||
goto return_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
writecount += 1;
|
|
||||||
|
|
||||||
if (flush || writecount == FSYNCLIMIT)
|
|
||||||
{
|
|
||||||
fd = fileno(file->sf_file);
|
|
||||||
fflush(file->sf_file);
|
|
||||||
fsync(fd);
|
|
||||||
writecount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = 0;
|
|
||||||
CHK_FILE(file);
|
|
||||||
return_rc:
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
skygw_file_t* skygw_file_alloc(const char* fname)
|
|
||||||
{
|
|
||||||
skygw_file_t* file;
|
|
||||||
|
|
||||||
if ((file = (skygw_file_t *) calloc(1, sizeof (skygw_file_t))) == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Error : Memory allocation for file %s failed.\n", fname);
|
|
||||||
perror("File allocation failed\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ss_dassert(file != NULL);
|
|
||||||
file->sf_chk_top = CHK_NUM_FILE;
|
|
||||||
file->sf_chk_tail = CHK_NUM_FILE;
|
|
||||||
file->sf_fname = strdup(fname);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
skygw_file_t* skygw_file_init(const char* fname,
|
|
||||||
const char* symlinkname,
|
|
||||||
skygw_open_mode_t mode)
|
|
||||||
{
|
|
||||||
skygw_file_t* file;
|
|
||||||
|
|
||||||
if ((file = skygw_file_alloc(fname)) == NULL)
|
|
||||||
{
|
|
||||||
/** Error was reported in skygw_file_alloc */
|
|
||||||
goto return_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* mode_string;
|
|
||||||
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case SKYGW_OPEN_TRUNCATE:
|
|
||||||
mode_string = "w";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ss_dassert(!true);
|
|
||||||
case SKYGW_OPEN_APPEND:
|
|
||||||
mode_string = "a";
|
|
||||||
};
|
|
||||||
|
|
||||||
if ((file->sf_file = fopen(file->sf_fname, mode_string)) == NULL)
|
|
||||||
{
|
|
||||||
int eno = errno;
|
|
||||||
errno = 0;
|
|
||||||
fprintf(stderr, "* Opening file %s failed due %d, %s.\n",
|
|
||||||
file->sf_fname, eno, mxs_strerror(eno));
|
|
||||||
free(file);
|
|
||||||
file = NULL;
|
|
||||||
goto return_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
setvbuf(file->sf_file, NULL, _IONBF, 0);
|
|
||||||
|
|
||||||
CHK_FILE(file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create symlink to newly created file if name was provided.
|
|
||||||
*/
|
|
||||||
if (symlinkname != NULL)
|
|
||||||
{
|
|
||||||
unlink(symlinkname);
|
|
||||||
int rc = symlink(fname, symlinkname);
|
|
||||||
|
|
||||||
if (rc != 0)
|
|
||||||
{
|
|
||||||
int eno = errno;
|
|
||||||
errno = 0;
|
|
||||||
fprintf(stderr, "failed to create symlink %s -> %s due %d, %s. Exiting.",
|
|
||||||
fname, symlinkname, eno, mxs_strerror(eno));
|
|
||||||
free(file);
|
|
||||||
file = NULL;
|
|
||||||
goto return_file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return_file:
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
void skygw_file_free(skygw_file_t* file)
|
|
||||||
{
|
|
||||||
if (file)
|
|
||||||
{
|
|
||||||
free(file->sf_fname);
|
|
||||||
free(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void skygw_file_close(skygw_file_t* file)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (file != NULL)
|
|
||||||
{
|
|
||||||
CHK_FILE(file);
|
|
||||||
|
|
||||||
fd = fileno(file->sf_file);
|
|
||||||
fsync(fd);
|
|
||||||
|
|
||||||
if ((err = fclose(file->sf_file)) != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "* Closing file %s failed due to %d, %s.\n",
|
|
||||||
file->sf_fname, errno, mxs_strerror(errno));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ss_dfprintf(stderr, "Closed %s\n", file->sf_fname);
|
|
||||||
skygw_file_free(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the number of decimal numbers from a size_t value.
|
|
||||||
*
|
|
||||||
* @param value value
|
|
||||||
*
|
|
||||||
* @return number of decimal numbers of which the value consists of
|
|
||||||
* value==123 returns 3, for example.
|
|
||||||
* @note Does the same as UINTLEN macro
|
|
||||||
*/
|
|
||||||
size_t get_decimal_len(
|
|
||||||
size_t value)
|
|
||||||
{
|
|
||||||
return value > 0 ? (size_t) log10((double) value) + 1 : 1;
|
|
||||||
}
|
|
||||||
@ -19,8 +19,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <maxscale/alloc.h>
|
#include <maxscale/alloc.h>
|
||||||
#include "../internal/skygw_utils.h"
|
|
||||||
#include <maxscale/log_manager.h>
|
#include <maxscale/log_manager.h>
|
||||||
|
#include <maxscale/debug.h>
|
||||||
|
|
||||||
static void skygw_log_enable(int priority)
|
static void skygw_log_enable(int priority)
|
||||||
{
|
{
|
||||||
@ -35,13 +35,8 @@ static void skygw_log_disable(int priority)
|
|||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
const char* logstr;
|
const char* logstr;
|
||||||
|
|
||||||
int i;
|
|
||||||
bool succp;
|
bool succp;
|
||||||
skygw_message_t* mes;
|
|
||||||
simple_mutex_t* mtx;
|
|
||||||
size_t nactive;
|
|
||||||
time_t t;
|
time_t t;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
char c;
|
char c;
|
||||||
|
|||||||
@ -109,7 +109,6 @@ bool run(const MXS_LOG_THROTTLING& throttling, int priority, size_t n_generate,
|
|||||||
cout << "Logging " << n_generate << " messages with throttling as " << throttling << "," << endl;
|
cout << "Logging " << n_generate << " messages with throttling as " << throttling << "," << endl;
|
||||||
|
|
||||||
mxs_log_set_throttling(&throttling); // Causes message to be logged.
|
mxs_log_set_throttling(&throttling); // Causes message to be logged.
|
||||||
mxs_log_flush_sync();
|
|
||||||
|
|
||||||
ifstream in(logfile.c_str());
|
ifstream in(logfile.c_str());
|
||||||
in.seekg(0, ios_base::end);
|
in.seekg(0, ios_base::end);
|
||||||
@ -145,8 +144,6 @@ bool run(const MXS_LOG_THROTTLING& throttling, int priority, size_t n_generate,
|
|||||||
ensure(rc == 0);
|
ensure(rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mxs_log_flush_sync();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < N_THREADS; ++i)
|
for (size_t i = 0; i < N_THREADS; ++i)
|
||||||
{
|
{
|
||||||
void* rv;
|
void* rv;
|
||||||
@ -247,7 +244,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
// 20 messages * N_THREADS, and since we are logging INFO messages, we should
|
// 20 messages * N_THREADS, and since we are logging INFO messages, we should
|
||||||
// get 20 * N_THREADS messages.
|
// get 20 * N_THREADS messages.
|
||||||
if (!run(t, LOG_INFO, 20, 20 * N_THREADS + 1)) // There will be 1 info message about log flushing.
|
if (!run(t, LOG_INFO, 20, 20 * N_THREADS))
|
||||||
{
|
{
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -539,15 +539,7 @@ struct subcommand shutdownoptions[] =
|
|||||||
|
|
||||||
static void sync_logs(DCB *dcb)
|
static void sync_logs(DCB *dcb)
|
||||||
{
|
{
|
||||||
if (mxs_log_flush_sync() == 0)
|
dcb_printf(dcb, "This command is deprecated: it does nothing.\n");
|
||||||
{
|
|
||||||
dcb_printf(dcb, "Logs flushed to disk\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dcb_printf(dcb, "Failed to flush logs to disk. Read the error log for "
|
|
||||||
"more details.\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct subcommand syncoptions[] =
|
struct subcommand syncoptions[] =
|
||||||
|
|||||||
Reference in New Issue
Block a user