Ingres CL LK
From Ingres Community Wiki
|
Ingres Compatability Library |
Compatibility Library Specification - LK
Abstract
This is the specification of the LK facility provided by the compatibility library for database locking.
Revision: 1.01, 17-Nov-1997
Document History
- Revision 1.01, last modified 17-Nov-1997.
- converted to html.
- Revision 1.0, last modified 2-Jan-91.
- Add LK_INTR_GRANT return from LKrequest.
- Fixed typos, including using lg as the document key!
- Add LK_EVCONNECT lock type, added introductory section on detecting client death.
- Post 6.3/02, 14-Aug-90,
- Modified subsequent to the 6.3/02 spec to add LK_A_INTERRUPT to LKalter, also adding descriptions of historically present flags.
- Documented LK_NODEADLOCK flag to LKrequest.
Specification
Introduction
LK provides locking management services for multiple transactions per process. The ability to manage multiple transaction in the same process is supported by the LK routines, with some assistance from the caller. The LK routines allow the caller to create many transactions in a process, but it is up to the caller to pass transaction identification information to the LK routines when a lock is requested or released. A new transaction is created by calling LKcreate_list. LKcreate_list returns a lock list identifier. This lock list identifer is passed to LKrequest and LKrelease to effect locks for a specific transaction.
Library
Now DMF was CL
Intended Uses
The LK routines are intended for the sole use of DMF.
Assumptions
It is assumed that the concept of a lock, a list of locks and the possiblity of deadlock between these sets is understood.
LK is used to set locks on objects for a transaction on behalf of the caller. It is the responsiblity of the caller to tell the locking system which transaction is requesting lock services.
The performance of the LK routines is paramount to the performance of transaction locking, and multiple server synchronization. Special care should be taken to insure that the LK routines are implemented in a efficent manner.
Definitions
| Lock | A lock is the name of a resource and the requested lock mode for that resource. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Lock Id | A lock identifier is a number that represents a unique and similar identifier for a lock. The resource portion of a lock identifier is the same for all locks on a resource. The lock portion of a lock identifier is different for every current lock. Lock identifiers can be used in place of lock keys in certain LK calls, and are usually faster then using the lock key. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Lock Key | A string of bytes that names the resource to be locked. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Lock Mode | One of the following modes: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NL Null, no lock. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IS Intent to Share, implies finer granularity locking. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IX Intent to Update, implies finer granularity locking. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| S Shared access only. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SIX Shared with intent to update. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X Exclusive access. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The following table shows which granted mode locks are compatible with the requested mode.
(See: Notes on Database Operating Systems for an in depth explanation.) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Lock List | A list of locks held by a transaction. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Shared Lock List | In order to allow multiple servers to share a common buffer cache, each server must be able to read new pages into the cache or toss old pages out of the cache. Both of these operations may require lock requests, since cache locks may be kept on the pages. When a server tosses out a page that has cache lock on it, the server must first release the lock. Since the page may have been read in by a different server, each server must be able to release any cache lock regardless of which server requested it.
To allow this, all cache locks are held on a common lock list - the buffer manager lock list. All servers are allowed to make lock requests on this lock list. A shared lock list is created by specifying the flag LK_SHARED to the LKcreate_list call. Once a shared lock list is created, it can be connected to by other threads by calling LKcreate_list with the LK_CONNECT flag and by specifying the unique key of the lock list to which to connect. The LKcreate_list call will return the lock list id which all lock requests on this list should be made. This id may be different for each connecting process. Each process wishing to use the shared lock list must make its own LKcreate_list(LK_CONNECT) call and make all lock requests on the list using the lock list id returned. When a process makes an LKrelease() call on a lock list that is a shared list, the list is not actually released unless there are no other connections to it. When the last connection to the shared list is released - either through an LKrelease call or because of the death of the process - the shared list will be released and all locks as well. The lock list attributes are assigned when the shared lock list is first created (caller specifying LK_SHARED rather than LK_CONNECT in LKcreate_list call). Subsequent connectors to the shared list get whatever attributes the lock list was created with. Currently, shared lock lists must be created with the attribute LK_NONPROTECT since there is no concept of a transaction owner of the list which must be recovered before the lock list can be released. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Lock Value | A value that can be stored with a lock, the value is returned on every lock request and can be set when a lock is converted or released from SIX or X mode. The value also includes the granted mode of the lock, which may be different then the requested mode of the lock. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Logical Lock | A lock that is requested and held until end of transaction. If the lock is requested again in a different mode, the resulting mode is determined from the following table.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Physical Lock | A lock that is held for a short time and released before end transaction. Physical locks are used to synchronize access to an object that is being logically locked at a finer granularity. A physical lock can explicitly be converted from any mode to any other mode. A lock remains physical as long as all future requests for the lock specify the physical attribute. If an existing physical lock is requested without the physical attribute, the lock becomes a logical lock. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Related Lock List | A related lock list in coordination with a normal lock list, define the set of locks held by a transaction. The related lock list holds locks that span transactions. An example would be a database lock. The lock is held for many transactions, and only released when the database is released. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Transaction | A unit of work that collects locks on objects so that updates to multiple objects are atomic and serializable. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Concepts
LK provides a service to create a lock list. This lock list can be created using a caller supplied unique identifier, or LK can be requested to generate a unique identifier. The identifiers supplied by the caller, typically a transaction identifier, can not be in the range of identifiers that LK will generate for identifers that are requested of LK. The lock list is assigned and lock list identifer that is returned to the caller. This identifier is used by all LK services to identify the lock list, (i.e. transaction), to operate on. A lock list can be located using the create list service by unique identifier. This is used for recovery purposes, and documented later.
Once a list has been created, lock requests can be performed. A lock request involves the following pieces of information: lock key, lock mode, lock list, lock id, timeout and flags. A typical request sets a lock on a lock key in a specific mode for a specific transaction that returns a lock identifier if the lock is granted before the timeout interval has elapsed. Variations on this theme allow the following scenerios:
- Request a lock on a resource that is already locked by this transaction. In this case the LK routines will convert the lock to it's lock mode described in the definitions for logical locks.
- Request a lock and it's associated value. When the lock is granted the value stored with the lock is also returned.
- Explicit requests for converting physical locks. A lock can be explicitly converted to a higher or a lower mode. This allows information to be passed between processes. A process which wants to set the lock requests it X mode, it then converts the lock to NL and the value passed in on this conversion request is stored with the lock. Another process can look at the value of the lock by requesting the lock, or converting an instance of the lock to get the new value.
Once a lock has been requested it is normally only released when a lock list is released. This is not true for physical locks. A physical lock can be released or converted to a higher lock mode or even converted to a lower lock mode. Physical locks are used to synchronize access to shared resources for short defined intervals while a transaction is manipulating the objects. This is most often used to increase the concurrency at the expense of the locking overhead. (An exclusive physical lock can be set on a page in a btree when a split is going to occur, and can be released to allow others access to the btree.) Physical locks can also be used to send short messages between processes by storing values with the locks and releasing the lock so that another process can aquire that lock and look and/or change the value. This feature is used to implement distributed object caching, using the value as a timestamp for the object.
When resources needed to store locks have been exhausted, the caller has the option of converting from finer granularity locking to coarser granularity locking and releasing the finer granularity locks. For example this happens when a cleint has a table locked in IX mode and is setting X page locks, decides to escalate by converting the table lock to X and releasing all the page locks. The release routine supports releasing locks that have a similar lock key prefix. Locks have similar prefixes when the first 16 bytes of the lock key are the same.
There is also support for requesting the list of locks held by a transaction. This is used for debugging purposes and for the distributed system to log the locks for the first phase of 2-phase commit. If a transaction has just been returned deadlock, there will be the ability to ask for the transactions involved in the deadlock cycle. This can then be logged so that the user can diagnose application locking problems.
The special support for recovery, allows another process to gain access to the transaction lock list of a caller whose process has aborted. This allows the recovery system to take over a transaction so that it can be aborted and the locks released when this has completed. The distributed transaction reincari4ion support allows the recovery system to write the list of locks held by a distributed transaction to the log for 2-phase commit. As part of recovery for 2-phase transactions, the recovery system will read the lock list from the log and set all the locks again so that the transaction still appears to be active and can wait until the outcome of the distributed transaction is known.
Detecting Client Death
LK is responsible for actively detecting processes that die while holding locks.
For instance, the event system uses locks to solve a death problem. When a server is killed (kill -9, or STOP), it doesn't have a chance to disconnect from the EV (event) subsystem. When events for which that server was registered are raised by other servers, event instances are queued to the "phantom" server in the EV subsystem's shared memory pool. Since the "phantom" server might no longer be around to dequeue the event instances queued for it, these event instances would remain allocated forever, eventually filling up the EV subsystem's shared memory pool. When this happens, subsequent RAISE DBEVENT requests are aborted.
To solve this, when a server connects to the EV subsystem, it requests an exclusive (LK_X) physical lock of type LK_EVCONNECT, using the lock list created for the local event thread. The first attribute (lk_key1) of the lock key is the server's process id, while the remaining attributes (lk_key2-6) are zero. If the server is killed, normal LAR cleanup will release the lock on behalf of the server. If the event thread is shut down in a server, the associated lock is released.
When a server attempts to queue an event instance in the EV subsystem to another server, it first requests a shared (LK_S) lock of type LK_EVCONNECT with a key value of the target server's pid. This lock is requested with the LK_NOWAIT flag. If the lock is not obtained (LK_BUSY), the requestor can assume the target server is still alive, and queue the event instance to it. If the lock is obtained, the requestor must release the lock, issue an error message, not queue the event instance to the server, and mark the target server as disabled to prevent further attempts to queue event instances to that server.
Header File <lk.h>
The header file <lk.h> must be included before using any of the functions provided. It also defines the following.
LK_LKID - the type of a lock id
This is the format of a lockid returned by LKrequest.
typedef struct
{
u_i4 lk_unique;
u_i4 lk_common;
} LK_LKID;
LK_LLID - a lock list identifier
This is the format of a lock list identifier returned by the LKcreate_list service.
typedef u_i4 LK_LLID;
LK_LOCK_KEY - template for a lock key
This structure defines the format of a key expected by the lock routines. There is minimal intepretation of the key by the locking routines.
typedef struct _LK_LOCK_KEY
{
i4 lk_type; /* The type of lock. */
#define LK_DATABASE 1
#define LK_TABLE 2
#define LK_PAGE 3
#define LK_EXTEND_FILE 4
#define LK_BM_PAGE 5
#define LK_CREATE_TABLE 6
#define LK_OWNER_ID 7
#define LK_CONFIG 8
#define LK_DB_TEMP_ID 9
#define LK_SV_DATABASE 10
#define LK_SV_TABLE 11
#define LK_SS_EVENT 12
#define LK_TBL_CONTROL 13
#define LK_JOURNAL 14
#define LK_OPEN_DB 15
#define LK_CKP_DB 16
#define LK_CKP_CLUSTER 17
#define LK_BM_LOCK 18
#define LK_BM_DATABASE 19
#define LK_BM_TABLE 20
#define LK_CONTROL 21
#define LK_EVCONNECT 22
i4 lk_key1;
i4 lk_key2;
i4 lk_key3;
i4 lk_key4;
i4 lk_key5;
i4 lk_key6;
};
LK_UNIQUE - the structure of a unique identifier
This structure defines what a unique identifier looks like. A caller defined unique identifer can not specify an lk_uhigh value of 0. This is reserved by the LK routines.
typedef struct _LK_UNIQUE
{
u_i4 lk_uhigh; /* Most significant part. */
u_i4 lk_ulow; /* Least significant part. */
};
LK_VALUE - the structure of a lock value
This structure defines what a lock value looks like.
typedef struct _LK_VALUE
{
u_i4 lk_high; /* Most significant part. */
u_i4 lk_low; /* Least significant part. */
i4 lk_mode; /* The granted mode of the lock. */
};
LK_STAT - locking statistics return structure
This structure is returned by LKshow.
typedef struct _LK_STAT
{
i4 create; /* Create lock list. */
i4 request; /* New lock request. */
i4 re_request; /* Re-request same lock. */
i4 convert; /* Explicit conversions. */
i4 release; /* Explicit releases. */
i4 escalate; /* Partial releases. */
i4 destroy; /* Release lock list. */
i4 wait; /* Requests that waited. */
i4 con_wait; /* Converts that waited. */
i4 con_search; /* Convert deadlock search. */
i4 con_dead; /* Convert deadlock. */
i4 dead_search; /* Deadlock searchs. */
i4 deadlock; /* Deadlocks. */
i4 cancel; /* cancels. */
i4 enq; /* enq requests. */
i4 deq; /* deq requests. */
i4 gdlck_search; /* # of pending global deadlock
** search requests. */
i4 gdeadlock; /* # of global deadlock detected. */
i4 gdlck_grant; /* # of global locks grant before the
** the global deadlock search.
*/
i4 totl_gdlck_search; /* # of global deadlck search requests*/
i4 gdlck_call; /* # of global deadlock search calls. */
i4 gdlck_sent; /* # of global deadlck messages sent. */
i4 cnt_gdlck_call; /* # of continue deadlock search calls*/
i4 cnt_gdlck_sent; /* # of continue deadlock message sent*/
i4 unsent_gdlck_search;/* # of unsent deadlck search requests*/
i4 sent_all; /* # of sent all deadlck search requst*/
} LK_STAT;
LK_LLB_INFO - lock list information
This structure is used to return information about lock lists.
typedef struct _LK_LLB_INFO
{
i4 llb_id; /* Internal identifier. */
i4 llb_status; /* Lock list status. */
i4 llb_key[2]; /* Lock list key. */
i4 llb_r_llb_id; /* Related lock list id. */
i4 llb_r_cnt; /* Related lock list count. */
i4 llb_lkb_count; /* Number of locks held. */
i4 llb_llkb_count; /* Number of logincal locks held. */
i4 llb_max_lkb; /* Maximum number of logincal locks
** allowed. */
i4 llb_wait_rsb_id; /* Wait RSB id. */
};
LK_LKB_INFO - information about locks
This structure returns information about a specific lock request.
typedef struct _LK_LKB_INFO
{
i4 lkb_id; /* Internal identifier. */
i4 lkb_rsb_id; /* Resource identifier. */
i4 lkb_llb_id; /* Lock list identifier. */
i4 lkb_phys_cnt; /* Physical lock count. */
char lkb_grant_mode; /* Lock grant mode. */
char lkb_request_mode; /* Lock convert mode. */
char lkb_state; /* Lock state. */
char lkb_flags; /* Lock flags. */
i4 lkb_key[7]; /* Lock key. */
i4 lkb_vms_lkid; /* VMS lock id. */
i4 lkb_vms_lkvalue[2]; /* VMS lock value. */
};
LK_RSB_INFO - information about a resource
This structure returns information about a lock resource.
typedef struct _LK_RSB_INFO
{
i4 rsb_id; /* Internal identifier. */
i4 rsb_grant; /* Group grant mode. */
i4 rsb_convert; /* Convert group mode. */
i4 rsb_key[7]; /* Lock key. */
i4 rsb_value[2]; /* Lock value. */
i4 rsb_invalid; /* The status of the lock value. */
i4 rsb_count; /* # of granted requests on resource. */
};
LKDSM - cluster deadlock search message block
This structure contains LK cluster deadlock search message block. It is used to transfer deadlock search information to/from CSP for performing global deadlock detection in a cluster environmemt.
typedef struct _LKDSM
{
LK_LOCK_KEY lock_key; /* Resource name to lock. */
u_i4 lock_req_mode; /* The requested lock mode for
** the resource. */
u_i4 lock_gnt_mode; /* The granted lock mode for
** the resource. */
u_i4 lockid; /* VMS lockid. */
LK_UNIQUE tran_id; /* Transaction identifier that
** waiting on the resource. */
LK_UNIQUE o_tran_id; /* The original transaction
** identifier that starting on
** the deadlock search. */
i4 lock_state; /* The state of the lock. */
#define LOCK_CONVERT 1
};
Executable Interface
The following functions are provided.
LKalter - alter the lock database
This routine handles the initialization and allocation of tables in the lock database. This routine can be used to dynamically change the size of the internal tables. These changes can only take place when the locking system has no active lists or active locks.
This routine is also used to control the interruptability of a particular lock list. Interruptible lock lists are made non-interruptible when transaction abort processing is done, so that subsequent interrupts will not abort the abort processing. Non-interruptible lock lists are occasionally made interruptible for the duration of a single lock request for which we want to allow interupts. (The notion of interruptability is discussed in the CS specification).
The interpretation of the value parameter depends on the setting of the flag parameter, as follows:
| LK_I_LLB | This flag is used to set the number of Lock List Blocks in the LK system. Each call to LKcreate_list requires a lock list block to store the lock list information. Lock lists are reused when they are released by LKrelease(). Each user thread typically requires 2 lock lists, and others are used by processes such as the RCP and Archiver. value should be a i4 indicating the number of lock lists. |
| LK_I_BLK | This flag is used to set the number of Lock Blocks in the LK system. Lock blocks are used to store information about lock Resources, and about lock Requests. If there are insufficient Lock Blocks, an LKrequest call will be rejected with the LK_NOLOCKS return code, and the caller is required to escalate to table-level locking or to otherwise issue fewer lock requests. value should be a i4 indicating the number of lock blocks. |
| LK_I_LKH | This flag value is used to specify a preferred size for the Lock Request Hash Table. A hash table is used in many LK implementations to quickly locate a lock request block. This value should be large enough to ensure that hash chains are short. value should be a i4 indicating the number of hash buckets in the LKH table. |
| LK_I_RSH | This flag value is used to specify a preferred size for the Lock Resource Hash Table. A hash table is used in many LK implementations to quickly locate a lock resource. This value should be large enough to ensure that hash chains are short. value should be a i4 indicating the number of hash buckets in the RSH table. |
| LK_I_MAX_LKB | This flag value is used to indicate the maximum number of locks which a single lock list may acquire. Placing a limit in this fashion prevents a single lock list from monopolizing the system lock resources. If a lock list attempts to acquire more than this many locks, the LKrequest call will be rejected with LK_NOLOCKS. Note that LK_PHYSICAL locks do not count against this limit. Also note that individual lock lists may override this setting through the 'count' parameter on the LKcreate_list() call. value should be a i4 indicating the max num of locks per list. |
| LK_A_NOINTERRUPT | This flag value is used to alter a lock list to be non-interruptible. Every lock request made against a non-interruptible lock list is non-interruptible. LKevent() waits, however, are not affected (they are controlled by the LK_E_INTERRUPT flag only). A lock list is typically converted from interruptible to non-interruptible when transaction abort processing begins. value should be the lock list ID (as returned from LKcreate_list()), coerced into a i4, of the lock list to be altered. |
| LK_A_INTERRUPT | This flag value is used to alter a lock list to be interruptible. Each LKrequest call made on an interruptible lock list is interruptible, unless the LK_NONINTR flag is passed to LKrequest(). Occasionally, a non-interruptible lock list is temporarily made interruptible (for the duration of issuing a single LKrequest() call), and then made non-interruptible again. value should be the lock list ID (as returned from LKcreate_list()), coerced into a i4, of the lock list to be altered. |
Inputs:
| flag | the LKalter operation which is desired. |
| value | the appropriate value (see above for details). |
Outputs:
| err_code | reason code for failure. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| LK_BUSY | list or locks are active. |
| LK_NOLOCKS | Not enough memory. |
Definition:
STATUS LKalter(flag, value, err_code) i4 flag; i4 value; CL_ERR_DESC *err_code;
LKcreate_list - Create a lock list
This function associates a unique identifier with a list that can contain a list of locks. Deadlock detection is performed between lists, as this is the way of identifying different threads of execution. A lock list can be related to another list by passing the lock list identifier of the related list. The related list cannot be released until all dependent lists have been released. This mechanism can be used to associate locks in different lists with the same thread. This works if the same lock does not appear in the related lock list and the created lock list. Only one level of lock lists are supported currently, this means that a related lock list cannot be related to another list.
Using the LK_RECOVER flag an existing lock list can be searched for and it's identifer returned. Using the LK_ASSIGN flag a unique number will be supplied for you and a lock identifer will be returned.
If the LK_SHARED flag is specified, then the lock list will be shareable by other processes. This means that other LK clients may connect to the same lock list and make lock calls on it (release locks already held on it, convert them, or request new locks).
If the caller specifies LK_CONNECT, then the request is to connect to an already existing shared lock list. The caller should not specify the LK_ASSIGN flag, but should pass in the key of the shared list in the 'unique_id' argument. This key can be obtained by a show operation on the lock list (LKshow). A lock list id will be returned to use to reference the shared lock list.
Note that two processes using a common shared lock list may use different lock list id's to reference the same lock list. Lock list id's are unique to each connection to a shared list.
Currently, shared lock lists must be of the type LK_NONPROTECT.
Inputs:
| flags | Create list options: | |
| LK_RECOVER | assume ownership of an already existing lock list. This is used only by the recovery system. | |
| LK_NONPROTECT | list holds locks that can be released without recovery. | |
| LK_ASSIGN | assign a unique lock list key to the created list. If not specified, then the caller supplies the key (unique_id argument). | |
| LK_NOINTERRUPT | lock requests on this list are not interruptable. | |
| LK_MASTER | lock list owned by recovery process. | |
| LK_SHARED | create shared lock list. | |
| LK_CONNECT | connect to existing shared lock list. | |
| unique_id | A unique value used to identify a | |
| related_lli | The lock list identifier of the list that should be related to this list. | |
| count | The maximum number of locks on the lock list. |
Outputs:
| lock_list_id | The lock list identifier assigned to this list. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| LK_BADPARAM | Something wrong with a parameter. |
| LK_NOLOCKS | No more lock resources available. |
Definition:
STATUS LKcreate_list(flags, related_lli, unique_id, lock_list_id, count, err_code) i4 flags; LK_LLID related_lli; LK_UNIQUE *unique_id; LK_LLID *lock_list_id; i4 count; CL_ERR_DESC *err_code;
LKevent - handle processing of a request service
LKevent offers a low-level event service to DBMS code. Clients may define an event, wait for the event to occur, and signal that the event has occurred. When waiting for an event, clients may request that the event be interruptible. Cross-process events are used by clients to manage events which synchronize shared memory management.
Inputs:
| flag | Flags for LKevent; one or more of: | |
| LK_E_SET | set this event | |
| LK_E_WAIT | wait for this event | |
| LK_E_CLR | clear (i.e., cause) this event | |
| LK_E_INTERRUPT | this wait is interruptible | |
| LK_E_CROSS_PROCESS | this event is cross-process | |
| lock_list_id | The lock list to use. | |
| event_type | Event type. | |
| event_value | Event value. |
Outputs:
| err_code | Reason for error status return. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| LK_BADPARAM | |
| LK_INTERRUPT | This event wait was interrupted. |
Definition:
STATUS LKevent(flag, lock_list_id, event_type, event_value, err_code) i4 flag; LK_LLID lock_list_id; u_i4 event_type; u_i4 event_value; CL_ERR_DESC *err_code;
LKinitialize - initialize the LK lock database
This routine is called once to initialize the LK database.
Inputs:
| None |
Outputs:
| None |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
Definition:
STATUS LKinitialize(err_code) CL_ERR_DESC *err_code;
LKrelease - release a lock or a whole lock list
This function can perform the following functions: release a whole lock list, release a partial lock list, release a specific physical lock. Releasing the whole lock list is usually requested when a transaction commits or aborts. Releasing part of the lock list is used when converting to larger granularity locking to release the lower granularity resources. Releasing a specific lock is used for objects that are just locked while being looked at or changed and are locked at a finer granularity. A lock can be released by lock identifier or by lock key. If a value is specified and the lock is currently granted in X or SIX mode the value is copied into the lock. If no value is specified the value is set to 0.
If the list released is a shared lock list, then the locks are not actually released until the last reference to the shared list is released.
Inputs:
| flags | Can be ONE or NONE of the following: | |
| LK_ALL | release all locks on lock list | |
| LK_PARTIAL | release partial list | |
| LK_AL_PHYS | release all physical locks | |
| Optionally may include: | ||
| LK_MULTITHREAD | lock list is shared | |
| lli | Lock list identifier. | |
| lockid | If flags != LK_ALL then this is a release of a specific lock. | |
| lockkey | If flags == zero and lockid was not specified or flag == LK_PARTIAL then this is the lockkey and is used to determine the lock. | |
| value | If this is a single lock release and granted mode is SIX or X then this value is copied to the lock. |
Outputs:
| None |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| LK_BADPARAM | Bad parameter. |
Definition:
STATUS LKrelease(flags, lock_list_id, lockid, lock_key, value, err_code) i4 flags; LK_LLID lock_list_id; LK_LKID *lockid; LK_LOCK_KEY *lock_key; LK_VALUE *value; CL_ERR_DESC *err_code;
LK_request - request a lock
This function handles requesting a lock. The lock can either be already granted to the lock list or it can be a new request. If it is a request for an existing granted lock, the mode is checked to determine if any lock conversion needs to take place to satisfy the request. The variable 'convert_mode[ ][ ]' is a mapping from grant mode and request mode to new mode. If granted mode equals request mode or new mode equals granted mode then nothing has to happen, otherwise a lock mode conversion is performed. If this is a request for a new lock that this lock list doesn't currently own then the resource is looked up and the lock is granted if compatible with all other locks on the resource. The lock request can be directed to abort if the lock can't immediately be granted using the LK_NOWAIT flag, or if the lock has waited for longer then a interval expressed in seconds or deadlock has been detected.
Using the LK_STATUS qualifier an alteri4e success status will be returned if this lock did not already belong to the current transaction. The LK_PHYSICAL qualifer is used on locks which will be released before end of transaction. Every LKrequest call for this lock by a transaction must include the LK_PHYSICAL flag. If the LK_PHYSICAL flag is left off a LKrequest call a convert or a LK_release for this lock will fail. LK_CONVERT is used to trigger a conversion for a lock. A conversion from a high lock mode to a low lock mode is only legal when used with the LK_PHYSICAL flag.
If the LK_NODEADLOCK flag is passed, then deadlock detection is not performed. This flag should ONLY be passed when caller code can guarantee through other mechanisms that deadlocks cannot occur and that the resource in question will eventually be acquired. This flag is typically used for special-purpose locks, such as the multi-server fast commit buffer cache locks.
If an address to receive the value is specified, the value stored with the lock will be returned in that variable when the lock is granted. If this is a conversion from X or SIX to a lower lock mode, the value in the callers value variable is stored with the lock.
Due to the asynchronous operation of interrupts, it may be the case that an interrupt is delivered to the thread precisely at the same time that the lock request is granted. LKrequest returns LK_INTR_GRANT when a lock has been granted at the same time as an interrupt arrives. Callers of LKrequest which can be interrupted must deal with this new error return and take the appropriate action. Typically, the appropriate action is the same as for the LK_INTERRUPT return code, but one important exception should be noted:
- The exception includes those short term locks (such as core system catalog pages) which must be released immediately (rather than waiting for the end of transaction abort processing, when all ordinary transaction locks are released). In this case the caller checks for the special LK_INTR_GRANT return from LKrequest and releases the short term lock before returning with the 'interrupted' status.
Note: The implementation of LK_INTR_GRANT is a optional feature of the LK CL. There is an important alteri4e way to provide this functionality. A CL writer may choose to handle the simultaneous arrival of both an interrupt and a lock grant by returning the lock grant status and calling CSattn() to requeue the interrupt. This technique effectively postpones the handling of the interrupt until the next interruptable suspension is performed (or until client code recognizes the interrupt through its normal interrupt polling mechanisms). This technique may require some cooperation between the CS and LK modules; such cooperation is not described further here.
The implementor may not simply return LK_INTERRUPT as was done in older implementations, as this may cause important locks to go unreleased. Nor should the implementor simply return the grant status without in some way processing the interrupt (or the interrupt will be lost, leading to a hung state in the server).
Inputs:
| flags | A combination of LK_NOWAIT, LK_STATUS LK_PHYSICAL, LK_ESCALATE, and LK_CONVERT if this is a convert request. | |
| LK_MULTITHREAD | This lock request comes from a multi-threaded server, and may be shared. | |
| LK_NONINTR | This lock request is non-interruptible. | |
| LK_NODEADLOCK | This lock request does not need deadlock detection. | |
| lock_list_id | The lock list identifier returned from a previous call to LK_create_list | |
| lock_key | A pointer to the resource name to lock. | |
| lock_mode | The requested lock mode for the resource. | |
| timeout | Optional value specifying the number of seconds to wait before aborting lock request. | |
| value | Optionally, if this is a convert down from LK_X or LK_SIX then this value replaces the value in the lock. |
Outputs:
| lockid | Optional pointer to location to return lock identifier. |
| value | If this is a request other then convert down from LKX or LK_SIZ then return the current value of the lock. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| LK_NEW_LOCK | Lock granted and never existed before. |
| LK_BADPARAM | Bad parameter. |
| LK_NOLOCKS | No available lock memory. |
| LK_DEADLOCK | Deadlock detected. |
| LK_TIMEOUT | Lock timed out before being granted. |
| LK_BUSY | Lock could not immediately be granted. |
| LK_VAL_NOTVALID | Invalid value parameter. |
| LK_INTERRUPT | Lock request was interrupted. |
| LK_INTR_GRANT | Thread was interrupted at the same time that lock was granted. Lock has been acquired. |
Definition:
STATUS LKrequest( flags, lock_list_id, lock_key, lock_mode, value, lockid, timeout, err_code) LK_LLID lock_list_id; LK_LOCK_KEY *lock_key; u_i4 lock_mode; LK_VALUE *value; LK_LKID *lockid; i4 timeout; CL_ERR_DESC *err_code;
LKshow - show information about locks
This routine can be asked to return the following information:
- Information about a specific lock for a lock list.
- Information about the deadlock that last occured for this list.
- Information about a specific resource.
- Information about all locks held by a lock list.
The last two pieces of information are variable length. They can return multiple entries for each successive call until no others exist. The consistency of these lists with respect to concurrent changes is not defined except if the object is known not to be changing at the moment.
Inputs:
| flag | One of the following flags: | |
| LK_S_RESOURCE | show all locks group by resource. | |
| LK_S_SRESOURCE | show specified resource. | |
| LK_S_LOCKS | show all locks group by lock list. | |
| LS_S_SLOCK | show specified lock. | |
| LK_S_OWNER | show owner of specified lock. | |
| LK_S_ORPHANED | show orphaned locks. | |
| LK_S_STAT | show locking stats. | |
| LK_S_LIST | show lock list. | |
| LK_S_LLB_INFO | return id of related lock list; info result set to NULL if none exists. | |
| LK_S_TRAN_LOCKS | return brief info about locks on specified lock list. | |
| LK_S_REL_TRAN_LOCKS | return brief info about locks on related lock list of the specified list. | |
| lli | The lock list to use. Required for: | |
| LK_S_LIST | list to show. | |
| LK_S_OWNER | list lock is held up. | |
| LK_S_TRAN_LOCKS | list holding locks to return info on. | |
| LK_S_REL_TRAN_LOCKS | list related to lib holding locks to return info on. | |
| LK_S_LLB_INFO | list to show. | |
| lockid | The lockid of lock to use. Required for: | |
| LK_S_SLOCK | lock to show. | |
| LK_S_SRESOURCE | resource to show. | |
| lock_key | The lock key to use. Required for: | |
| LK_S_OWNER | key of lock. | |
| info_size | The size of the buffer. | |
| info_buffer | The address of the buffer to return the information. | |
| context | Set to zero on first call, LK uses this to continue the LK service. |
Outputs:
| info_result | The resulting length of the buffer. |
| context | Updated context information. |
| info_buffer | The information to be returned. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| LK_MORE | Sucessful and more information to return. |
| LK_BADPARARM | Bad parameter. |
Definition:
STATUS LKshow(flag, id, lockid, lock_key, info_size, info_buffer, info_result, context, err_code) i4 flag; i4 id; LK_LKID *lockid; LK_LOCK_KEY *lock_key; u_i4 info_size; PTR info_buffer; u_i4 *info_result; u_i4 *context; CL_ERR_DESC *err_code;
Examples
LK_UNQIUE xid_1[2] = { 1, 1 };
LK_LLID lli_1;
i4 err_code;
i4 status;
i4 context;
LK_UNIQUE xid[2] = { 1, 1};
int context;
LK_LLID lli;
LK_LKID lockid;
int status;
LK_LOCK_KEY lock_key[6] = { 1, 2, 3, 4, -1, 5 };
int i;
/* Test bad parameters on LKcreate_list. */
status = LKcreate_list(0, 0, 0, &lli_1, &err_code);
if (status != LK_BADPARAM)
error();
status = LKcreate_list(0, 0, xid_1, 0, &err_code);
if (status != LK_BADPARAM)
error();
status = LKcreate_list(0, 1234567890, xid_1, &lli_1, &err_code);
if (status != LK_BADPARAM)
error();
status = LKcreate_list(0, 0, xid_1, &lli_1, &err_code);
if (status)
error();
if (status == 0 && err_code)
error();
status = LKcreate_list(0, 0, xid_1, &lli_1, &err_code);
if (status != LK_BADPARAM)
error();
/* Test release with bad arguments. */
status = LKrelease(0, 1234567890, 0, 0, 0, &err_code);
if (status != LK_BADPARAM)
error();
status = LKrelease(0, lli_1, 0, 0, 0, &err_code);
if (status != LK_BADPARAM)
error();
status = LKrelease(LK_ALL, lli_1, 0, 0, 0, &err_code);
if (status)
error();
if (err_code)
error();
/* Create a list to play with. */
status = LKcreate_list(0, 0, xid, &lli, &err_code);
if (status)
error();
/* Test bad lli. */
status = LKrequest(0, 1234567890, lock_key, LK_X, 0, 0, 0, &err_code);
if (status != LK_BADPARAM)
error();
/* Test missing lock_key. */
status = LKrequest(0, lli, 0, LK_X, 0, 0, 0, &err_code);
if (status != LK_BADPARAM)
error();
/* Test bad lock mode parameters. */
status = LKrequest(0, lli, lock_key, -1234567890, 0, 0, 0, &err_code);
if (status != LK_BADPARAM)
error();
status = LKrequest(0, lli, lock_key, 1234567890, 0, 0, 0, &err_code);
if (status != LK_BADPARAM)
error();
/* Get a lock and try implicit and explicit conversions. */
status = LKrequest(0, lli, lock_key, LK_IS, 0, 0, 0, &err_code);
if (status)
error();
status = LKrequest(0, lli, lock_key, LK_S, 0, 0, 0, &err_code);
if (status)
error();
status = LKrequest(LK_CONVERT, lli, lock_key, LK_X, 0, 0, 0, &err_code);
if (status)
error();
/* Request a handfull of locks. */
for (i = 0; i < 32; i++)
{
lock_key[4] = i;
status = LKrequest(0, lli, lock_key, LK_X, 0, 0, 0, &err_code);
if (status)
error();
}
/* Release all the locks and the list. */
status = LKrelease(LK_ALL, lli, 0, 0, 0, &err_code);
if (status)
error();
/* Create a list to play with. */
status = LKcreate_list(0, 0, xid, &lli, &err_code);
if (status)
error();
for (i = 0; i < 1000; i++)
{
status = LKrequest(LK_PHYSICAL, lli, lock_key, LK_X, 0, &lockid, 0, &err_code);
if (status)
error();
status = LKrelease(0, lli, &lockid, 0, 0, &err_code);
if (status)
error();
}
status = LKrequest(LK_PHYSICAL, lli, lock_key, LK_N, 0, &lockid, 0, &err_code);
if (status)
error();
for (i = 0; i < 1000; i++)
{
status = LKrequest(LK_CONVERT | LK_PHYSICAL, lli, 0, LK_X, 0, &lockid, 0, &err_code);
if (status)
error();
status = LKrequest(LK_CONVERT | LK_PHYSICAL, lli, 0, LK_N, 0, &lockid, 0, &err_code);
if (status)
error();
}
status = LKrelease(0, lli, &lockid, 0, 0, &err_code);
if (status)
error();
for (i = 0; i < 1000; i++)
{
status = LKrequest(LK_PHYSICAL, lli, lock_key, LK_N, 0, &lockid, 0, &err_code);
if (status)
error();
}
status = LKrelease(0, lli, &lockid, 0, 0, &err_code);
if (status)
error();
|
Ingres Compatability Library |
