Ingres CL LK

From Ingres Community Wiki

Jump to: navigation, search

Ingres Compatability Library
Architecture - Overview - Suggestions - GL: BA - BT - ERGL - handy - HSH - LC - LL - MEGL - MM - MO - MU - PM - SP - TMGL - CL: CI - CK - CM - CP - CS - CSMT - CV - CX - DI - DL - DS - ER - ERold - EX - FP - GC - GV - handy - ID - JF - LG - LK - LO - ME - MH - NM - OL - PC - PE - QU - SA - SI - SR - ST - TC - TE - TH - TM - TR - UT

Contents

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.
Lock Mode Compatibility
NL IS IX S SIX X
NL Y Y Y Y Y Y
IS Y Y Y Y Y N
IX Y Y Y N N N
S Y Y N Y N N
SIX Y Y N N N N
X Y N N N N N

(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.
Lock Mode Conversion Compatibility
NL IS IX S SIX X
NL NL IS IX S SIX X
IS IS IS IS S SIX X
IX IX IX IX SIX SIX SIX
S S S SIX S SIX SIX
SIX SIX SIX SIX SIX SIX X
X X X X X X X
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
Architecture - Overview - Suggestions - GL: BA - BT - ERGL - handy - HSH - LC - LL - MEGL - MM - MO - MU - PM - SP - TMGL - CL: CI - CK - CM - CP - CS - CSMT - CV - CX - DI - DL - DS - ER - ERold - EX - FP - GC - GV - handy - ID - JF - LG - LK - LO - ME - MH - NM - OL - PC - PE - QU - SA - SI - SR - ST - TC - TE - TH - TM - TR - UT

Personal tools
Developing With