Wednesday, December 29, 2021

Db2 for z/OS Data Sharing: is your Lock Structure the Right Size?

Recently I've encountered some situations in which organizations running Db2 for z/OS in data sharing mode had lock structures that were not sized for maximum benefit. In this blog entry, my aim is to shed some light on lock structure sizing, and to suggest actions that you might take to assess lock structure sizing in your environment and to make appropriate adjustments.

First, as is my custom, I'll provide some background information.


One structure, two purposes

A lot of you are probably familiar with Db2 for z/OS data sharing. That is a technology, leveraging an IBM Z (i.e., mainframe) cluster configuration called a Parallel Sysplex, that allows multiple Db2 subsystems (referred to as members of the data sharing group) to share read/write access to a single instance of a database. Because the members of a Db2 data sharing group can (and typically do) run in several z/OS LPARs (logical partitions) that themselves run (usually) in several different IBM Z servers, Db2 data sharing can provide tremendous scalability (up to 32 Db2 subsystems can be members of a data sharing group) and tremendous availability (the need for planned downtime can be virtually eliminated, and the impact of unplanned outages can be greatly reduced).

One of the things that enables Db2 data sharing technology to work is what's called global locking. The concept is pretty simple: if an application process connected to member DBP1 of a 4-way (for example) Db2 data sharing group changes data on page P1 of table space TS1, a "local" X-lock (the usual kind of Db2 lock associated with a data-change action) on the page keeps other application processes connected to DBP1 from accessing data on the page until the local X-lock is released by way of the application commit that "hardens" the data-change action. All well and good and normal, but what about application processes connected to the other members of the 4-way data sharing group? How do they know that data on page P1 of table space TS1 is not to be accessed until the application process connected to member DBP1 commits its data-changing action? Here's how: the applications connected to the other members of the data sharing group know that they have to wait on a commit by the DBP1-connected application because in addition to the local X-lock on the page in question there is also a global lock on the page, and that global lock is visible to all application processes connected to other members of the data sharing group.

Where does this global X-lock on page P1 of table space TS1 go? It goes in what's called the lock structure of the data sharing group. That structure - one of several that makes Db2 data sharing work, others being the shared communications area and group buffer pools - is located in a shared-memory LPAR called a coupling facility, and the contents of the structure are visible to all members of the data sharing group because all the members are connected to the coupling facility LPAR (and, almost certainly, to at least one other CF LPAR - a Parallel Sysplex will typically have more than one coupling facility LPAR so as to preclude a single-point-of-failure situation).

Here's something kind of interesting: a global lock actually goes to two places in the lock structure (if it's an X-lock, associated with a data-change action, versus an S-lock, which is associated with a data-read request). Those two places are the two parts of the lock structure: the lock table and the lock list:

  • The lock table can be thought of as a super-fast global lock contention detector. How it works: when a global X-lock is requested on a page (or on a row, if the table space in question is defined with row-level locking), a component of the z/OS operating system for the LPAR in which the member Db2 subsystem runs takes the identifier of the resource to be locked (a page, in this example) and runs it through a hashing algorithm. The output of this hashing algorithm relates to a particular entry in the lock table - basically, the hashing algorithm says, "To see if an incompatible global lock is already held by a member Db2 on this resource, check this entry in the lock table." The lock table entry is checked, and in a few microseconds the requesting Db2 member gets its answer - the global lock it wants on the page can be acquired, or it can't (at least not right away - see the description of false contention near the end of this blog entry). This global lock contention check is also performed for S-lock requests that are associated with data-read actions.
  • The lock list is, indeed (in essence), a list of locks - specifically, of currently-held global X-locks, associated with data-change actions. What is this list for? Well, suppose that member DBP1 of a 4-way data sharing group terminates abnormally (i.e., fails - and that could be a result of the Db2 subsystem failing by itself, or terminating abnormally as a result of the associated z/OS LPAR or IBM Z server failing). It's likely that some application processes connected to DBP1 were in the midst of changing data at the time of the subsystem failure, and that means that some data pages (or maybe rows) were X-locked at the time of the failure. Those outstanding X-locks prevent access to data that is in an uncommitted state (because the associated units of work were in-flight at the time of the failure of DBP1), but that blocking of access to uncommitted data is only effective if the other members of the data sharing group are aware of the retained page (or row) X-locks (they are called "retained locks" because they will be held until the failed Db2 subsystem can be restarted to release them - restart of a failed Db2 subsystem is usually automatic and usually completes quite quickly). The other members of the data sharing group are aware of DBP1's retained X-locks thanks to the information in the lock list.


For the lock structure, size matters - but how?

If you're implementing a new data sharing group, 128 MB is often a good initial size for a lock structure in a production environment (assuming that coupling facility LPAR memory is sufficient). Suppose that you have an existing lock structure. Is it the right size? To answer that question, you have to consider the two aforementioned parts of the lock structure: the lock list and the lock table. If the lock list is too small, the effect will often be quite apparent: data-changing programs will fail because they can't get the global X-locks they need, owing to the fact that the lock list is full (the SQL error code in that case would be a -904, indicating "resource unavailable," and the accompanying reason code will be 00C900BF). Certainly, you'd like to make the lock list part of the lock structure larger before it fills up and programs start abending. To stay ahead of the game in this regard, you can look for instances of the Db2 (actually, IRLM) message DXR142E, which shows that the lock list is X% full, with "X" being 80, 90 or 100. Needless to say, 100% full is not good. 90% full will also likely result in at least some program failures. Suffice it to say that if this message is issued on your system, 80% is the only "in-use" value that you want to see, and if you see "80% in-use" you'll want to make the lock list bigger (you can also issue, periodically, the Db2 command -DISPLAY GROUP, or generate and review an RMF Coupling Facility Activity report - in either case, see what percentage of the list entries in the lock structure are in-use).

If you want or need to make the lock list part of a lock structure bigger, how can you do that? Really easily, if the maximum size of the lock structure (indicated by the value of the SIZE specification for the structure in the coupling facility resource management - aka CFRM - policy) is larger than the structure's currently allocated size (as seen in the output of the Db2 -DISPLAY GROUP command, or in an RMF Coupling Facility Activity Report). When that is true, a z/OS SETXCF command can be issued to dynamically increase the lock structure size, and all of the space so added will go towards enlarging the lock list part of the structure. If the lock structure's current size is the same as the maximum size for the structure, lock list enlargement will require a change in the structure's specifications in the CFRM policy, followed by a rebuild of the structure (that rebuild will typically complete in a short time, but it can impact Db2-accessing application processes, so take the action at a time when system activity is at a relatively low level). More information on lock list size adjustments can be found in an entry I posted to this blog back in 2013.

How about the lock table part of the lock structure? Is yours large enough? In contrast to the lock structure, the lock table can't "run out of space" and cause programs to fail. How, then, do you know if a lock table size increase would be advisable? The key here is the "false contention" rate for the data sharing group (or for a member or members of the group - both a Db2 monitor statistics report and an RMF Coupling Facility Activity report can be used to see false contention at either the group or a member level). What is "false contention?" It's global lock contention that is initially perceived but later found to be not real. How does that happen? Recall the previous reference to the lock table and the associated hashing algorithm. A lock table has a certain number of entries, determined by the size of the table and the size of the lock entries therein. The size of a lock table entry will vary according to the number of members in a data sharing group, but for my example of a 4-way group the lock entry size would be 2 bytes. If the lock structure size is 128 MB, the lock table size will be 64 MB (the lock table part of the lock structure will always have a size that is a power of 2). That 64 MB lock table will accommodate a little over 33 million two-byte lock entries. 33 million may sound like a lot, but there are probably way more than 33 million lock-able things in the data sharing group's database (think about the possibility of row-level locking for a 100 million-row table, and you're already way past 33 million lock-able things).

How do you manage global lock contention detection with a 33 million-entry lock table when there are more (probably WAY more) than 33 million lock-able things in the database? That's where the hashing algorithm comes in. That algorithm will cause several different lock-able things to hash to a single entry in the lock table, and that reality makes false contention a possibility. Suppose an application process connected to member DBP1 of the 4-way data sharing group needs a global X-lock on page P1 of table space TS1. DBP1 propagates that request to the lock table, and receives in response an indication that contention is detected. Is it real contention? The z/OS LPARs in the Sysplex can communicate with each other to make that determination, and it may be found that the initial indication of contention was in fact false, meaning that incompatible lock requests (i.e., an X and and X, or an X and an S) for two different resources hashed to the same entry in the lock table. When the initially indicated contention is seen to be false, the application that requested the global lock (the request for which contention was initially indicated) gets the lock and keeps on trucking. That's a good thing, but resolving false contention involves some overhead that you'd like to minimize. Here's where lock table sizing comes in. As a general rule, you like for false contention to account for less than half of the global lock contention in the data sharing group (the total rate of global lock contention and the rate of false contention can both be seen via a Db2 monitor statistics report or an RMF coupling facility activity report).

What if the rate of false contention in your system is higher than you want it to be? In that case, consider doubling the size of the lock table (remember, the lock table size will always be a power of 2), or even quadrupling the lock table size, if the rate of false contention is way higher than you want and the CF LPAR holding the structure has sufficient memory to accommodate the larger lock structure size. If you double the lock table size, you'll double the number of lock entries, and that will mean that fewer lock-able things will hash to the same lock table entry, and THAT should result in a lower false contention rate, boosting the CPU efficiency of the data sharing group's operation.

Here's something you need to keep in mind with regard to increasing the size of a Db2 data sharing group's lock table: this cannot be done without a rebuild of the associated lock structure. As previously mentioned, a lock structure's size can be dynamically increased via a SETXCF command (assuming the structure is not already at its maximum size, per the CFRM policy), but all of that space dynamically added will go towards increasing lock list space, not lock table space. A bigger lock table will require a change in the lock structure's specifications in the CFRM policy, followed by a rebuild of the structure to put the change in effect. If the lock structure's current size is 128 MB, you might change its INITSIZE in the CFRM policy (the initial structure size) to 256 MB, and rebuild the structure to take the lock table size from 64 MB to 128 MB. A lock structure size that's a power of 2 is often reasonable - it will cause lock structure space to be divided 50-50 between the lock table and the lock list. Note that if the lock structure INITSIZE is not a power of two, as a general rule the lock table size will be the power of 2 that will result in the space division between lock table and lock list being as equal as possible.

And that wraps up this overview of Db2 lock structure sizing. I hope that the information will be useful for you.

36 comments:

  1. Very well written and useful set of information

    ReplyDelete
  2. When I issued the display locks for a tablespace->under the lock info i got -h-s,pp,i -h-tells it is held by process with s(readnlock) and pp(partition lock) but i dont find any info from any manuals on what "I " stand for.The only possible options for lock duration is A,c,W.Any idea whta dies I stand for?

    ReplyDelete
    Replies
    1. Check the Db2 for z/OS online documentation for the DSNT361I message, at https://www.ibm.com/docs/en/db2-for-zos/12?topic=messages-dsnt361i. On that page, look at the information under the headings "lock type" and "lock duration." Under "lock type," you'll see that "pp" indicates a page set or partition physical lock (P-lock). Under "lock duration," you'll see that "i" also indicates a page set or partition P-lock. P-locks are unique to a Db2 for z/OS data sharing environment, and they are more about data coherency (i.e., ensuring that data in objects subject to inter-Db2 read/write interest doesn't get trashed) than data access concurrency. P-locks taken at the page set or partition level are long-duration - they are not released until the data set associated with the page set or partition in question is closed on the member that holds the P-lock.

      If you want to know more about how page set- and partition-level P-locks are used in a Db2 for z/OS data sharing system, check the information on this documentation page: https://www.ibm.com/docs/en/db2-for-zos/12?topic=dependency-how-db2-tracks-interest.

      Robert

      Delete
    2. Great!! I have spent high time in searching with keywords like "lock duration "I", " lockinfo" ,display db ts locks command " in google.But unfortunately I dint find answer in IBM manuals.But you were able to get it so quick.I think I need to look for better keywords for search order.

      Delete
  3. Hello,An load job got contention issue.But I see folks do this calculation -irlmwrt*utimeout for estimating wait time .Per my surfing ,I see both are timeout at application & at utility level .But have not clue why we need to multiply both?

    ReplyDelete
    Replies
    1. Sorry, this blog is not a general Q&A resource for Db2 for z/OS. I can only respond to questions about entries in the blog, and this blog entry has nothing to do with Db2 utility timeouts. For general Db2 for z/OS Q&A I suggest using the Db2-L forum managed by the International Db2 Users Group, also known as IDUG. See https://www.idug.org/communities/community-home?CommunityKey=02a8700a-dc76-4190-9a3c-24f0738c1067. You have to be an IDUG member to post questions in Db2-L, but an IDUG standard membership is free (see https://www.idug.org/membership/become-member).

      Robert

      Delete
  4. I faced this error when I tried to drop the database.Fixing lock strcuture is something that is done by system dba in my shop.Is there any other option to fix this from DBA standpoint to successfully accomplish this drop database?

    ReplyDelete
    Replies
    1. You state that "I faced this error." What error? What error code and message did you receive when you tried to drop a database?

      Robert

      Delete
    2. Sorry missed to include error .Here is the error I got
      SQLCODE = -904, ERROR, UNAVAILABLE *
      * RESOURCE. REASON 00C900BF, *
      * RESOURCE NAME DSNDB01.SYSLGRNX.....

      Delete
    3. If the lock list part of the Db2 lock structure gets full, you need more lock list space. That's usually done by a z/OS systems programmer.

      Robert

      Delete
  5. When does a lock will hold both SIX and IX lock in same DB2 region ? As per LOCk mode table format in IBM manual.I see both are not compatible.If that is case,how can it acquire ISX and IX in same object

    ReplyDelete
    Replies
    1. I am not sure of the page of the Db2 for z/OS documentation to which you are referring, but it may be describing physical locks. Physical locks, which are only relevant in a Db2 for z/OS data sharing environment, are not like traditional logical locks, in that they do not affect concurrency of access to data; rather, physical locks determine how members of a Db2 data sharing group will use the group buffer pools when accessing various objects (table spaces or indexes, or partitions of partitioned table spaces or indexes), to ensure that data coherency is maintained when process on several members of the group are accessing the same database objects in read/write mode. When a Db2 member of the group has ab SIX physical lock on (for example) a partition of a table space, it means, "I am updating data in this partition, and at least one other member of the group is reading this partition." If another member of the data sharing group has an IS physical lock on the same partition, it means, "I am reading from this partition, and at least one other member of the group is updating the partition."

      Robert

      Delete
    2. I was referring to table 2 from below url:https://www.ibm.com/docs/en/db2-for-zos/12?topic=locks-lock-modes-compatibility.
      Per table ,SIX and IX compatibility is "NO" but I see both SIX and IX placed on same object in same region.How is that possible?

      Delete
    3. You say, "I see both SIX and IX placed on same object in same region." How is it that you see this information? In the output of a Db2 -DISPLAY DATABASE command? In a display or a report generated by a Db2 monitor?

      Also, when you say, "region," to what are you referring?

      Robert

      Delete
    4. Region meaning -> Same environment/DB2 member

      Delete
    5. I saw that info from display claimers on that tablespace

      Delete
    6. Hmm. I wouldn't expect to see lock information in the output of a -DISPLAY DATABASE command with the CLAIMERS option specified - I'd expect to see lock information in the output of -DISPLAY DATABASE if the LOCKS option had been specified. Claims and locks are two different things.

      In any case, "member" implies data sharing. In a data sharing environment, you have physical as well as logical locks (see https://www.ibm.com/docs/en/db2-for-zos/13?topic=pools-physical-locks-in-data-sharing). In the output of -DISPLAY DATABASE with LOCKS specified, PP indicates a page set physical lock. One Db2 member will hold one page set physical lock on a given page set or partition (of an object). Different members of a data sharing group can have different types of page set physical lock on the same page set or partition, depending on whether they are only reading from the page set or partition or are changing data in the page set or partition. Page set physical locks are used to determine how a member Db2 subsystem is to use the group buffer pool associated with the page set or partition in question.

      Robert

      Delete
  6. Hello,I would like to know what locks below sql statement will acquire
    Declare STV cursor FOR select col1,col2,col3 from table1 where status =:H and type =:H
    FOR UPDATE OF status fetch first row only
    This select sql has cursor as well as for update of clause but the IBM manual has given separate lock info
    for select with cursor and select with update .
    https://www.ibm.com/docs/en/db2-for-zos/12?topic=types-locks-acquired-sql-statements
    which table I should look at for this sql? Is it TABLE 4 or TABLE 1.

    ReplyDelete
    Replies
    1. Table 4. The FOR UPDATE OF clause means that the cusror associated with the SELECT is neither read-only nor ambiguous; therefore, table 1 does not apply.

      Robert

      Delete
    2. The 210 resource code indicates that the deadlock happened at the partition level. Process A had a lock on partition 2 of table space TSA1, and process B needed a lock on that partition that was incompatible with the lock currently held on the partition by process A (and, this being a deadlock, we also know that process B held a lock on some resource that process A needed to lock - in an incompatible way - in order to proceed).

      Normally, the lock acquired by a data-changing process on a table space partition will be an IX lock. IX locks do not conflict with each other. Typically, when there is lock contention at a partition level it's because some process acquired an exclusive lock (X or S, but in this case, probably X, because data-change activity was involved) on the partition in question. Why would a process get an X lock on a partition? Probably, either because the process issued the SQL statement LOCK TABLE table-name IN EXCLUSIVE MODE, or (more likely) lock escalation occurred (the result of one of the processes hitting the limit on locks held on the table space - that limit is typically specified via the ZPARM parameter NUMLKTS).

      Robert

      Delete
    3. With respect to what you said "Normally, the lock acquired by a data-changing process on a table space partition will be an IX lock" but from this link,I only see "U lock" for both "SELECT ..FOR UPDATE OF" & "UPDATE WITHOUT CURSOR" statements for LOCKSIZE ANY & ISOLATION CS under column "LOCK DATA PG OR ROW".Am I referring incorrect column?
      https://www.ibm.com/docs/en/db2-for-zos/12?topic=types-locks-acquired-sql-statements

      Delete
    4. A U lock would be acquired in some circumstances on a page or a row (depending on whether page-level or row-level locking is in use for the target table space). A lock on a page or a row is a "child" lock in a Db2 for z/OS context. Before a child lock can be acquired, the associated "parent" lock has to be acquired (that would be on a table space or table for a non-universal table space, or on a partition for a universal table space). For a U child lock, the associated parent lock would typically be IX (see https://www.ibm.com/docs/en/db2-for-zos/13?topic=locks-lock-size).

      Robert

      Delete
    5. How can an "U lock"(child lock) of "locksize any" be escalated to "X lock" when the parent lock(tablespace/table) is IX ?
      Page/row locks gets escalated to table/tablespace locks.So it should be escalated to IX right?
      X lock is not mentioned anywhere in the table.

      Delete
    6. Lock escalation is explained on this documentation page: https://www.ibm.com/docs/en/db2-for-zos/13?topic=types-lock-escalation. Lock escalation occurs when a process has acquired more locks than are permitted to be held by one process on one table. Escalation does not involve "escalating" a child lock into a parent lock; rather, it involves changing an IX table space (or partition) lock to X, or changing an IS table space (or partition) lock to S.

      Robert

      Delete
  7. Hello Rob,you have stated that when an escalation happens for "IX" lock it will be "X" lock likewise what will be the locks acquired for each type of locks when an escalation occurs.
    Will be it always from intent lock to actual lock ?
    I could not find that info in manuals.

    ReplyDelete
    Replies
    1. Db2 for z/OS lock escalation involves substituting a parent-level lock (generally, a table space- or partition-level lock) for child locks (page or row locks), and it happens when a process has acquired the limit on the number of child locks that can be acquired for one table space (that limit is specified via the NUMLKKTS parameter in ZPARM - see https://www.ibm.com/docs/en/db2-for-zos/13?topic=2-locks-per-tablespace-field-numlkts-subsystem-parameter). The table space- or partition-level lock acquired by a process via lock escalation will be exclusive in nature. If the process that caused lock escalation to occur was changing data in the table space in question, the process will get an X lock on the table space or partition. If the process that caused lock escalation to occur was just reading data in the table space in question, the process will get an S lock on the table space or partition. More information can be found at https://www.ibm.com/docs/en/db2-for-zos/13?topic=types-lock-escalation.

      Robert

      Delete
    2. I see your below response for previous questions .
      "For a U child lock, the associated parent lock would typically be IX (see https://www.ibm.com/docs/en/db2-for-zos/13?topic=locks-lock-size)"

      Couldn't see this in link ? where is this given .can you please point this ?

      Delete
    3. I just referenced that documentation page in relation to the concept of parent and child locks in a Db2 for z/OS context. The fact that a U child lock will usually have associated with it an IX parent lock is shown on the documentation page at https://www.ibm.com/docs/en/db2-for-zos/13?topic=types-locks-acquired-sql-statements. See table 4 on that page (U child-locks are typically related to the use of a cursor with a FOR UPDATE OF specification). CS is the most commonly-used isolation level, and in table 4, in the row for LOCKSIZE ANY/PAGE/ROW and ISOLATION(CS), you'll see that the child lock type (page or row) is U and the parent lock type (table space or partition) is IX.

      Robert

      Delete
    4. Gotcha. I went through your statement that "an parent lock will be acquired before an child lock".
      When a process tries to access an page(for an update) of an tablespace/table, would it first put an IX lock(parent lock) in tablespace/table and then U lock (child lock) in page/row even though it access only a page? Is that right


      Delete
    5. The parent lock is always acquired first. If the required parent lock cannot be acquired, the SQL data-change statement will fail.

      Robert

      Delete
  8. From manual and documents ,I see Lock escalation happens when it reaches max locks (per NUMLKTS) .I also see this happens when NUMLKUS is reached.Which is correct ?

    ReplyDelete
    Replies
    1. Whatever you saw that indicates that reaching the NUMLKUS limit triggers lock escalation is incorrect. When a process hits the NUMLKUS limit and tries to acquire another lock, it will get a -904 SQL error code (see https://www.ibm.com/docs/en/db2-for-zos/13?topic=2-locks-per-user-field-numlkus-subsystem-parameter). Lock escalation occurs when a process exceeds the NUMLKTS limit (see https://www.ibm.com/docs/en/db2-for-zos/13?topic=2-locks-per-tablespace-field-numlkts-subsystem-parameter).

      Robert

      Delete
    2. Is lock escalation a good thing or bad thing?
      Lockmax-0, indicates that the number of locks on the table or table space are not counted and escalation does not occur.
      Should we thing about preventing lock escalation by giving high value for lockmax ? or should we release all low level locks so do we allow for lock escalation to happen ?

      Delete
    3. There's no one-size-fits-all answer to that question. As a general rule, lock escalation is something you don't want to see. It could conceivably be helpful if a given table space is accessed by transactions during the day and exclusively by a certain batch process at night. If the batch process does a lot of data-change work and issues few (if any) commits, allowing the batch process to trigger lock escalation could enhance that process's CPU efficiency. If lock escalation occurs for a given table space and that causes issues for processes other than the one that triggered escalation, you could certainly disable lock escalation for the table space via an ALTER with LOCKMAX 0.

      Robert

      Delete