Merge branch 'develop' into MAX-324

Conflicts:
	macros.cmake
	server/core/config.c
	server/core/service.c
	server/modules/routing/CMakeLists.txt
This commit is contained in:
Markus Makela 2015-02-24 06:26:55 +02:00
commit 9e7afeb302
36 changed files with 9590 additions and 308 deletions

View File

@ -137,7 +137,10 @@ if( NOT ( (DEFINED INSTALL_SYSTEM_FILES) AND ( NOT ( INSTALL_SYSTEM_FILES ) ) )
else()
configure_file(${CMAKE_SOURCE_DIR}/etc/init.d/maxscale.in ${CMAKE_BINARY_DIR}/maxscale @ONLY)
endif()
if(NOT PACKAGE)
if(PACKAGE)
message(STATUS "maxscale.conf will unpack to: /etc/ld.so.conf.d")
message(STATUS "startup scripts will unpack to to: /etc/init.d")
else()
install(FILES ${CMAKE_BINARY_DIR}/maxscale DESTINATION /etc/init.d
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(FILES ${CMAKE_BINARY_DIR}/maxscale.conf DESTINATION /etc/ld.so.conf.d
@ -263,3 +266,8 @@ add_custom_target(generate_html
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
-P generate-html.cmake
COMMENT "Generating HTML files" VERBATIM)
if(PACKAGE)
message(STATUS "You can install startup scripts and system configuration files for MaxScale by running the 'postinst' shell script located at ${CMAKE_INSTALL_PREFIX}.")
message(STATUS "To remove these installed files, run the 'postrm' shell script located in the same folder.")
endif()

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,8 @@
## Design Documents
- [Session Commands design (in development)](http://mariadb-corporation.github.io/MaxScale/Design-Documents/)
- [Core Objects Design (in development)](http://mariadb-corporation.github.io/MaxScale/Design-Documents/core-objects-html-docs)
- [Binlog Router Design (in development)](http://mariadb-corporation.github.io/MaxScale/Design-Documents/binlog-router-html-docs)
- [DCB States (to be replaced in StarUML)](Design-Documents/DCB-States.pdf)
## Earlier Release Notes

View File

@ -3,25 +3,25 @@ Configuration & Usage Scenarios
# Introduction
The purpose of this document is to describe how to configure MaxScale and to discuss some possible usage scenarios for MaxScale. MaxScale is designed with flexibility in mind, and consists of an event processing core with various support functions and plugin modules that tailor the behaviour of the MaxScale itself.
The purpose of this document is to describe how to configure MaxScale and to discuss some possible usage scenarios for MaxScale. MaxScale is designed with flexibility in mind, and consists of an event processing core with various support functions and plugin modules that tailor the behaviour of the MaxScale itself.
## Terms
Term | Description
-------------------|------------------
service | A service represents a set of databases with a specific access mechanism that is offered to clients of MaxScale. The access mechanism defines the algorithm that MaxScale will use to direct particular requests to the individual databases.
server | A server represents an individual database server to which a client can be connected via MaxScale.
router | A router is a module within MaxScale that will route client requests to the various database servers which MaxScale provides a service interface to.
connection routing | Connection routing is a method of handling requests in which MaxScale will accept connections from a client and route data on that connection to a single database using a single connection. Connection based routing will not examine individual requests on a connection and it will not move that connection once it is established.
statement routing | Statement routing is a method of handling requests in which each request within a connection will be handled individually. Requests may be sent to one or more servers and connections may be dynamically added or removed from the session.
protocol | A protocol is a module of software that is used to communicate with another software entity within the system. MaxScale supports the dynamic loading of protocol modules to allow for increased flexibility.
module | A module is a separate code entity that may be loaded dynamically into MaxScale to increase the available functionality. Modules are implemented as run-time loadable shared objects.
monitor | A monitor is a module that can be executed within MaxScale to monitor the state of a set of database. The use of an internal monitor is optional, monitoring may be performed externally to MaxScale.
listener | A listener is the network endpoint that is used to listen for connections to MaxScale from the client applications. A listener is associated to a single service, however a service may have many listeners.
connection failover| When a connection currently being used between MaxScale and the database server fails a replacement will be automatically created to another server by MaxScale without client intervention
backend database | A term used to refer to a database that sits behind MaxScale and is accessed by applications via MaxScale.
filter | A module that can be placed between the client and the MaxScale router module. All client data passes through the filter module and may be examined or modified by the filter modules. Filters may be chained together to form processing pipelines.
service | A service represents a set of databases with a specific access mechanism that is offered to clients of MaxScale. The access mechanism defines the algorithm that MaxScale will use to direct particular requests to the individual databases.
server | A server represents an individual database server to which a client can be connected via MaxScale.
router | A router is a module within MaxScale that will route client requests to the various database servers which MaxScale provides a service interface to.
connection routing | Connection routing is a method of handling requests in which MaxScale will accept connections from a client and route data on that connection to a single database using a single connection. Connection based routing will not examine individual requests on a connection and it will not move that connection once it is established.
statement routing | Statement routing is a method of handling requests in which each request within a connection will be handled individually. Requests may be sent to one or more servers and connections may be dynamically added or removed from the session.
protocol | A protocol is a module of software that is used to communicate with another software entity within the system. MaxScale supports the dynamic loading of protocol modules to allow for increased flexibility.
module | A module is a separate code entity that may be loaded dynamically into MaxScale to increase the available functionality. Modules are implemented as run-time loadable shared objects.
monitor | A monitor is a module that can be executed within MaxScale to monitor the state of a set of database. The use of an internal monitor is optional, monitoring may be performed externally to MaxScale.
listener | A listener is the network endpoint that is used to listen for connections to MaxScale from the client applications. A listener is associated to a single service, however a service may have many listeners.
connection failover| When a connection currently being used between MaxScale and the database server fails a replacement will be automatically created to another server by MaxScale without client intervention
backend database | A term used to refer to a database that sits behind MaxScale and is accessed by applications via MaxScale.
filter | A module that can be placed between the client and the MaxScale router module. All client data passes through the filter module and may be examined or modified by the filter modules. Filters may be chained together to form processing pipelines.
# Configuration
@ -125,7 +125,7 @@ router=readconnroute
router_options=master,slave
```
A more complete description of router options and what is available for a given router is included with the documentation of the router itself.
A more complete description of router options and what is available for a given router is included with the documentation of the router itself.
### `filters`
@ -217,7 +217,7 @@ This parameter enables matching of "127.0.0.1" (localhost) against "%" wildcard
This parameter sets a custom version string that is sent in the MySQL Handshake from MaxScale to clients.
Example:
Example:
```
version_string=5.5.37-MariaDB-RWsplit
@ -237,11 +237,11 @@ serversize=10
The service would then have the parameter weightby set. If there are 4 servers defined in the service, serverA, serverB, serverC and serverD, with the serversize set as shown in the table below, the connections would balanced using the percentages in this table.
Server |serversize|% connections
Server |serversize|% connections
---------|----------|-------------
serverA | 10 | 18%
serverB | 15 | 27%
serverC | 10 | 18%
serverA | 10 | 18%
serverB | 15 | 27%
serverC | 10 | 18%
serverD | 20 | 36%
### `auth_all_servers`
@ -254,6 +254,17 @@ The strip_db_esc parameter strips escape characters from database names of grant
This parameter takes a boolean value and when enabled, will strip all `\` characters from the database names.
### `connection_timeout`
The connection_timeout parameter is used to disconnect sessions to MaxScale that have been idle for too long. The session timeouts are disabled by default. To enable them, define the timeout in seconds in the service's configuration section.
Example:
```
[Test Service]
connection_timeout=300
```
## Server
Server sections are used to define the backend database servers that can be formed into a service. A server may be a member of one or more services within MaxScale. Servers are identified by a server name which is the section name in the configuration file. Servers have a type parameter of server, plus address port and protocol parameters.
@ -294,7 +305,7 @@ The monitor has a username and password that is used to connect to all servers f
monitorpw=mymonitorpasswd
```
The monpasswd parameter may be either a plain text password or it may be an encrypted password. See the section on encrypting passwords for use in the MaxScale.cnf file.
The monpasswd parameter may be either a plain text password or it may be an encrypted password. See the section on encrypting passwords for use in the MaxScale.cnf file.
## Listener
@ -303,10 +314,10 @@ The listener defines a port and protocol pair that is used to listen for connect
```
[<Listener name>]
type=listener
service=<Service name>]
protocol=[MySQLClient|HTTPD]
address=[IP|hostname]
port=<Listen port number>
service=<Service name>]
protocol=[MySQLClient|HTTPD]
address=[IP|hostname]
port=<Listen port number>
socket=<Socket path>
```
@ -356,7 +367,7 @@ passwd=6628C50E07CCE1F0392EDEEB9D1203F3
filters=QLA
```
![image alt text](images/image_10.png)
![image alt text](images/image_10.png)
See the Services section for more details on how to configure the various options of a service. Note that some filters require parsing of the statement which makes them compatible with statement-based routers only, such as Read/Write Split router.
@ -419,7 +430,7 @@ disable_master_failback=0
### `module`
The module parameter defines the name of the loadable module that implements the monitor. This module is loaded and executed on a separate thread within MaxScale.
The module parameter defines the name of the loadable module that implements the monitor. This module is loaded and executed on a separate thread within MaxScale.
### `servers`
@ -433,7 +444,7 @@ Individual servers may define override values for the user and password the moni
### `passwd`
The password parameter may be either a plain text password or it may be an encrypted password. See the section on encrypting passwords for use in the `MaxScale.cnf` file.
The password parameter may be either a plain text password or it may be an encrypted password. See the section on encrypting passwords for use in the `MaxScale.cnf` file.
### `monitor_interval`
@ -477,7 +488,7 @@ By default, if a node takes a lower index than the current master one the monito
The server status field may have the `SERVER_MASTER_STICKINESS` bit, meaning the current master selection is not based on the available rules but it's the one previously selected and then kept, accordingly to option value equal 1.
Anyway, a new master will be selected in case of current master failure, regardless the option value.
Anyway, a new master will be selected in case of current master failure, regardless the option value.
### `backend_connect_timeout`
@ -527,7 +538,7 @@ Connection based routing is a mechanism by which MaxScale will, for each incomin
## Statement Based Routing
Statement based routing is somewhat different, the routing modules examine every statement the client sends and determines, on a per statement basis, which of the set of backend servers in the service is best to execute the statement. This gives better dynamic balancing of the load within the cluster but comes at a cost. The query router must understand the statement that is being routed and may have to parse the statement in order to achieve this.
Statement based routing is somewhat different, the routing modules examine every statement the client sends and determines, on a per statement basis, which of the set of backend servers in the service is best to execute the statement. This gives better dynamic balancing of the load within the cluster but comes at a cost. The query router must understand the statement that is being routed and may have to parse the statement in order to achieve this.
Parsing within the router adds overhead to the cost of routing and makes this type of router best suitable for loads in which the gains outweigh this added cost. The added cost from statement parsing also gives the possibility to create and use new type of filters which are based on statement processing. In contrast to the added processing cost, statement-based routing may increase the performance of the cluster by offloading statements away from the master when possible.
@ -651,7 +662,7 @@ servers=server1,server2
user=monitor
passwd=monitor
[MySQL Cluster Service]
[MySQL Cluster Service]
type=service
router=readconnroute
router_options=ndb
@ -668,7 +679,7 @@ The `ndb` router option simply means: access all SQL nodes marked with NDB statu
### Read/Write Split Router
The Read/Write Split Router is implemented in readwritesplit module. It is a statement-based router that has been designed for use within Master/Slave replication environments. It examines and optionally parses every statement to find out whether the statement can be routed to slave instead of master.
The Read/Write Split Router is implemented in readwritesplit module. It is a statement-based router that has been designed for use within Master/Slave replication environments. It examines and optionally parses every statement to find out whether the statement can be routed to slave instead of master.
#### Starting a readwritesplit router session
@ -711,17 +722,19 @@ A third class of statements includes those which modify session data, such as se
Session commands include for example:
* `SET` statements
* `SET` statements
* `USE `*`<dbname>`*
* system/user-defined variable assignments embedded in read-only statements, such as `SELECT (@myvar := 5)`
* `PREPARE` statements
* `PREPARE` statements
* `QUIT`, `PING`, `STMT RESET`, `CHANGE USER`, etc. commands
**NOTE: if variable assignment is embedded in a write statement it is routed to _Master_ only. For example, `INSERT INTO t1 values(@myvar:=5, 7)` would be routed to _Master_ only.**
The router stores all of the executed session commands so that in case of a slave failure, a replacement slave can be chosen and the session command history can be repeated on that new slave. This means that the router stores each executed session command for the duration of the session. Applications that use long-running sessions might cause MaxScale to consume a growing amount of memory unless the sessions are closed. This can be solved by setting a connection timeout on the application side.
#### Configuring the Read/Write Split router
Read/Write Split router-specific settings are specified in the configuration file of MaxScale in its specific section. The section can be freely named but the name is used later as a reference from listener section.
Read/Write Split router-specific settings are specified in the configuration file of MaxScale in its specific section. The section can be freely named but the name is used later as a reference from listener section.
The configuration consists of mandatory and optional parameters.
@ -770,15 +783,15 @@ Please note max_slave_replication_lag must be greater than monitor interval.
where *<criteria>* is one of the following:
* `LEAST_GLOBAL_CONNECTIONS`, the slave with least connections in total
* `LEAST_ROUTER_CONNECTIONS`, the slave with least connections from this router
* `LEAST_BEHIND_MASTER`, the slave with smallest replication lag
* `LEAST_CURRENT_OPERATIONS` (default), the slave with least active operations
* `LEAST_ROUTER_CONNECTIONS`, the slave with least connections from this router
* `LEAST_BEHIND_MASTER`, the slave with smallest replication lag
* `LEAST_CURRENT_OPERATIONS` (default), the slave with least active operations
`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]
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:
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:
INSERT INTO test.t1 VALUES (@myid:=@myid+1)
@ -815,7 +828,7 @@ The client would merely connect to port 4044 on the MaxScale host and statements
#### Galera Cluster Configuration for Read/Write Split router
Galera monitor assigns Master and Slave roles to appropriate sync'ed Galera nodes. Using **readwritesplit** with Galera is seamless; the only change needed to the configuration above is replacing the list of MySQL replication servers with list of Galera nodes. With the same example as above:
Simply configure a RWSplit Service with Galera nodes:
@ -1188,7 +1201,7 @@ before being sent to the server. Note that the text in the match string is case-
## Tee Filter
The **tee** filter is a filter module for MaxScale that acts as a "plumbing" fitting in the MaxScale filter toolkit. It can be used in a filter pipeline of a service to make a copy of requests from the client and dispatch a copy of the request to another service within MaxScale.
The **tee** filter is a filter module for MaxScale that acts as a "plumbing" fitting in the MaxScale filter toolkit. It can be used in a filter pipeline of a service to make a copy of requests from the client and dispatch a copy of the request to another service within MaxScale.
The configuration block for the **tee** filter requires the minimal filter parameters in its section within the `MaxScale.cnf` file that defines the filter to load and the service to send the duplicates to.
@ -1336,4 +1349,3 @@ socket=/servers/maxscale/galera.sock
TCP/IP Traffic must be permitted to 192.1681.3.33 port 4408
For Unix socket, the socket file path (example: `/servers/maxscale/galera.sock`) must be writable by the Unix user MaxScale runs as.

View File

@ -1364,12 +1364,12 @@ int skygw_log_write_flush(
* Find out the length of log string (to be formatted str).
*/
va_start(valist, str);
len = vsnprintf(NULL, 0, str, valist);
len = sizeof(char) * vsnprintf(NULL, 0, str, valist);
va_end(valist);
/**
* Add one for line feed.
*/
len += 1;
len += sizeof(char);
/**
* Write log string to buffer and add to file write list.
*/

View File

@ -47,10 +47,10 @@ macro(set_variables)
# password of MaxScale user
set(TEST_PASSWORD "maxpwd" CACHE STRING "password of MaxScale user")
# Use static version of libmysqld
set(STATIC_EMBEDDED TRUE CACHE BOOL "Use static version of libmysqld")
# Build RabbitMQ components
set(BUILD_RABBITMQ FALSE CACHE BOOL "Build RabbitMQ components")

View File

@ -1219,7 +1219,8 @@ inline void add_str(char** buf, int* buflen, int* bufsize, char* str)
if(*buf)
strcat(*buf," ");
}
strcat(*buf,str);
if(*buf)
strcat(*buf,str);
*buflen += isize;
}

View File

@ -40,6 +40,7 @@
* internal router suppression of messages
* 30/10/14 Massimiliano Pinto Added disable_master_failback parameter
* 07/11/14 Massimiliano Pinto Addition of monitor timeouts for connect/read/write
* 20/02/15 Markus Mäkelä Added connection_timeout parameter for services
*
* @endverbatim
*/
@ -278,29 +279,41 @@ int error_count = 0;
char *user;
char *auth;
char *enable_root_user;
char *auth_all_servers;
char *connection_timeout;
char *auth_all_servers;
char *strip_db_esc;
char *weightby;
char *version_string;
bool is_rwsplit = false;
bool is_schemarouter = false;
char *allow_localhost_match_wildcard_host;
obj->element = service_alloc(obj->object, router);
user = config_get_value(obj->parameters, "user");
auth = config_get_value(obj->parameters, "passwd");
enable_root_user = config_get_value(
obj->parameters,
"enable_root_user");
auth_all_servers = config_get_value(
obj->parameters,
"auth_all_servers");
strip_db_esc = config_get_value(
obj->parameters,
"strip_db_esc");
connection_timeout =
config_get_value(
obj->parameters,
"connection_timeout");
auth_all_servers =
config_get_value(
obj->parameters,
"auth_all_servers");
strip_db_esc =
config_get_value(
obj->parameters,
"strip_db_esc");
allow_localhost_match_wildcard_host =
config_get_value(obj->parameters,
"localhost_match_wildcard_host");
weightby = config_get_value(obj->parameters, "weightby");
version_string = config_get_value(obj->parameters,
@ -310,14 +323,10 @@ int error_count = 0;
{
is_rwsplit = true;
}
else if (strncasecmp(router, "schemarouter", strlen("schemarouter")+1) == 0)
{
is_schemarouter = true;
}
else if(strncasecmp(router, "shardrouter", strlen("schemarouter")+1) == 0)
{
is_schemarouter = true;
}
char *allow_localhost_match_wildcard_host =
config_get_value(obj->parameters, "localhost_match_wildcard_host");
if (obj->element == NULL) /*< if module load failed */
{
LOGIF(LE, (skygw_log_write_flush(
@ -331,41 +340,36 @@ int error_count = 0;
continue; /*< process next obj */
}
if (version_string != NULL)
{
((SERVICE *)(obj->element))->version_string =
strdup(version_string);
}
else
{
if (gateway.version_string != NULL)
{
((SERVICE *)(obj->element))->version_string =
strdup(gateway.version_string);
}
if (version_string) {
((SERVICE *)(obj->element))->version_string = strdup(version_string);
} else {
if (gateway.version_string)
((SERVICE *)(obj->element))->version_string = strdup(gateway.version_string);
}
if (is_rwsplit)
{
max_slave_conn_str =
config_get_value(obj->parameters,
"max_slave_connections");
max_slave_rlag_str =
config_get_value(obj->parameters,
"max_slave_replication_lag");
}
max_slave_conn_str =
config_get_value(obj->parameters,
"max_slave_connections");
max_slave_rlag_str =
config_get_value(obj->parameters,
"max_slave_replication_lag");
if (enable_root_user)
serviceEnableRootUser(
obj->element,
config_truth_value(enable_root_user));
if(auth_all_servers)
serviceAuthAllServers(obj->element,
config_truth_value(auth_all_servers));
if (connection_timeout)
serviceSetTimeout(
obj->element,
atoi(connection_timeout));
if(auth_all_servers)
serviceAuthAllServers(obj->element,
config_truth_value(auth_all_servers));
if(strip_db_esc)
serviceStripDbEsc(obj->element,
config_truth_value(strip_db_esc));
serviceStripDbEsc(obj->element,
config_truth_value(strip_db_esc));
if (weightby)
serviceWeightBy(obj->element, weightby);
@ -380,7 +384,9 @@ int error_count = 0;
if (obj->element && user && auth)
{
serviceSetUser(obj->element, user, auth);
serviceSetUser(obj->element,
user,
auth);
}
else if (user && auth == NULL)
{
@ -392,7 +398,7 @@ int error_count = 0;
obj->object)));
}
/** Read, validate and set max_slave_connections */
if (is_rwsplit && max_slave_conn_str != NULL)
if (max_slave_conn_str != NULL)
{
CONFIG_PARAMETER* param;
bool succp;
@ -430,7 +436,7 @@ int error_count = 0;
}
}
/** Read, validate and set max_slave_replication_lag */
if (is_rwsplit && max_slave_rlag_str != NULL)
if (max_slave_rlag_str != NULL)
{
CONFIG_PARAMETER* param;
bool succp;
@ -466,58 +472,6 @@ int error_count = 0;
param->value)));
}
}
if(is_schemarouter)
{
CONFIG_PARAMETER* param = NULL;
char* subservices;
bool succp = true;
subservices =
config_get_value(obj->parameters,
"subservices");
if (subservices != NULL)
{
param = config_get_param(
obj->parameters,
"subservices");
if (param == NULL)
{
succp = false;
}
else
{
param->qfd.valstr = strdup(param->value);
param->qfd_param_type = STRING_TYPE;
succp = service_set_param_value(
obj->element,
param,
subservices,
COUNT_NONE,
STRING_TYPE);
}
}
if (!succp)
{
if(param){
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"* Warning : invalid value type "
"for parameter \'%s.%s = %s\'\n\tExpected "
"type is [master|all] for "
"use sql variables in.",
((SERVICE*)obj->element)->name,
param->name,
param->value)));
}else{
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"Error : parameter was NULL")));
}
}
}
/** Parameters for rwsplit router only */
if (is_rwsplit)
{
@ -1365,32 +1319,32 @@ SERVER *server;
char *user;
char *auth;
char *enable_root_user;
char* auth_all_servers;
char *connection_timeout;
char* auth_all_servers;
char* strip_db_esc;
char* max_slave_conn_str;
char* max_slave_rlag_str;
char* max_slave_conn_str;
char* max_slave_rlag_str;
char *version_string;
char *allow_localhost_match_wildcard_host;
enable_root_user = config_get_value(obj->parameters, "enable_root_user");
user = config_get_value(obj->parameters,
connection_timeout = config_get_value(obj->parameters, "connection_timeout");
user = config_get_value(obj->parameters,
"user");
auth = config_get_value(obj->parameters,
"passwd");
auth_all_servers = config_get_value(obj->parameters, "auth_all_servers");
strip_db_esc = config_get_value(obj->parameters, "strip_db_esc");
auth_all_servers = config_get_value(obj->parameters, "auth_all_servers");
strip_db_esc = config_get_value(obj->parameters, "strip_db_esc");
version_string = config_get_value(obj->parameters, "version_string");
allow_localhost_match_wildcard_host = config_get_value(obj->parameters, "localhost_match_wildcard_host");
allow_localhost_match_wildcard_host =
config_get_value(obj->parameters,
"localhost_match_wildcard_host");
if (version_string)
{
if (service->version_string)
{
if (version_string) {
if (service->version_string) {
free(service->version_string);
}
service->version_string = strdup(version_string);
@ -1402,10 +1356,16 @@ SERVER *server;
auth);
if (enable_root_user)
serviceEnableRootUser(service, atoi(enable_root_user));
if (connection_timeout)
serviceSetTimeout(service, atoi(connection_timeout));
if(auth_all_servers)
serviceAuthAllServers(service, atoi(auth_all_servers));
if(strip_db_esc)
serviceStripDbEsc(service, atoi(strip_db_esc));
if (allow_localhost_match_wildcard_host)
serviceEnableLocalhostMatchWildcardHost(
service,
@ -1484,24 +1444,21 @@ SERVER *server;
if (!succp)
{
if(param)
{
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"* Warning : invalid value type "
"for parameter \'%s.%s = %s\'\n\tExpected "
"type is <int> for maximum "
"slave replication lag.",
((SERVICE*)obj->element)->name,
param->name,
param->value)));
}
else
{
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"Error : parameter was NULL")));
}
if(param){
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"* Warning : invalid value type "
"for parameter \'%s.%s = %s\'\n\tExpected "
"type is <int> for maximum "
"slave replication lag.",
((SERVICE*)obj->element)->name,
param->name,
param->value)));
}else{
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"Error : parameter was NULL")));
}
}
}
}
@ -1510,53 +1467,58 @@ SERVER *server;
}
else
{
char *user;
char *user;
char *auth;
char *enable_root_user;
char *connection_timeout;
char *allow_localhost_match_wildcard_host;
char *auth_all_servers;
char *strip_db_esc;
char *auth_all_servers;
char *strip_db_esc;
enable_root_user =
config_get_value(obj->parameters,
"enable_root_user");
connection_timeout = config_get_value(obj->parameters,
"connection_timeout");
auth_all_servers =
config_get_value(obj->parameters,
"auth_all_servers");
strip_db_esc =
config_get_value(obj->parameters,
"strip_db_esc");
allow_localhost_match_wildcard_host =
config_get_value(obj->parameters,
"localhost_match_wildcard_host");
user = config_get_value(obj->parameters,
"user");
config_get_value(obj->parameters, "localhost_match_wildcard_host");
user = config_get_value(obj->parameters,
"user");
auth = config_get_value(obj->parameters,
"passwd");
"passwd");
obj->element = service_alloc(obj->object,
router);
router);
if (obj->element && user && auth)
{
serviceSetUser(obj->element,
user,
auth);
if (enable_root_user)
serviceEnableRootUser(obj->element,
atoi(enable_root_user));
if(auth_all_servers)
serviceAuthAllServers(obj->element, atoi(auth_all_servers));
if(strip_db_esc)
serviceStripDbEsc(obj->element, atoi(strip_db_esc));
serviceEnableRootUser(obj->element, atoi(enable_root_user));
if (connection_timeout)
serviceSetTimeout(obj->element, atoi(connection_timeout));
if (allow_localhost_match_wildcard_host)
serviceEnableLocalhostMatchWildcardHost(
obj->element,
atoi(allow_localhost_match_wildcard_host));
}
}
} /*< if router */
}
else
{
obj->element = NULL;
@ -1772,17 +1734,18 @@ static char *service_params[] =
"servers",
"user",
"passwd",
"enable_root_user",
"enable_root_user",
"connection_timeout",
"auth_all_servers",
"strip_db_esc",
"localhost_match_wildcard_host",
"strip_db_esc",
"localhost_match_wildcard_host",
"max_slave_connections",
"max_slave_replication_lag",
"use_sql_variables_in", /*< rwsplit only */
"subservices",
"version_string",
"filters",
"weightby",
"use_sql_variables_in", /*< rwsplit only */
"subservices",
"version_string",
"filters",
"weightby",
NULL
};

View File

@ -70,6 +70,7 @@
#include <skygw_utils.h>
#include <log_manager.h>
#include <hashtable.h>
#include <hk_heartbeat.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -816,6 +817,9 @@ int dcb_read(
n = 0;
goto return_n;
}
dcb->last_read = hkheartbeat;
bufsize = MIN(b, MAX_BUFFER_SIZE);
if ((buffer = gwbuf_alloc(bufsize)) == NULL)

View File

@ -632,7 +632,8 @@ static bool resolve_maxscale_homedir(
* 3. if /etc/MaxScale/MaxScale.cnf didn't exist or wasn't accessible, home
* isn't specified. Thus, try to access $PWD/MaxScale.cnf .
*/
tmp = strndup(getenv("PWD"), PATH_MAX);
char *pwd = getenv("PWD");
tmp = strndup(pwd ? pwd : "PWD_NOT_SET", PATH_MAX);
tmp2 = get_expanded_pathname(p_home_dir, tmp, default_cnf_fname);
free(tmp2); /*< full path isn't needed so simply free it */

View File

@ -57,6 +57,7 @@
#include <log_manager.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <housekeeper.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -250,7 +251,7 @@ GWPROTOCOL *funcs;
else
{
/* Save authentication data to file cache */
char *ptr, path[4096];
char *ptr, path[4097];
int mkdir_rval = 0;
strcpy(path, "/usr/local/skysql/MaxScale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
@ -431,6 +432,12 @@ int listeners = 0;
service->stats.started = time(0);
}
/** Add the task that monitors session timeouts */
if(service->conn_timeout > 0)
{
hktask_add("connection_timeout",session_close_timeouts,NULL,5);
}
return listeners;
}
@ -839,6 +846,25 @@ int serviceStripDbEsc(SERVICE* service, int action)
return 1;
}
/**
* Sets the session timeout for the service.
* @param service Service to configure
* @param val Timeout in seconds
* @return 1 on success, 0 when the value is invalid
*/
int
serviceSetTimeout(SERVICE *service, int val)
{
if(val < 0)
return 0;
service->conn_timeout = val;
return 1;
}
/**
* Trim whitespace from the from an rear of a string
*

View File

@ -42,6 +42,7 @@
#include <atomic.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <housekeeper.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -909,3 +910,35 @@ SESSION *get_all_sessions()
{
return allSessions;
}
/**
* Close sessions that have been idle for too long.
*
* If the time since a session last sent data is grater than the set value in the
* service, it is disconnected. The default value for the timeout for a service is 0.
* This means that connections are never timed out.
* @param data NULL, this is only here to satisfy the housekeeper function requirements.
*/
void session_close_timeouts(void* data)
{
SESSION* ses;
spinlock_acquire(&session_spin);
ses = get_all_sessions();
spinlock_release(&session_spin);
while(ses)
{
if(ses->client && ses->client->state == DCB_STATE_POLLING &&
ses->service->conn_timeout > 0 &&
hkheartbeat - ses->client->last_read > ses->service->conn_timeout * 10)
{
ses->client->func.hangup(ses->client);
}
spinlock_acquire(&session_spin);
ses = ses->next;
spinlock_release(&session_spin);
}
}

View File

@ -33,6 +33,17 @@
#include <maxscale_test.h>
#include <service.h>
#include <poll.h>
#include <dcb.h>
#include "housekeeper.h"
static bool success = false;
int hup(DCB* dcb)
{
success = true;
}
/**
* test1 Allocate a service and do lots of other things
*
@ -40,19 +51,24 @@
static int
test1()
{
SERVICE *service;
int result;
int argc = 3;
char buffer[1024];
sprintf(buffer,"%s",TEST_LOG_DIR);
char* argv[] = {
"log_manager",
"-j",
buffer,
NULL
SERVICE *service;
SESSION *session;
DCB *dcb;
int result;
int argc = 3;
char* argv[] =
{
"log_manager",
"-j",
TEST_LOG_DIR,
NULL
};
skygw_logmanager_init(argc,argv);
poll_init();
hkinit();
/* Service tests */
ss_dfprintf(stderr,
"testservice : creating service called MyService with router nonexistent");
@ -66,10 +82,10 @@ poll_init();
ss_info_dassert(NULL != service, "New service with valid router must not be null");
ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation");
ss_info_dassert(0 == strcmp("MyService", service_get_name(service)), "Service must have given name");
ss_dfprintf(stderr, "\t..done\nAdding protocol HTTPD.");
ss_info_dassert(0 != serviceAddProtocol(service, "HTTPD", "localhost", 9876), "Add Protocol should succeed");
ss_info_dassert(0 != serviceHasProtocol(service, "HTTPD", 9876), "Service should have new protocol as requested");
serviceStartProtocol(service, "HTTPD", 9876);
ss_dfprintf(stderr, "\t..done\nAdding protocol testprotocol.");
ss_info_dassert(0 != serviceAddProtocol(service, "testprotocol", "localhost", 9876), "Add Protocol should succeed");
ss_info_dassert(0 != serviceHasProtocol(service, "testprotocol", 9876), "Service should have new protocol as requested");
serviceStartProtocol(service, "testprotocol", 9876);
skygw_log_sync_all();
ss_dfprintf(stderr, "\t..done\nStarting Service.");
result = serviceStart(service);
@ -81,13 +97,41 @@ poll_init();
result = serviceStartAll();
skygw_log_sync_all();
ss_info_dassert(0 != result, "Start all should succeed");
ss_dfprintf(stderr, "\t..done\nTiming out a session.");
service->conn_timeout = 1;
result = serviceStart(service);
skygw_log_sync_all();
ss_info_dassert(0 != result, "Start should succeed");
result = serviceStop(service);
skygw_log_sync_all();
ss_info_dassert(0 != result, "Stop should succeed");
dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
ss_info_dassert(dcb != NULL, "DCB allocation failed");
session = session_alloc(service,dcb);
ss_info_dassert(session != NULL, "Session allocation failed");
session->client->state = DCB_STATE_POLLING;
session->client->func.hangup = hup;
sleep(15);
ss_info_dassert(success, "Session timeout failed");
ss_dfprintf(stderr, "\t..done\nStopping Service.");
ss_info_dassert(0 != serviceStop(service), "Stop should succeed");
ss_dfprintf(stderr, "\t..done\n");
/** This is never used in MaxScale and will always fail due to service's
* stats.n_current value never being decremented */
/*
ss_dfprintf(stderr, "\t..done\nFreeing Service.");
ss_info_dassert(0 != service_free(service), "Free should succeed");
ss_dfprintf(stderr, "\t..done\n");
*/
return 0;
}

View File

@ -261,7 +261,7 @@ typedef struct dcb {
SPINLOCK polloutlock;
int polloutbusy;
int writecheck;
time_t last_read; /*< Last time the DCB received data */
unsigned int high_water; /**< High water mark */
unsigned int low_water; /**< Low water mark */
struct server *server; /**< The associated backend server */

View File

@ -0,0 +1,11 @@
#ifndef _HK_HEARTBEAT_H
#define _HK_HEARTBEAT_H
/**
* The global housekeeper heartbeat value. This value is increamente
* every 100ms and may be used for crude timing etc.
*/
extern unsigned long hkheartbeat;
#endif

View File

@ -19,7 +19,7 @@
*/
#include <time.h>
#include <dcb.h>
#include <hk_heartbeat.h>
/**
* @file housekeeper.h A mechanism to have task run periodically
*
@ -52,12 +52,6 @@ typedef 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);

View File

@ -146,6 +146,7 @@ typedef struct service {
rate_limit; /**< The refresh rate limit for users table */
FILTER_DEF **filters; /**< Ordered list of filters */
int n_filters; /**< Number of filters */
int conn_timeout; /*< Session timeout in seconds */
char *weightby;
struct service *next; /**< The next service in the linked list */
} SERVICE;
@ -176,6 +177,7 @@ extern int serviceSetUser(SERVICE *, char *, char *);
extern int serviceGetUser(SERVICE *, char **, char **);
extern void serviceSetFilters(SERVICE *, char *);
extern int serviceEnableRootUser(SERVICE *, int );
extern int serviceSetTimeout(SERVICE *, int );
extern void serviceWeightBy(SERVICE *, char *);
extern char *serviceGetWeightingParameter(SERVICE *);
extern int serviceEnableLocalhostMatchWildcardHost(SERVICE *, int);

View File

@ -33,6 +33,7 @@
* 02-09-2013 Massimiliano Pinto Added session ref counter
* 29-05-2014 Mark Riddoch Support for filter mechanism
* added
* 20-02-2015 Markus Mäkelä Added session timeouts
*
* @endverbatim
*/
@ -167,5 +168,6 @@ 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);
void session_close_timeouts(void* data);
#endif

View File

@ -31,7 +31,7 @@
*/
#include <dcb.h>
#include <spinlock.h>
#include <housekeeper.h>
/**
* The telnetd specific protocol structure to put in the DCB.
*/

View File

@ -61,6 +61,7 @@
#include <users.h>
#include <dbusers.h>
#include <version.h>
#include <housekeeper.h>
#define GW_MYSQL_VERSION "MaxScale " MAXSCALE_VERSION
#define GW_MYSQL_LOOP_TIMEOUT 300000000

View File

@ -30,7 +30,7 @@
* @endverbatim
*/
#include <dcb.h>
#include <housekeeper.h>
/**
* The telnetd specific protocol structure to put in the DCB.
*/

View File

@ -42,7 +42,10 @@
#include <dcb.h>
#include <modinfo.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 void monitorMain(void *);

View File

@ -14,6 +14,11 @@ add_library(HTTPD SHARED httpd.c)
target_link_libraries(HTTPD log_manager utils)
install(TARGETS HTTPD DESTINATION modules)
if(BUILD_TESTS)
add_library(testprotocol SHARED testprotocol.c)
install(TARGETS testprotocol DESTINATION modules)
endif()
add_library(maxscaled SHARED maxscaled.c)
target_link_libraries(maxscaled log_manager utils)
install(TARGETS maxscaled DESTINATION modules)

View File

@ -144,6 +144,7 @@ char *password;
if ((n = dcb_read(dcb, &head)) != -1)
{
if (head)
{
unsigned char *ptr = GWBUF_DATA(head);

View File

@ -447,7 +447,7 @@ static int gw_read_backend_event(DCB *dcb) {
/* read available backend data */
rc = dcb_read(dcb, &read_buffer);
if (rc < 0)
{
GWBUF* errbuf;

View File

@ -576,6 +576,7 @@ int gw_read_client_event(
CHK_PROTOCOL(protocol);
rc = dcb_read(dcb, &read_buffer);
if (rc < 0)
{
dcb_close(dcb);

View File

@ -170,6 +170,9 @@ int gw_read_backend_handshake(
if ((n = dcb_read(dcb, &head)) != -1)
{
dcb->last_read = hkheartbeat;
if (head)
{
payload = GWBUF_DATA(head);
@ -420,6 +423,8 @@ int gw_receive_backend_auth(
n = dcb_read(dcb, &head);
dcb->last_read = hkheartbeat;
/*<
* Read didn't fail and there is enough data for mysql packet.
*/

View File

@ -156,6 +156,7 @@ char *password, *t;
if ((n = dcb_read(dcb, &head)) != -1)
{
if (head)
{
unsigned char *ptr = GWBUF_DATA(head);

View File

@ -0,0 +1,107 @@
/*
* This file is distributed as part of the MariaDB Corporation 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 Corporation Ab 2013-2014
*/
/**
* @file testprotocol.c - Testing protocol module
*
* Not intended for actual use. This protocol module does nothing useful and
* is only meant to test that the module loading works.
*
* @verbatim
* Revision History
* Date Who Description
* 20/02/2015 Markus Mäkelä Initial implementation
*
* @endverbatim
*/
#include <modinfo.h>
#include <dcb.h>
#include <buffer.h>
MODULE_INFO info = {
MODULE_API_PROTOCOL,
MODULE_IN_DEVELOPMENT,
GWPROTOCOL_VERSION,
"Test protocol"
};
static char *version_str = "V1.0.0";
static int test_read(DCB* dcb){ return 1;}
static int test_write(DCB *dcb, GWBUF* buf){ return 1;}
static int test_write_ready(DCB *dcb){ return 1;}
static int test_error(DCB *dcb){ return 1;}
static int test_hangup(DCB *dcb){ return 1;}
static int test_accept(DCB *dcb){ return 1;}
static int test_connect(struct dcb *dcb, struct server *srv, struct session *ses){ return 1;}
static int test_close(DCB *dcb){ return 1;}
static int test_listen(DCB *dcb, char *config){ return 1;}
static int test_auth(DCB* dcb, struct server *srv, struct session *ses, GWBUF *buf){ return 1;}
static int test_session(DCB *dcb, void* data){ return 1;}
/**
* The "module object" for the httpd protocol module.
*/
static GWPROTOCOL MyObject = {
test_read, /**< Read - EPOLLIN handler */
test_write, /**< Write - data from gateway */
test_write_ready, /**< WriteReady - EPOLLOUT handler */
test_error, /**< Error - EPOLLERR handler */
test_hangup, /**< HangUp - EPOLLHUP handler */
test_accept, /**< Accept */
test_connect, /**< Connect */
test_close, /**< Close */
test_listen, /**< Create a listener */
test_auth, /**< Authentication */
test_session /**< Session */
};
/**
* Implementation of the mandatory version entry point
*
* @return version string of the module
*/
char *
version()
{
return version_str;
}
/**
* The module initialisation routine, called when the module
* is first loaded.
*/
void
ModuleInit()
{
}
/**
* The module entry point routine. It is this routine that
* must populate the structure that is referred to as the
* "module object", this is a structure with the set of
* external entry points for this module.
*
* @return The module object
*/
GWPROTOCOL *
GetModuleObject()
{
return &MyObject;
}

View File

@ -1,5 +1,8 @@
if(BUILD_TESTS)
add_subdirectory(test)
add_library(testroute SHARED testroute.c)
target_link_libraries(testroute log_manager utils)
install(TARGETS testroute DESTINATION modules)
endif()
add_library(testroute SHARED testroute.c)

View File

@ -432,7 +432,7 @@ unsigned char *defuuid;
* Now start the replication from the master to MaxScale
*/
blr_start_master(inst);
free(name);
return (ROUTER *)inst;
}

View File

@ -668,7 +668,7 @@ GWBUF *
blr_cache_read_response(ROUTER_INSTANCE *router, char *response)
{
struct stat statb;
char path[4096], *ptr;
char path[4097], *ptr;
int fd;
GWBUF *buf;

View File

@ -142,6 +142,7 @@ GWBUF *buf;
sprintf(name, "%s Master", router->service->name);
hktask_oneshot(name, blr_start_master, router,
BLR_MASTER_BACKOFF_TIME * router->retry_backoff++);
free(name);
}
if (router->retry_backoff > BLR_MAX_BACKOFF)
router->retry_backoff = BLR_MAX_BACKOFF;
@ -203,11 +204,12 @@ GWBUF *ptr;
router->master_state = BLRM_UNCONNECTED;
if ((name = malloc(strlen(router->service->name)
+ strlen(" Master")+1)) != NULL);
+ strlen(" Master")+1)) != NULL)
{
sprintf(name, "%s Master", router->service->name);
hktask_oneshot(name, blr_start_master, router,
BLR_MASTER_BACKOFF_TIME * router->retry_backoff++);
free(name);
}
if (router->retry_backoff > BLR_MAX_BACKOFF)
router->retry_backoff = BLR_MAX_BACKOFF;
@ -283,10 +285,11 @@ blr_master_delayed_connect(ROUTER_INSTANCE *router)
char *name;
if ((name = malloc(strlen(router->service->name)
+ strlen(" Master Recovery")+1)) != NULL);
+ strlen(" Master Recovery")+1)) != NULL)
{
sprintf(name, "%s Master Recovery", router->service->name);
hktask_oneshot(name, blr_start_master, router, 60);
free(name);
}
}
@ -407,6 +410,7 @@ char query[128];
}
router->master_state = BLRM_HBPERIOD;
router->master->func.write(router->master, buf);
free(val);
break;
}
case BLRM_HBPERIOD:
@ -511,7 +515,7 @@ char query[128];
GWBUF_CONSUME_ALL(router->saved_master.select1);
router->saved_master.select1 = buf;
blr_cache_response(router, "select1", buf);
buf = blr_make_query("SELECT VERSION();");
buf = blr_make_query("SELECT VERSION()");
router->master_state = BLRM_SELECTVER;
router->master->func.write(router->master, buf);
break;
@ -521,7 +525,7 @@ char query[128];
GWBUF_CONSUME_ALL(router->saved_master.selectver);
router->saved_master.selectver = buf;
blr_cache_response(router, "selectver", buf);
buf = blr_make_query("SELECT @@version_comment limit 1;");
buf = blr_make_query("SELECT @@version_comment limit 1");
router->master_state = BLRM_SELECTVERCOM;
router->master->func.write(router->master, buf);
break;
@ -531,7 +535,7 @@ char query[128];
GWBUF_CONSUME_ALL(router->saved_master.selectvercom);
router->saved_master.selectvercom = buf;
blr_cache_response(router, "selectvercom", buf);
buf = blr_make_query("SELECT @@hostname;");
buf = blr_make_query("SELECT @@hostname");
router->master_state = BLRM_SELECTHOSTNAME;
router->master->func.write(router->master, buf);
break;
@ -541,7 +545,7 @@ char query[128];
GWBUF_CONSUME_ALL(router->saved_master.selecthostname);
router->saved_master.selecthostname = buf;
blr_cache_response(router, "selecthostname", buf);
buf = blr_make_query("SELECT @@max_allowed_packet;");
buf = blr_make_query("SELECT @@max_allowed_packet");
router->master_state = BLRM_MAP;
router->master->func.write(router->master, buf);
break;
@ -701,7 +705,7 @@ blr_handle_binlog_record(ROUTER_INSTANCE *router, GWBUF *pkt)
{
uint8_t *msg = NULL, *ptr, *pdata;
REP_HEADER hdr;
unsigned int len, reslen;
unsigned int len = 0, reslen;
unsigned int pkt_length;
int no_residual = 1;
int preslen = -1;

View File

@ -1371,7 +1371,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
GWBUF *head, *record;
REP_HEADER hdr;
int written, rval = 1, burst;
int rotating;
int rotating = 0;
unsigned long burst_size;
uint8_t *ptr;

View File

@ -3756,7 +3756,7 @@ static GWBUF* sescmd_cursor_process_replies(
dcb_close(bref->bref_dcb);
*reconnect = true;
if(replybuf)
gwbuf_free(replybuf);
gwbuf_consume(replybuf,gwbuf_length(replybuf));
}
}
/** This is a response from the master and it is the "right" one.

View File

@ -33,9 +33,16 @@ static void *newSession(ROUTER *instance, SESSION *session);
static void closeSession(ROUTER *instance, void *session);
static void freeSession(ROUTER *instance, void *session);
static int routeQuery(ROUTER *instance, void *session, GWBUF *queue);
static void clientReply(ROUTER *instance, void *session, GWBUF *queue);
static void diagnostic(ROUTER *instance, DCB *dcb);
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
static void handleError(
ROUTER *instance,
void *router_session,
GWBUF *errbuf,
DCB *backend_dcb,
error_action_t action,
bool *succp);
static ROUTER_OBJECT MyObject = {
createInstance,
@ -44,11 +51,17 @@ static ROUTER_OBJECT MyObject = {
freeSession,
routeQuery,
diagnostic,
NULL,
NULL,
clientReply,
handleError,
getCapabilities
};
typedef struct{
}TESTROUTER;
typedef struct{
}TESTSESSION;
/**
* Implementation of the mandatory version entry point
*
@ -96,7 +109,8 @@ GetModuleObject()
static ROUTER *
createInstance(SERVICE *service, char **options)
{
return NULL;
return (ROUTER*)malloc(sizeof(TESTROUTER));
}
/**
@ -109,7 +123,7 @@ createInstance(SERVICE *service, char **options)
static void *
newSession(ROUTER *instance, SESSION *session)
{
return NULL;
return (SESSION*)malloc(sizeof(TESTSESSION));
}
/**
@ -128,7 +142,7 @@ static void freeSession(
ROUTER* router_instance,
void* router_client_session)
{
return;
free(router_client_session);
}
static int
@ -137,6 +151,10 @@ routeQuery(ROUTER *instance, void *session, GWBUF *queue)
return 0;
}
void clientReply(ROUTER* instance, void* session, GWBUF* queue)
{
}
/**
* Diagnostics routine
*
@ -154,3 +172,14 @@ static uint8_t getCapabilities(
{
return 0;
}
static void handleError(
ROUTER *instance,
void *router_session,
GWBUF *errbuf,
DCB *backend_dcb,
error_action_t action,
bool *succp)
{
}