My session management (Zebra Session) uses user-level locks to avoid race conditions between two requests in the same session. To start the session, GET_LOCK is used. After closing the session, RELEASE_LOCK is used.
MariaDB [planner_20201026]> select GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaaa', '5');
+-------------------------------------------------------------------+
| GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaaa', '5') |
+-------------------------------------------------------------------+
| 1 |
+-------------------------------------------------------------------+
1 row in set (0.000 sec)
MariaDB [planner_20201026]> select RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaa');
+-----------------------------------------------------------------+
| RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaa') |
+-----------------------------------------------------------------+
| NULL |
+-----------------------------------------------------------------+
1 row in set (0.000 sec)
Now I am in a situation because of a reason which I do not know yet where the lock was not released properly. GET_LOCK finishes because of the timeout, RELEASE_LOCK tells me that it cannot release the lock because it was (according to the documentation) established by another thread:
MariaDB [xyz]> select GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b', '5');
+-------------------------------------------------------------------+
| GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b', '5') |
+-------------------------------------------------------------------+
| 0 |
+-------------------------------------------------------------------+
1 row in set (5.015 sec)
MariaDB [xyz]> select RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b');
+------------------------------------------------------------------+
| RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b') |
+------------------------------------------------------------------+
| 0 |
+------------------------------------------------------------------+
1 row in set (0.000 sec)
The session is now more or less blocked/useless/doomed, each request takes TIMEOUT seconds extra.
Is there any chance how I can clear that lock, especially after a timeout?
You can only use RELEASE_LOCK() to release a lock acquired in the same thread. A thread has no privilege to force another thread to give up its lock.
That would be a pretty useless locking system if you could acquire a lock but any other thread could unilaterally force you to release it!
One way you could work around this is to call IS_USED_LOCK() to tell you which thread holds the lock. It returns the integer thread id of the holder, or NULL if the lock is not held by anyone.
Then if you have SUPER privilege, your thread can KILL that other thread, and this will force it to release its lock (as well as disconnecting that client). But that's a pretty rude thing to do.
I have a feeling this is an XY Problem. You are searching for a solution to force locks held by other threads to be released, but this is a bad solution because it doesn't solve your real problem.
The real problem is:
Now I am in a situation because of a reason which I do not know yet where the lock was not released properly.
You need to think harder about this and design a system where you do not lose track of who has acquired the lock.
Hint: GET_LOCK(name, 0)
may help. This returns immediately (that is, with zero seconds of timeout). If the lock can be acquired, it is acquired, and the return value of GET_LOCK is 1. If it was already held by another thread, the GET_LOCK still returns immediately, but with a return value of 0, telling you that it could not be acquired.
Bill, thank you. I used IS_USED_LOCK(...) and found out that the lock is head by a thread 23610, SHOW PROCESSLIST told me that it was sleeping and time was 7133, nearly two hours old! Then I terminated my webserver which should also have closed database connections automatically, did not change anything. I ran KILL 23610 and the thread was gone, GET_LOCK(...) worked again.
Sounds like you have a client program that might acquire a lock and hold onto the lock while it runs other code, or maybe even if it freezes. I recommend doing a code review and make sure you structure your code to release the lock promptly, and do not allow any code between the GET_LOCK() and RELEASE_LOCK() that might freeze or run in unbounded time.
Well... From your profile I see that you know PHP a bit. Zebra Sessions replaces file sessions with sessions in the database. Other solutions ignore the race condition issue completely (which is in traditional sessions resolved with file locks). Zebra Sessions does it with locks (GET_LOCK and RELEASE_LOCK). PHP should always write back the session automatically and if this does not happen, closing the connection should finally release the lock. But somehow it did not happen today. At least not in production but on my dev machine. I'll have an eye on it.
I wouldn't use MySQL for PHP sessions. Use an in-memory cache server like Redis or Memcached.
Do you use some form of "connection pooling"? Maybe it is failing to release locks. I am generally opposed to GET_LOCK, PHP sessions, and code where I don't acquire a lock and release it in the same function, with both steps visible on the screen at the same time. (C++ has an advantage here -- acquiring a lock can be in a constructor and releasing it can be in the implicit destructor. A beautiful way to never lose a LOCK.)