MXS-1929: Store service active state atomically
When a session is closed, it releases a reference on the service and checks if it was the last session for a destroyed service. The state of the service was loaded after the reference count was decremented. This behavior introduced a race condition where it was possible for a service to be freed twice, first by the thread that marked the service as destroyed and again by the last session for that service. By always loading the service state before decrementing the reference count, we avoid this race condition. Currently, the memory ordering used for the reference counting is too strict and could be relaxed. By default, all atomic operations use sequentially consistent memory ordering. This guarantees correct behavior but imposes a performance penalty. Incrementing the reference counts could be done with a relaxed memory order as long as as we know the reference we're incrementing is valid. Releasing a reference must use an acquire-release order to guarantee the read-modify-write operation is successful.
This commit is contained in:
@ -413,8 +413,9 @@ static void session_free(MXS_SESSION *session)
|
||||
|
||||
session->state = SESSION_STATE_FREE;
|
||||
session_final_free(session);
|
||||
bool should_destroy = !atomic_load_int(&service->active);
|
||||
|
||||
if (atomic_add(&service->client_count, -1) == 1 && !service->active)
|
||||
if (atomic_add(&service->client_count, -1) && should_destroy)
|
||||
{
|
||||
// Destroy the service in the main routing worker thread
|
||||
mxs::RoutingWorker* main_worker = mxs::RoutingWorker::get(mxs::RoutingWorker::MAIN);
|
||||
|
Reference in New Issue
Block a user