Merge branch 'develop' into 1.2.1-binlog_router_trx
This commit is contained in:
@ -75,12 +75,12 @@ There is a possibility for misbehavior; if `USE mytable` was executed in one of
|
||||
The above-mentioned behavior can be partially controller with the `use_sql_variables_in` configuration parameter.
|
||||
|
||||
```
|
||||
use_sql_variables_in=[master|all] (master)
|
||||
use_sql_variables_in=[master|all] (default: all)
|
||||
```
|
||||
|
||||
Server-side session variables are called as SQL variables. If "master" or no value is set, SQL variables are read and written in master only. Autocommit values and prepared statements are routed to all nodes always.
|
||||
Server-side session variables are called as SQL variables. If "master" is set, SQL variables are read and written in master only. Autocommit values and prepared statements are routed to all nodes always.
|
||||
|
||||
**NOTE**: If variable is written as a part of write query, it is treated like write query and not routed to all servers. For example, `INSERT INTO test.t1 VALUES (@myvar:= 7)` will be routed to the master and an error in the error log will be written.
|
||||
**NOTE**: If variable is written as a part of write query, it is treated like write query and not routed to all servers. For example, `INSERT INTO test.t1 VALUES (@myvar:= 7)` will not be routed and an error in the error log will be written. Add the `use_sql_variables_in=master` to the service definition to allow these queries.
|
||||
|
||||
#### Examples of session command limitations
|
||||
|
||||
|
@ -65,7 +65,7 @@ where *<criteria>* is one of the following:
|
||||
|
||||
**`use_sql_variables_in`** specifies where should queries, which read session variable, be routed. The syntax for `use_sql_variable_in` is:
|
||||
|
||||
use_sql_variables_in=[master|all]
|
||||
use_sql_variables_in=[master|all] (default: all)
|
||||
|
||||
When value all is used, queries reading session variables can be routed to any available slave (depending on selection criteria). Note, that queries modifying session variables are routed to all backend servers by default, excluding write queries with embedded session variable modifications, such as:
|
||||
|
||||
|
@ -86,6 +86,10 @@
|
||||
#include <ini.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#define STRING_BUFFER_SIZE 1024
|
||||
#define PIDFD_CLOSED -1
|
||||
|
||||
/** for procname */
|
||||
#if !defined(_GNU_SOURCE)
|
||||
@ -139,7 +143,7 @@ static char datadir[PATH_MAX+1] = "";
|
||||
static bool datadir_defined = false; /*< If the datadir was already set */
|
||||
/* The data directory we created for this gateway instance */
|
||||
static char pidfile[PATH_MAX+1] = "";
|
||||
|
||||
static int pidfd = PIDFD_CLOSED;
|
||||
|
||||
/**
|
||||
* exit flag for log flusher.
|
||||
@ -181,6 +185,7 @@ static void log_flush_shutdown(void);
|
||||
static void log_flush_cb(void* arg);
|
||||
static int write_pid_file(); /* write MaxScale pidfile */
|
||||
static void unlink_pidfile(void); /* remove pidfile */
|
||||
static void unlock_pidfile();
|
||||
static void libmysqld_done(void);
|
||||
static bool file_write_header(FILE* outfile);
|
||||
static bool file_write_footer(FILE* outfile);
|
||||
@ -207,7 +212,7 @@ static bool resolve_maxscale_conf_fname(
|
||||
|
||||
static char* check_dir_access(char* dirname,bool,bool);
|
||||
static int set_user();
|
||||
|
||||
bool pid_file_exists();
|
||||
/** SSL multi-threading functions and structures */
|
||||
|
||||
static SPINLOCK* ssl_locks;
|
||||
@ -1816,8 +1821,22 @@ int main(int argc, char **argv)
|
||||
"MaxScale is running in process %i",
|
||||
getpid())));
|
||||
|
||||
/** Check if a MaxScale process is already running */
|
||||
if(pid_file_exists())
|
||||
{
|
||||
/** There is a process with the PID of the maxscale.pid file running.
|
||||
* Assuming that this is an already running MaxScale process, we
|
||||
* should exit with an error code. */
|
||||
rc = MAXSCALE_ALREADYRUNNING;
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
/* Write process pid into MaxScale pidfile */
|
||||
write_pid_file();
|
||||
if(write_pid_file() != 0)
|
||||
{
|
||||
rc = MAXSCALE_ALREADYRUNNING;
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
/* Init MaxScale poll system */
|
||||
poll_init();
|
||||
@ -1922,6 +1941,7 @@ int main(int argc, char **argv)
|
||||
|
||||
unload_all_modules();
|
||||
/* Remove Pidfile */
|
||||
unlock_pidfile();
|
||||
unlink_pidfile();
|
||||
|
||||
return_main:
|
||||
@ -1983,6 +2003,21 @@ static void log_flush_cb(
|
||||
"Finished MaxScale log flusher.")));
|
||||
}
|
||||
|
||||
static void unlock_pidfile()
|
||||
{
|
||||
if(pidfd != PIDFD_CLOSED)
|
||||
{
|
||||
if(flock(pidfd,LOCK_UN|LOCK_NB) != 0)
|
||||
{
|
||||
char logbuf[STRING_BUFFER_SIZE + PATH_MAX];
|
||||
char* logerr = "Failed to unlock PID file '%s'.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pidfile);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
}
|
||||
close(pidfd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink pid file, called at program exit
|
||||
*/
|
||||
@ -2000,6 +2035,131 @@ static void unlink_pidfile(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the maxscale.pid file exists and has a valid PID in it. If one has already been
|
||||
* written and a MaxScale process is running, this instance of MaxScale should shut down.
|
||||
* @return True if the conditions for starting MaxScale are not met and false if
|
||||
* no PID file was found or there is no process running with the PID of the maxscale.pid
|
||||
* file. If false is returned, this process should continue normally.
|
||||
*/
|
||||
bool pid_file_exists()
|
||||
{
|
||||
char pathbuf[PATH_MAX+1];
|
||||
char logbuf[STRING_BUFFER_SIZE + PATH_MAX];
|
||||
char pidbuf[STRING_BUFFER_SIZE];
|
||||
pid_t pid;
|
||||
bool lock_failed = false;
|
||||
|
||||
snprintf(pathbuf, PATH_MAX, "%s/maxscale.pid",get_piddir());
|
||||
pathbuf[PATH_MAX] = '\0';
|
||||
|
||||
if(access(pathbuf,F_OK) != 0)
|
||||
return false;
|
||||
|
||||
if(access(pathbuf,R_OK) == 0)
|
||||
{
|
||||
int fd, b;
|
||||
|
||||
if((fd = open(pathbuf, O_RDWR)) == -1)
|
||||
{
|
||||
char* logerr = "Failed to open PID file '%s'.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pathbuf);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
return true;
|
||||
}
|
||||
if(flock(fd,LOCK_EX|LOCK_NB))
|
||||
{
|
||||
if(errno != EWOULDBLOCK)
|
||||
{
|
||||
char* logerr = "Failed to lock PID file '%s'.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pathbuf);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
lock_failed = true;
|
||||
}
|
||||
|
||||
pidfd = fd;
|
||||
b = read(fd,pidbuf,sizeof(pidbuf));
|
||||
|
||||
if(b == -1)
|
||||
{
|
||||
char* logerr = "Failed to read from PID file '%s'.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pathbuf);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
unlock_pidfile();
|
||||
return true;
|
||||
}
|
||||
else if(b == 0)
|
||||
{
|
||||
/** Empty file */
|
||||
char* logerr = "PID file read from '%s'. File was empty.\n"
|
||||
"If the file is the correct PID file and no other MaxScale processes "
|
||||
"are running, please remove it manually and start MaxScale again.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pathbuf);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
unlock_pidfile();
|
||||
return true;
|
||||
}
|
||||
|
||||
pidbuf[b < sizeof(pidbuf) ? b : sizeof(pidbuf) - 1] = '\0';
|
||||
pid = strtol(pidbuf,NULL,0);
|
||||
|
||||
if(pid < 1)
|
||||
{
|
||||
/** Bad PID */
|
||||
char* logerr = "PID file read from '%s'. File contents not valid.\n"
|
||||
"If the file is the correct PID file and no other MaxScale processes "
|
||||
"are running, please remove it manually and start MaxScale again.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pathbuf);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
unlock_pidfile();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(kill(pid,0) == -1)
|
||||
{
|
||||
if(errno == ESRCH)
|
||||
{
|
||||
/** no such process, old PID file */
|
||||
if(lock_failed)
|
||||
{
|
||||
char* logerr = "Locking the PID file '%s' failed. Read PID from file and no process found with PID %d. "
|
||||
"Confirm that no other process holds the lock on the PID file.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pathbuf,pid);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, 0);
|
||||
close(fd);
|
||||
}
|
||||
return lock_failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
char* logerr = "Failed to check the existence of process %d read from file '%s'";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pid,pathbuf);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
unlock_pidfile();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char* logerr = "MaxScale is already running. Process id: %d. "
|
||||
"Use another location for the PID file to run multiple instances of MaxScale on the same machine.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pid);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, 0);
|
||||
unlock_pidfile();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char* logerr = "Cannot open PID file '%s', no read permissions. "
|
||||
"Please confirm that the user running MaxScale has read permissions on the file.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pathbuf);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write process pid into pidfile anc close it
|
||||
* Parameters:
|
||||
@ -2009,33 +2169,58 @@ static void unlink_pidfile(void)
|
||||
*/
|
||||
|
||||
static int write_pid_file() {
|
||||
|
||||
int fd = -1;
|
||||
char logbuf[STRING_BUFFER_SIZE + PATH_MAX];
|
||||
char pidstr[STRING_BUFFER_SIZE];
|
||||
|
||||
snprintf(pidfile, PATH_MAX, "%s/maxscale.pid",get_piddir());
|
||||
|
||||
fd = open(pidfile, O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "MaxScale failed to open pidFile %s: error %d, %s\n", pidfile, errno, strerror(errno));
|
||||
return 1;
|
||||
} else {
|
||||
char pidstr[50]="";
|
||||
/* truncate pidfile content */
|
||||
if (ftruncate(fd, 0) == -1) {
|
||||
fprintf(stderr, "MaxScale failed to truncate pidfile %s: error %d, %s\n", pidfile, errno, strerror(errno));
|
||||
if(pidfd == PIDFD_CLOSED)
|
||||
{
|
||||
int fd = -1;
|
||||
|
||||
fd = open(pidfile, O_WRONLY | O_CREAT, 0777);
|
||||
if (fd == -1) {
|
||||
char* logerr = "Failed to open PID file '%s'.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pidfile);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(flock(fd,LOCK_EX|LOCK_NB))
|
||||
{
|
||||
if(errno == EWOULDBLOCK)
|
||||
{
|
||||
snprintf(logbuf,sizeof(logbuf),"Failed to lock PID file '%s', another process is holding a lock on it. "
|
||||
"Please confirm that no other MaxScale process is using the same PID file location.",pidfile);
|
||||
}
|
||||
|
||||
snprintf(pidstr, sizeof(pidstr)-1, "%d", getpid());
|
||||
|
||||
if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
|
||||
fprintf(stderr, "MaxScale failed to write into pidfile %s: error %d, %s\n", pidfile, errno, strerror(errno));
|
||||
/* close file and return */
|
||||
close(fd);
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
snprintf(logbuf,sizeof(logbuf),"Failed to lock PID file '%s'.",pidfile);
|
||||
}
|
||||
|
||||
/* close file */
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
pidfd = fd;
|
||||
}
|
||||
|
||||
/* truncate pidfile content */
|
||||
if (ftruncate(pidfd, 0)) {
|
||||
char* logerr = "MaxScale failed to truncate PID file '%s'.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pidfile);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
unlock_pidfile();
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(pidstr, sizeof(pidstr)-1, "%d", getpid());
|
||||
|
||||
if (pwrite(pidfd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
|
||||
char* logerr = "MaxScale failed to write into PID file '%s'.";
|
||||
snprintf(logbuf,sizeof(logbuf),logerr,pidfile);
|
||||
print_log_n_stderr(true, true, logbuf, logbuf, errno);
|
||||
unlock_pidfile();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* success */
|
||||
|
@ -67,7 +67,7 @@ int set_and_get_single_mysql_users_ipv4(char *username, unsigned long ipv4, char
|
||||
}
|
||||
if ((service = (SERVICE *)calloc(1, sizeof(SERVICE))) == NULL) {
|
||||
fprintf(stderr, "service_alloc() failed\n");
|
||||
dcb_free(dcb);
|
||||
dcb_close(dcb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ int set_and_get_single_mysql_users_ipv4(char *username, unsigned long ipv4, char
|
||||
fprintf(stderr, "Failed adding %s@%s(%lu)\n", username, ret_ip, fix_ipv4);
|
||||
users_free(mysql_users);
|
||||
free(service);
|
||||
dcb_free(dcb);
|
||||
dcb_close(dcb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ int set_and_get_single_mysql_users_ipv4(char *username, unsigned long ipv4, char
|
||||
|
||||
users_free(mysql_users);
|
||||
free(service);
|
||||
dcb_free(dcb);
|
||||
dcb_close(dcb);
|
||||
|
||||
if (!fetch_data)
|
||||
return 1;
|
||||
@ -198,7 +198,7 @@ int set_and_get_mysql_users_wildcards(char *username, char *hostname, char *pass
|
||||
}
|
||||
if ((service = (SERVICE *)calloc(1, sizeof(SERVICE))) == NULL) {
|
||||
fprintf(stderr, "service_alloc() failed\n");
|
||||
dcb_free(dcb);
|
||||
dcb_close(dcb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -208,7 +208,7 @@ int set_and_get_mysql_users_wildcards(char *username, char *hostname, char *pass
|
||||
if(!setipaddress(&client_addr.sin_addr, from)) {
|
||||
fprintf(stderr, "setipaddress failed for host [%s]\n", from);
|
||||
free(service);
|
||||
dcb_free(dcb);
|
||||
dcb_close(dcb);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -216,7 +216,7 @@ int set_and_get_mysql_users_wildcards(char *username, char *hostname, char *pass
|
||||
if ((data = (MYSQL_session *) calloc(1, sizeof(MYSQL_session))) == NULL) {
|
||||
fprintf(stderr, "MYSQL_session alloc failed\n");
|
||||
free(service);
|
||||
dcb_free(dcb);
|
||||
dcb_close(dcb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ int set_and_get_mysql_users_wildcards(char *username, char *hostname, char *pass
|
||||
else
|
||||
strncpy(data->db, "",MYSQL_DATABASE_MAXLEN);
|
||||
|
||||
/* freed by dcb_free(dcb) */
|
||||
/* freed by dcb_close(dcb) */
|
||||
dcb->data = data;
|
||||
|
||||
// the routine returns 1 on success
|
||||
@ -264,7 +264,7 @@ int set_and_get_mysql_users_wildcards(char *username, char *hostname, char *pass
|
||||
|
||||
users_free(mysql_users);
|
||||
free(service);
|
||||
dcb_free(dcb);
|
||||
dcb_close(dcb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -63,6 +63,9 @@ static char* server_groups[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int config_load(char *);
|
||||
int module_create_feedback_report(GWBUF **buffer, MODULES *modules, FEEDBACK_CONF *cfg);
|
||||
int do_http_post(GWBUF *buffer, void *cfg);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
@ -37,7 +37,7 @@
|
||||
#define MAXSCALE_BADCONFIG 1 /* Configuration fiel error */
|
||||
#define MAXSCALE_NOLIBRARY 2 /* No embedded library found */
|
||||
#define MAXSCALE_NOSERVICES 3 /* No servics are running */
|
||||
#define MAXSCALE_HOMELESS 4 /* No MaxScale Home */
|
||||
#define MAXSCALE_ALREADYRUNNING 4 /* MaxScale is already runing */
|
||||
#define MAXSCALE_BADARG 5 /* Bad command line argument */
|
||||
#define MAXSCALE_INTERNALERROR 6 /* Internal error, see error log */
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user