The configuration updating in readwritesplit was the inspiration for the
mxs::rworker_local type. Due to this, taking it into use simply means that
the type changes from Config to mxs::rworker_local<Config>.
The configuration doesn't need to be contained in shared pointer as each
session holds its own version of it. This removes most of the overhead in
configuration reloading. The only thing that's left is any overhead added
by the use of thread-local storage.
By using the worker local data mechanism, data can be efficiently cached
on the local worker. This avoids all synchronization on reads and only
requires synchronization on a configuration update.
As an additional observation, the testing of std::mutex and SPINLOCK shows
that std::mutex far outperforms the MaxScale SPINLOCK even on
non-conflicting workloads.
Relaced router_options with configuration parameters in the createInstance
router entry point. The same needs to be done for the filter API as barely
any filters use the feature.
Some routers (binlogrouter) still support router_options but using it is
deprecated. This had to be done as their use wasn't deprecated in 2.2.
The parameter accepts both counts and percentages which requires special
handling in the router. This needs to be done when the configuration is
updated.
Added a new router API entry point that allows configuration changes after
the instance has been created. This makes alterations to most service
parameters at runtime possible.
An option to reconfiguration would have been the creation of a new
service and the eventual destruction of the old one. This would be a more
complicated and costly method but from an architectural point of view it
is interesting.
The actual implementation of the configuration change is left to the
router. Currently, only readwritesplit performs reconfiguration as
implementing it with versioned configurations is very easy.
Versioned configurations can be considered an adequate first step but it
is not an optimal solution as it causes a bottleneck in the reference
counting of the shared configuration. Thread-specific configuration
definitions would make for a more efficient solution but the
implementation is more complex.
By using a shared pointer instead of a plain object, we can replace the
router configuration without it affecting existing sessions. This is a
change that is required to enable runtime reconfiguration of
readwritesplit.
The optimistic_trx parameter will control whether transactions are assumed
to be read-only and will be optimistically executed on slave
servers. Currently, the parameter does nothing.
Readwritesplit now keeps track of how many read-only and read-write
transactions have been executed. This allows a coarse estimation of how
widely read-only transactions are done even without explicit read-only
transactions being used (i.e. START TRANSACTION READ ONLY).
Readwritesplit had redundant parameter values in the
`router_diagnostics`. All module parameters with their current values are
already displayed in the `parameters` member of the resource.
Added the `transaction_replay_max_size` parameter that controls the
maximum size of a transaction that can be replayed. If the limit is
exceeded, the stored statements are released thus preventing the
transaction from being replayed.
This limitation prevents accidental misuse of the transaction replaying
system when autocommit is disabled. It also allows the user to control the
amount of memory that MaxScale will use.
The transaction retrying behavior is now configurable and documented. The
`transaction_replay` parameter implicitly enables the required
functionality in the router that it needs.
Configuring the parameter current doesn't have enough of an effect to
warrant having a configuration option for it.
Also took mxs::extract_sql into use in the INFO level message.
By adding a boolean parameter, the feature can be enabled with sensible
default values. Renamed the query_retry parameters and set the defaults to
acceptable values.
Added new parameters to diagnostic output. Also did some minor renaming.
This is a proof-of-concept that validates the query retrying method. The
actual implementation of the query retrying mechanism needs more thought
as using the housekeeper is not very efficient.
Keeping track of the closed state of the session inside the router session
itself is not needed as the MaxScale core should already do that.
The skygw_chk_t variables are rather meaningless and are obsoleted by
Valgrind/ASAN.
Most of the funtionality is now a member function of either the RWSplit or
RWSplitSession class. This removes the need to pass the router and session
parameters to all functions.
The get_backend_from_dcb function needs to check that the backend is in
use before comparing the pointer. This prevents stale pointers from being
used and is logically more sound than relying on raw DCB matches.
Moved the RWBackend class implementation into its own file. Made some of
the command type functions a part of the <maxscale/protocol/mysql.h>
header to make it reusable.
Before the transaction migration is implemented, the connection must be
closed if a transaction is open and the connection to the master is
lost. Doing this retains the same transactionality as a direct connection
to the server would.
When a non-connected target is chosed as the target server and the session
command history is not empty, the query needs to be placed into the query
queue and routed only after the session commands have been executed.
Enabling the session command history but limiting it to a history of 50
commands allows reconnections for sessions that don't change the state too
often.
As pooled connections will exceed this limit quite fast, they are not able
to reconnect to servers once connections are lost. To solve this problem,
the session command history needs a compaction process that removes
redundant history.
The `master_reconnection` parameter now controls both the reconnection of
the master server as well as the migration of the master server to another
server. Although these two cases appear to be different, the end result
from readwritesplit's point of view is the same and are thus controlled
with the same parameter.
The RWBackend class now resets its internal state when it is closed. This
allows readwritesplit to handle the case when a result was expected from
the master but the master died before the result was returned. The same
code should also handle slave connection failures mid-result, allowing
Backend reuse.
Added a test case that verifies the new functionality when combined with
`master_failure_mode=error_on_write`.
Moved session command execution into the Backend class itself as the
session commands are defined as a related part of it. This allows all
connections to execute session commands if some are available.
Removed explicit SERVER_REF usage in the readwritesplit connection
creation code and replaced it with SRWBackend. This allows the removal of
the get_root_master_backend function which duplicated the functionality in
get_root_master.