Services can now be destroyed if they have no active listeners and they
are not linked to servers. When these conditions are met, the service will
be destroyed when the last session for the service is closed.
The closing of a service will close all listeners that were once assigned
to the service. This allows closing of the ports at runtime which
previously was done only on shutdown.
Exposed the command through the REST API but not through MaxAdmin as it is
deprecated.
When a listener is removed from a service, it should also be removed from
any workers it has been added to. This guarantees that if the opening of
the listener was successful, no requests will be accepted on it after the
removal of the listener.
By creating the router instance as a part of the service allocation
process, we are guaranteed that either the creation of the service is
completely successful or it fails. This should make runtime creation of
services easier.
The configuration system that modules use allows the SSL parameter
validation to be simplified. It should also provide more consistent error
messages for similar types of errors.
The SSL_LISTENER initialization is now done in one step. There was no good
reason to do it in two separate steps for listeners but in one step for
servers.
The `ssl` parameter now also accepts boolean values. As the parameter
behaves like a boolean and looks like a boolean, it ought to be a
boolean. It still accepts the custom `required` and `disabled` values
simply for backwards compatibility.
Also added the missing freeing functions for the SSL_LISTENER type. This
prevents failed SSL_LISTENER creations from leaking memory.
The common monitor parameters are now stored as module-style
parameters. This makes the error reporting as well as the type checks for
the parameters consistent with parameters declared by the modules.
The same mechanism that is used for modules can be used for the
configuration of the core objects. This removes the need for the redundant
code that validates various values that is already present in the code
that modules use.
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.
If a router parameter has no default value, the previous value would be
returned as an empty string. A debug assertion would be triggered when a
parameter of this type was altered.
When a new router parameter is encountered and the alteration fails, the
modified value in the service need to be removed. Previously, the new
value would have been stored in the service with an empty value which
would have caused problems.
The runtime configuration of a MaxScale can now be exported to a single
file. This allows modifications made via runtime configuration commands to
be "committed" for later use.
The log manager is the only one that uses the mlist_t versioned list. The
counter that keeps track of the version number was not modified using
atomic operations meaning that the compiler is free to optimize away parts
of the lock-free versioning mechanism that uses it.
To prevent this optimization, the variable is declared volatile. A rewrite
is direly needed but it cannot be done in 2.2.
Due to the skewed accept distribution without SO_REUSEPORT, we use
round-robin assignment of workers for new client connections. This
provides better performance as work is more likely to be evenly
distributed across all threads.
Using a least-busy-worker algorithm would provide a more stable result but
this is not trivially simple to implement. For this reason, the
round-robin based approach was chosen for 2.2.
The id has now been moved from mxs::Worker to mxs::RoutingWorker
and the implications are felt in many places.
The primary need for the id was to be able to access worker specfic
data, maintained outside of a routing worker, when given a worker
(the id is used to index into an array). Slightly related to that
was the need to be able to iterate over all workers. That obviously
implies some kind of collection.
That causes all sorts of issues if there is a need for being able
to create and destroy a worker at runtime. With the id removed from
mxs::Worker all those issues are gone, and its perfectly ok to create
and destory mxs::Workers as needed.
Further, while there is a need to broadcast a particular message to
all _routing_ workers, it hardly makes sense to broadcast a particular
message too _all_ workers. Consequently, only routing workers are kept
in a collection and all static member functions dealing with all
workers (e.g. broadcast) have now been moved to mxs::RoutingWorker.
Now, instead of passing the id around we instead deal directly
with the worker pointer. Later the data in all those external arrays
will be moved into mxs::[Worker|RoutingWorker] so that worker related
data is maintained in exactly one place.
MaxScale now defines events for which the syslog
facility and level can explicitly be defined by the
administrator. Currently there is only one such
event, namelt AUTHENTICATION_FAILURE.
In a subsequent commit, config.cc will be modified so
that event-related configuration parameters are passed
to event::configure() and in another subsequent commit
the authenticators will be modifed to use this mechanism.
In practice a line like:
MXS_WARNING("%s: login attempt for user '%s'@[%s]:%s, "
"authentication failed.",
dcb->service->name, client_data->user,
dcb->remote, dcb->path);
will be changed to
MXS_LOG_EVENT(event::AUTHENTICATION_FAILURE,
"%s: login attempt for user '%s'@[%s]:%s, "
"authentication failed.",
dcb->service->name, client_data->user,
dcb->remote, dcb->path);
By storing a link to the backend DCBs in the session object itself, we can
reach all related objects from the session. This removes the need to
iterate over all DCBs to find the set of related DCBs.
MonitorDestroy() (renamed to monitor_destroy()) will be used for
actually destroying the monitor instance, that is, execute
destroyInstance() on the loaded module instance and freeing the
the monitor instance.
TODO: monitor_deactivate() could do all the stuff which is currently
done to the monitor in config_runtime(), instead of just
turning off the flag.
Fixed string truncation warnings by reducing max parameter lengths by one
where applicable. The binlogrouter filename lengths are slightly different
so using memcpy to work around the warnings is an adequate "solution"
until the root of the problem is solved.
Removed unnecessary CMake policy settings from qc_sqlite. Adding a
self-dependency on the source file of an external project has no effect
and only caused warnings to be logged.
When providing pointer to instance and pointer to member function
of the class of the instance, the pointer to the member function
should be first and the pointer to the instance second.
There's now double bookkeeping:
- All delayed calls are in a map whose key is the next
invocation time. Since it's a map (and not an unordered_map)
it's sorted just the way we want to have it.
- In addition, there's an unordered set for each tag.
With this arrangement we can easily invoke the delayed calls
in the right order and be able to efficiently remove all
delayed calls related to a particular tag.
When canceling, a DelayedCall instance must be removed from the
collection holding all delayed calls. Consequently priority_queue
cannot be used as it 1) does not provide access to the underlying
collection and 2) the underlying collection (vector or deque)
is a bad choise if items in the middle needs to be removed.
The interface for canceling calls is now geared towards the needs
of sessions. Basically the idea is as follows:
class MyFilterSession : public maxscale::FilterSession
{
...
int MyFilterSession::routeQuery(GWBUF* pPacket)
{
...
if (needs_to_be_delayed())
{
Worker* pWorker = Worker::current();
void* pTag = this;
pWorker->delayed_call(5000, pTag, this,
&MyFilterSession::delayed_routeQuery,
pPacket);
return 1;
}
...
}
bool MyFilterSession::delayed_routeQuery(Worker::Call:action_t action,
GWBUF* pPacket)
{
if (action == Worker::Call::EXECUTE)
{
routeQuery(pPacket);
}
else
{
ss_dassert(action == Worker::Call::CANCEL);
gwbuf_free(pPacket);
}
return false;
}
~MyFilterSession()
{
void* pTag = this;
Worker::current()->cancel_delayed_calls(pTag);
}
}
The alternative, returning some key that the caller must keep
around seems more cumbersome for the general case.
It's now possible to provide Worker with a function to call
at a later time. It's possible to provide a function or a
member function (with the object), taking zero or one argument
of any kind. The argument must be copyable.
There's currently no way to cancel a call, which must be added
as typically the delayed calling is associated with a session
and if the session is closed before the delayed call is made,
bad things are likely to happen.