From 4bca9aa02305aa271dab52f3519427758992f640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Tue, 7 Nov 2017 09:24:18 +0200 Subject: [PATCH 1/4] Fix and improve binlogrouter GTID option processing The transaction safety was checked even if master GTID registration was disabled. This always caused a failure when the router was started without the transaction safety parameter. As transaction safety is required by the GTID registration, it is not very helpful to refuse to start if an invalid set of options is detected. To make usage of the master GTID registration easier, the transaction safety is also automatically enabled. --- Documentation/Routers/Binlogrouter.md | 24 +++++++++++------------ server/modules/routing/binlogrouter/blr.c | 14 +++---------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/Documentation/Routers/Binlogrouter.md b/Documentation/Routers/Binlogrouter.md index 69a11b4c3..f209c7027 100644 --- a/Documentation/Routers/Binlogrouter.md +++ b/Documentation/Routers/Binlogrouter.md @@ -296,13 +296,13 @@ Example: ``` ### `mariadb10_master_gtid` -This option allows MaxScale binlog router to register -with MariaDB 10.X master using GTID instead of _binlog_file_ name -and _position_ in CHANGE MASTER TO admin command. -The user can set a known GTID or an empty value -(in this case the Master server will send events -from it's first available binlog file). +This option allows MaxScale binlog router to register with MariaDB 10.X master +using GTID instead of _binlog_file_ name and _position_ in CHANGE MASTER TO +admin command. This feature is disabled by default. + +The user can set a known GTID or an empty value (in this case the Master server +will send events from it's first available binlog file). Example of MaxScale connection to a MariaDB 10.X Master @@ -316,13 +316,13 @@ MariaDB> CHANGE MASTER TO MariaDB> START SLAVE; ``` -If using GTID request then it's no longer possible to use -MASTER_LOG_FILE and MASTER_LOG_POS in `CHANGE MASTER TO` -command: an error will be reported. +If using GTID request then it's no longer possible to use MASTER_LOG_FILE and +MASTER_LOG_POS in `CHANGE MASTER TO` command: an error will be reported. -The default option value is _Off_, setting it to _On_ -automatically sets _mariadb10_slave_gtid_ to _On_ -(which enables GTID storage and GTID slave connections) +If this feature is enabled, the _mariadb10_slave_gtid_ and +_transaction_safety_ features will be automatically enabled. The binlog +files will also be stored in a hierarchical directory tree instead of a +single directory. **Note:** diff --git a/server/modules/routing/binlogrouter/blr.c b/server/modules/routing/binlogrouter/blr.c index e7c485b67..522dd8f99 100644 --- a/server/modules/routing/binlogrouter/blr.c +++ b/server/modules/routing/binlogrouter/blr.c @@ -770,6 +770,8 @@ createInstance(SERVICE *service, char **options) { /* Force GTID slave request handling */ inst->mariadb10_gtid = true; + /* Force transaction safety */ + inst->trx_safe = true; /* Force binlog storage as tree */ inst->storage_type = BLR_BINLOG_STORAGE_TREE; } @@ -782,18 +784,8 @@ createInstance(SERVICE *service, char **options) "'tree' mode using GTID domain_id and server_id"); /* Enable MariaDB the GTID maps store */ - if (inst->mariadb10_compat && - inst->mariadb10_gtid) + if (inst->mariadb10_compat && inst->mariadb10_master_gtid) { - if (!inst->trx_safe) - { - MXS_ERROR("MariaDB GTID can be enabled only" - " with Transaction Safety feature." - " Please enable it with option 'transaction_safety = on'"); - free_instance(inst); - return NULL; - } - /* Create/Open R/W GTID sqlite3 storage */ if (!blr_open_gtid_maps_storage(inst)) { From e7342324d77d5e84f41d54728d1cb2b62acb21ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Tue, 7 Nov 2017 10:57:40 +0200 Subject: [PATCH 2/4] Update binlogrouter documentation and release notes Removed references to removed parameters, and updated release notes. --- .../Release-Notes/MaxScale-2.2.1-Release-Notes.md | 12 +++++++++--- Documentation/Routers/Binlogrouter.md | 7 +++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md index e5780c0eb..b0adad25b 100644 --- a/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md @@ -9,12 +9,18 @@ For any problems you encounter, please consider submitting a bug report at [Jira](https://jira.mariadb.org). ## Changed Features + ### Binlog server -- MariaDB 10 GTID is always enabled for slave connections. -- Automatically set binlog storage to 'tree' mode when -_mariadb10_master_gtid_ option is on. +* The `mariadb10_slave_gtid` parameter was removed and slave connections can now + always register with MariaDB 10 GTID. +* The `binlog_structure` parameter was removed and the binlogs are stored + automatically in 'tree' mode when `mariadb10_master_gtid` is enabled. + +* If `mariadb10_master_gtid` is enabled, the `transaction_safety` is + automatically enabled. In MaxScale 2.2.0, if `transaction_safety` was disabled + when `mariadb10_master_gtid` was enabled MaxScale would refuse to start. ## Dropped Features diff --git a/Documentation/Routers/Binlogrouter.md b/Documentation/Routers/Binlogrouter.md index f209c7027..1c4ef2d6d 100644 --- a/Documentation/Routers/Binlogrouter.md +++ b/Documentation/Routers/Binlogrouter.md @@ -319,10 +319,9 @@ MariaDB> START SLAVE; If using GTID request then it's no longer possible to use MASTER_LOG_FILE and MASTER_LOG_POS in `CHANGE MASTER TO` command: an error will be reported. -If this feature is enabled, the _mariadb10_slave_gtid_ and -_transaction_safety_ features will be automatically enabled. The binlog -files will also be stored in a hierarchical directory tree instead of a -single directory. +If this feature is enabled, the _transaction_safety_ option will be +automatically enabled. The binlog files will also be stored in a +hierarchical directory tree instead of a single directory. **Note:** From b1b78a5be770baa604122b78dddaa303f5f754c1 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 8 Nov 2017 09:59:41 +0200 Subject: [PATCH 3/4] Remove references to QUEUE_CONFIG Only used in conjunction with queued connections, which are not enabled anyway. Once that comes on the table again, better to use some standard data structures. --- include/maxscale/service.h | 2 -- server/core/config_runtime.cc | 4 +++- server/core/dcb.cc | 12 ++++------ server/core/service.cc | 44 ++++------------------------------- 4 files changed, 13 insertions(+), 49 deletions(-) diff --git a/include/maxscale/service.h b/include/maxscale/service.h index ac1574647..0da2dcfa3 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -35,7 +35,6 @@ #include #include #include -#include #include MXS_BEGIN_DECLS @@ -128,7 +127,6 @@ typedef struct service int state; /**< The service state */ int client_count; /**< Number of connected clients */ int max_connections; /**< Maximum client connections */ - QUEUE_CONFIG *queued_connections; /**< Queued connections, if set */ SERV_LISTENER *ports; /**< Linked list of ports and protocols * that this service will listen on */ char *routerModule; /**< Name of router module to use */ diff --git a/server/core/config_runtime.cc b/server/core/config_runtime.cc index 5c4b2ca48..54d57a486 100644 --- a/server/core/config_runtime.cc +++ b/server/core/config_runtime.cc @@ -596,7 +596,9 @@ bool runtime_alter_service(SERVICE *service, const char* zKey, const char* zValu { valid = true; // TODO: Once connection queues are implemented, use correct values - serviceSetConnectionLimits(service, i, 0, 0); + const int queued_connections = 0; // At most this many pending connections. + const int timeout = 0; // Wait at most this much for a connection. + serviceSetConnectionLimits(service, i, queued_connections, timeout); } } else if (key == CN_CONNECTION_TIMEOUT) diff --git a/server/core/dcb.cc b/server/core/dcb.cc index 41aa75638..df7459f55 100644 --- a/server/core/dcb.cc +++ b/server/core/dcb.cc @@ -56,7 +56,6 @@ #include #include "maxscale/modules.h" -#include "maxscale/queuemanager.h" #include "maxscale/semaphore.hh" #include "maxscale/session.h" #include "maxscale/worker.hh" @@ -2435,14 +2434,13 @@ dcb_accept(DCB *listener) if (client_dcb->service->max_connections && client_dcb->service->client_count >= client_dcb->service->max_connections) { - if (!mxs_enqueue(client_dcb->service->queued_connections, client_dcb)) + // TODO: If connections can be queued, this is the place to put the + // TODO: connection on that queue. + if (client_dcb->func.connlimit) { - if (client_dcb->func.connlimit) - { - client_dcb->func.connlimit(client_dcb, client_dcb->service->max_connections); - } - dcb_close(client_dcb); + client_dcb->func.connlimit(client_dcb, client_dcb->service->max_connections); } + dcb_close(client_dcb); client_dcb = NULL; } } diff --git a/server/core/service.cc b/server/core/service.cc index 7906a8bc4..a043f1324 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -54,7 +53,6 @@ #include "maxscale/config.h" #include "maxscale/filter.h" #include "maxscale/modules.h" -#include "maxscale/queuemanager.h" #include "maxscale/service.h" /** This define is needed in CentOS 6 systems */ @@ -97,7 +95,6 @@ static int find_type(typelib_t* tl, const char* needle, int maxlen); static void service_add_qualified_param(SERVICE* svc, MXS_CONFIG_PARAMETER* param); static void service_internal_restart(void *data); -static void service_queue_check(void *data); static void service_calculate_weights(SERVICE *service); SERVICE* service_alloc(const char *name, const char *router) @@ -145,7 +142,6 @@ SERVICE* service_alloc(const char *name, const char *router) service->name = my_name; service->routerModule = my_router; service->users_from_all = false; - service->queued_connections = NULL; service->localhost_match_wildcard_host = SERVICE_PARAM_UNINIT; service->retry_start = true; service->conn_idle_timeout = SERVICE_NO_SESSION_TIMEOUT; @@ -1157,6 +1153,8 @@ void serviceSetVersionString(SERVICE *service, const char* value) * @param max The maximum number of client connections at any one time * @param queued The maximum number of connections to queue up when * max_connections clients are already connected + * @param timeout Maximum amount of time to wait for a connection to + * become available. * @return 1 on success, 0 when the values are invalid */ int @@ -1169,45 +1167,13 @@ serviceSetConnectionLimits(SERVICE *service, int max, int queued, int timeout) } service->max_connections = max; - if (queued && timeout) - { - char callback_name[100]; - sprintf(callback_name, "Check queued connections %p", service); - /* If memory allocation fails, result will be null so no queue */ - service->queued_connections = mxs_queue_alloc(queued, timeout); - if (service->queued_connections) - { - hktask_add(callback_name, service_queue_check, (void *)service->queued_connections, 1); - } - } + + ss_info_dassert(queued == 0, "Queued connections not implemented."); + ss_info_dassert(timeout == 0, "Queued connections not implemented."); return 1; } -/* - * @brief The callback function triggered by housekeeping every second - * - * This function removes any expired connection requests from the queue, and - * sends an error message "too many connections" for them. - * - * @param The parameter provided by the callback is the queue config - */ -static void -service_queue_check(void *data) -{ - QUEUE_ENTRY expired; - QUEUE_CONFIG *queue_config = (QUEUE_CONFIG *)data; - /* The queued connections are in a FIFO queue, so we only look at the */ - /* start of the queue, and remove any expired entries. As soon as this */ - /* returns nothing, we stop. */ - while ((mxs_dequeue_if_expired(queue_config, &expired))) - { - DCB *dcb = (DCB *)expired.queued_object; - dcb->func.connlimit(dcb, queue_config->queue_limit); - dcb_close(dcb); - } -} - /** * Enable or disable the restarting of the service on failure. * @param service Service to configure From 42d9064b046a6fa5898f4d4bc8f6795cf71f22dc Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 8 Nov 2017 10:07:37 +0200 Subject: [PATCH 4/4] Remoeve queuemanager.[h|cc] --- include/maxscale/queuemanager.h | 26 --- server/core/CMakeLists.txt | 1 - server/core/maxscale/queuemanager.h | 54 ------ server/core/queuemanager.cc | 229 ----------------------- server/core/test/CMakeLists.txt | 3 - server/core/test/testqueuemanager.cc | 259 --------------------------- 6 files changed, 572 deletions(-) delete mode 100644 include/maxscale/queuemanager.h delete mode 100644 server/core/maxscale/queuemanager.h delete mode 100644 server/core/queuemanager.cc delete mode 100644 server/core/test/testqueuemanager.cc diff --git a/include/maxscale/queuemanager.h b/include/maxscale/queuemanager.h deleted file mode 100644 index 57f33c7f3..000000000 --- a/include/maxscale/queuemanager.h +++ /dev/null @@ -1,26 +0,0 @@ -#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 queuemanager.h The Queue Manager public header - */ - -#include - -MXS_BEGIN_DECLS - -struct queue_config; -typedef struct queue_config QUEUE_CONFIG; - -MXS_END_DECLS diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 3c27a7461..e228c5a9d 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -33,7 +33,6 @@ add_library(maxscale-common SHARED paths.cc poll.cc query_classifier.cc - queuemanager.cc random_jkiss.cc resultset.cc resource.cc diff --git a/server/core/maxscale/queuemanager.h b/server/core/maxscale/queuemanager.h deleted file mode 100644 index 32851d50b..000000000 --- a/server/core/maxscale/queuemanager.h +++ /dev/null @@ -1,54 +0,0 @@ -#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/queuemanager.h - The private queuemanager interface - */ - -#include - -#include - -MXS_BEGIN_DECLS - -typedef struct queue_entry -{ - void *queued_object; - long heartbeat; -#if defined(SS_DEBUG) - long sequence_check; -#endif /* SS_DEBUG */ -} QUEUE_ENTRY; - -struct queue_config -{ - int queue_limit; - int start; - int end; - int timeout; - bool has_entries; - SPINLOCK queue_lock; - QUEUE_ENTRY *queue_array; -#if defined(SS_DEBUG) - long sequence_number; -#endif /* SS_DEBUG */ -}; - -QUEUE_CONFIG *mxs_queue_alloc(int limit, int timeout); -void mxs_queue_free(QUEUE_CONFIG *queue_config); -bool mxs_enqueue(QUEUE_CONFIG *queue_config, void *new_entry); -bool mxs_dequeue(QUEUE_CONFIG *queue_config, QUEUE_ENTRY *result); -bool mxs_dequeue_if_expired(QUEUE_CONFIG *queue_config, QUEUE_ENTRY *result); - -MXS_END_DECLS diff --git a/server/core/queuemanager.cc b/server/core/queuemanager.cc deleted file mode 100644 index 937e32440..000000000 --- a/server/core/queuemanager.cc +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2016 MariaDB Corporation Ab - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file and at www.mariadb.com/bsl11. - * - * Change Date: 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 queuemanager.c - Logic for FIFO queue handling - * - * MaxScale contains a number of FIFO queues. This code attempts to provide - * standard functions for handling them. - * - * @verbatim - * Revision History - * - * Date Who Description - * 27/04/16 Martin Brampton Initial implementation - * - * @endverbatim - */ -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "maxscale/queuemanager.h" - -#if defined(SS_DEBUG) -int debug_check_fail = 0; -#endif /* SS_DEBUG */ - -static inline int mxs_queue_count(QUEUE_CONFIG*); - -/** - * @brief Allocate a new queue - * - * Provides for FIFO queues, this is the first operation to be requested - * for the use of a queue. - * - * @param limit The maximum size of the queue - * @param timeout The maximum time for which an entry is valid - * @return QUEUE_CONFIG A queue configuration and anchor structure - */ -QUEUE_CONFIG -*mxs_queue_alloc(int limit, int timeout) -{ - QUEUE_CONFIG *new_queue = (QUEUE_CONFIG *)MXS_CALLOC(1, sizeof(QUEUE_CONFIG)); - if (new_queue) - { - new_queue->queue_array = (QUEUE_ENTRY*)MXS_CALLOC(limit + 1, sizeof(QUEUE_ENTRY)); - if (new_queue->queue_array) - { - new_queue->queue_limit = limit; - new_queue->timeout = timeout; - spinlock_init(&new_queue->queue_lock); -#if defined(SS_DEBUG) - new_queue->sequence_number = 0; -#endif /* SS_DEBUG */ - return new_queue; - } - MXS_FREE(new_queue); - } - return NULL; -} - -/** - * @brief Free a queue configuration - * - * Provides for FIFO queues, this is the last operation to be requested, when - * there is no further use for the queue. - * - * @param QUEUE_CONFIG A queue configuration and anchor structure - */ -void mxs_queue_free(QUEUE_CONFIG *queue_config) -{ - if (queue_config) - { - MXS_FREE(queue_config->queue_array); - MXS_FREE(queue_config); - } -} - -/** - * @brief Add an item to a queue - * - * Add a new item to a FIFO queue. If the queue config is null, this function - * will behave as if the queue is full. - * - * @param queue_config The configuration and anchor structure for the queue - * @param new_entry The new entry, to be added - * @return bool Whether the enqueue succeeded - */ -bool mxs_enqueue(QUEUE_CONFIG *queue_config, void *new_entry) -{ - bool result = false; - - if (queue_config) - { - spinlock_acquire(&queue_config->queue_lock); - if (mxs_queue_count(queue_config) < queue_config->queue_limit) - { - queue_config->queue_array[queue_config->end].queued_object = new_entry; - queue_config->queue_array[queue_config->end].heartbeat = hkheartbeat; -#if defined(SS_DEBUG) - queue_config->queue_array[queue_config->end].sequence_check = queue_config->sequence_number; - queue_config->sequence_number++; -#endif /* SS_DEBUG */ - queue_config->end++; - if (queue_config->end > queue_config->queue_limit) - { - queue_config->end = 0; - } - queue_config->has_entries = true; - result = true; - } - else - { - result = false; - } - spinlock_release(&queue_config->queue_lock); - } - return result; -} - -/** - * @brief Remove an item from a queue - * - * Remove an item from a FIFO queue. If the queue config is NULL, the function - * will behave as if for an empty queue. - * - * @param queue_config The configuration and anchor structure for the queue - * @param result A queue entry structure that will receive the result - * @return bool indicating whether an item was successfully dequeued - */ -bool mxs_dequeue(QUEUE_CONFIG *queue_config, QUEUE_ENTRY *result) -{ - QUEUE_ENTRY *found = NULL; - - if (queue_config && queue_config->has_entries) - { - spinlock_acquire(&queue_config->queue_lock); - if (mxs_queue_count(queue_config) > 0) - { - found = &(queue_config->queue_array[queue_config->start]); -#if defined(SS_DEBUG) - ss_dassert((queue_config->sequence_number) == (found->sequence_check + mxs_queue_count(queue_config))); - if ((queue_config->sequence_number) != (found->sequence_check + mxs_queue_count(queue_config))) - { - debug_check_fail++; - } -#endif /* SS_DEBUG */ - result->heartbeat = found->heartbeat; - result->queued_object = found->queued_object; - if (++queue_config->start > queue_config->queue_limit) - { - queue_config->start = 0; - } - queue_config->has_entries = (mxs_queue_count(queue_config) > 0); - } - spinlock_release(&queue_config->queue_lock); - } - return (found != NULL); -} - -/** - * @brief Remove an item from a queue if it has passed the timeout limit - * - * Remove an item from a FIFO queue if expired. If the queue config is NULL, - * the function will behave as for an empty queue. - * - * @param queue_config The configuration and anchor structure for the queue - * @param result A queue entry structure that will receive the result - * @return bool indicating whether an item was successfully dequeued - */ -bool mxs_dequeue_if_expired(QUEUE_CONFIG *queue_config, QUEUE_ENTRY *result) -{ - QUEUE_ENTRY *found = NULL; - - if (queue_config && queue_config->has_entries) - { - spinlock_acquire(&queue_config->queue_lock); - if (mxs_queue_count(queue_config) > 0) - { - found = &(queue_config->queue_array[queue_config->start]); - if (found->heartbeat > hkheartbeat - queue_config->timeout) - { - found = NULL; - } - else - { -#if defined(SS_DEBUG) - ss_dassert((queue_config->sequence_number) == (found->sequence_check + mxs_queue_count(queue_config))); - if ((queue_config->sequence_number) != (found->sequence_check + mxs_queue_count(queue_config))) - { - debug_check_fail++; - } -#endif /* SS_DEBUG */ - result->heartbeat = found->heartbeat; - result->queued_object = found->queued_object; - if (++queue_config->start > queue_config->queue_limit) - { - queue_config->start = 0; - } - queue_config->has_entries = (mxs_queue_count(queue_config) > 0); - } - } - spinlock_release(&queue_config->queue_lock); - } - return (found != NULL); -} - -static inline int mxs_queue_count(QUEUE_CONFIG *queue_config) -{ - int count = queue_config->end - queue_config->start; - return count < 0 ? (count + queue_config->queue_limit + 1) : count; -} diff --git a/server/core/test/CMakeLists.txt b/server/core/test/CMakeLists.txt index dd9d2e539..8127adf2d 100644 --- a/server/core/test/CMakeLists.txt +++ b/server/core/test/CMakeLists.txt @@ -10,7 +10,6 @@ add_executable(test_logorder testlogorder.cc) add_executable(test_logthrottling testlogthrottling.cc) add_executable(test_modutil testmodutil.cc) add_executable(test_poll testpoll.cc) -add_executable(test_queuemanager testqueuemanager.cc) add_executable(test_semaphore testsemaphore.cc) add_executable(test_server testserver.cc) add_executable(test_service testservice.cc) @@ -37,7 +36,6 @@ target_link_libraries(test_logorder maxscale-common) target_link_libraries(test_logthrottling maxscale-common) target_link_libraries(test_modutil maxscale-common) target_link_libraries(test_poll maxscale-common) -target_link_libraries(test_queuemanager maxscale-common) target_link_libraries(test_semaphore maxscale-common) target_link_libraries(test_server maxscale-common) target_link_libraries(test_service maxscale-common) @@ -66,7 +64,6 @@ add_test(TestMaxScalePCRE2 testmaxscalepcre2) add_test(TestModutil test_modutil) add_test(NAME TestMaxPasswd COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/testmaxpasswd.sh) add_test(TestPoll test_poll) -add_test(TestQueueManager test_queuemanager) add_test(TestSemaphore test_semaphore) add_test(TestServer test_server) add_test(TestService test_service) diff --git a/server/core/test/testqueuemanager.cc b/server/core/test/testqueuemanager.cc deleted file mode 100644 index 5e4849949..000000000 --- a/server/core/test/testqueuemanager.cc +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2016 MariaDB Corporation Ab - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file and at www.mariadb.com/bsl11. - * - * Change Date: 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. - */ - -/** - * - * @verbatim - * Revision History - * - * Date Who Description - * 21/06/2016 Martin Brampton Initial implementation - * - * @endverbatim - */ - -// To ensure that ss_info_assert asserts also when builing in non-debug mode. -#if !defined(SS_DEBUG) -#define SS_DEBUG -int debug_check_fail = 1; -#else -// This is defined in the queuemanager code but only in debug builds -extern int debug_check_fail; -#endif -#if defined(NDEBUG) -#undef NDEBUG -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "../maxscale/queuemanager.h" -#include "test_utils.h" - -/** - * test1 Allocate a queue and do lots of other things - * - */ - -#define TEST_QUEUE_SIZE 5 -#define HEARTBEATS_TO_EXPIRE 3 -#define NUMBER_OF_THREADS 4 -#define THREAD_TEST_COUNT 1000000 - -static QUEUE_CONFIG *thread_queue; - -static int -test1() -{ - QUEUE_CONFIG *queue; - int filled = 0; - int emptied = 0; - int expired = 0; - int input_counter = 0; - int output_counter = 0; - - random_jkiss_init(); - hkheartbeat = 0; - - queue = mxs_queue_alloc(TEST_QUEUE_SIZE, HEARTBEATS_TO_EXPIRE); - - { - QUEUE_ENTRY entry; - if (mxs_dequeue(queue, &entry)) - { - ss_dfprintf(stderr, "\nError mxs_dequeue on empty queue did not return false.\n"); - return 1; - } - - if (mxs_dequeue_if_expired(queue, &entry)) - { - ss_dfprintf(stderr, "\nError mxs_dequeue_if_expired on empty queue did not return false.\n"); - return 1; - } - } - - while (filled < 250 || emptied < 250 || expired < 250) - { - ss_dfprintf(stderr, "Input counter %d and output counter %d\n", input_counter, output_counter); - ss_dfprintf(stderr, "Difference between counters %d\n", input_counter - output_counter); - ss_dfprintf(stderr, "Filled %d, emptied %d, expired %d\n", filled, emptied, expired); - if (random_jkiss() % 2) - { - int *entrynumber = (int*)MXS_MALLOC(sizeof(int)); - *entrynumber = input_counter; - if (mxs_enqueue(queue, entrynumber)) - { - input_counter++; - if ((input_counter - output_counter) > TEST_QUEUE_SIZE) - { - ss_dfprintf(stderr, "\nQueue full, but mxs_enqueue accepted entry.\n"); - return 3; - } - } - else - { - QUEUE_ENTRY entry; - - if ((input_counter - output_counter) != TEST_QUEUE_SIZE) - { - ss_dfprintf(stderr, "\nFailed enqueue, but input counter %d and output counter %d do not differ by %d.\n", - input_counter, - output_counter, - TEST_QUEUE_SIZE); - return 4; - } - filled++; - if (0 == (random_jkiss() % 5)) - { - if ((mxs_dequeue_if_expired(queue, &entry))) - { - if ((entry.heartbeat) > (hkheartbeat - HEARTBEATS_TO_EXPIRE)) - { - ss_dfprintf(stderr, "\nReturned an expired entry even though none or not expired.\n"); - return 5; - } - if (*(int *)entry.queued_object != output_counter) - { - ss_dfprintf(stderr, "\nOutput counter was %d, but dequeue gave %d.\n", - output_counter, - *(int *)entry.queued_object); - return 10; - } - output_counter++; - MXS_FREE(entry.queued_object); - } - else - { - hkheartbeat += (HEARTBEATS_TO_EXPIRE + 1); - if (mxs_dequeue_if_expired(queue, &entry)) - { - if (*(int *)entry.queued_object != output_counter) - { - ss_dfprintf(stderr, "\nOutput counter was %d, but dequeue gave %d.\n", - output_counter, - *(int *)entry.queued_object); - return 6; - } - output_counter++; - MXS_FREE(entry.queued_object); - } - else - { - ss_dfprintf(stderr, "\nReturned no expired entry even though all are expired.\n"); - return 7; - } - expired++; - } - } - } - } - else - { - QUEUE_ENTRY entry; - if (mxs_dequeue(queue, &entry)) - { - if (*(int *)entry.queued_object != output_counter) - { - ss_dfprintf(stderr, "\nOutput counter was %d, but dequeue gave %d.\n", - output_counter, - *(int *)entry.queued_object); - return 8; - } - output_counter++; - MXS_FREE(entry.queued_object); - } - else - { - if (input_counter != output_counter) - { - ss_dfprintf(stderr, "\nNULL from dequeue, but input counter %d and output counter %d.\n", - input_counter, - output_counter); - return 9; - } - emptied++; - } - } - } - - ss_dfprintf(stderr, "Successfully ended test\n"); - mxs_queue_free(queue); - return 0; -} - -static void * -thread_test(void *arg) -{ - int i; - QUEUE_ENTRY entry; - int emptied = 0; - int filled = 0; - - for (i = 0; i < THREAD_TEST_COUNT; i++) - { - if (random_jkiss() % 2) - { - if (!mxs_enqueue(thread_queue, (void *)"Just for test")) - { - filled++; - } - } - else - { - if (!mxs_dequeue(thread_queue, &entry)) - { - emptied++; - } - } - } - ss_dfprintf(stderr, "Queue was full %d times, empty %d times\n", filled, emptied); - - return NULL; -} - -static int -test2() -{ - pthread_t tid[NUMBER_OF_THREADS]; - int err, i, limit; - - thread_queue = mxs_queue_alloc(TEST_QUEUE_SIZE, HEARTBEATS_TO_EXPIRE); - limit = NUMBER_OF_THREADS; - for (i = 0; i < limit; i++) - { - err = pthread_create(&tid[i], NULL, thread_test, NULL); - ss_info_dassert((0 == err), "Must create threads successfully"); - } - for (i = 0; i < limit; i++) - { - err = pthread_join(tid[i], NULL); - ss_info_dassert((0 == err), "Must join threads successfully"); - ss_dfprintf(stderr, "\nThread %d ended with debug check fail at %d.\n", i, debug_check_fail); - } - mxs_queue_free(thread_queue); - return debug_check_fail ? 1 : 0; -} - -int main(int argc, char **argv) -{ - int result = 0; - - result += (test1() ? 1 : 0); - result += (test2() ? 1 : 0); - - exit(result); -}