diff --git a/CMakeLists.txt b/CMakeLists.txt index 590c8f07d..da4e956d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ configure_file(${CMAKE_SOURCE_DIR}/include/maxscale/adminusers.h.in ${CMAKE_BINA configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.h.in ${CMAKE_BINARY_DIR}/include/maxscale/maxscale_test.h @ONLY) configure_file(${CMAKE_SOURCE_DIR}/etc/postinst.in ${CMAKE_BINARY_DIR}/postinst @ONLY) configure_file(${CMAKE_SOURCE_DIR}/etc/postrm.in ${CMAKE_BINARY_DIR}/postrm @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/etc/upstart/maxscale.conf.in ${CMAKE_BINARY_DIR}/upstart/maxscale.conf @ONLY) configure_file(${CMAKE_SOURCE_DIR}/server/test/maxscale_test.cnf ${CMAKE_BINARY_DIR}/maxscale.cnf @ONLY) set(FLAGS "-Wall -Wno-unused-variable -Wno-unused-function -Werror -fPIC" CACHE STRING "Compilation flags") diff --git a/Documentation/Filters/Database-Firewall-Filter.md b/Documentation/Filters/Database-Firewall-Filter.md index 615109fe2..c50c4d1b7 100644 --- a/Documentation/Filters/Database-Firewall-Filter.md +++ b/Documentation/Filters/Database-Firewall-Filter.md @@ -157,7 +157,7 @@ This limits the rule to be active only on certain types of queries. The possible The `users` directive defines the users to which the rule should be applied. -`users NAME ... match [any|all|strict_all] rules RULE [,...]` +`users NAME... match { any | all | strict_all } rules RULE...` The first keyword is `users`, which identifies this line as a user definition line. diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 769bb2aa0..545f4c597 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -673,7 +673,7 @@ grants when loading the users from the backend server. This parameter takes a boolean value and when enabled, will strip all backslash (`\`) characters from the database names. The default value for this parameter -is true. +is true since MaxScale 2.0.1. In previous version, the default value was false. Some visual database management tools automatically escape some characters and this might cause conflicts when MariaDB MaxScale tries to authenticate users. diff --git a/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md b/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md index a8e0f7bd2..9106066a2 100644 --- a/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md +++ b/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md @@ -54,6 +54,8 @@ If your system does not support systemd you can start MariaDB MaxScale using the service maxscale start ``` +Starting with version 2.0.3, MaxScale also supports Upstart. + An example configuration file is installed into the `/etc/` folder. This file should be changed according to your needs. ## Install MariaDB MaxScale Using a Tarball diff --git a/Documentation/Release-Notes/MaxScale-2.0.3-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.0.3-Release-Notes.md new file mode 100644 index 000000000..aaa94a3a7 --- /dev/null +++ b/Documentation/Release-Notes/MaxScale-2.0.3-Release-Notes.md @@ -0,0 +1,48 @@ +# MariaDB MaxScale 2.0.3 Release Notes + +Release 2.0.3 is a GA release. + +This document describes the changes in release 2.0.3, when compared to +release [2.0.2](MaxScale-2.0.2-Release-Notes.md). + +If you are upgrading from release 1.4.4, please also read the release +notes of release [2.0.0](./MaxScale-2.0.0-Release-Notes.md) and +release [2.0.1](./MaxScale-2.0.1-Release-Notes.md). + +For any problems you encounter, please submit a bug report at +[Jira](https://jira.mariadb.org). + +## Updated Features + +### [MXS-1027] (https://jira.mariadb.org/browse/MXS-1027) Add Upstart support (including respawn) for MaxScale + +MaxScale now provides an Upstart configuration file for systems that do not +support systemd. + +## Bug fixes + +[Here](https://jira.mariadb.org/issues/?jql=project%20%3D%20MXS%20AND%20issuetype%20%3D%20Bug%20AND%20status%20%3D%20Closed%20AND%20fixVersion%20%3D%202.0.3) +is a list of bugs fixed since the release of MaxScale 2.0.1. + +* [MXS-1009](https://jira.mariadb.org/browse/MXS-1009): maxinfo sigsegv in spinlock_release + +## Known Issues and Limitations + +There are some limitations and known issues within this version of MaxScale. +For more information, please refer to the [Limitations](../About/Limitations.md) document. + +## Packaging + +RPM and Debian packages are provided for the Linux distributions supported +by MariaDB Enterprise. + +Packages can be downloaded [here](https://mariadb.com/resources/downloads). + +## Source Code + +The source code of MaxScale is tagged at GitHub with a tag, which is derived +from the version of MaxScale. For instance, the tag of version `X.Y.Z` of MaxScale +is `maxscale-X.Y.Z`. + +The source code is available [here](https://github.com/mariadb-corporation/MaxScale). + diff --git a/cmake/init_scripts.cmake b/cmake/init_scripts.cmake index 1f07ee8de..d85b86163 100644 --- a/cmake/init_scripts.cmake +++ b/cmake/init_scripts.cmake @@ -23,14 +23,18 @@ if(PACKAGE) message(STATUS "maxscale.conf will unpack to: /etc/ld.so.conf.d") message(STATUS "startup scripts will unpack to to: /etc/init.d") message(STATUS "systemd service files will unpack to to: /usr/lib/systemd/system") + message(STATUS "upstart files will unpack to: /etc/init/") install_file(${CMAKE_BINARY_DIR}/maxscale core) install_file(${CMAKE_BINARY_DIR}/maxscale.conf core) install_file(${CMAKE_BINARY_DIR}/maxscale.service core) + install_file(${CMAKE_BINARY_DIR}/upstart/maxscale.conf core) else() install(PROGRAMS ${CMAKE_BINARY_DIR}/maxscale DESTINATION /etc/init.d COMPONENT core) install(FILES ${CMAKE_BINARY_DIR}/maxscale.conf DESTINATION /etc/ld.so.conf.d COMPONENT core) install(FILES ${CMAKE_BINARY_DIR}/maxscale.service DESTINATION /usr/lib/systemd/system COMPONENT core) + install(FILES ${CMAKE_BINARY_DIR}/upstart/maxscale.conf DESTINATION /etc/init/) message(STATUS "Installing maxscale.conf to: /etc/ld.so.conf.d") message(STATUS "Installing startup scripts to: /etc/init.d") message(STATUS "Installing systemd service files to: /usr/lib/systemd/system") + message(STATUS "Installing upstart files to: /etc/init/") endif() diff --git a/etc/postinst.in b/etc/postinst.in index ed155b2b1..91c0e09c8 100755 --- a/etc/postinst.in +++ b/etc/postinst.in @@ -50,6 +50,11 @@ then systemctl daemon-reload fi else + if [ -d "/etc/init/" ] + then + cp @CMAKE_INSTALL_PREFIX@/@MAXSCALE_SHAREDIR@/upstart/maxscale.conf /etc/init/ + fi + # If systemd is not present, use init.d scripts if [ -f "@CMAKE_INSTALL_PREFIX@/@MAXSCALE_SHAREDIR@/maxscale" ] then diff --git a/etc/upstart/maxscale.conf.in b/etc/upstart/maxscale.conf.in new file mode 100644 index 000000000..bbbc89b5f --- /dev/null +++ b/etc/upstart/maxscale.conf.in @@ -0,0 +1,26 @@ +# MaxScale service + +description "MariaDB MaxScale" + +start on stopped rc RUNLEVEL=[2345] +stop on starting rc runlevel [!2345] + +# Respawn the process on abnormal exits +respawn + +# Uncomment this to limit respawns to two every five minutes +# respawn limit 2 5 + +# Unlimited open files +limit nofile unlimited unlimited + +# Make sure /var/run/maxscale exists +pre-start exec /usr/bin/install -d -o maxscale -g maxscale @MAXSCALE_VARDIR@/run/maxscale + +# Change the user to maxscale:maxscale +setuid maxscale +setgid maxscale + +# Start MaxScale +expect fork +exec /usr/bin/maxscale diff --git a/server/core/gateway.cc b/server/core/gateway.cc index 1d9f34d44..b34998269 100644 --- a/server/core/gateway.cc +++ b/server/core/gateway.cc @@ -1075,6 +1075,11 @@ bool disable_signals(void) return false; } + if (!delete_signal(&sigset, SIGCHLD, "SIGCHLD")) + { + return false; + } + #ifdef SIGBUS if (!delete_signal(&sigset, SIGBUS, "SIGBUS")) { diff --git a/server/modules/authenticator/NullAuthAllow/null_auth_allow.c b/server/modules/authenticator/NullAuthAllow/null_auth_allow.c index 954c15abf..a2a7db9eb 100644 --- a/server/modules/authenticator/NullAuthAllow/null_auth_allow.c +++ b/server/modules/authenticator/NullAuthAllow/null_auth_allow.c @@ -33,6 +33,9 @@ #include #include +/** MXS-1026: Without MySQL protocol data structures, the NullAuth authenticator will crash. */ +#include + /* @see function load_module in load_utils.c for explanation of the following * lint directives. */ @@ -130,6 +133,11 @@ null_auth_authenticate(DCB *dcb) static int null_auth_set_protocol_data(DCB *dcb, GWBUF *buf) { + /** MXS-1026: This will just prevent a crash when the NullAuth authenticator + * is used. This does not provide a way to use MaxScale with no authentication. */ + dcb->data = calloc(1, sizeof(MYSQL_session)); + dcb->protocol = mysql_protocol_init(dcb, dcb->fd); + return 0; } diff --git a/server/modules/protocol/CDC/cdc.c b/server/modules/protocol/CDC/cdc.c index 05031ed84..1843c7408 100644 --- a/server/modules/protocol/CDC/cdc.c +++ b/server/modules/protocol/CDC/cdc.c @@ -447,7 +447,7 @@ cdc_protocol_done(DCB* dcb) static void write_auth_ack(DCB *dcb) { - dcb_printf(dcb, "OK"); + dcb_printf(dcb, "OK\n"); } /** @@ -459,6 +459,6 @@ write_auth_ack(DCB *dcb) static void write_auth_err(DCB *dcb) { - dcb_printf(dcb, "ERR, code 11, msg: abcd"); + dcb_printf(dcb, "ERROR: Authentication failed\n"); } diff --git a/server/modules/routing/avrorouter/avro_client.c b/server/modules/routing/avrorouter/avro_client.c index fc1341e0a..64efed432 100644 --- a/server/modules/routing/avrorouter/avro_client.c +++ b/server/modules/routing/avrorouter/avro_client.c @@ -78,7 +78,7 @@ avro_client_handle_request(AVRO_INSTANCE *router, AVRO_CLIENT *client, GWBUF *qu if (avro_client_do_registration(router, client, queue) == 0) { client->state = AVRO_CLIENT_ERRORED; - dcb_printf(client->dcb, "ERR, code 12, msg: Registration failed"); + dcb_printf(client->dcb, "ERR, code 12, msg: Registration failed\n"); /* force disconnection */ dcb_close(client->dcb); rval = 0; @@ -86,7 +86,7 @@ avro_client_handle_request(AVRO_INSTANCE *router, AVRO_CLIENT *client, GWBUF *qu else { /* Send OK ack to client */ - dcb_printf(client->dcb, "OK"); + dcb_printf(client->dcb, "OK\n"); client->state = AVRO_CLIENT_REGISTERED; MXS_INFO("%s: Client [%s] has completed REGISTRATION action", @@ -503,7 +503,7 @@ avro_client_process_command(AVRO_INSTANCE *router, AVRO_CLIENT *client, GWBUF *q { GWBUF *reply = gwbuf_alloc(5); memcpy(GWBUF_DATA(reply), "ECHO:", 5); - reply = gwbuf_append(reply, queue); + reply = gwbuf_append(reply, gwbuf_clone(queue)); client->dcb->func.write(client->dcb, reply); } } @@ -556,11 +556,15 @@ const char* get_avrofile_name(const char *file_ptr, int data_len, char *dest) static int send_row(DCB *dcb, json_t* row) { char *json = json_dumps(row, JSON_PRESERVE_ORDER); - GWBUF *buf; + size_t len = strlen(json); + GWBUF *buf = gwbuf_alloc(len + 1); int rc = 0; - if (json && (buf = gwbuf_alloc_and_load(strlen(json), (void*)json))) + if (json && buf) { + uint8_t *data = GWBUF_DATA(buf); + memcpy(data, json, len); + data[len] = '\n'; rc = dcb->func.write(dcb, buf); } else diff --git a/server/modules/routing/binlogrouter/blr_file.c b/server/modules/routing/binlogrouter/blr_file.c index 3c8b3a1b5..0db36dbfd 100644 --- a/server/modules/routing/binlogrouter/blr_file.c +++ b/server/modules/routing/binlogrouter/blr_file.c @@ -565,7 +565,7 @@ blr_write_binlog_record(ROUTER_INSTANCE *router, REP_HEADER *hdr, uint32_t size, if (ftruncate(router->binlog_fd, router->binlog_position)) { MXS_ERROR("%s: Failed to truncate binlog record at %lu of %s, %s. ", - router->service->name, router->last_written, + router->service->name, router->binlog_position, router->binlog_name, strerror_r(errno, err_msg, sizeof(err_msg))); } diff --git a/server/modules/routing/binlogrouter/blr_master.c b/server/modules/routing/binlogrouter/blr_master.c index 96c382f0c..06c90ed56 100644 --- a/server/modules/routing/binlogrouter/blr_master.c +++ b/server/modules/routing/binlogrouter/blr_master.c @@ -1335,7 +1335,7 @@ blr_handle_binlog_record(ROUTER_INSTANCE *router, GWBUF *pkt) db_name_len = ptr[4 + 20 + 4 + 4]; var_block_len = ptr[4 + 20 + 4 + 4 + 1 + 2]; - statement_len = len - (4 + 20 + 4 + 4 + 1 + 2 + 2 + var_block_len + 1 + db_name_len) - semisync_bytes; + statement_len = len - (4 + 20 + 4 + 4 + 1 + 2 + 2 + var_block_len + 1 + db_name_len); statement_sql = MXS_CALLOC(1, statement_len + 1); MXS_ABORT_IF_NULL(statement_sql); memcpy(statement_sql, @@ -1470,7 +1470,7 @@ blr_handle_binlog_record(ROUTER_INSTANCE *router, GWBUF *pkt) /* Check for rotate event */ if (hdr.event_type == ROTATE_EVENT) { - if (!blr_rotate_event(router, ptr, &hdr)) + if (!blr_rotate_event(router, ptr + offset, &hdr)) { gwbuf_free(pkt); blr_master_close(router); diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index 3b779e83f..b77804f8f 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -398,9 +398,20 @@ static void closeSession(ROUTER *instance, void *router_session) } bref_clear_state(bref, BREF_IN_USE); bref_set_state(bref, BREF_CLOSED); - dcb_close(dcb); - /** Decrease server reference connection count */ + RW_CHK_DCB(bref, dcb); + + /** MXS-956: This will prevent closed DCBs from being closed twice. + * It should not happen but for currently unknown reasons, a DCB + * gets closed twice; first in handleError and a second time here. */ + if (dcb && dcb->state == DCB_STATE_POLLING) + { + dcb_close(dcb); + } + + RW_CLOSE_BREF(bref); + + /** decrease server current connection counters */ atomic_add(&bref->ref->connections, -1); } else @@ -1282,6 +1293,13 @@ static void handleError(ROUTER *instance, void *router_session, CHK_DCB(problem_dcb); + if (!rses_begin_locked_router_action(rses)) + { + /** Session is already closed */ + *succp = false; + return; + } + /** Don't handle same error twice on same DCB */ if (problem_dcb->dcb_errhandle_called) { @@ -1291,6 +1309,7 @@ static void handleError(ROUTER *instance, void *router_session, * be safe with the code as it stands on 9 Sept 2015 - MNB */ *succp = true; + rses_end_locked_router_action(rses); return; } else @@ -1300,6 +1319,7 @@ static void handleError(ROUTER *instance, void *router_session, session = problem_dcb->session; bool close_dcb = true; + backend_ref_t *bref = get_bref_from_dcb(rses, problem_dcb); if (session == NULL || rses == NULL) { @@ -1318,15 +1338,6 @@ static void handleError(ROUTER *instance, void *router_session, { case ERRACT_NEW_CONNECTION: { - if (!rses_begin_locked_router_action(rses)) - { - close_dcb = false; /* With the assumption that if the router session is closed, - * then so is the dcb. - */ - *succp = false; - break; - } - /** * If master has lost its Master status error can't be * handled so that session could continue. @@ -1334,7 +1345,6 @@ static void handleError(ROUTER *instance, void *router_session, if (rses->rses_master_ref && rses->rses_master_ref->bref_dcb == problem_dcb) { SERVER *srv = rses->rses_master_ref->ref->server; - backend_ref_t *bref = get_bref_from_dcb(rses, problem_dcb); bool can_continue = false; if (rses->rses_config.rw_master_failure_mode != RW_FAIL_INSTANTLY && @@ -1372,18 +1382,56 @@ static void handleError(ROUTER *instance, void *router_session, "corresponding backend ref.", srv->name, srv->port); } } - else + else if (bref) { - /** - * This is called in hope of getting replacement for - * failed slave(s). - */ + /** We should reconnect only if we find a backend for this + * DCB. If this DCB is an older DCB that has been closed, + * we can ignore it. */ *succp = handle_error_new_connection(inst, &rses, problem_dcb, errmsgbuf); } - dcb_close(problem_dcb); + RW_CHK_DCB(bref, problem_dcb); + + if (bref) + { + /** This is a valid DCB for a backend ref */ + + if (!BREF_IS_IN_USE(bref) || bref->bref_dcb != problem_dcb) + { + /** The backend is closed or the reference was replaced */ + dcb_close(problem_dcb); + RW_CLOSE_BREF(bref); + } + else + { + MXS_ERROR("Backend '%s' is still in use and points to the problem DCB. Not closing.", + bref->ref->server->unique_name); + } + } + else + { + const char *remote = problem_dcb->state == DCB_STATE_POLLING && + problem_dcb->server ? problem_dcb->server->unique_name : "CLOSED"; + + MXS_ERROR("DCB connected to '%s' is not in use by the router " + "session, not closing it. DCB is in state '%s'", + remote, STRDCBSTATE(problem_dcb->state)); + MXS_ERROR("Backends currently in use:"); + + for (int i = 0; i < rses->rses_nbackends; i++) + { + dcb_state_t state = DCB_STATE_UNDEFINED; + if (BREF_IS_IN_USE(&rses->rses_backend_ref[i])) + { + state = rses->rses_backend_ref[i].bref_dcb->state; + } + + MXS_ERROR("%p: %s - %p", &rses->rses_backend_ref[i], STRDCBSTATE(state), + rses->rses_backend_ref[i].bref_dcb); + } + } + close_dcb = false; - rses_end_locked_router_action(rses); break; } @@ -1404,8 +1452,11 @@ static void handleError(ROUTER *instance, void *router_session, if (close_dcb) { + RW_CHK_DCB(bref, problem_dcb); dcb_close(problem_dcb); + RW_CLOSE_BREF(bref); } + rses_end_locked_router_action(rses); } /** @@ -1428,33 +1479,22 @@ static void handle_error_reply_client(SESSION *ses, ROUTER_CLIENT_SES *rses, client_dcb = ses->client_dcb; spinlock_release(&ses->ses_lock); - if (rses_begin_locked_router_action(rses)) + if ((bref = get_bref_from_dcb(rses, backend_dcb)) != NULL) { - /** - * If bref exists, mark it closed - */ - if ((bref = get_bref_from_dcb(rses, backend_dcb)) != NULL) - { - CHK_BACKEND_REF(bref); + CHK_BACKEND_REF(bref); - if (BREF_IS_IN_USE(bref)) - { - close_failed_bref(bref, false); - dcb_close(backend_dcb); - } - } - else + if (BREF_IS_IN_USE(bref)) { - // All dcbs should be associated with a backend reference. - ss_dassert(!true); + close_failed_bref(bref, false); + RW_CHK_DCB(bref, backend_dcb); + dcb_close(backend_dcb); + RW_CLOSE_BREF(bref); } - - rses_end_locked_router_action(rses); } else { - // The session has already been closed, hence the dcb has been - // closed as well. + // All dcbs should be associated with a backend reference. + ss_dassert(!true); } if (sesstate == SESSION_STATE_ROUTER_READY) diff --git a/server/modules/routing/readwritesplit/readwritesplit.h b/server/modules/routing/readwritesplit/readwritesplit.h index 216c96205..cf1a7910a 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.h +++ b/server/modules/routing/readwritesplit/readwritesplit.h @@ -200,6 +200,7 @@ typedef struct backend_ref_st #if defined(SS_DEBUG) skygw_chk_t bref_chk_tail; #endif + int closed_at; /** DEBUG: Line number where this backend reference was closed */ } backend_ref_t; /** diff --git a/server/modules/routing/readwritesplit/rwsplit_internal.h b/server/modules/routing/readwritesplit/rwsplit_internal.h index e5f38b377..133637b2f 100644 --- a/server/modules/routing/readwritesplit/rwsplit_internal.h +++ b/server/modules/routing/readwritesplit/rwsplit_internal.h @@ -30,7 +30,17 @@ MXS_BEGIN_DECLS * rwsplit_tmp_table_multi functions */ #include - + +#define RW_CHK_DCB(bref, dcb) \ +do{ \ + if(dcb->state == DCB_STATE_DISCONNECTED){ \ + MXS_NOTICE("DCB was closed on line %d and another attempt to close it is made on line %d." , \ + (bref) ? (bref)->closed_at : -1, __LINE__); \ + } \ +}while (false) + +#define RW_CLOSE_BREF(b) do{ if (bref){ bref->closed_at = __LINE__; } } while (false) + /* * The following are implemented in rwsplit_mysql.c */ diff --git a/server/modules/routing/readwritesplit/rwsplit_select_backends.c b/server/modules/routing/readwritesplit/rwsplit_select_backends.c index 59b599276..678c860e7 100644 --- a/server/modules/routing/readwritesplit/rwsplit_select_backends.c +++ b/server/modules/routing/readwritesplit/rwsplit_select_backends.c @@ -301,7 +301,9 @@ bool select_connect_backend_servers(backend_ref_t **p_master_ref, /** Decrease backend's connection counter. */ atomic_add(&backend_ref[i].ref->connections, -1); + RW_CHK_DCB(&backend_ref[i], backend_ref[i].bref_dcb); dcb_close(backend_ref[i].bref_dcb); + RW_CLOSE_BREF(&backend_ref[i]); } } } @@ -411,6 +413,7 @@ static bool connect_server(backend_ref_t *bref, SESSION *session, bool execute_h if (bref->bref_dcb != NULL) { bref_clear_state(bref, BREF_CLOSED); + bref->closed_at = 0; if (!execute_history || execute_sescmd_history(bref)) { @@ -429,7 +432,9 @@ static bool connect_server(backend_ref_t *bref, SESSION *session, bool execute_h bref->ref->server->unique_name, bref->ref->server->name, bref->ref->server->port); + RW_CHK_DCB(bref, bref->bref_dcb); dcb_close(bref->bref_dcb); + RW_CLOSE_BREF(bref); bref->bref_dcb = NULL; } } diff --git a/server/modules/routing/readwritesplit/rwsplit_session_cmd.c b/server/modules/routing/readwritesplit/rwsplit_session_cmd.c index f215eaa7e..c967aaf41 100644 --- a/server/modules/routing/readwritesplit/rwsplit_session_cmd.c +++ b/server/modules/routing/readwritesplit/rwsplit_session_cmd.c @@ -176,10 +176,9 @@ GWBUF *sescmd_cursor_process_replies(GWBUF *replybuf, bref->ref->server->unique_name); close_failed_bref(bref, true); - if (bref->bref_dcb) - { - dcb_close(bref->bref_dcb); - } + RW_CHK_DCB(bref, bref->bref_dcb); + dcb_close(bref->bref_dcb); + RW_CLOSE_BREF(bref); *reconnect = true; gwbuf_free(replybuf); replybuf = NULL; @@ -217,7 +216,9 @@ GWBUF *sescmd_cursor_process_replies(GWBUF *replybuf, if (ses->rses_backend_ref[i].bref_dcb) { + RW_CHK_DCB(&ses->rses_backend_ref[i], ses->rses_backend_ref[i].bref_dcb); dcb_close(ses->rses_backend_ref[i].bref_dcb); + RW_CLOSE_BREF(&ses->rses_backend_ref[i]); } *reconnect = true; MXS_INFO("Disabling slave %s:%d, result differs from "