Greetings LMDB Community,
I am delving into the thread-safety aspects of LMDB, specifically regarding the use of readonly cursors across multiple threads. With the MDB_NOTLS flag enabled, which disables thread-local storage, my understanding is that readonly transactions may be shared between threads, provided there is proper synchronization to prevent concurrent access.
Building upon this, I seek clarity on the following: Can multiple threads safely access a single readonly cursor derived from such a synchronized readonly transaction when MDB_NOTLS is enabled?
Upon reviewing the LMDB source code, I noticed that cursors are tied to transactions (see mdb.c#L1335). This suggests that if threads can synchronously share a transaction, they might also share a cursor associated with it for data retrieval.
Meanwhile, while looking at the LMDB document (http://www.lmdb.tech/doc/group__mdb.html#gad7ea55da06b77513609efebd44b26920), it says “Cursors may not span transactions”, which is a little confusing for me. To be crystal transparent, does it mean that, even if MDB_NOTLS is set, a cursor opened by a readonly transaction still has to stay with one single thread for its entire lifetime, and cannot be used by another thread even at a different time?
Thank you in advance for your assistance!
Best, Xiaoya
xiaoya2wei@gmail.com wrote:
Greetings LMDB Community,
I am delving into the thread-safety aspects of LMDB, specifically regarding the use of readonly cursors across multiple threads. With the MDB_NOTLS flag enabled, which disables thread-local storage, my understanding is that readonly transactions may be shared between threads, provided there is proper synchronization to prevent concurrent access.
Building upon this, I seek clarity on the following: Can multiple threads safely access a single readonly cursor derived from such a synchronized readonly transaction when MDB_NOTLS is enabled?
Upon reviewing the LMDB source code, I noticed that cursors are tied to transactions (see mdb.c#L1335). This suggests that if threads can synchronously share a transaction, they might also share a cursor associated with it for data retrieval.
Meanwhile, while looking at the LMDB document (http://www.lmdb.tech/doc/group__mdb.html#gad7ea55da06b77513609efebd44b26920), it says “Cursors may not span transactions”, which is a little confusing for me. To be crystal transparent, does it mean that, even if MDB_NOTLS is set, a cursor opened by a readonly transaction still has to stay with one single thread for its entire lifetime, and cannot be used by another thread even at a different time?
No that's not what it means. If it were to mean that, it would have said "cursors may not span threads".
Thanks Howard,
Then I guess I have 2 follow-up questions:
1. Just to confirm (something I didn't get a clear answer): when MDB_NOTLS is set, a cursor opened by a rw txn can be serially accessed by multiple threads, one at a time. Is this write? 2. What does "Cursors may not span transactions" specifically mean? In my understanding, a cursor belongs to one and only one txn, I didn't find an LMDB API that allows users to operate a cursor with some random transactions?
Thanks, Xiaoya
xiaoya2wei@gmail.com wrote:
Thanks Howard,
Then I guess I have 2 follow-up questions:
- Just to confirm (something I didn't get a clear answer): when MDB_NOTLS is set, a cursor opened by a rw txn can be serially accessed by multiple threads, one at a time. Is this write?
No. MDB_NOTLS has no relevance to rw txns. The docs state quite clearly that it only affects read-only txns. Read more carefully.
- What does "Cursors may not span transactions" specifically mean? In my understanding, a cursor belongs to one and only one txn, I didn't find an LMDB API that allows users to operate a cursor with some random transactions?
Read more carefully.
Thanks Howard,
I might still borrow a few minutes from you for the followings
No. MDB_NOTLS has no relevance to rw txns. The docs state quite clearly that it only affects read-only txns. Read more carefully.
Sorry I had a typo in the previous reply, I meant to say "ro txn". Let me rephrase the whole question: I create an LMDB env with MDB_NOTLS, and open a readonly txn from this env with "mdb_txn_begin" and flag "MDB_RDONLY". Then I open N cursors from this readonly txn, namely cursor_0, cursor_1, ..., cursor_{N-1}; meanwhile my application can use M threads. So if I guarantee that, at any times, *at most 1* of the M threads is accessing *one of* the N cursors, then my application is thread-safe in using LMDB.
Is this correct understanding?
Read more carefully.
One may interpret it in many ways, like "cursors might not outlive a txn's lifecycle", or "cursor and its transaction might not be accessed by different threads". I'd appreciate if it can be more clarified.
Thanks, Xiaoya
openldap-technical@openldap.org