Handling concurrency issues
By default, the database server runs UDRs concurrently. A UDR that uses data it shares with other UDRs or with multiple instances of the same routine must implement concurrency control on its data.
When the named-memory functions mi_named_alloc(), mi_named_zalloc(), and mi_named_get() return the address of a named-memory block, they do not request a lock on this named memory. It is the responsibility of your UDRs or DataBlade to manage concurrency issues on the named-memory block.
The greater the memory duration that is associated with the named memory, the more likely that you must manage concurrency of that memory. If the named memory is never updated (it is read-only), there are no concurrency problems. However, if any UDR updates the named memory that has a duration of PER_COMMAND or greater, there are concurrency issues just like there are for any global variable that gets updated.
SELECT * FROM my_table
WHERE myfunc(column1) = 1
OR myfunc(column2) = 2
The following table shows possible concurrency issues of named_mem1.
Named-memory allocation | Concurrency issues? |
---|---|
mi_named_alloc (2048, "named_mem1", PER_COMMAND, nmem1_ptr) | Yes Each invocation of myfunc() in the query gets it own private instance of named_mem1, which expires when the UDR completes, but there might be multiple threads running in a subquery that share the same PER_COMMAND pool. If PER_COMMAND memory is cached in the MI_FPARAM user data, however, there are no concurrency issues because each thread has its own MI_FPARAM structure. Unless you need memory to be shared between threads, this is the preferable alternative for PER_COMMAND. |
mi_named_alloc (2048, "named_mem1", PER_SESSION, nmem1_ptr) | Yes Each invocation of myfunc() in the same query accesses the same named_mem1. This memory does not get deallocated until the session closes. |
mi_named_alloc(2048, "named_mem1", PER_SYSTEM, nmem1_ptr) | Yes Every invocation of myfunc() in every SQL statement accesses the same named_mem1. This memory does not get deallocated until the database server shuts down. |
Memory-locking task | DataBlade API memory-locking function |
---|---|
Request a lock on the specified named-memory block and wait for the lock to be obtained. | mi_lock_memory() |
Request a lock on the specified named-memory block and do not wait for the lock to be obtained. | mi_try_lock_memory() |
Unlock the specified named-memory block. | mi_unlock_memory() |
- The safest approach, even for threads that only read named memory,
is to lock the named-memory block.
After the named-memory block is locked, you can guarantee that all accesses will obtain a consistent read.
- Keep the time that you lock a named-memory block as short as possible. The DataBlade API locking interface is intended to be used in a tightly coupled, fast section of code that protects a critical region during modification. Code must follow these steps:
- Lock the named memory with mi_lock_memory() or mi_try_lock_memory().
- Perform the modification or consistent read.
- Immediately unlock the memory with mi_unlock_memory().
- If you need to hold locks for a long time, do it with SQL in a client application.
typedef struct
{
mi_integer is_initialized;
... other members here....
} MyInfo;