Distributed SQL does not run on a CICS TCB by accident. It runs on a database access thread (DBAT) in the DDF path. Local programs use allied threads instead. This page explains how DB2 pools DBATs, how MAXDBAT and CONDBAT differ, what protected threads mean in CICS, and how to keep a JDBC pool from knocking the door down.
Three words get mixed in every war room:
| Kind | Where | Notes |
|---|---|---|
| DBAT (in use) | DDF | Paired with an active connection running SQL |
| DBAT (pooled) | DDF | Disconnected from a connection; waiting for reuse |
| Inactive connection | DDF | Socket held; no DBAT; counts on CONDBAT |
| Allied thread | CICS/IMS/TSO/batch/CAF/RRSAF | Local attachment; CTHREAD |
| CICS protected | CICS allied | Kept for the same DB2ENTRY/transid |
A DBAT is created for DRDA work. It runs under a WLM-managed preemptible independent enclave SRB in DIST—zIIP-eligible, interruptible like a TCB, reported as one transaction even if work spans DIST and DBM1. When the client is between transactions, you want the expensive thread back in a pool and the cheap socket left waiting.
An allied thread is the local twin: CICS, IMS, TSO, batch, CAF, or RRSAF. Those address spaces attach through a language interface, not through DIST.CTHREAD caps allied threads. MAXDBAT caps DBATs. IBM requires CTHREAD + MAXDBAT not to exceed the documented combined maximum (20000 in current manuals). Raising MAXDBAT without watching allied demand still exhausts the same overall budget.
Subsystem parameter CMTSTAT is the big switch:
A DBAT is not poolable at commit if it still owns:
Those are legitimate designs; they just mean each such session occupies a DBAT for its life, so MAXDBAT must cover them plus everyone else.
| Parameter | Meaning |
|---|---|
| MAXDBAT | Max allocated DBATs (in use + pooled) |
| CONDBAT | Max inbound DDF connections; must be >= MAXDBAT |
| CMTSTAT | INACTIVE pools DBATs at commit; ACTIVE keeps DBAT until disconnect |
| POOLINAC | Seconds a pooled DBAT may sit unused (default 120) |
| IDTHTOIN | Idle timeout for in-use threads, not pooled DBATs |
| CTHREAD | Max allied threads; CTHREAD + MAXDBAT has an overall cap |
If MAXDBAT is reached, new transactions queue (they still hold connections up to CONDBAT). DISPLAY DDF DETAIL shows queued requests. If CONDBAT is reached—or CONDBAT is 0—the connect is rejected. MAXDBAT=0 also forces CONDBAT to 0 and refuses DDF SQL. Set MAXDBAT high enough for peaks, low enough that a runaway pool cannot drown DBM1. Queuing for a second is better than a frozen subsystem.
POOLINAC trims the pool after a surge. A pooled DBAT unused for that many seconds is eligible to be terminated on Db2’s purge cycle. A very large POOLINAC leaves DBATs sitting around after the rush; the default 120 seconds is a sound start. IDTHTOIN does not apply to pooled DBATs—only to threads that are in use and idle (client thinking, dropped laptop, forgotten WITH HOLD cursor).
CONDBAT must be at least the sum of client pool sizes that can connect at once. A dozen application servers each opening 200 connections is 2400 CONDBAT before you count anything else.
A high-performance DBAT is an optimization, not a third thread type. Ingredients:
RELEASE(DEALLOCATE) avoids repeated package allocation. Combined with HP DBATs, that allocation can last for the life of the thread. BNDOPT deallocates the HP DBAT when the connection ends. BNDPOOL can put that DBAT back in the pool for another connection. PKGREL(COMMIT) forces RELEASE(COMMIT) behavior even if the package said DEALLOCATE.
The risk: HP DBATs occupy MAXDBAT longer and can starve ordinary pooled work. Do not bind every package DEALLOCATE, and do not size the client pool as if threads were free. John Campbell’s usual warning is: implement HP DBATs on purpose, watch DISPLAY DDF, and keep a MAXDBAT cushion.
In CICS, a protected thread stays allocated to a DB2ENTRY so the next transaction with that entry reuses it. That is allied-thread reuse, analogous in spirit to pooling but a different attachment. Too many protected threads plus a busy DDF system compete for the same Db2 engine (CTHREAD + MAXDBAT, EDM, locks, CPU).
IMS and RRSAF have their own reuse stories (PSB schedule, stored-procedure WLM environments). When you capacity-plan “threads,” always split allied versus DBAT instead of quoting one number.
JDBC pools should be sized to concurrent transactions, with a modest spare, not to total logged-in users. Each pooled connection is an inactive DDF connection most of the time (good) but still a CONDBAT slot (not free). Test:
1234-DISPLAY DDF DETAIL -DISPLAY THREAD (*) DETAIL -DISPLAY THREAD (*) TYPE(INACTIVE) -MODIFY DDF PKGREL(BNDOPT)
Look for active DBATs, pooled DBATs, inactive connections, and queued requests. If queued stays non-zero, either MAXDBAT is too low for a healthy peak or SQL is too slow (threads held). If inactive connections sit near CONDBAT, shrink client pools. If pooled DBATs never shrink after a peak, check POOLINAC.
The library phone line is a connection (CONDBAT: how many phones can be off the hook). A DBAT is an actual librarian who walks to the stacks (MAXDBAT: how many librarians). When you hang up politely but leave the line open for the next question (inactive connection), the librarian can help someone else (pooled DBAT). If you keep a book on the desk (WITH HOLD cursor), that librarian cannot go help yet. Allied threads are people who already live in the building (CICS) and never called the front desk. Protected CICS threads are a librarian assigned to one classroom for the whole morning. High-performance DBATs are librarians who keep their cart packed between questions so they start faster—and therefore stay busy longer.
1. What is a DBAT?
2. What does CONDBAT limit?
3. With CMTSTAT=INACTIVE, what happens at COMMIT (when the DBAT can be pooled)?
4. Which condition prevents pooling a DBAT at commit?
5. What is an allied thread?