minad/lmdb — pull request #19 by vjoel (2014-07-14 05:15:41+00:00)
Title: Fix #12.

Tentatively, this fixes #12, which turns out to be a deadlock between two threads that are each attempting a write transaction.

For example, suppose thread 1 is in its transaction and therefore holds the MDB write mutex. It may release the Ruby GVL (in #12, this happens because of the sleep call) but it will eventually attempt to reacquire the GVL to continue with its transaction block, before it can release the mutex.

Now, suppose thread 2 acquires the Ruby GVL when thread 1 releases it. Then thread 2, starting a write transaction, attempts to acquire the MDB write mutex. Deadlock.

This patch handles the situation by releasing the GVL before calling txn_begin() and reacquiring it after the call. So, in the above example, thread 2 does not hold the GVL while it waits on the MDB write mutex. Thread 1 can grab the GVL, finish its transaction, and release the mutex, letting thread 2 proceed.

One uncertainty is whether the `stop_txn_begin` un-blocking function ever needs to do anything. See the docs for `rb_thread_call_without_gvl`. Perhaps imitating `rb_waitpid()` is correct.