Fix in-source builds

The internal header directory conflicted with in-source builds causing a
build failure. This is fixed by renaming the internal header directory to
something other than maxscale.

The renaming pointed out a few problems in a couple of source files that
appeared to include internal headers when the headers were in fact public
headers.

Fixed maxctrl in-source builds by making the copying of the sources
optional.
This commit is contained in:
Markus Mäkelä
2017-11-22 08:12:09 +02:00
parent 6054fa0957
commit 396b81f336
74 changed files with 135 additions and 129 deletions

View File

@ -0,0 +1,121 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <string>
#include <microhttpd.h>
#include <maxscale/thread.h>
class Client
{
Client(const Client&);
Client& operator=(const Client&);
public:
enum state
{
OK,
FAILED,
INIT,
CLOSED
};
/**
* @brief Create a new client
*
* @param connection The connection handle for this client
*/
Client(MHD_Connection *connection):
m_connection(connection),
m_state(INIT)
{
}
~Client()
{
}
/**
* @brief Process a client request
*
* This function can be called multiple times if a PUT/POST/PATCH
* uploads a large amount of data.
*
* @param url Requested URL
* @param method Request method
* @param data Pointer to request data
* @param size Size of request data
*
* @return MHD_YES on success, MHD_NO on error
*/
int process(std::string url, std::string method, const char* data, size_t *size);
/**
* @brief Authenticate the client
*
* @param connection The MHD connection object
* @param url Requested URL
* @param method The request method
*
* @return True if authentication was successful
*/
bool auth(MHD_Connection* connection, const char* url, const char* method);
/**
* Get client state
*
* @return The client state
*/
state get_state() const
{
return m_state;
}
/**
* Close the client connection
*
* All further requests will be rejected immediately
*/
void close()
{
m_state = CLOSED;
}
private:
MHD_Connection* m_connection; /**< Connection handle */
std::string m_data; /**< Uploaded data */
state m_state; /**< Client state */
};
/**
* @brief Start the administrative interface
*
* @return True if the interface was successfully started
*/
bool mxs_admin_init();
/**
* @brief Shutdown the administrative interface
*/
void mxs_admin_shutdown();
/**
* @brief Check if admin interface uses HTTPS protocol
*
* @return True if HTTPS is enabled
*/
bool mxs_admin_https_enabled();

View File

@ -0,0 +1,166 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file core/maxscale/config.h - The private config interface
*/
#include <maxscale/config.h>
#include <maxscale/ssl.h>
#include <maxscale/jansson.h>
MXS_BEGIN_DECLS
#define DEFAULT_NBPOLLS 3 /**< Default number of non block polls before we block */
#define DEFAULT_POLLSLEEP 1000 /**< Default poll wait time (milliseconds) */
#define DEFAULT_NTHREADS 1 /**< Default number of polling threads */
#define DEFAULT_QUERY_RETRIES 0 /**< Number of retries for interrupted queries */
#define DEFAULT_QUERY_RETRY_TIMEOUT 5 /**< Timeout for query retries */
/**
* Maximum length for configuration parameter value.
*/
enum
{
MAX_PARAM_LEN = 256
};
/** Object type specific parameter name lists */
extern const char *config_service_params[];
extern const char *config_listener_params[];
extern const char *config_monitor_params[];
extern const char *config_filter_params[];
extern const char *config_server_params[];
/**
* Set the defaults for the global configuration options
*/
void config_set_global_defaults();
/**
* @brief Generate default module parameters
*
* Adds any default parameters to @c ctx that aren't already in it.
*
* @param ctx Configuration context where the parameters are added
* @param params Module parameters
*/
void config_add_defaults(CONFIG_CONTEXT *ctx, const MXS_MODULE_PARAM *params);
char* config_clean_string_list(const char* str);
MXS_CONFIG_PARAMETER* config_clone_param(const MXS_CONFIG_PARAMETER* param);
bool config_load(const char *);
void config_parameter_free(MXS_CONFIG_PARAMETER* p1);
/**
* @brief Creates an empty configuration context
*
* @param section Context name
* @return New context or NULL on memory allocation failure
*/
CONFIG_CONTEXT* config_context_create(const char *section);
/**
* @brief Free a configuration context
*
* @param context The context to free
*/
void config_context_free(CONFIG_CONTEXT *context);
/**
* @brief Add a parameter to a configuration context
*
* @param obj Context where the parameter should be added
* @param key Key to add
* @param value Value for the key
* @return True on success, false on memory allocation error
*/
bool config_add_param(CONFIG_CONTEXT* obj, const char* key, const char* value);
/**
* @brief Append to an existing parameter
*
* @param obj Configuration context
* @param key Parameter name
* @param value Value to append to the parameter
* @return True on success, false on memory allocation error
*/
bool config_append_param(CONFIG_CONTEXT* obj, const char* key, const char* value);
/**
* @brief Replace an existing parameter
*
* @param obj Configuration context
* @param key Parameter name
* @param value Parameter value
* @return True on success, false on memory allocation error
*/
bool config_replace_param(CONFIG_CONTEXT* obj, const char* key, const char* value);
/**
* @brief Construct an SSL structure
*
* The SSL structure is used by both listeners and servers.
*
* TODO: Rename to something like @c config_construct_ssl
*
* @param obj Configuration context
* @param require_cert Whether certificates are required
* @param error_count Pointer to an int which is incremented for each error
* @return New SSL_LISTENER structure or NULL on error
*/
SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj, bool require_cert, int *error_count);
/**
* @brief Check if all SSL parameters are defined
*
* Helper function to check whether all of the required SSL parameters are defined
* in the configuration context. The checked parameters are 'ssl', 'ssl_key',
* 'ssl_cert' and 'ssl_ca_cert'. The 'ssl' parameter must also have a value of
* 'required'.
*
* @param obj Configuration context
* @return True if all required parameters are present
*/
bool config_have_required_ssl_params(CONFIG_CONTEXT *obj);
/**
* @brief Add non-standard module type parameters to a JSON object
*
* @param mod Module whose parameters are inspected
* @param parameters List of configuration parameters for the module
* @param type_params NULL terminated list of default module type parameters
* @param output Output JSON object where the parameters are added
*/
void config_add_module_params_json(const MXS_MODULE* mod,
MXS_CONFIG_PARAMETER* parameters,
const char** type_params,
json_t* output);
/**
* @brief Convert section names to new format
*
* @param section Section name to fix
*/
void fix_section_name(char *section);
/**
* @brief Serialize global options
*
* @return True if options were serialized successfully
*/
bool config_global_serialize();
MXS_END_DECLS

View File

@ -0,0 +1,337 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file config_runtime.h - Functions for runtime configuration modifications
*/
#include <maxscale/cdefs.h>
#include <maxscale/adminusers.h>
#include <maxscale/monitor.h>
#include <maxscale/server.h>
#include <maxscale/service.h>
MXS_BEGIN_DECLS
/**
* @brief Create a new server
*
* This function creates a new, persistent server by first allocating a new
* server and then storing the resulting configuration file on disk. This
* function should be used only from administrative interface modules and internal
* modules should use server_alloc() instead.
*
* @param name Server name
* @param address Network address
* @param port Network port
* @param protocol Protocol module name
* @param authenticator Authenticator module name
* @param options Options for the authenticator module
* @return True on success, false if an error occurred
*/
bool runtime_create_server(const char *name, const char *address,
const char *port, const char *protocol,
const char *authenticator, const char *options);
/**
* @brief Destroy a server
*
* This removes any created server configuration files and marks the server removed
* If the server is not in use.
*
* @param server Server to destroy
* @return True if server was destroyed
*/
bool runtime_destroy_server(SERVER *server);
/**
* @brief Link a server to an object
*
* This function links the server to another object. The target can be either
* a monitor or a service.
*
* @param server Server to link
* @param target The monitor or service where the server is added
* @return True if the object was found and the server was linked to it, false
* if no object matching @c target was found
*/
bool runtime_link_server(SERVER *server, const char *target);
/**
* @brief Unlink a server from an object
*
* This function unlinks the server from another object. The target can be either
* a monitor or a service.
*
* @param server Server to unlink
* @param target The monitor or service from which the server is removed
* @return True if the object was found and the server was unlinked from it, false
* if no object matching @c target was found
*/
bool runtime_unlink_server(SERVER *server, const char *target);
/**
* @brief Alter server parameters
*
* @param server Server to alter
* @param key Key to modify
* @param value New value
* @return True if @c key was one of the supported parameters
*/
bool runtime_alter_server(SERVER *server, const char *key, const char *value);
/**
* @brief Enable SSL for a server
*
* The @c key , @c cert and @c ca parameters are required. @c version and @c depth
* are optional.
*
* @note SSL cannot be disabled at runtime.
*
* @param server Server to configure
* @param key Path to SSL private key
* @param cert Path to SSL public certificate
* @param ca Path to certificate authority
* @param version Required SSL Version
* @param depth Certificate verification depth
* @return True if SSL was successfully enabled
*/
bool runtime_enable_server_ssl(SERVER *server, const char *key, const char *cert,
const char *ca, const char *version, const char *depth);
/**
* @brief Alter monitor parameters
*
* @param monitor Monitor to alter
* @param key Key to modify
* @param value New value
* @return True if @c key was one of the supported parameters
*/
bool runtime_alter_monitor(MXS_MONITOR *monitor, const char *key, const char *value);
/**
* @brief Alter service parameters
*
* @param monitor Service to alter
* @param key Key to modify
* @param value New value
*
* @return True if @c key was one of the supported parameters
*/
bool runtime_alter_service(SERVICE *service, const char* zKey, const char* zValue);
/**
* @brief Alter MaxScale parameters
*
* @param name Key to modify
* @param value New value
*
* @return True if @c key was one of the supported parameters
*/
bool runtime_alter_maxscale(const char* name, const char* value);
/**
* @brief Create a new listener for a service
*
* This function adds a new listener to a service and starts it.
*
* @param service Service where the listener is added
* @param name Name of the listener
* @param addr Listening address, NULL for default of ::
* @param port Listening port, NULL for default of 3306
* @param proto Listener protocol, NULL for default of "MySQLClient"
* @param auth Listener authenticator, NULL for protocol default authenticator
* @param auth_opt Options for the authenticator, NULL for no options
* @param ssl_key SSL key, NULL for no key
* @param ssl_cert SSL cert, NULL for no cert
* @param ssl_ca SSL CA cert, NULL for no CA cert
* @param ssl_version SSL version, NULL for default of "MAX"
* @param ssl_depth SSL cert verification depth, NULL for default
*
* @return True if the listener was successfully created and started
*/
bool runtime_create_listener(SERVICE *service, const char *name, const char *addr,
const char *port, const char *proto, const char *auth,
const char *auth_opt, const char *ssl_key,
const char *ssl_cert, const char *ssl_ca,
const char *ssl_version, const char *ssl_depth);
/**
* @brief Destroy a listener
*
* This disables the listener by removing it from the polling system. It also
* removes any generated configurations for this listener.
*
* @param service Service where the listener exists
* @param name Name of the listener
*
* @return True if the listener was successfully destroyed
*/
bool runtime_destroy_listener(SERVICE *service, const char *name);
/**
* @brief Create a new monitor
*
* @param name Name of the monitor
* @param module Monitor module
* @return True if new monitor was created and persisted
*/
bool runtime_create_monitor(const char *name, const char *module);
/**
* @brief Destroy a monitor
*
* Monitors are not removed from the runtime configuration but they are stopped.
* Destroyed monitor are removed after a restart.
*
* @param monitor Monitor to destroy
* @return True if monitor was destroyed
*/
bool runtime_destroy_monitor(MXS_MONITOR *monitor);
/**
* @brief Create a new server from JSON
*
* @param json JSON defining the server
*
* @return Created server or NULL on error
*/
SERVER* runtime_create_server_from_json(json_t* json);
/**
* @brief Alter a server using JSON
*
* @param server Server to alter
* @param new_json JSON definition of the updated server
*
* @return True if the server was successfully modified to represent @c new_json
*/
bool runtime_alter_server_from_json(SERVER* server, json_t* new_json);
/**
* @brief Alter server relationships
*
* @param server Server to alter
* @param type Type of the relation, either @c services or @c monitors
* @param json JSON that defines the relationship data
*
* @return True if the relationships were successfully modified
*/
bool runtime_alter_server_relationships_from_json(SERVER* server, const char* type, json_t* json);
/**
* @brief Create a new monitor from JSON
*
* @param json JSON defining the monitor
*
* @return Created monitor or NULL on error
*/
MXS_MONITOR* runtime_create_monitor_from_json(json_t* json);
/**
* @brief Alter a monitor using JSON
*
* @param monitor Monitor to alter
* @param new_json JSON definition of the updated monitor
*
* @return True if the monitor was successfully modified to represent @c new_json
*/
bool runtime_alter_monitor_from_json(MXS_MONITOR* monitor, json_t* new_json);
/**
* @brief Alter monitor relationships
*
* @param monitor Monitor to alter
* @param json JSON that defines the new relationships
*
* @return True if the relationships were successfully modified
*/
bool runtime_alter_monitor_relationships_from_json(MXS_MONITOR* monitor, json_t* json);
/**
* @brief Alter a service using JSON
*
* @param service Service to alter
* @param new_json JSON definition of the updated service
*
* @return True if the service was successfully modified to represent @c new_json
*/
bool runtime_alter_service_from_json(SERVICE* service, json_t* new_json);
/**
* @brief Alter service relationships
*
* @param service Service to alter
* @param json JSON that defines the new relationships
*
* @return True if the relationships were successfully modified
*/
bool runtime_alter_service_relationships_from_json(SERVICE* service, json_t* json);
/**
* @brief Create a listener from JSON
*
* @param service Service where the listener is created
* @param json JSON definition of the new listener
*
* @return True if the listener was successfully created and started
*/
bool runtime_create_listener_from_json(SERVICE* service, json_t* json);
/**
* @brief Alter logging options using JSON
*
* @param json JSON definition of the updated logging options
*
* @return True if the modifications were successful
*/
bool runtime_alter_logs_from_json(json_t* json);
/**
* @brief Get current runtime error in JSON format
*
* @return The latest runtime error in JSON format or NULL if no error has occurred
*/
json_t* runtime_get_json_error();
/**
* @brief Create a new user account
*
* @param json JSON defining the user
*
* @return True if the user was successfully created
*/
bool runtime_create_user_from_json(json_t* json);
/**
* @brief Remove admin user
*
* @param id Username of the network user
* @param type USER_TYPE_INET for network user and USER_TYPE_UNIX for enabled accounts
*
* @return True if user was successfully removed
*/
bool runtime_remove_user(const char* id, enum user_type type);
/**
* @brief Alter core MaxScale parameters from JSON
*
* @param new_json JSON defining the new core parameters
*
* @return True if the core parameters are valid and were successfully applied
*/
bool runtime_alter_maxscale_from_json(json_t* new_json);
MXS_END_DECLS

View File

@ -0,0 +1,22 @@
#pragma once
/*
* 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: 2020-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/dcb.h>
MXS_BEGIN_DECLS
void dcb_free_all_memory(DCB *dcb);
void dcb_final_close(DCB *dcb);
MXS_END_DECLS

View File

@ -0,0 +1,99 @@
#pragma once
/*
* 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: 2020-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 <unistd.h>
MXS_BEGIN_DECLS
#define MAXSCALE_EXTCMD_ARG_MAX 256
typedef struct extern_cmd_t
{
char** argv; /**< Argument vector for the command, first being the
* actual command being executed */
int n_exec; /**< Number of times executed */
pid_t child; /**< PID of the child process */
uint32_t timeout; /**< Command timeout in seconds */
} EXTERNCMD;
char* externcmd_extract_command(const char* argstr);
/**
* Allocate a new external command.
*
* The name and parameters are copied into the external command structure so
* the original memory can be freed if needed.
*
* @param command Command to execute with the parameters
* @param timeout Command timeout in seconds
*
* @return Pointer to new external command struct or NULL if an error occurred
*/
EXTERNCMD* externcmd_allocate(const char* argstr, uint32_t timeout);
/**
* Free a previously allocated external command
*
* @param cmd Command to free
*/
void externcmd_free(EXTERNCMD* cmd);
/**
* Execute a command
*
* The output of the command must be freed by the caller by calling MXS_FREE.
*
* @param cmd Command to execute
*
* @return The return value of the executed command or -1 on error
*/
int externcmd_execute(EXTERNCMD* cmd);
/**
* Substitute all occurrences of @c match with @c replace in the arguments for @c cmd
*
* @param cmd External command
* @param match Match string
* @param replace Replacement string
*
* @return True if replacement was successful, false on error
*/
bool externcmd_substitute_arg(EXTERNCMD* cmd, const char* re, const char* replace);
/**
* Check if a command can be executed
*
* Checks if the file being executed exists and if the current user has execution
* permissions on the file.
*
* @param argstr Command to check, can contain arguments for the command
*
* @return True if the file was found and the use has execution permissions to it
*/
bool externcmd_can_execute(const char* argstr);
/**
* Simple matching of string and command
*
* @param cmd Command where the match is searched from
* @param match String to search for
*
* @return True if the string matched
*/
bool externcmd_matches(const EXTERNCMD* cmd, const char* match);
MXS_END_DECLS

View File

@ -0,0 +1,51 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file core/maxscale/filter.h - The private filter interface
*/
#include <maxscale/filter.h>
MXS_BEGIN_DECLS
/**
* The definition of a filter from the configuration file.
* This is basically the link between a plugin to load and the
* options to pass to that plugin.
*/
struct mxs_filter_def
{
char *name; /**< The Filter name */
char *module; /**< The module to load */
char **options; /**< The options set for this filter */
MXS_CONFIG_PARAMETER *parameters; /**< The filter parameters */
MXS_FILTER* filter; /**< The runtime filter */
MXS_FILTER_OBJECT *obj; /**< The "MODULE_OBJECT" for the filter */
SPINLOCK spin; /**< Spinlock to protect the filter definition */
struct mxs_filter_def *next; /**< Next filter in the chain of all filters */
};
void filter_add_option(MXS_FILTER_DEF *filter_def, const char *option);
void filter_add_parameter(MXS_FILTER_DEF *filter_def, const char *name, const char *value);
MXS_FILTER_DEF *filter_alloc(const char *name, const char *module_name);
MXS_DOWNSTREAM *filter_apply(MXS_FILTER_DEF *filter_def, MXS_SESSION *session, MXS_DOWNSTREAM *downstream);
void filter_free(MXS_FILTER_DEF *filter_def);
bool filter_load(MXS_FILTER_DEF *filter_def);
int filter_standard_parameter(const char *name);
MXS_UPSTREAM *filter_upstream(MXS_FILTER_DEF *filter_def,
MXS_FILTER_SESSION *fsession,
MXS_UPSTREAM *upstream);
MXS_END_DECLS

View File

@ -0,0 +1,296 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <deque>
#include <map>
#include <string>
#include <tr1/memory>
#include <cstdint>
#include <microhttpd.h>
#include <maxscale/jansson.hh>
#include <maxscale/utils.hh>
#include <maxscale/http.hh>
// The API version part of the URL
#define MXS_REST_API_VERSION "v1"
static int value_iterator(void *cls,
enum MHD_ValueKind kind,
const char *key,
const char *value)
{
std::pair<std::string, std::string>* cmp = (std::pair<std::string, std::string>*)cls;
if (strcasecmp(cmp->first.c_str(), key) == 0 && value)
{
cmp->second = value;
return MHD_NO;
}
return MHD_YES;
}
static int value_sum_iterator(void *cls,
enum MHD_ValueKind kind,
const char *key,
const char *value)
{
size_t& count = *(size_t*)cls;
count++;
return MHD_YES;
}
static int value_copy_iterator(void *cls,
enum MHD_ValueKind kind,
const char *key,
const char *value)
{
std::string k = key;
if (value)
{
k += "=";
k += value;
}
char**& dest = *(char***) cls;
*dest = MXS_STRDUP_A(k.c_str());
dest++;
return MHD_YES;
}
class HttpRequest
{
HttpRequest(const HttpRequest&);
HttpRequest& operator = (const HttpRequest);
public:
/**
* @brief Parse a request
*
* @param request Request to parse
*
* @return Parsed statement or NULL if request is not valid
*/
HttpRequest(struct MHD_Connection *connection, std::string url, std::string method, json_t* data);
~HttpRequest();
/**
* @brief Return request verb type
*
* @return One of the HTTP verb values
*/
const std::string& get_verb() const
{
return m_verb;
}
/**
* @brief Get header value
*
* @param header Header to get
*
* @return Header value or empty string if the header was not found
*/
std::string get_header(const std::string& header) const
{
std::pair<std::string, std::string> p;
p.first = header;
MHD_get_connection_values(m_connection, MHD_HEADER_KIND,
value_iterator, &p);
return p.second;
}
/**
* @brief Get option value
*
* @param header Option to get
*
* @return Option value or empty string if the option was not found
*/
std::string get_option(const std::string& option) const
{
std::pair<std::string, std::string> p;
p.first = option;
MHD_get_connection_values(m_connection, MHD_GET_ARGUMENT_KIND,
value_iterator, &p);
return p.second;
}
/**
* @brief Get request option count
*
* @return Number of options in the request
*/
size_t get_option_count() const
{
size_t rval = 0;
MHD_get_connection_values(m_connection, MHD_GET_ARGUMENT_KIND,
value_sum_iterator, &rval);
return rval;
}
/**
* @brief Copy options to an array
*
* The @c dest parameter must be able to hold at least get_option_count()
* pointers. The values stored need to be freed by the caller.
*
* @param dest Destination where options are copied
*/
void copy_options(char** dest) const
{
MHD_get_connection_values(m_connection, MHD_GET_ARGUMENT_KIND,
value_copy_iterator, &dest);
}
/**
* @brief Return request body
*
* @return Request body or empty string if no body is defined
*/
const std::string& get_json_str() const
{
return m_json_string;
}
/**
* @brief Return raw JSON body
*
* @return Raw JSON body or NULL if no body is defined
*/
json_t* get_json() const
{
return m_json.get();
}
/**
* @brief Get complete request URI
*
* @return The complete request URI
*/
std::string get_uri() const
{
return m_resource;
}
/**
* @brief Get URI part
*
* @param idx Zero indexed part number in URI
*
* @return The request URI part or empty string if no part was found
*/
std::string uri_part(uint32_t idx) const
{
return m_resource_parts.size() > idx ? m_resource_parts[idx] : "";
}
/**
* @brief Return a segment of the URI
*
* Combines a range of parts into a segment of the URI. Each part is
* separated by a forward slash.
*
* @param start Start of range
* @param end End of range, not inclusive
*
* @return The URI segment that matches this range
*/
std::string uri_segment(uint32_t start, uint32_t end) const
{
std::string rval;
for (uint32_t i = start; i < end && i < m_resource_parts.size(); i++)
{
if (i > start)
{
rval += "/";
}
rval += m_resource_parts[i];
}
return rval;
}
/**
* @brief Return how many parts are in the URI
*
* @return Number of URI parts
*/
size_t uri_part_count() const
{
return m_resource_parts.size();
}
/**
* @brief Return the last part of the URI
*
* @return The last URI part
*/
std::string last_uri_part() const
{
return m_resource_parts.size() > 0 ? m_resource_parts[m_resource_parts.size() - 1] : "";
}
/**
* @brief Return the value of the Host header
*
* @return The value of the Host header
*/
const char* host() const
{
return m_hostname.c_str();
}
/**
* @brief Convert request to string format
*
* The returned string should be logically equivalent to the original request.
*
* @return The request in string format
*/
std::string to_string() const;
/**
* @brief Drop the API version prefix
*
* @return True if prefix is present and was successfully removed
*/
bool validate_api_version();
private:
/** Constants */
static const std::string HTTP_PREFIX;
static const std::string HTTPS_PREFIX;
std::map<std::string, std::string> m_options; /**< Request options */
mxs::Closer<json_t*> m_json; /**< Request body */
std::string m_json_string; /**< String version of @c m_json */
std::string m_resource; /**< Requested resource */
std::deque<std::string> m_resource_parts; /**< @c m_resource split into parts */
std::string m_verb; /**< Request method */
std::string m_hostname; /**< The value of the Host header */
struct MHD_Connection* m_connection;
};

View File

@ -0,0 +1,91 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <map>
#include <string>
#include <tr1/memory>
#include <microhttpd.h>
#include <maxscale/jansson.hh>
#include <maxscale/http.hh>
/**
* A list of default headers that are generated with each response
*/
#define HTTP_RESPONSE_HEADER_DATE "Date"
#define HTTP_RESPONSE_HEADER_LAST_MODIFIED "Last-Modified"
#define HTTP_RESPONSE_HEADER_ETAG "ETag"
#define HTTP_RESPONSE_HEADER_ACCEPT "Accept"
#define HTTP_RESPONSE_HEADER_CONTENT_TYPE "Content-Type"
typedef std::map<std::string, std::string> Headers;
class HttpResponse
{
public:
/**
* @brief Create new HTTP response
*
* @param response Response body
* @param code HTTP return code
*/
HttpResponse(int code = MHD_HTTP_OK, json_t* response = NULL);
HttpResponse(const HttpResponse& response);
HttpResponse& operator = (const HttpResponse& response);
~HttpResponse();
/**
* @brief Get the response body
*
* @return The response body
*/
json_t* get_response() const;
/**
* @brief Drop response body
*
* This discards the message body.
*/
void drop_response();
/**
* @brief Get the HTTP response code
*
* @return The HTTP response code
*/
int get_code() const;
/**
* @brief Add an extra header to this response
*
* @param key Header name
* @param value Header value
*/
void add_header(const std::string& key, const std::string& value);
/**
* @brief Get request headers
*
* @return Headers of this request
*/
const Headers& get_headers() const;
private:
json_t* m_body; /**< Message body */
int m_code; /**< The HTTP code for the response */
Headers m_headers; /**< Extra headers */
};

View File

@ -0,0 +1,38 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file core/maxscale/maxscale.h - The private maxscale general definitions
*/
#include <maxscale/maxscale.h>
MXS_BEGIN_DECLS
/**
* Initiate shutdown of MaxScale.
*
* This functions informs all threads that they should stop the
* processing and exit.
*
* @return How many times maxscale_shutdown() has been called.
*/
int maxscale_shutdown(void);
/**
* Reset the start time from which the uptime is calculated.
*/
void maxscale_reset_starttime(void);
MXS_END_DECLS

View File

@ -0,0 +1,207 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <maxscale/poll_core.hh>
namespace maxscale
{
class MessageQueue;
class Worker;
/**
* An instance of @c MessageQueueMessage can be sent over a @c MessageQueue from
* one context to another. The instance will be copied verbatim without any
* interpretation, so if the same message is sent to multiple recipients it is
* the caller's and recipient's responsibility to manage the lifetime and
* concurrent access of anything possibly pointed to from the message.
*/
class MessageQueueMessage /* final */
{
public:
/**
* Constructor
*
* @param id The id of the message. The meaning is an affair between the sender
* and the recipient.
* @param arg1 First argument.
* @param arg2 Second argument.
*/
explicit MessageQueueMessage(uint64_t id = 0, intptr_t arg1 = 0, intptr_t arg2 = 0)
: m_id(id)
, m_arg1(arg1)
, m_arg2(arg2)
{
}
uint32_t id() const
{
return m_id;
}
intptr_t arg1() const
{
return m_arg1;
}
intptr_t arg2() const
{
return m_arg2;
}
MessageQueueMessage& set_id(uint64_t id)
{
m_id = id;
return *this;
}
MessageQueueMessage& set_arg1(intptr_t arg1)
{
m_arg1 = arg1;
return *this;
}
MessageQueueMessage& set_arg2(intptr_t arg2)
{
m_arg2 = arg2;
return *this;
}
private:
uint64_t m_id;
intptr_t m_arg1;
intptr_t m_arg2;
};
/**
* A @c MessageQueueHandler will be delivered messages received over a
* @c MessageQueue.
*/
class MessageQueueHandler
{
public:
/**
* Message delivery.
*
* @param queue The queue over which the message was received.
* @param message The message.
*/
virtual void handle_message(MessageQueue& queue, const MessageQueueMessage& message) = 0;
};
/**
* The class @c MessageQueue provides a cross thread message queue implemented
* on top of a pipe.
*/
class MessageQueue : private MxsPollData
{
MessageQueue(const MessageQueue&);
MessageQueue& operator = (const MessageQueue&);
public:
typedef MessageQueueHandler Handler;
typedef MessageQueueMessage Message;
/**
* Initializes the message queue mechanism. To be called once at
* process startup.
*
* @return True if the initialization succeeded, false otherwise.
*/
static bool init();
/**
* Finalizes the message queue mechanism. To be called once at
* process shutdown, if the initialization succeeded.
*/
static void finish();
/**
* Creates a @c MessageQueue with the provided handler.
*
* @param pHandler The handler that will receive the messages sent over the
* message queue. Note that the handler *must* remain valid
* for the lifetime of the @c MessageQueue.
*
* @return A pointer to a new @c MessageQueue or NULL if an error occurred.
*
* @attention Before the message queue can be used, it must be added to
* a worker.
*/
static MessageQueue* create(Handler* pHandler);
/**
* Destructor
*
* Removes itself If still added to a worker and closes the pipe.
*/
~MessageQueue();
/**
* Posts a message over the queue to the handler provided when the
* @c MessageQueue was created.
*
* @param message The message to be posted. A bitwise copy of the message
* will be delivered to the handler, after an unspecified time.
*
* @return True if the message could be posted, false otherwise. Note that
* a return value of true only means that the message could successfully
* be posted, not that it has reached the handler.
*
* @attention Note that the message queue must have been added to a worker
* before a message can be posted.
*/
bool post(const Message& message) const;
/**
* Adds the message queue to a particular worker.
*
* @param pWorker The worker the message queue should be added to.
* Must remain valid until the message queue is removed
* from it.
*
* @return True if the message queue could be added, otherwise false.
*
* @attention If the message queue is currently added to a worker, it
* will first be removed from that worker.
*/
bool add_to_worker(Worker* pWorker);
/**
* Removes the message queue from the worker it is currently added to.
*
* @return The worker the message queue was associated with, or NULL
* if it was not associated with any.
*/
Worker* remove_from_worker();
private:
MessageQueue(Handler* pHandler, int read_fd, int write_fd);
uint32_t handle_poll_events(int thread_id, uint32_t events);
static uint32_t poll_handler(MXS_POLL_DATA* pData, int thread_id, uint32_t events);
private:
Handler& m_handler;
int m_read_fd;
int m_write_fd;
Worker* m_pWorker;
};
}

View File

@ -0,0 +1,81 @@
#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: 2020-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 */
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

View File

@ -0,0 +1,154 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file modules.h Utilities for loading modules
*/
#include <maxscale/cdefs.h>
#include <maxscale/dcb.h>
#include <maxscale/modinfo.h>
#include <maxscale/resultset.h>
#include <maxscale/debug.h>
MXS_BEGIN_DECLS
/**
* Module types
*/
#define MODULE_PROTOCOL "Protocol" /**< A protocol module type */
#define MODULE_AUTHENTICATOR "Authenticator" /**< An authenticator module type */
#define MODULE_ROUTER "Router" /**< A router module type */
#define MODULE_MONITOR "Monitor" /**< A database monitor module type */
#define MODULE_FILTER "Filter" /**< A filter module type */
#define MODULE_QUERY_CLASSIFIER "QueryClassifier" /**< A query classifier module type */
/**
*@brief Load a module
*
* @param module Name of the module to load
* @param type Type of module, used purely for registration
* @return The module specific entry point structure or NULL
*/
void *load_module(const char *module, const char *type);
/**
* @brief Get a module
*
* @param name Name of the module
* @param type The module type or NULL for any type
* @return The loaded module or NULL if the module is not loaded
*/
const MXS_MODULE *get_module(const char *name, const char *type);
/**
* @brief Unload a module.
*
* No errors are returned since it is not clear that much can be done
* to fix issues relating to unloading modules.
*
* @param module The name of the module
*/
void unload_module(const char *module);
/**
* @brief Unload all modules
*
* Remove all the modules from the system, called during shutdown
* to allow termination hooks to be called.
*/
void unload_all_modules();
/**
* @brief Print Modules
*
* Diagnostic routine to display all the loaded modules
*/
void printModules();
/**
* @brief Print Modules to a DCB
*
* Diagnostic routine to display all the loaded modules
*/
void dprintAllModules(DCB *);
/**
* @brief Return a resultset that has the current set of modules in it
*
* @return A Result set
*/
RESULTSET *moduleGetList();
typedef struct mxs_module_iterator
{
const char* type;
void* position;
} MXS_MODULE_ITERATOR;
/**
* @brief Returns an iterator to modules.
*
* @attention It is unspecified whether a module loaded after the iterator
* was created, will be returned by the iterator. The behaviour
* is undefined if a module is unloaded while an iteration is
* being performed.
*
* @param type The type of modules that should be returned. If NULL,
* then all modules are returned.
*
* @return An iterator.
*/
MXS_MODULE_ITERATOR mxs_module_iterator_get(const char* type);
/**
* @brief Indicates whether the iterator has a module to return.
*
* @param iterator An iterator
*
* @return True if a subsequent call to @c mxs_module_iterator_get
* will return a module.
*/
bool mxs_module_iterator_has_next(const MXS_MODULE_ITERATOR* iterator);
/**
* @brief Returns the next module and advances the iterator.
*
* @param iterator An iterator.
*
* @return A module if there was a module to return, NULL otherwise.
*/
MXS_MODULE* mxs_module_iterator_get_next(MXS_MODULE_ITERATOR* iterator);
/**
* @brief Convert module to JSON
*
* @param module Module to convert
* @param host Hostname of this server
*
* @return The module in JSON format
*/
json_t* module_to_json(const MXS_MODULE* module, const char* host);
/**
* @brief Convert all modules to JSON
*
* @param host The hostname of this server
*
* @return Array of modules in JSON format
*/
json_t* module_list_to_json(const char* host);
MXS_END_DECLS

View File

@ -0,0 +1,121 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file core/maxscale/monitor.h - The private monitor interface
*/
#include <maxscale/monitor.h>
#include "externcmd.h"
MXS_BEGIN_DECLS
#define MON_ARG_MAX 8192
#define DEFAULT_CONNECT_TIMEOUT 3
#define DEFAULT_READ_TIMEOUT 1
#define DEFAULT_WRITE_TIMEOUT 2
#define DEFAULT_CONNECTION_ATTEMPTS 1
#define DEFAULT_MONITOR_INTERVAL 2000 // in milliseconds
/** Default maximum journal age in seconds */
#define DEFAULT_JOURNAL_MAX_AGE 28800
/** Default script execution timeout in seconds */
#define DEFAULT_SCRIPT_TIMEOUT 90
/**
* Monitor network timeout types
*/
typedef enum
{
MONITOR_CONNECT_TIMEOUT = 0,
MONITOR_READ_TIMEOUT = 1,
MONITOR_WRITE_TIMEOUT = 2,
MONITOR_CONNECT_ATTEMPTS = 3
} monitor_timeouts_t;
MXS_MONITOR *monitor_alloc(const char *, const char *);
void monitor_free(MXS_MONITOR *);
void monitorStart(MXS_MONITOR *, const MXS_CONFIG_PARAMETER*);
void monitorStop(MXS_MONITOR *);
void monitorDestroy(MXS_MONITOR* monitor);
void monitorStopAll();
void monitorStartAll();
MXS_MONITOR *monitor_find(const char *);
MXS_MONITOR* monitor_repurpose_destroyed(const char* name, const char* module);
void monitorShow(DCB *, MXS_MONITOR *);
void monitorShowAll(DCB *);
void monitorList(DCB *);
RESULTSET *monitorGetList();
bool monitorAddServer(MXS_MONITOR *mon, SERVER *server);
void monitorRemoveServer(MXS_MONITOR *mon, SERVER *server);
void monitorAddUser(MXS_MONITOR *, const char *, const char *);
void monitorAddParameters(MXS_MONITOR *monitor, MXS_CONFIG_PARAMETER *params);
bool monitorRemoveParameter(MXS_MONITOR *monitor, const char *key);
void monitorSetInterval (MXS_MONITOR *, unsigned long);
bool monitorSetNetworkTimeout(MXS_MONITOR *, int, int, const char*);
void monitorSetJournalMaxAge(MXS_MONITOR *mon, time_t value);
void monitorSetScriptTimeout(MXS_MONITOR *mon, uint32_t value);
/**
* @brief Serialize a monitor to a file
*
* This converts the static configuration of the monitor into an INI format file.
*
* @param monitor Monitor to serialize
* @return True if serialization was successful
*/
bool monitor_serialize(const MXS_MONITOR *monitor);
/**
* Check if a server is being monitored and return the monitor.
* @param server Server that is queried
* @return The monitor watching this server, or NULL if not monitored
*/
MXS_MONITOR* monitor_server_in_use(const SERVER *server);
/**
* Launch a script
*
* @param mon Owning monitor
* @param ptr The server which has changed state
* @param script Script to execute
* @param timeout Timeout in seconds for the script
*
* @return Return value of the executed script or -1 on error
*/
int monitor_launch_script(MXS_MONITOR* mon, MXS_MONITORED_SERVER* ptr, const char* script, uint32_t timeout);
/**
* Launch a command
*
* @param mon Owning monitor
* @param ptr The server which has changed state
* @param cmd The command to execute.
*
* @note All default script variables will be replaced.
*
* @return Return value of the executed script or -1 on error.
*/
int monitor_launch_command(MXS_MONITOR* mon, MXS_MONITORED_SERVER* ptr, EXTERNCMD* cmd);
MXS_END_DECLS

View File

@ -0,0 +1,64 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file core/maxscale/poll.h - The private poll interface
*/
#include <maxscale/poll.h>
#include <maxscale/resultset.h>
MXS_BEGIN_DECLS
struct mxs_worker;
#define MAX_EVENTS 1000
/**
* A statistic identifier that can be returned by poll_get_stat
*/
typedef enum
{
POLL_STAT_READ,
POLL_STAT_WRITE,
POLL_STAT_ERROR,
POLL_STAT_HANGUP,
POLL_STAT_ACCEPT,
POLL_STAT_EVQ_LEN,
POLL_STAT_EVQ_MAX,
POLL_STAT_MAX_QTIME,
POLL_STAT_MAX_EXECTIME
} POLL_STAT;
enum poll_message
{
POLL_MSG_CLEAN_PERSISTENT = 0x01
};
void poll_init();
//void poll_finish(); // TODO: Add this.
void poll_set_maxwait(unsigned int);
void poll_set_nonblocking_polls(unsigned int);
void dprintPollStats(DCB *);
void dShowThreads(DCB *dcb);
void dShowEventQ(DCB *dcb);
void dShowEventStats(DCB *dcb);
int64_t poll_get_stat(POLL_STAT stat);
RESULTSET *eventTimesGetList();
MXS_END_DECLS

View File

@ -0,0 +1,39 @@
#pragma once
/*
* 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: 2020-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 <maxscale/query_classifier.h>
MXS_BEGIN_DECLS
typedef enum qc_trx_parse_using
{
QC_TRX_PARSE_USING_QC, /**< Use the query classifier. */
QC_TRX_PARSE_USING_PARSER, /**< Use custom parser. */
} qc_trx_parse_using_t;
/**
* Returns the type bitmask of transaction related statements.
*
* @param stmt A COM_QUERY or COM_STMT_PREPARE packet.
* @param use What method should be used.
*
* @return The relevant type bits if the statement is transaction
* related, otherwise 0.
*
* @see qc_get_trx_type_mask
*/
uint32_t qc_get_trx_type_mask_using(GWBUF* stmt, qc_trx_parse_using_t use);
MXS_END_DECLS

View File

@ -0,0 +1,98 @@
#pragma once
/*
* 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: 2020-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.
*/
/** @file REST API resources */
#include <maxscale/cppdefs.hh>
#include <string>
#include <deque>
#include <maxscale/server.h>
#include <maxscale/http.hh>
#include "httprequest.hh"
#include "httpresponse.hh"
#include "monitor.h"
#include "service.h"
#include "filter.h"
#include "session.h"
typedef HttpResponse (*ResourceCallback)(const HttpRequest& request);
class Resource
{
Resource(const Resource&);
Resource& operator = (const Resource&);
public:
enum resource_constraint
{
NONE = 0,
REQUIRE_BODY = (1 << 0)
};
Resource(ResourceCallback cb, int components, ...);
~Resource();
/**
* @brief Check if a request matches this resource
*
* @param request Request to match
*
* @return True if this request matches this resource
*/
bool match(const HttpRequest& request) const;
/**
* @brief Handle a HTTP request
*
* @param request Request to handle
*
* @return Response to the request
*/
HttpResponse call(const HttpRequest& request) const;
/**
* Add a resource constraint
*
* @param type Constraint to add
*/
void add_constraint(resource_constraint type);
/**
* Whether resource requires a request body
*
* @return True if resource requires a request body
*/
bool requires_body() const;
private:
bool matching_variable_path(const std::string& path, const std::string& target) const;
ResourceCallback m_cb; /**< Resource handler callback */
std::deque<std::string> m_path; /**< Path components */
bool m_is_glob; /**< Does this path glob? */
uint32_t m_constraints; /**< Resource constraints */
};
/**
* @brief Handle a HTTP request
*
* @param request Request to handle
*
* @return Response to request
*/
HttpResponse resource_handle_request(const HttpRequest& request);

View File

@ -0,0 +1,43 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file core/maxscale/secrets.h - MaxScale config file password encryption/decryption
*/
#include <maxscale/secrets.h>
MXS_BEGIN_DECLS
#define MAXSCALE_KEYLEN 32
#define MAXSCALE_IV_LEN 16
/**
* The key structure held in the secrets file
*/
typedef struct maxkeys
{
unsigned char enckey[MAXSCALE_KEYLEN];
unsigned char initvector[MAXSCALE_IV_LEN];
} MAXKEYS;
enum
{
MXS_PASSWORD_MAXLEN = 79
};
int secrets_write_keys(const char *directory);
char *encrypt_password(const char*, const char *);
MXS_END_DECLS

View File

@ -0,0 +1,143 @@
#pragma once
/*
* 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: 2020-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/service.h>
MXS_BEGIN_DECLS
/**
* @file service.h - MaxScale internal service functions
*/
/**
* Service life cycle management
*
* These functions should only be called by the MaxScale core.
*/
/**
* @brief Allocate a new service
*
* @param name The service name
* @param router The router module this service uses
*
* @return The newly created service or NULL if an error occurred
*/
SERVICE* service_alloc(const char *name, const char *router);
/**
* @brief Free the specified service
*
* @param service The service to free
*/
void service_free(SERVICE *service);
/**
* @brief Shut all services down
*
* Turns on the shutdown flag in each service. This should be done as
* part of the MaxScale shutdown.
*/
void service_shutdown(void);
/**
* @brief Destroy all service router and filter instances
*
* Calls the @c destroyInstance entry point of each service' router and
* filters. This should be done after all worker threads have exited.
*/
void service_destroy_instances(void);
/**
* @brief Launch all services
*
* Initialize and start all services. This should only be called once by the
* main initialization code.
*
* @return Number of successfully started services
*/
int service_launch_all(void);
/**
* Creating and adding new components to services
*/
SERV_LISTENER* serviceCreateListener(SERVICE *service, const char *name,
const char *protocol, const char *address,
unsigned short port, const char *authenticator,
const char *options, SSL_LISTENER *ssl);
void serviceRemoveBackend(SERVICE *service, const SERVER *server);
/**
* @brief Serialize a service to a file
*
* This converts @c service into an INI format file.
*
* NOTE: This does not persist the complete service configuration and requires
* that an existing service configuration is in the main configuration file.
*
* @param service Service to serialize
* @return False if the serialization of the service fails, true if it was successful
*/
bool service_serialize(const SERVICE *service);
/**
* Internal utility functions
*/
char* service_get_name(SERVICE* service);
bool service_all_services_have_listeners(void);
int service_isvalid(SERVICE *service);
/**
* Check if a service uses @c servers
* @param server Server that is queried
* @return True if server is used by at least one service
*/
bool service_server_in_use(const SERVER *server);
/** Update the server weights used by services */
void service_update_weights();
/**
* Alteration of the service configuration
*/
void serviceAddRouterOption(SERVICE *service, char *option);
void serviceClearRouterOptions(SERVICE *service);
void service_update(SERVICE *service, char *router, char *user, char *auth);
/**
* @brief Add parameters to a service
*
* A copy of @c param is added to @c service.
*
* @param service Service where the parameters are added
* @param param Parameters to add
*/
void service_add_parameters(SERVICE *service, const MXS_CONFIG_PARAMETER *param);
/**
* @brief Set listener rebinding interval
*
* @param service Service to configure
* @param value String value o
*/
void service_set_retry_interval(SERVICE *service, int value);
/**
* Internal debugging diagnostics
*/
void printService(SERVICE *service);
void printAllServices(void);
MXS_END_DECLS

View File

@ -0,0 +1,77 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file core/maxscale/session.h - The private session interface
*/
#include <maxscale/session.h>
MXS_BEGIN_DECLS
#define SESSION_STATS_INIT {0}
#define MXS_DOWNSTREAM_INIT {0}
#define MXS_UPSTREAM_INIT {0}
#define SESSION_FILTER_INIT {0}
#define SESSION_INIT {.ses_chk_top = CHK_NUM_SESSION, \
.stats = SESSION_STATS_INIT, .head = MXS_DOWNSTREAM_INIT, .tail = MXS_UPSTREAM_INIT, \
.state = SESSION_STATE_ALLOC, .client_protocol_data = 0, .ses_chk_tail = CHK_NUM_SESSION}
#define SESSION_PROTOCOL(x, type) DCB_PROTOCOL((x)->client_dcb, type)
/**
* Filter type for the sessionGetList call
*/
typedef enum
{
SESSION_LIST_ALL,
SESSION_LIST_CONNECTION
} SESSIONLISTFILTER;
int session_isvalid(MXS_SESSION *);
const char *session_state(mxs_session_state_t);
/**
* Link a session to a backend DCB.
*
* @param session The session to link with the dcb
* @param dcb The backend DCB to be linked
*/
void session_link_backend_dcb(MXS_SESSION *session, struct dcb *dcb);
RESULTSET *sessionGetList(SESSIONLISTFILTER);
void printAllSessions();
void printSession(MXS_SESSION *);
void dprintSessionList(DCB *pdcb);
void dprintAllSessions(struct dcb *);
void dprintSession(struct dcb *, MXS_SESSION *);
void dListSessions(struct dcb *);
/**
* @brief Get a session reference
*
* This creates an additional reference to a session which allows it to live
* as long as it is needed.
*
* @param session Session reference to get
* @return Reference to a MXS_SESSION
*
* @note The caller must free the session reference by calling session_put_ref
*/
MXS_SESSION* session_get_ref(MXS_SESSION *sessoin);
MXS_END_DECLS

View File

@ -0,0 +1,39 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <maxscale/session.h>
namespace maxscale
{
/**
* Specialization of RegistryTraits for the session registry.
*/
template<>
struct RegistryTraits<MXS_SESSION>
{
typedef uint64_t id_type;
typedef MXS_SESSION* entry_type;
static id_type get_id(entry_type entry)
{
return entry->ses_id;
}
static entry_type null_entry()
{
return NULL;
}
};
}

View File

@ -0,0 +1,170 @@
#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: 2020-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 struct skygw_rwlock_st
{
skygw_chk_t srw_chk_top;
pthread_rwlock_t* srw_rwlock;
pthread_t srw_rwlock_thr;
skygw_chk_t srw_chk_tail;
} skygw_rwlock_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) * sizeof(char);
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) * sizeof(
char);
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 */
void acquire_lock(int* l);
void release_lock(int* l);
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 */
int skygw_rwlock_wrlock(skygw_rwlock_t* rwlock);
int skygw_rwlock_rdlock(skygw_rwlock_t* rwlock);
int skygw_rwlock_unlock(skygw_rwlock_t* rwlock);
int skygw_rwlock_init(skygw_rwlock_t** rwlock);
size_t get_decimal_len(size_t s);
MXS_END_DECLS
#endif /* SKYGW_UTILS_H */

View File

@ -0,0 +1,37 @@
#pragma once
/*
* 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: 2020-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.
*/
/**
* @file
*
* Internal code for the statistics system.
*/
#include <maxscale/statistics.h>
MXS_BEGIN_DECLS
/**
* @brief Initialize statistics system
*
* This function should only be called once by the MaxScale core.
*/
void ts_stats_init();
/**
* @brief Terminate statistics system
*/
void ts_stats_end();
MXS_END_DECLS

View File

@ -0,0 +1,806 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <ctype.h>
#include <maxscale/customparser.hh>
#include <maxscale/query_classifier.h>
namespace maxscale
{
#define TBP_EXPECT_TOKEN(string_literal) string_literal, (sizeof(string_literal) - 1)
// For debugging purposes.
// #define TBP_LOG_UNEXPECTED_AND_EXHAUSTED
#undef TBP_LOG_UNEXPECTED_AND_EXHAUSTED
/**
* @class TrxBoundaryParser
*
* @ TrxBoundaryParser is a class capable of parsing and returning the
* correct type mask of statements affecting the transaction state and
* autocommit mode.
*
* The class is intended to be used in context where the performance is
* of utmost importance; consequently it is defined in its entirety
* in the header to allow for aggressive inlining.
*/
class TrxBoundaryParser : public maxscale::CustomParser
{
TrxBoundaryParser(const TrxBoundaryParser&);
TrxBoundaryParser& operator = (const TrxBoundaryParser&);
public:
enum token_t
{
TK_AUTOCOMMIT,
TK_BEGIN,
TK_COMMA,
TK_COMMIT,
TK_CONSISTENT,
TK_DOT,
TK_EQ,
TK_FALSE,
TK_GLOBAL,
TK_GLOBAL_VAR,
TK_ONE,
TK_ONLY,
TK_READ,
TK_ROLLBACK,
TK_SESSION,
TK_SESSION_VAR,
TK_SET,
TK_SNAPSHOT,
TK_START,
TK_TRANSACTION,
TK_TRUE,
TK_WITH,
TK_WORK,
TK_WRITE,
TK_ZERO,
PARSER_UNKNOWN_TOKEN,
PARSER_EXHAUSTED,
};
/**
* TrxBoundaryParser is not thread-safe. As a very lightweight class,
* the intention is that an instance is created on the stack whenever
* parsing needs to be performed.
*
* @code
* void f(GWBUF *pBuf)
* {
* TrxBoundaryParser tbp;
*
* uint32_t type_mask = tbp.parse(pBuf);
* ...
* }
* @endcode
*/
TrxBoundaryParser()
{
}
/**
* Return the type mask of a statement, provided the statement affects
* transaction state or autocommit mode.
*
* @param pSql SQL statament.
* @param len Length of pSql.
*
* @return The corresponding type mask or 0, if the statement does not
* affect transaction state or autocommit mode.
*/
uint32_t type_mask_of(const char* pSql, size_t len)
{
uint32_t type_mask = 0;
m_pSql = pSql;
m_len = len;
m_pI = m_pSql;
m_pEnd = m_pI + m_len;
return parse();
}
/**
* Return the type mask of a statement, provided the statement affects
* transaction state or autocommit mode.
*
* @param pBuf A COM_QUERY
*
* @return The corresponding type mask or 0, if the statement does not
* affect transaction state or autocommit mode.
*/
uint32_t type_mask_of(GWBUF* pBuf)
{
uint32_t type_mask = 0;
char* pSql;
if (modutil_extract_SQL(pBuf, &pSql, &m_len))
{
m_pSql = pSql;
m_pI = m_pSql;
m_pEnd = m_pI + m_len;
type_mask = parse();
}
return type_mask;
}
private:
enum token_required_t
{
TOKEN_REQUIRED,
TOKEN_NOT_REQUIRED,
};
void log_unexpected()
{
#ifdef TBP_LOG_UNEXPECTED_AND_EXHAUSTED
MXS_NOTICE("Transaction tracking: In statement '%.*s', unexpected token at '%.*s'.",
(int)m_len, m_pSql, (int)(m_pEnd - m_pI), m_pI);
#endif
}
void log_exhausted()
{
#ifdef TBP_LOG_UNEXPECTED_AND_EXHAUSTED
MXS_NOTICE("Transaction tracking: More tokens expected in statement '%.*s'.", (int)m_len, m_pSql);
#endif
}
uint32_t parse()
{
uint32_t type_mask = 0;
token_t token = next_token();
switch (token)
{
case TK_BEGIN:
type_mask = parse_begin(type_mask);
break;
case TK_COMMIT:
type_mask = parse_commit(type_mask);
break;
case TK_ROLLBACK:
type_mask = parse_rollback(type_mask);
break;
case TK_START:
type_mask = parse_start(type_mask);
break;
case TK_SET:
type_mask = parse_set(0);
break;
default:
;
}
return type_mask;
}
uint32_t parse_begin(uint32_t type_mask)
{
type_mask |= QUERY_TYPE_BEGIN_TRX;
token_t token = next_token();
switch (token)
{
case TK_WORK:
type_mask = parse_work(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_commit(uint32_t type_mask)
{
type_mask |= QUERY_TYPE_COMMIT;
token_t token = next_token();
switch (token)
{
case TK_WORK:
type_mask = parse_work(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_only(uint32_t type_mask)
{
type_mask |= QUERY_TYPE_READ;
token_t token = next_token();
switch (token)
{
case TK_COMMA:
type_mask = parse_transaction(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_read(uint32_t type_mask)
{
token_t token = next_token(TOKEN_REQUIRED);
switch (token)
{
case TK_ONLY:
type_mask = parse_only(type_mask);
break;
case TK_WRITE:
type_mask = parse_write(type_mask);
break;
case PARSER_EXHAUSTED:
type_mask = 0;
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_rollback(uint32_t type_mask)
{
type_mask |= QUERY_TYPE_ROLLBACK;
token_t token = next_token();
switch (token)
{
case TK_WORK:
type_mask = parse_work(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_set_autocommit(uint32_t type_mask)
{
token_t token = next_token(TOKEN_REQUIRED);
switch (token)
{
case TK_EQ:
token = next_token(TOKEN_REQUIRED);
if (token == TK_ONE || token == TK_TRUE)
{
type_mask |= (QUERY_TYPE_COMMIT | QUERY_TYPE_ENABLE_AUTOCOMMIT);
}
else if (token == TK_ZERO || token == TK_FALSE)
{
type_mask = (QUERY_TYPE_BEGIN_TRX | QUERY_TYPE_DISABLE_AUTOCOMMIT);
}
else
{
type_mask = 0;
if (token != PARSER_EXHAUSTED)
{
log_unexpected();
}
}
break;
case PARSER_EXHAUSTED:
type_mask = 0;
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_set(uint32_t type_mask)
{
token_t token = next_token(TOKEN_REQUIRED);
switch (token)
{
case TK_AUTOCOMMIT:
type_mask = parse_set_autocommit(type_mask);
break;
case TK_GLOBAL:
case TK_SESSION:
token = next_token(TOKEN_REQUIRED);
if (token == TK_AUTOCOMMIT)
{
type_mask = parse_set_autocommit(type_mask);
}
else
{
type_mask = 0;
if (token != PARSER_EXHAUSTED)
{
log_unexpected();
}
}
break;
case TK_GLOBAL_VAR:
case TK_SESSION_VAR:
token = next_token(TOKEN_REQUIRED);
if (token == TK_DOT)
{
token = next_token(TOKEN_REQUIRED);
if (token == TK_AUTOCOMMIT)
{
type_mask = parse_set_autocommit(type_mask);
}
else
{
type_mask = 0;
if (token != PARSER_EXHAUSTED)
{
log_unexpected();
}
}
}
else
{
type_mask = 0;
if (token != PARSER_EXHAUSTED)
{
log_unexpected();
}
}
break;
case PARSER_EXHAUSTED:
type_mask = 0;
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_start(uint32_t type_mask)
{
token_t token = next_token(TOKEN_REQUIRED);
switch (token)
{
case TK_TRANSACTION:
type_mask = parse_transaction(type_mask);
break;
case PARSER_EXHAUSTED:
type_mask = 0;
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_transaction(uint32_t type_mask)
{
type_mask |= QUERY_TYPE_BEGIN_TRX;
token_t token = next_token();
switch (token)
{
case TK_READ:
type_mask = parse_read(type_mask);
break;
case TK_WITH:
type_mask = parse_with_consistent_snapshot(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_with_consistent_snapshot(uint32_t type_mask)
{
token_t token = next_token(TOKEN_REQUIRED);
if (token == TK_CONSISTENT)
{
token = next_token(TOKEN_REQUIRED);
if (token == TK_SNAPSHOT)
{
token = next_token();
switch (token)
{
case TK_COMMA:
type_mask = parse_transaction(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
}
}
return type_mask;
}
uint32_t parse_work(uint32_t type_mask)
{
token_t token = next_token();
switch (token)
{
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
uint32_t parse_write(uint32_t type_mask)
{
type_mask |= QUERY_TYPE_WRITE;
token_t token = next_token();
switch (token)
{
case TK_COMMA:
type_mask = parse_transaction(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
return type_mask;
}
// Significantly faster than library version.
static char toupper(char c)
{
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
}
token_t expect_token(const char* zWord, int len, token_t token)
{
const char* pI = m_pI;
const char* pEnd = zWord + len;
while ((pI < m_pEnd) && (zWord < pEnd) && (toupper(*pI) == *zWord))
{
++pI;
++zWord;
}
if (zWord == pEnd)
{
if ((pI == m_pEnd) || (!isalpha(*pI))) // Handwritten isalpha not faster than library version.
{
m_pI = pI;
}
else
{
token = PARSER_UNKNOWN_TOKEN;
}
}
else
{
token = PARSER_UNKNOWN_TOKEN;
}
return token;
}
void bypass_whitespace()
{
m_pI = modutil_MySQL_bypass_whitespace(const_cast<char*>(m_pI), m_pEnd - m_pI);
}
token_t next_token(token_required_t required = TOKEN_NOT_REQUIRED)
{
token_t token = PARSER_UNKNOWN_TOKEN;
bypass_whitespace();
if (m_pI == m_pEnd)
{
token = PARSER_EXHAUSTED;
}
else if (*m_pI == ';')
{
++m_pI;
while ((m_pI != m_pEnd) && isspace(*m_pI))
{
++m_pI;
}
if (m_pI != m_pEnd)
{
MXS_WARNING("Non-space data found after semi-colon: '%.*s'.",
(int)(m_pEnd - m_pI), m_pI);
}
token = PARSER_EXHAUSTED;
}
else
{
switch (*m_pI)
{
case '@':
if (is_next_alpha('A', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("@@AUTOCOMMIT"), TK_AUTOCOMMIT);
}
else if (is_next_alpha('S', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("@@SESSION"), TK_SESSION_VAR);
}
else if (is_next_alpha('G', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("@@GLOBAL"), TK_GLOBAL_VAR);
}
break;
case 'a':
case 'A':
token = expect_token(TBP_EXPECT_TOKEN("AUTOCOMMIT"), TK_AUTOCOMMIT);
break;
case 'b':
case 'B':
token = expect_token(TBP_EXPECT_TOKEN("BEGIN"), TK_BEGIN);
break;
case ',':
++m_pI;
token = TK_COMMA;
break;
case 'c':
case 'C':
if (is_next_alpha('O'))
{
if (is_next_alpha('M', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("COMMIT"), TK_COMMIT);
}
else if (is_next_alpha('N', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("CONSISTENT"), TK_CONSISTENT);
}
}
break;
case '.':
++m_pI;
token = TK_DOT;
break;
case '=':
++m_pI;
token = TK_EQ;
break;
case 'f':
case 'F':
token = expect_token(TBP_EXPECT_TOKEN("FALSE"), TK_FALSE);
break;
case 'g':
case 'G':
token = expect_token(TBP_EXPECT_TOKEN("GLOBAL"), TK_GLOBAL);
break;
case '1':
{
char c;
if (!peek_next_char(&c) || !isdigit(c))
{
++m_pI;
token = TK_ONE;
}
}
break;
case 'o':
case 'O':
if (is_next_alpha('F'))
{
token = expect_token(TBP_EXPECT_TOKEN("OFF"), TK_ZERO);
}
else if (is_next_alpha('N'))
{
if (is_next_alpha('L', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("ONLY"), TK_ONLY);
}
else
{
token = expect_token(TBP_EXPECT_TOKEN("ON"), TK_ONE);
}
}
break;
case 'r':
case 'R':
if (is_next_alpha('E'))
{
token = expect_token(TBP_EXPECT_TOKEN("READ"), TK_READ);
}
else if (is_next_alpha('O'))
{
token = expect_token(TBP_EXPECT_TOKEN("ROLLBACK"), TK_ROLLBACK);
}
break;
case 's':
case 'S':
if (is_next_alpha('E'))
{
if (is_next_alpha('S', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("SESSION"), TK_SESSION);
}
else
{
token = expect_token(TBP_EXPECT_TOKEN("SET"), TK_SET);
}
}
else if (is_next_alpha('N'))
{
token = expect_token(TBP_EXPECT_TOKEN("SNAPSHOT"), TK_SNAPSHOT);
}
else if (is_next_alpha('T'))
{
token = expect_token(TBP_EXPECT_TOKEN("START"), TK_START);
}
break;
case 't':
case 'T':
if (is_next_alpha('R'))
{
if (is_next_alpha('A', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("TRANSACTION"), TK_TRANSACTION);
}
else if (is_next_alpha('U', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("TRUE"), TK_TRUE);
}
}
break;
case 'w':
case 'W':
if (is_next_alpha('I'))
{
token = expect_token(TBP_EXPECT_TOKEN("WITH"), TK_WITH);
}
else if (is_next_alpha('O'))
{
token = expect_token(TBP_EXPECT_TOKEN("WORK"), TK_WORK);
}
else if (is_next_alpha('R'))
{
token = expect_token(TBP_EXPECT_TOKEN("WRITE"), TK_WRITE);
}
break;
case '0':
{
char c;
if (!peek_next_char(&c) || !isdigit(c))
{
++m_pI;
token = TK_ZERO;
}
}
break;
default:
;
}
}
if ((token == PARSER_EXHAUSTED) && (required == TOKEN_REQUIRED))
{
log_exhausted();
}
return token;
}
};
}

View File

@ -0,0 +1,28 @@
#pragma once
/*
* 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: 2020-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/worker.h>
MXS_BEGIN_DECLS
/**
* Query whether worker should shutdown.
*
* @param worker The worker in question.
*
* @return True, if the worker should shut down, false otherwise.
*/
bool mxs_worker_should_shutdown(MXS_WORKER* worker);
MXS_END_DECLS

View File

@ -0,0 +1,528 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <memory>
#include <vector>
#include <maxscale/platform.h>
#include <maxscale/session.h>
#include <maxscale/utils.hh>
#include "messagequeue.hh"
#include "poll.h"
#include "worker.h"
#include "workertask.hh"
#include "session.hh"
namespace maxscale
{
class Semaphore;
struct WORKER_STATISTICS
{
WORKER_STATISTICS()
{
memset(this, 0, sizeof(WORKER_STATISTICS));
}
enum
{
MAXNFDS = 10,
N_QUEUE_TIMES = 30
};
int64_t n_read; /*< Number of read events */
int64_t n_write; /*< Number of write events */
int64_t n_error; /*< Number of error events */
int64_t n_hup; /*< Number of hangup events */
int64_t n_accept; /*< Number of accept events */
int64_t n_polls; /*< Number of poll cycles */
int64_t n_pollev; /*< Number of polls returning events */
int64_t n_nbpollev; /*< Number of polls returning events */
int64_t n_fds[MAXNFDS]; /*< Number of wakeups with particular n_fds value */
int64_t evq_length; /*< Event queue length */
int64_t evq_max; /*< Maximum event queue length */
int64_t blockingpolls; /*< Number of epoll_waits with a timeout specified */
uint32_t qtimes[N_QUEUE_TIMES + 1];
uint32_t exectimes[N_QUEUE_TIMES + 1];
int64_t maxqtime;
int64_t maxexectime;
};
class Worker : public MXS_WORKER
, private MessageQueue::Handler
, private MXS_POLL_DATA
{
Worker(const Worker&);
Worker& operator = (const Worker&);
public:
typedef WORKER_STATISTICS STATISTICS;
typedef WorkerTask Task;
typedef WorkerDisposableTask DisposableTask;
typedef Registry<MXS_SESSION> SessionsById;
typedef std::vector<DCB*> Zombies;
enum state_t
{
STOPPED,
IDLE,
POLLING,
PROCESSING,
ZPROCESSING
};
enum execute_mode_t
{
EXECUTE_AUTO, /**< Execute tasks immediately */
EXECUTE_QUEUED /**< Only queue tasks for execution */
};
/**
* Initialize the worker mechanism.
*
* To be called once at process startup. This will cause as many workers
* to be created as the number of threads defined.
*
* @return True if the initialization succeeded, false otherwise.
*/
static bool init();
/**
* Finalize the worker mechanism.
*
* To be called once at process shutdown. This will cause all workers
* to be destroyed. When the function is called, no worker should be
* running anymore.
*/
static void finish();
/**
* Returns the id of the worker
*
* @return The id of the worker.
*/
int id() const
{
return m_id;
}
/**
* Returns the state of the worker.
*
* @return The current state.
*
* @attentions The state might have changed the moment after the function returns.
*/
state_t state() const
{
return m_state;
}
/**
* Returns statistics for this worker.
*
* @return The worker specific statistics.
*
* @attentions The statistics may change at any time.
*/
const STATISTICS& statistics() const
{
return m_statistics;
}
/**
* Returns statistics for all workers.
*
* @return Combined statistics.
*
* @attentions The statistics may no longer be accurate by the time it has
* been returned. The returned values may also not represent a
* 100% consistent set.
*/
static STATISTICS get_statistics();
/**
* Return a specific combined statistic value.
*
* @param what What to return.
*
* @return The corresponding value.
*/
static int64_t get_one_statistic(POLL_STAT what);
/**
* Return this worker's statistics.
*
* @return Local statistics for this worker.
*/
const STATISTICS& get_local_statistics() const
{
return m_statistics;
}
/**
* Add a file descriptor to the epoll instance of the worker.
*
* @param fd The file descriptor to be added.
* @param events Mask of epoll event types.
* @param pData The poll data associated with the descriptor:
*
* data->handler : Handler that knows how to deal with events
* for this particular type of 'struct mxs_poll_data'.
* data->thread.id: Will be updated by the worker.
*
* @attention The provided file descriptor must be non-blocking.
* @attention @c pData must remain valid until the file descriptor is
* removed from the worker.
*
* @return True, if the descriptor could be added, false otherwise.
*/
bool add_fd(int fd, uint32_t events, MXS_POLL_DATA* pData);
/**
* Add a file descriptor to the epoll instance shared between all workers.
* Events occuring on the provided file descriptor will be handled by all
* workers. This is primarily intended for listening sockets where the
* only event is EPOLLIN, signaling that accept() can be used on the listening
* socket for creating a connected socket to a client.
*
* @param fd The file descriptor to be added.
* @param events Mask of epoll event types.
* @param pData The poll data associated with the descriptor:
*
* data->handler : Handler that knows how to deal with events
* for this particular type of 'struct mxs_poll_data'.
* data->thread.id: 0
*
* @return True, if the descriptor could be added, false otherwise.
*/
static bool add_shared_fd(int fd, uint32_t events, MXS_POLL_DATA* pData);
/**
* Remove a file descriptor from the worker's epoll instance.
*
* @param fd The file descriptor to be removed.
*
* @return True on success, false on failure.
*/
bool remove_fd(int fd);
/**
* Remove a file descriptor from the epoll instance shared between all workers.
*
* @param fd The file descriptor to be removed.
*
* @return True on success, false on failure.
*/
static bool remove_shared_fd(int fd);
/**
* Register zombie for later deletion.
*
* @param pZombie DCB that will be deleted at end of event loop.
*
* @note The DCB must be owned by this worker.
*/
void register_zombie(DCB* pZombie);
/**
* Main function of worker.
*
* The worker will run the poll loop, until it is told to shut down.
*
* @attention This function will run in the calling thread.
*/
void run();
/**
* Run worker in separate thread.
*
* This function will start a new thread, in which the `run`
* function will be executed.
*
* @param stack_size The stack size of the new thread. A value of 0 means
* that the pthread default should be used.
*
* @return True if the thread could be started, false otherwise.
*/
bool start(size_t stack_size = 0);
/**
* Waits for the worker to finish.
*/
void join();
/**
* Initate shutdown of worker.
*
* @attention A call to this function will only initiate the shutdowm,
* the worker will not have shut down when the function returns.
*
* @attention This function is signal safe.
*/
void shutdown();
/**
* Query whether worker should shutdown.
*
* @return True, if the worker should shut down, false otherwise.
*/
bool should_shutdown() const
{
return m_should_shutdown;
}
/**
* Posts a task to a worker for execution.
*
* @param pTask The task to be executed.
* @param pSem If non-NULL, will be posted once the task's `execute` return.
* @param mode Execution mode
*
* @return True if the task could be posted (i.e. not executed), false otherwise.
*
* @attention The instance must remain valid for as long as it takes for the
* task to be transferred to the worker and its `execute` function
* to be called.
*
* The semaphore can be used for waiting for the task to be finished.
*
* @code
* Semaphore sem;
* MyTask task;
*
* pWorker->execute(&task, &sem);
* sem.wait();
*
* MyResult& result = task.result();
* @endcode
*/
bool post(Task* pTask, Semaphore* pSem = NULL, enum execute_mode_t mode = EXECUTE_AUTO);
/**
* Posts a task to a worker for execution.
*
* @param pTask The task to be executed.
* @param mode Execution mode
*
* @return True if the task could be posted (i.e. not executed), false otherwise.
*
* @attention Once the task has been executed, it will be deleted.
*/
bool post(std::auto_ptr<DisposableTask> sTask, enum execute_mode_t mode = EXECUTE_AUTO);
template<class T>
bool post(std::auto_ptr<T> sTask, enum execute_mode_t mode = EXECUTE_AUTO)
{
return post(std::auto_ptr<DisposableTask>(sTask.release()), mode);
}
/**
* Posts a task to all workers for execution.
*
* @param pTask The task to be executed.
* @param pSem If non-NULL, will be posted once per worker when the task's
* `execute` return.
*
* @return How many workers the task was posted to.
*
* @attention The very same task will be posted to all workers. The task
* should either not have any sharable data or then it should
* have data specific to each worker that can be accessed
* without locks.
*/
static size_t broadcast(Task* pTask, Semaphore* pSem = NULL);
/**
* Posts a task to all workers for execution.
*
* @param pTask The task to be executed.
*
* @return How many workers the task was posted to.
*
* @attention The very same task will be posted to all workers. The task
* should either not have any sharable data or then it should
* have data specific to each worker that can be accessed
* without locks.
*
* @attention Once the task has been executed by all workers, it will
* be deleted.
*/
static size_t broadcast(std::auto_ptr<DisposableTask> sTask);
template<class T>
static size_t broadcast(std::auto_ptr<T> sTask)
{
return broadcast(std::auto_ptr<DisposableTask>(sTask.release()));
}
/**
* Executes a task on all workers in serial mode (the task is executed
* on at most one worker thread at a time). When the function returns
* the task has been executed on all workers.
*
* @param task The task to be executed.
*
* @return How many workers the task was posted to.
*
* @warning This function is extremely inefficient and will be slow compared
* to the other functions. Only use this function when printing thread-specific
* data to stdout.
*/
static size_t execute_serially(Task& task);
/**
* Executes a task on all workers concurrently and waits until all workers
* are done. That is, when the function returns the task has been executed
* by all workers.
*
* @param task The task to be executed.
*
* @return How many workers the task was posted to.
*/
static size_t execute_concurrently(Task& task);
/**
* Post a message to a worker.
*
* @param msg_id The message id.
* @param arg1 Message specific first argument.
* @param arg2 Message specific second argument.
*
* @return True if the message could be sent, false otherwise. If the message
* posting fails, errno is set appropriately.
*
* @attention The return value tells *only* whether the message could be sent,
* *not* that it has reached the worker.
*
* @attention This function is signal safe.
*/
bool post_message(uint32_t msg_id, intptr_t arg1, intptr_t arg2);
/**
* Return a reference to the session registry of this worker.
*
* @return Session registry.
*/
SessionsById& session_registry();
/**
* Broadcast a message to all worker.
*
* @param msg_id The message id.
* @param arg1 Message specific first argument.
* @param arg2 Message specific second argument.
*
* @return The number of messages posted; if less that ne number of workers
* then some postings failed.
*
* @attention The return value tells *only* whether message could be posted,
* *not* that it has reached the worker.
*
* @attentsion Exactly the same arguments are passed to all workers. Take that
* into account if the passed data must be freed.
*
* @attention This function is signal safe.
*/
static size_t broadcast_message(uint32_t msg_id, intptr_t arg1, intptr_t arg2);
/**
* Initate shutdown of all workers.
*
* @attention A call to this function will only initiate the shutdowm,
* the workers will not have shut down when the function returns.
*
* @attention This function is signal safe.
*/
static void shutdown_all();
/**
* Return the worker associated with the provided worker id.
*
* @param worker_id A worker id.
*
* @return The corresponding worker instance, or NULL if the id does
* not correspond to a worker.
*/
static Worker* get(int worker_id);
/**
* Return the worker associated with the current thread.
*
* @return The worker instance, or NULL if the current thread does not have a worker.
*/
static Worker* get_current();
/**
* Return the worker id associated with the current thread.
*
* @return A worker instance, or -1 if the current thread does not have a worker.
*/
static int get_current_id();
/**
* Set the number of non-blocking poll cycles that will be done before
* a blocking poll will take place.
*
* @param nbpolls Number of non-blocking polls to perform before blocking.
*/
static void set_nonblocking_polls(unsigned int nbpolls);
/**
* Maximum time to block in epoll_wait.
*
* @param maxwait Maximum wait time in millliseconds.
*/
static void set_maxwait(unsigned int maxwait);
private:
Worker(int id,
int epoll_fd);
virtual ~Worker();
static Worker* create(int id, int epoll_listener_fd);
void delete_zombies();
bool post_disposable(DisposableTask* pTask, enum execute_mode_t mode = EXECUTE_AUTO);
void handle_message(MessageQueue& queue, const MessageQueue::Message& msg); // override
static void thread_main(void* arg);
void poll_waitevents();
static uint32_t epoll_instance_handler(struct mxs_poll_data* data, int wid, uint32_t events);
uint32_t handle_epoll_events(uint32_t events);
private:
int m_id; /*< The id of the worker. */
state_t m_state; /*< The state of the worker */
int m_epoll_fd; /*< The epoll file descriptor. */
STATISTICS m_statistics; /*< Worker statistics. */
MessageQueue* m_pQueue; /*< The message queue of the worker. */
THREAD m_thread; /*< The thread handle of the worker. */
bool m_started; /*< Whether the thread has been started or not. */
bool m_should_shutdown; /*< Whether shutdown should be performed. */
bool m_shutdown_initiated; /*< Whether shutdown has been initated. */
SessionsById m_sessions; /*< A mapping of session_id->MXS_SESSION. The map
* should contain sessions exclusive to this
* worker and not e.g. listener sessions. For now,
* it's up to the protocol to decide whether a new
* session is added to the map. */
Zombies m_zombies; /*< DCBs to be deleted. */
};
}

View File

@ -0,0 +1,84 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
namespace maxscale
{
class Worker;
/**
* A WorkerTask represents a task to be performed by a Worker.
*/
class WorkerTask
{
public:
/**
* Destructor
*/
virtual ~WorkerTask();
/**
* @brief Called in the context of a specific worker.
*
* @param worker The worker in whose context `execute` is called.
*
* @attention As the function is called by a worker, the body of `execute`
* should execute quickly and not perform any blocking operations.
*/
virtual void execute(Worker& worker) = 0;
};
/**
* A WorkerDisposableTask represents a task to be performed by a Worker.
*
* When the task has been executed, the instance will automatically be
* deleted.
*/
class WorkerDisposableTask
{
public:
/**
* Destructor
*/
virtual ~WorkerDisposableTask();
protected:
/**
* Constructor
*/
WorkerDisposableTask();
/**
* @brief Called in the context of a specific worker.
*
* @param worker The worker in whose context `execute` is called.
*
* @attention As the function is called by a worker, the body of `execute`
* should execute quickly and not perform any blocking operations.
*/
virtual void execute(Worker& worker) = 0;
private:
friend class Worker;
void inc_ref();
void dec_ref();
private:
int32_t m_count;
};
}