Concurrency Control

To implement concurrency control, you must make decisions about the multithreading model you will use and how your driver’s callback functions will access global storage. The following sections discuss these issues.

Multithreading Models

Your driver can support one of two threading models, which are specified by the following constants:

 


Value

Description

VdkDrv_MTHot

The driver is capable of handling multiple simultaneous calls on the same instance of the session object. For example, a gateway driver could handle multiple accesses for the same collection simultaneously.

VdkDrv_MTReentrant

The driver can support multiple session objects, but only one call at a time. For example, a gateway driver could handle simultaneous calls for different collections, but not for the same collection. This is the default threading model.


Consider the following diagram, in which an application opens two collections to your repository:



The application accesses two collections; each collection is associated with its own separate VDK session. The Verity engine creates an instance of your gateway driver for each session, each with its own GDK session. This is shown by instances A and B in the diagram. The Verity engine may create additional threads to operate on a collection; for example, one thread may index in the background while another thread performs a search as shown in instance B.

Instance A only has one thread accessing the driver’s per-session storage; therefore, no session-level resources are shared. Instance B has two threads accessing the driver’s per-session storage. Because you typically cannot control the conditions under which your gateway driver will be called, you must use the VdkDrv_MTReentrant multithreading model unless you control concurrent access to this storage. If you use the VdkDrv_MTReentrant multithreading model, only one of the threads in instance B will be allowed to execute any of your gateway driver’s callback functions at a time; the other thread will be blocked, waiting for execution of the other thread to complete.

If your driver controls concurrent access, you can use the VdkDrv_MTHot multithreading model. In that case, your driver takes the responsibility for controlling access to per-session (non-stack) structures. The techniques for controlling concurrent access to per-session storage are the same as those for controlling access to the gateway driver’s global storage, which are described in the following section.

Accessing Global Storage

Typically, a driver contains global storage that is shared across all instances of the driver; for example, memory to store the GDK library handle needed to implement security. (For more information, see The GDK Library.) You must always protect global memory. Two ways you can protect global memory are as follows:

You can serialize access to it via thread-synchronization objects, such as a semaphore or mutex.

 

If the memory is read-only, you can initialize it once and then read it without additional protection.

 

These techniques are not mutually exclusive. You can use a thread-synchronization object to protect global structures that need to be updated and treat other global structures as read-only.

Serializing access via a thread-synchronization object is a standard technique for protecting a resource and is not discussed further. The initialization of read-only memory itself requires serial access as well; however, the serialization is only required once, during initialization of the global read-only structures.

If you initialize read-only memory in your VdkDrvNewCBFnc function, you must set up a locking mechanism to serialize execution of this function, as well as your VdkDrvFreeCBFnc function, within the process. To handle this case, you must set up a variable of type VdkDrvStaticLock in your driver’s global memory and initialize it to 0, as in the following statement:

static VdkDrvStaticLock lock = {0};

You must also identify the lock variable to the Verity engine by associating a pointer to it with the name VdkDrv_NeedLock in the attributes array. For an example, see Dynamic Data Access (DDA) Driver Initialization.