CBL-7717 : Lockmanager resources release on shutdown#451
Conversation
Aniket392
commented
Jan 5, 2026
- LockManager uses a RefQueueCleanerThread to monitor for garbage-collected locks.
- This thread is created as non-daemon to ensure proper cleanup , but it prevents JVM exit until all locks are released.
- When databases or other peer objects aren't explicitly closed, their locks remain in the LockManager's locks map , causing the thread to wait indefinitely.
- Clears all remaining locks from the map
- Stops the cleaner thread by calling its quit() method
- Logs the shutdown operation for debugging
| if (t != null) { | ||
| t.quit(); | ||
| } | ||
| } |
There was a problem hiding this comment.
A couple of things to discuss :
-
This doesn't prevent a new lock to be added (e.g. there is another thread acquiring the lock at the same time). Should we throw an exception if there is a request for a new lock after the shutdown is called?
-
Is using reference queue to clean up lock objects really needed? I understand that we start to use the cleaner and reference queue to allow the native objects to be cleaned on non GC thread, but these are just simple objects.
There was a problem hiding this comment.
- I have added to prevent this race condition
- Yes, the ReferenceQueue is essential for LockManager they represent locks on native peer resources (C4Database, C4Collection, etc.) that must be freed regardless of Java object lifecycle. Without ReferenceQueue cleanup, if a database object is garbage collected without explicit closure, the native peer remains locked and the LockManager thread waits indefinitely, preventing JVM exit
There was a problem hiding this comment.
After spending time tryin to understand this, it's perfectly fine to use ReferenceQueue to clean up the LockRef in the locks map and to shutdown the queue thread.
Alternatively, instead of adding a specific shutdown method, the created RefQueueCleanerThread can be a daemon thread as :
- There is no specific resources to clean up except removing a weak object from the map.
- Based on my understanding, it seems like in C4Peer, we are using CBLExecutor which creates daemon threads for cleaning native peers.
| } | ||
| } | ||
|
|
||
| public static void shutdown() { |
There was a problem hiding this comment.
Shouldn't this be marked with @synchronized or something? Or does that not work with static methods?
There was a problem hiding this comment.
@synchronized annotation is generally used in kotlin
For java we can use synchronized keyword as public static synchronized void shutdown()(but we can use some library to use annotation)
It works same as synchronized block, which we have used in shutdown, only difference being that synchronized keyword synchronizes the entire method, so only one thread at a time can execute any static synchronized method of that class
On other hand if we use synchronized block, we can specifically mention on which object we want to put lock on