HP.com home ALLBASE/SQL Performance and Monitoring Guidelines: HP 9000 Computer Systems > Chapter 7 Troubleshooting with SQLMON

Lock Subsystem

» 

Technical documentation

Complete book in PDF
» Feedback
 

 » Table of Contents

 » Index

Use the Lock subsystem to troubleshoot performance bottlenecks caused by lock contention. This section describes how to handle lock waits, deadlocks, and lock allocation failures.

Lock Waits

If an end user complains of a hung session, perhaps his or her session is actually waiting for a lock. A session will wait for a lock if another session has already acquired an incompatible lock on the same object. For more information on lock waits, see the chapter "Concurrency Control through Locks and Isolation Levels" in the ALLBASE/SQL Database Administration Guide.

For example, we can use SQLMON to find out why the session of the user logged on as BNORTON appears to be hung. Since the user is connected to the PartsDBE DBEnvironment, issue the following command:

  SQLMONITOR OVERVIEW => SET DBENV PartsDBE

To make the screens easier to read, set the lock filter to limit the lock information displayed to locks for which at least one session is waiting (W) and locks that are being converted to a stronger mode (C):

  SQLMONITOR OVERVIEW => SET LOCKFILTER //WC//

Overview Session Screen

Invoke the Overview Session screen to obtain the PIDs of all database sessions connected to the DBEnvironment:

  SQLMONITOR OVERVIEW => /o s

From the following screen, we can see that the BNORTON login has a PID of 26180 and a wait status.

[wlockover]

Lock Session Screen

To get locking information for PID 26180, access the Lock Session screen:

  SQLMONITOR OVERVIEW => /loc s

  PID: 26180

The value of the GWC field in the following screen verifies that the database session that appears to be hung is actually waiting to convert a lock. The WAITS FOR column identifies PID 6167 as the session that is causing PID 26180 to wait.

[wlocksesa]

Now you can invoke the Lock Session screen for PID 6167, which has acquired a lock on the PurchDB.Vendors table. To make the screen easier to read, limit the lock information displayed to the PurchDB.Vendors table. Change the lock filter so that all locks are displayed.

  SQLMONITOR LOCK => SET LOCKTABFILTER PurchDB.Vendors

  SQLMONITOR LOCK => SET LOCKFILTER ////

  SQLMONITOR LOCK => /loc s 6167
[wlocksesb]

Lock Impede Screen

To identify all sessions that are impeded by PID 6167, invoke the Lock Impede screen:

  SQLMONITOR LOCK => i

  PID: 6167

The following screen reveals that the lock held by PID 6167 is causing a number of other sessions, including PID 26180, to wait.

[wlockimp]

To solve this problem, you should investigate PID 6167. The Lock Session screen reveals that PID 6167 is running ISQL, and is run by the user logged on as DGREEN. If PID 6167 does not immediately end the transaction holding the incompatible lock, you should consider executing the ISQL statement TERMINATE USER. If the transaction has been marked with a label, you can clearly identify the part of the program the user is running. PID 6167 is executing a repeatable read (RR) transaction.

A better solution might be to change the transaction's isolation level. The XID field displays a system-generated integer that uniquely identifies the transaction, but it does not identify the SQL statements that have been executed. The LABEL field displays an 8-character string that the application program defines in the BEGIN WORK or SET TRANSACTION statements. If the application program uses the LABEL field carefully, it will be easy for you to debug all the transactions in your application programs.

Deadlocks

A deadlock occurs when two transactions are each waiting for a database object which the other has locked. ALLBASE/SQL automatically detects deadlocks and resolves them by rolling back one of the transactions. For a detailed discussion on deadlocks, see the chapter "Concurrency Control through Locks and Isolation Levels" in the ALLBASE/SQL Database Administration Guide.

To examine the locks that cause a deadlock, you must freeze one of the sessions before ALLBASE/SQL rolls it back and releases its locks. The steps in the following example show how to create a deadlock, freeze a session, and use SQLMON to examine the deadlocked session's locks. To perform these steps, you will need access to a Sample DBEnvironment and the ability to create at least four windows on your workstation or PC. For instructions on setting up the Sample DBEnvironment, see the chapter "Practice with ALLBASE/SQL Using PartsDBE" in Up and Running with ALLBASE/SQL.

Step 1 Open Four Windows

Use the windows as follows:

Window 1

The first ISQL session that is deadlocked.

Window 2

The second deadlocked ISQL session. Since this session will be rolled back by ALLBASE/SQL, it is the one you want to freeze.

Window 3

An SQLMON session for examining the locks held by the deadlocked sessions.

Window 4

The window used to create the file that releases the session in window 2.

Step 2 Set Up the Freeze

In window 2, set the DBCORERR environment variable to 1024 before running ISQL. If you are using the C shell, issue the following command:

  % setenv DBCORERR 1024

Korn shell and Bourne shell users should use the following commands:

  % DBCORERR=1024

  % export DBCORERR

When troubleshooting a production system, set the DBCORERR environment variable for all sessions that might be involved in the deadlock, since it is difficult to predict which session will be rolled back. See the section "Freezing DBEnvironment Sessions" in this chapter for more information on setting the DBCORERR environment variable.

Step 3 Create a Deadlock

Run ISQL in windows 1 and 2, and issue the following statements:

Window 1

CONNECT TO PartsDBE

Window 2

CONNECT TO PartsDBE

Window 1

UPDATE PurchDB.Parts SET SalesPrice = 1.2 * SalesPrice

Window 2

SELECT * FROM PurchDB.SupplyPrice

Window 2

Exit from the ISQL browser but do not commit work.

Window 1

UPDATE PurchDB.SupplyPrice SET UnitPrice = 1.2 * UnitPrice

Window 2

SELECT * FROM PurchDB.Parts

When you complete step g, you see a message in window 2:

   *****PID=4727******RC=1024 : Wed Mar 31 14:08:07 1993

This message indicates that the DBEnvironment session having PID 4727 (that is, the session running in window 2) is frozen on DBCORE error 1024, which means that a deadlock has been detected. Under these circumstances, ALLBASE/SQL does not roll back the session until you release it. This will be described in “Step 5 Release the Frozen Session”.

The deadlock is illustrated in Figure 7-1 “Deadlock Example”.

Figure 7-1 Deadlock Example

[Deadlock Example]

PID 4687 is running in window 1, and PID 4727 is running in window 2. The solid lines represent locks that have been granted, and the dashed lines represent sessions that have been waiting to acquire locks. The letter S designates a share lock, and the number 6 represents a share plus intent exclusive (SIX) lock. This lock information is displayed by the SQLMON screens accessed in the next step.

Step 4 Examine the Locks with SQLMON

In window 3, run SQLMON and set the DBEnvironment to PartsDBE. Issue the SET LOCKFILTER command to limit the lock information displayed to sessions that are waiting to acquire or convert locks.

  % sqlmon

  SQLMONITOR OVERVIEW => SET DBENV PartsDBE

  SQLMONITOR OVERVIEW => SET LOCKFILTER //WC//

Invoke the Lock screen to see which tables have been locked:

  SQLMONITOR OVERVIEW => /lock
[lock]

In the Lock screen, you can see the PurchDB.Parts and PurchDB.SupplyPrice tables. There are two locks on each table: a share plus intent exclusive (6) lock, and a share (S) lock. The characters displayed in inverse video represent locks held by sessions that are waiting.

To identify the PID of each session in the lock queue of each of the objects shown above, access the Lock Object screen:

  SQLMONITOR LOCK => o

In the following screen, PID 4687 has been granted (G) a share plus intent exclusive (6) lock on the PurchDB.Parts table. PID 4727 is waiting to acquire a share (S) lock on PurchDB.Parts. A share (S) lock has been granted to PID 4727 on the PurchDB.SupplyPrice table, and PID 4687 is waiting to acquire a share plus intent exclusive (6) lock on PurchDB.SupplyPrice.

[dlockob]

Use the Lock Impede screen to verify that the sessions are deadlocked. To identify which sessions are impeded by PID 4687, invoke the Lock Impede screen as follows:

  SQLMONITOR LOCK => i

  PID: 4687

In the following screen, PID 4727 is listed in the WAITING column. PID 4727 is waiting for PID 4687 to release the lock it holds on PurchDB.Parts.

[dlockimpa]

If you specify PID 4727, you see the following screen.

[dlockimsu]

Note that PID 4687 is waiting for PID 4727 to release the lock on the table PurchDB.Supplyprice. These two sessions are indeed deadlocked.

Step 5 Release the Frozen Session

In window 4, edit a file named /tmp/SQLunfrz.ALL and enter the deadlock error number, 1024, on the first line. When you save the file, the session is released, and a message such as the following is displayed in window 2:

   ***** UNFREEZING PID=4727******RC=1024 : Wed Mar 31 14:54:38 1993

   Deadlock detected.  (DBERR 14024)

Lock Allocation Failures

If a session requests a lock when space is not available in the runtime control block, a lock allocation error (DBERR 4008) occurs. In the example that follows, the session that encounters DBERR 4008 is frozen, allowing you to examine the locks with SQLMON.

Step 1 Open Three Windows

To perform the steps in this example, your workstation or PC must have a windows environment. The windows will be used as follows:

Window 1

The DBEnvironment session that encounters the lock allocation failure

Window 2

An SQLMON session

Window 3

The window used to create the file that releases the session in window 1

Step 2 Set Up the Freeze

In window 1, set the DBCORERR environment variable to 1035. If you are using the C shell, issue the following command:

  % setenv DBCORERR 1035

Korn shell and Bourne shell users should use the following commands:

  % DBCORERR=1035

  % export DBCORERR

Step 3 Generate the Error

In window 1, run the application that encounters the lock allocation failure. When DBCORE detects the failure, it freezes the session and displays a message such as the following on standard output:

   *****PID=17325******RC=1035 : Wed Apr  7 11:09:57 1993

Step 4 Investigate the Session with SQLMON

In window 2, run SQLMON, set the DBEnvironment option, and invoke the Overview screen:

  % sqlmon

  SQLMONITOR OVERVIEW => SET DBENV DBEnvironmentName

  SQLMONITOR OVERVIEW => o

The Overview screen shown below indicates that the runtime control block space is nearly full and no more control blocks can be allocated.

[allocover]

Access the Lock Memory screen as follows:

  SQLMONITOR OVERVIEW => /loc m

In the screen that follows, PID 17325 has a total of 324 locks. Most of the locks are held on rows, because the table in this example was created with the PUBLICROW type. To solve this problem, you should either alter the table to PUBLIC to avoid numerous row level locks, or allocate additional runtime control block pages.

  Leslie-Anne says that a new screen is needed
[allocmem]

Step 5 Release the Frozen Session

In window 3, edit a file named /tmp/SQLunfrz.ALL and enter the lock allocation failure error number, 1035, on the first line. When you save the file, the session is released, and a message such as the following appears in window 1:

   ***** UNFREEZING PID=17325******RC=1035 : Wed Apr  7 11:29:26 1993

  ALLBASE/SQL shared memory lock allocation failed in DBCore.  (DBERR 4008)

Freezing DBEnvironment Sessions

ALLBASE/SQL allows you to freeze a session whenever it encounters a certain DBCORE error. While the session is frozen, you can use SQLMON to examine the session's locks.

To freeze a session, set the DBCORERR environment variable to one or more DBCORE error numbers. When the session encounters the errors you specify, it freezes. For example, to freeze a session that encounters either DBCORE error 1024 (deadlock) or 1035 (lock allocation failure), set DBCORERR from the C shell as follows:

  % setenv DBCORERR "1024 1035"

Korn shell and Bourne shell users should use the following commands:

  % DBCORERR="1024 1035"

  % export DBCORERR

If you set DBCORERR to a negative number, a session freezes if it encounters an error whose number is greater than the absolute value of DBCORERR. For example, if DBCORERR is set to -4000, the session freezes if it encounters a DBCORE error greater than 4000.

When a session freezes, a message appears on standard output. The PID identifies the frozen session, and the RC field designates the DBCORE error number:

  *****PID=18250******RC=1024 : Mon Mar 22 11:14:53 1993

DBCORE is a set of internal ALLBASE/SQL routines. DBCORE errors have different error numbers than DBERR errors. For example, the DBCORE error number for detecting deadlocks is 1024, but the DBERR number is 14024. When setting the DBCORERR environment variable, be sure to use the DBCORE error number, not the DBERR error number.

Releasing DBEnvironment Sessions

To release a session, use a text editor to enter DBCORE error numbers in a file. When you save the file, the frozen session resumes execution. The DBCORE error numbers in the file must correspond to the value of the DBCORERR environment variable. To release a session on any DBCORE error number, enter an ASCII zero in the file.

The file can contain one or more lines, and each line can contain one or more numbers. You can name the file as follows:

SQLunfrz

Releases only those sessions running from the subdirectory containing this file.

/tmp/SQLunfrz.xxx

Releases only the session whose PID is specified in xxx. For example, if the PID is 8895, the name of the file should be /tmp/SQLunfrz.8895.

/tmp/SQLunfrz.ALL

Releases only the frozen sessions that qualify, according to the error numbers entered in the file.

For example, to release any session that froze because it encountered either DBCORE error 1024 or 1035, used an editor to create a file named /tmp/SQLunfrz.ALL, and add the following lines to it:

  1024

  1035

When ALLBASE/SQL releases a session, it displays a message on standard output like the one below:

  ***** UNFREEZING PID=18250******RC=1024 : Mon Mar 22 11:16:59 1993