I decided to play around with my experimental C++ bindings and successfully managed to get libcouchbase working with threads.
To be able to use libcouchbase in a relatively seamless fashion; gaining the performance benefits of asynchronous IO while maintaining a synchronous usage pattern. This is similar to what we have in Java.
While libcouchbase is "thread safe", the instance must be locked (by the application) when the application schedules the operation and unlocked after a call to lcb_wait or similar; thus making access to libcouchbase serialized not only for the internal library structures but for I/O as well.
The definition of Multi Threaded means to allow a usage pattern similar to the Java or .NET client libraries where the client is thread safe without any user locking.
While a single-threaded asynchronous application is an acceptable design pattern for an application, many applications are threaded, typically to simplify development where many different sockets are not anticipated.
Considering libcouchbase' primary use as a platform layer for higher level SDKs, some of these languages feature threading support built in to the language (and thus becoming a simple model for concurrency); Currently in these situations, especially when interaction with Couchbase is large, the developer has to either rewrite his/her application in an asynchronous fashion (and use an SDK-specific IOPS structure) or create an instance-per-thread or a pool of instances -- all of which have application-side management overhead.
Languages which feature threading support include Python, PHP, and Erlang. Allowing a threading model for the end-user which maps natively to the model used by libcouchbase makes maintenance simpler for the specific SDK.
This section will outline some of the technical details and/or requirements needed to use libcouchbase in an MT environment
libcouchbase consists of three primary states which in normal use cases do not often interleave
This is how operation data (i.e. key, value, etc) are placed into the relevant server's userspace write buffer; this is a simple process from an architecture perspective.
After an operation has been scheduled, the IO subsystem is then instructed to notify the library when the relevant IO operations have taken place (or are ready to be executed, depending on the IO version)
This is the wait phase of the library. During this stage libcouchbase is considered to be idle (i.e. not performing any operations). The application control is transferred to the I/O system which may either wait for libcouchbase operations or wait for other events (which may be scheduled by the application itself)
This takes place when the IO transfers control back to the library (often temporarily); the library in turn invokes a user callback which handles the response information. Once the user has processed the response, control is returned back to libcouchbase which in turn transfers control back to the IO subsystem.
This section outlines the aspects of libcouchbase which aren't typically thread safe and must be locked.
The userspace buffers for scheduling commands are not thread safe; thus an LCBMT implementation will ensure that concurrent access to these buffers does not take place.
Typically these buffers are only touched during the initial scheduling phase of the operation, but may also be modified during the dispatch phase (i.e. when a configuration change has taken place and buffers must be relocated to a different servers).
These are not thread safe; IO systems typically maintain a linked list of "events" or "sockets"; and thus it is not safe to modify them from different threads. Note however that typically IO routines may be called from any thread so long as two threads are not calling them concurrently.
While strictly a subset of userspace buffers, these refer to the responses relayed back to the user. For a proper MT implementation, the response must either be copied and then delivered synchronously, or the callback must synchronize with the requesting thread to ensure exeuction continues only after the user has declared that it is done with the response.