diff --git a/include/maxscale/router.hh b/include/maxscale/router.hh new file mode 100644 index 000000000..f26533db5 --- /dev/null +++ b/include/maxscale/router.hh @@ -0,0 +1,248 @@ +#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: 2019-07-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 +#include + +namespace maxscale +{ + +/** + * @class RouterSession router.hh + * + * RouterSession is a base class for router sessions. A concrete router session + * class should be derived from this class and override all relevant functions. + * + * Note that even though this class is intended to be derived from, no functions + * are virtual. That is by design, as the class will be used in a context where + * the concrete class is known. That is, there is no need for the virtual mechanism. + */ +class RouterSession : public MXS_ROUTER_SESSION +{ +public: + /** + * The RouterSession instance will be deleted when a client session + * has terminated. Will be called only after @c close() has been called. + */ + ~RouterSession(); + + /** + * Called when a client session has been closed. + */ + void close(); + + /** + * Called when a packet being is routed to the backend. The router should + * forward the packet to the appropriate server(s). + * + * @param pPacket A client packet. + */ + int32_t routeQuery(GWBUF* pPacket); + + /** + * Called when a packet is routed to the client. The router should + * forward the packet to the client using `MXS_SESSION_ROUTE_REPLY`. + * + * @param pPacket A client packet. + * @param pBackend The backend the packet is coming from. + */ + void clientReply(GWBUF* pPacket, DCB* pBackend); + + /** + * + * @param pMessage The rror message. + * @param pProblem The DCB on which the error occurred. + * @param action The context. + * @param pSuccess On output, if false, the session will be terminated. + */ + void handleError(GWBUF* pMessage, + DCB* pProblem, + mxs_error_action_t action, + bool* pSuccess); + +protected: + RouterSession(MXS_SESSION* pSession); + +protected: + MXS_SESSION* m_pSession; /*< The MXS_SESSION this router session is associated with. */ +}; + + +/** + * @class Router router.hh + * + * An instantiation of the Router template is used for creating a router. + * Router is an example of the "Curiously recurring template pattern" + * https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern + * that is used for compile time polymorfism. + * + * The typical way for using the template is as follows: + * + * @code + * class MyRouterSession : public maxscale::RouterSession + * { + * // Override the relevant functions. + * }; + * + * class MyRouter : public maxscale::Router + * { + * public: + * static MyRouter* create(SERVICE* pService, char** pzOptions); + * + * MyRouterSession* newSession(MXS_SESSION* pSession); + * + * void diagnostics(DCB* pDcb); + * uint64_t getCapabilities(); + * }; + * @endcode + * + * The concrete router class must implement the methods @c create, @c newSession, + * @c diagnostics and @c getCapabilities, with the prototypes as shown above. + * + * The plugin function @c GetModuleObject is then implemented as follows: + * + * @code + * extern "C" MXS_MODULE* MXS_CREATE_MODULE() + * { + * static MXS_MODULE module_object = + * { + * ... + * &MyRouter::s_object, + * ... + * }; + * + * return &module_object; + * } + * @endcode + */ +template +class Router : public MXS_ROUTER +{ +public: + static MXS_ROUTER* createInstance(SERVICE* pService, char** pzOptions) + { + RouterType* pRouter = NULL; + + MXS_EXCEPTION_GUARD(pRouter = RouterType::create(pService, pzOptions)); + + return pRouter; + } + + static MXS_ROUTER_SESSION* newSession(MXS_ROUTER* pInstance, MXS_SESSION* pSession) + { + RouterType* pRouter = static_cast(pInstance); + RouterSessionType* pRouter_session; + + MXS_EXCEPTION_GUARD(pRouter_session = pRouter->newSession(pSession)); + + return pRouter_session; + } + + static void closeSession(MXS_ROUTER*, MXS_ROUTER_SESSION* pData) + { + RouterSessionType* pRouter_session = static_cast(pData); + + MXS_EXCEPTION_GUARD(pRouter_session->close()); + } + + static void freeSession(MXS_ROUTER*, MXS_ROUTER_SESSION* pData) + { + RouterSessionType* pRouter_session = static_cast(pData); + + MXS_EXCEPTION_GUARD(delete pRouter_session); + } + + static int32_t routeQuery(MXS_ROUTER*, MXS_ROUTER_SESSION* pData, GWBUF* pPacket) + { + RouterSessionType* pRouter_session = static_cast(pData); + + int32_t rv = 0; + MXS_EXCEPTION_GUARD(rv = pRouter_session->routeQuery(pPacket)); + + return rv; + } + + static void diagnostics(MXS_ROUTER* pInstance, DCB* pDcb) + { + RouterType* pRouter = static_cast(pInstance); + + MXS_EXCEPTION_GUARD(pRouter->diagnostics(pDcb)); + } + + static void clientReply(MXS_ROUTER*, MXS_ROUTER_SESSION* pData, GWBUF* pPacket, DCB* pBackend) + { + RouterSessionType* pRouter_session = static_cast(pData); + + MXS_EXCEPTION_GUARD(pRouter_session->clientReply(pPacket, pBackend)); + } + + static void handleError(MXS_ROUTER* pInstance, + MXS_ROUTER_SESSION* pData, + GWBUF* pMessage, + DCB* pProblem, + mxs_error_action_t action, + bool* pSuccess) + { + RouterSessionType* pRouter_session = static_cast(pData); + + MXS_EXCEPTION_GUARD(pRouter_session->handleError(pMessage, pProblem, action, pSuccess)); + } + + static uint64_t getCapabilities(MXS_ROUTER* pInstance) + { + uint64_t rv = 0; + + RouterType* pRouter = static_cast(pInstance); + + MXS_EXCEPTION_GUARD(rv = pRouter->getCapabilities()); + + return rv; + } + + static void destroyInstance(MXS_ROUTER* pInstance) + { + RouterType* pRouter = static_cast(pInstance); + + MXS_EXCEPTION_GUARD(delete pRouter); + } + + static MXS_ROUTER_OBJECT s_object; + +protected: + Router(SERVICE *pService) + : m_pService(pService) + { + } + + SERVICE* m_pService; +}; + + +template +MXS_ROUTER_OBJECT Router::s_object = +{ + &Router::createInstance, + &Router::newSession, + &Router::closeSession, + &Router::freeSession, + &Router::routeQuery, + &Router::diagnostics, + &Router::clientReply, + &Router::handleError, + &Router::getCapabilities, + &Router::destroyInstance, +}; + + +} diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 11ebb97a8..b32196c08 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(maxscale-common SHARED adminusers.c alloc.c authenticator.c atomic.c buffer.c config.c config_runtime.c dcb.c filter.c filter.cc externcmd.c paths.c hashtable.c hint.c housekeeper.c load_utils.c log_manager.cc maxscale_pcre2.c misc.c mlist.c modutil.c monitor.c queuemanager.c query_classifier.c poll.c random_jkiss.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c skygw_utils.cc statistics.c listener.c ssl.c mysql_utils.c mysql_binlog.c modulecmd.c ) +add_library(maxscale-common SHARED adminusers.c alloc.c authenticator.c atomic.c buffer.c config.c config_runtime.c dcb.c filter.c filter.cc externcmd.c paths.c hashtable.c hint.c housekeeper.c load_utils.c log_manager.cc maxscale_pcre2.c misc.c mlist.c modutil.c monitor.c queuemanager.c query_classifier.c poll.c random_jkiss.c resultset.c router.cc secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c skygw_utils.cc statistics.c listener.c ssl.c mysql_utils.c mysql_binlog.c modulecmd.c ) if(WITH_JEMALLOC) target_link_libraries(maxscale-common ${JEMALLOC_LIBRARIES}) diff --git a/server/core/router.cc b/server/core/router.cc new file mode 100644 index 000000000..e189680c5 --- /dev/null +++ b/server/core/router.cc @@ -0,0 +1,51 @@ +/* + * 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: 2019-07-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 + +namespace maxscale +{ + +// +// RouterSession +// +RouterSession::RouterSession(MXS_SESSION* pSession) + : m_pSession(pSession) +{ +} + +RouterSession::~RouterSession() +{ +} + +void RouterSession::close() +{ +} + +int32_t RouterSession::routeQuery(GWBUF* pPacket) +{ + return 0; +} + +void RouterSession::clientReply(GWBUF* pPacket, DCB* pBackend) +{ +} + +void RouterSession::handleError(GWBUF* pMessage, + DCB* pProblem, + mxs_error_action_t action, + bool* pSuccess) +{ +} + +}