AWS m2: Add IMS DB/DL/I emulation (JHDB) FAQ section
Summary
Adds a large FAQ section documenting JHDB IMS DB/DL/I emulation, including hierarchy mapping, DL/I calls, locking/isolation, transaction boundaries, checkpoint/restart, and rollback behavior; also fixes minor typos.
Security assessment
The added FAQ documents JHDB's locking/isolation and hold-for-update behavior, which is security-adjacent guidance for data integrity and concurrency control. It does not address a specific vulnerability or CVE, so security_issue_related is false. The change is primarily functional documentation with minor typo fixes.
Evidence
+Yes, a hold-for-update is available — that is exactly what the GHU/GHN (hold) calls do, and it is required before DLET/REPL.
Diff
diff --git a/m2/latest/userguide/ba-faq.md b/m2/latest/userguide/ba-faq.md index 10e8b380a..74e67c98d 100644 --- a//m2/latest/userguide/ba-faq.md +++ b//m2/latest/userguide/ba-faq.md @@ -7 +7 @@ -GeneralAWS Transform for mainframe RuntimeDataTransformationDeploymentSecurity +GeneralAWS Transform for mainframe RuntimeDataIMS DB/DL/I emulation (JHDB)TransformationDeploymentSecurity @@ -82 +82 @@ For information on Gapwalk, see [AWS Transform for mainframe Runtime artifacts ] - 4. **How to request access to the AWS Transform for mainframe Runtime ?** + 4. **How do I request access to the AWS Transform for mainframe Runtime?** @@ -236 +236 @@ AWS Transform for mainframe frameworks and libraries are updated through regular - 41. **What are the supported version of tools (Tomcat, Postgres, MQ, etc.) and dependencies (Spring, Angular, etc.) the AWS Transform for mainframe Runtime uses ?** + 41. **What are the supported versions of tools (Tomcat, Postgres, MQ, etc.) and dependencies (Spring, Angular, etc.) that the AWS Transform for mainframe Runtime uses?** @@ -279 +279 @@ Yes, in the main configuration file, and no database is required (for more infor -The JHDB (Java Hierarchical DataBase) API. +The JHDB (Java Hierarchical DataBase) API. For more information, see [IMS DB/DL/I emulation (JHDB)](https://docs.aws.amazon.com/m2/latest/userguide/ba-faq.html#ba-faq-jhdb). @@ -289 +289 @@ AWS Transform for mainframe DB modernization Tool ([Data Migrator](https://bluin - 11. **How does AWS Transform for mainframe handles legacy memory layouts and data structures?** + 11. **How does AWS Transform for mainframe handle legacy memory layouts and data structures?** @@ -293 +293 @@ AWS Transform for mainframe handles legacy memory layouts through the [Record](h - 12. **How does AWS Transform for mainframe deals with VSAM data sets modernization?** + 12. **How does AWS Transform for mainframe deal with VSAM data sets modernization?** @@ -299,0 +300,415 @@ The [Blusam](https://docs.aws.amazon.com/m2/latest/userguide/ba-shared-blusam.ht +## IMS DB/DL/I emulation (JHDB) + +The IMS DB/DL/I emulation feature is **JHDB** (Java Hierarchical DataBase). + +###### Note + +JHDB and Blusam are separate components. IMS DB is modernized by JHDB (hierarchical data stored relationally on PostgreSQL/Aurora). VSAM is modernized by Blusam. They are independent components with independent behavior and should be assessed separately; for example, their locking models differ. + +Your DL/I calls are **not** rewritten into hand-written SQL in the generated code. The generated Java keeps the original call and hands it to the JHDB runtime, passing the same function code, PCB, I/O area, and SSAs your program built. The runtime performs the hierarchical navigation and returns the segment and status code. + +Legacy: + + + CALL 'CBLTDLI' USING FUNC-GU PCB-MASK SEGMENT-IO-AREA ROOT-SSA. + +Generated Java (conceptually — the same call, routed to the runtime): + + + callSubProgram("CBLTDLI", func /*GU*/, pcbMask, segmentIoArea, rootSsa); + +CICS `EXEC DLI` works the same way; its status is returned in the DIB instead of the PCB. Because of this, the DL/I semantics your program relies on (current position, status codes, insert/delete rules, locking) are provided by the runtime, and your business logic keeps checking the PCB/DIB status exactly as before. + + 1. **How is the parent-child segment hierarchy mapped, and is DL/I current position (the GN/GNP cursor) reproduced?** + +**Hierarchy mapping.** Each segment type becomes a PostgreSQL table named `<DBDName>_<SegmentName>`, and each segment occurrence is one row. The parent-child relationship is carried by a concatenated key column (`_concatkey`): a child's `_concatkey` is its parent's `_concatkey` followed by the child's own key, so every descendant's key begins with its ancestor's key. Retrieving all children of a parent is therefore a key-prefix match. (Older `_parent` / `_logicalparent` id columns still exist for backward compatibility, but `_concatkey` is the mechanism used.) + +Example — a two-level database (account summary to detail): + + DBD PADB + PAUTSUM0 (root, key ACCNTID) -> table PADB_PAUTSUM0 + PAUTDTL1 (child, key PAUT9CTS) -> table PADB_PAUTDTL1 + +A detail row under account `0000012345` gets `_concatkey = <ACCNTID key> + <detail key>`, so it "begins with" the summary row's key. That is how the runtime knows it is a child of that summary. + +Logical relationships and logical segments are also supported: a logical segment is exposed as a database view, and a logical child's key begins with its logical parent's key (`lp_concatkey`). + +**DL/I current position.** Yes — the GN/GNP cursor is reproduced by the runtime, not by the generated code. The runtime remembers the current position (and the "established parent" that GNP navigates within) per PCB, advances it on each successful GU/GN/GNP, and clears it at end of the unit of work — exactly like IMS. Your program does not manage position; it just issues the next GN/GNP. + + 2. **Are keyed read (GU), sequential browse (GN), and get-(hold)-next-within-parent (GNP/GHNP) reproduced?** + +Yes, all three, with the hold variants (GHU/GHN/GHNP). + + * **GU (keyed read)** — retrieves the first segment matching the SSA; with no SSA, the first segment of that type. + + * **GN (sequential browse)** — retrieves the next segment in hierarchical order from the current position. With no position established yet, it behaves like GU (first record). + + * **GNP (get next within parent)** — retrieves the next child under the parent established by the previous GU/GN. + + * **GHU/GHN/GHNP (hold variants)** — same as above, but they hold the segment for a following update/delete (see the locking and hold-for-update question). + +Example — browse all summaries, and for each one browse its details (the classic unload pattern): + + * Get next summary (root) in sequence + CALL 'CBLTDLI' USING FUNC-GN PCB-MASK PENDING-AUTH-SUMMARY ROOT-SSA. + * Get next detail under that summary + CALL 'CBLTDLI' USING FUNC-GNP PCB-MASK PENDING-AUTH-DETAILS CHILD-SSA. + +Generated Java (the call keeps its shape — function code, PCB, I/O area, SSA — and is routed to the runtime): + + // GN: get next summary + ctrl.callSubProgram("CBLTDLI", CallBuilder.newInstance() + .byReference(ctx.getFuncGn().getFuncGnReference()) + .byReference(ctx.getPautbpcb()) // PCB mask + .byReference(ctx.getPendingAuthSummary()) // I/O area + .byReference(ctx.getRootSsa()) + .getArguments(), ctx); + + // GNP: get next detail under the established parent + ctrl.callSubProgram("CBLTDLI", CallBuilder.newInstance() + .byReference(ctx.getFuncGnp().getFuncGnpReference()) + .byReference(ctx.getPautbpcb()) + .byReference(ctx.getPendingAuthDetails()) + .byReference(ctx.getChildSsa()) + .getArguments(), ctx); + +This produces exactly the IMS traversal: GN walks roots in key order; after a GN on the summary, GNP returns that summary's details one by one until `GE` (no more children). + + 3. **Are qualified reads with range/comparison conditions (GT/GE/LT/LE) supported?** + +Yes. A qualified SSA with a relational operator becomes an equivalent condition against the segment, so range and comparison reads behave as on IMS. Supported operators are `=`, `>`, `>=`, `<`, `<=`, `!=`, plus boolean `OR` between conditions. + +Example — read the first detail whose timestamp field is greater than a value: + + 01 DTL-SSA. + 05 FILLER PIC X(08) VALUE 'PAUTDTL1'. + 05 FILLER PIC X(01) VALUE '('. + 05 FILLER PIC X(08) VALUE 'PAUT9CTS'. + 05 FILLER PIC X(02) VALUE 'GT'. *> greater-than + 05 SSA-VAL PIC X(08). + 05 FILLER PIC X(01) VALUE ')'. + + CALL 'CBLTDLI' USING FUNC-GN PCB-MASK PENDING-AUTH-DETAILS DTL-SSA. + +Generated Java — the qualified SSA becomes a search argument carrying the operator and value (this is the form produced from a CICS `EXEC DLI GN ... WHERE(field > value)`): + + ctrl.callSubProgram("CBLTDLI", CallBuilder.newInstance() + .byReference(ctx.getFuncGn().getFuncGnReference()) + .byReference(ctx.getPautbpcb()) + .byReference(ctx.getPendingAuthDetails()) + .byReference(SSABuilder.newInstance() + .segmentName("PAUTDTL1") + .addWhereClause("PAUT9CTS", ">", ctx.getSsaVal().getSsaValReference()) // GT condition + .build()) + .getArguments(), ctx); + +The runtime returns the first qualifying segment in hierarchic order, or `GE` if none. Multi-level qualified SSAs (a condition at the parent level and another at the child level) and `OR` combinations are handled the same way — each becomes an additional `addWhereClause(...)` / segment in the same call. + + 4. **How are ISRT/DLET/REPL expressed?** + +They are issued exactly as on IMS — same function code, same SSAs — and the runtime performs the hierarchical insert/delete/replace. + +**ISRT (insert).** For a dependent segment, a prior call must have established position on the parent. Insert of a logical child also creates/links its logical parent and paired segment when the DBD requires it. + + * Establish the parent, then insert the child under it + CALL 'CBLTDLI' USING FUNC-GU PCB-MASK PENDING-AUTH-SUMMARY ROOT-SSA. + CALL 'CBLTDLI' USING FUNC-ISRT PCB-MASK PENDING-AUTH-DETAILS CHILD-SSA. + +Generated Java for the ISRT (as it actually appears in the modernized program): + + ctrl.callSubProgram("CBLTDLI", CallBuilder.newInstance() + .byReference(ctx.getFuncIsrt().getFuncIsrtReference()) + .byReference(ctx.getPautbpcb()) + .byReference(ctx.getPendingAuthDetails()) + .byReference(ctx.getChildSsa()) + .getArguments(), ctx); + +**DLET (delete).** Requires a preceding hold call (GHU/GHN, or `LOCKED` under EXEC DLI). Deleting a segment cascades to its dependents, and IMS delete rules are honored (for example, deleting a logical parent that still has logical children is rejected). + + CALL 'CBLTDLI' USING FUNC-GHU PCB-MASK PENDING-AUTH-DETAILS CHILD-SSA. *> hold + CALL 'CBLTDLI' USING FUNC-DLET PCB-MASK PENDING-AUTH-DETAILS. *> delete + +**REPL (replace).** Also requires a preceding hold. Only changed fields are updated; paired segments are updated together. + + CALL 'CBLTDLI' USING FUNC-GHU PCB-MASK PENDING-AUTH-SUMMARY ROOT-SSA. *> hold + MOVE NEW-VALUES TO PENDING-AUTH-SUMMARY. + CALL 'CBLTDLI' USING FUNC-REPL PCB-MASK PENDING-AUTH-SUMMARY. *> replace + +Generated Java for the hold-then-delete pair (DLET takes no SSA — it deletes the held segment): + + // GHU: hold + ctrl.callSubProgram("CBLTDLI", CallBuilder.newInstance() + .byReference(ctx.getFuncGhu().getFuncGhuReference()) + .byReference(ctx.getPautbpcb()) + .byReference(ctx.getPendingAuthDetails()) + .byReference(ctx.getChildSsa()) + .getArguments(), ctx); + + // DLET: delete the held segment + ctrl.callSubProgram("CBLTDLI", CallBuilder.newInstance() + .byReference(ctx.getFuncDlet().getFuncDletReference()) + .byReference(ctx.getPautbpcb()) + .byReference(ctx.getPendingAuthDetails()) + .getArguments(), ctx); + +If DLET/REPL is issued without a preceding hold, the runtime returns status `DJ`, just like IMS. + + 5. **How are transaction boundaries (DB-INIT/DB-TERM) managed, and how do batch (BMP) and online (MPP) differ?** + +The runtime manages commit and rollback for you: + + * **Batch (BMP-equivalent).** The program runs as a unit of work; database changes are committed at normal end (or at a checkpoint) and rolled back on failure. `CHKP` (checkpoint) and restart are supported, so a long batch can checkpoint and be restarted. + + * **Online/message-driven (MPP-equivalent).** Work is scoped to one message. The unit of work begins when the transaction gets its input message and ends at the sync point, so each message is committed independently. Under CICS, an `EXEC CICS SYNCPOINT` commits. + +Example — a checkpoint in a batch program: + + EXEC DLI CHKP ID(WK-CHKPT-ID) END-EXEC. + +The practical difference: a batch program controls its own commit/checkpoint cadence, while an online transaction commits once per message. In both cases a failure rolls the current unit of work back to the last commit point. + + 6. **What locking/isolation applies, and can a pessimistic "hold for update" be acquired?** + +Yes, a hold-for-update is available — that is exactly what the GHU/GHN (hold) calls do, and it is required before DLET/REPL. When you issue a hold call, the runtime holds the segment so your subsequent update/delete is safe; the hold is released when your position moves or the unit of work ends. + +Important characteristic to note for a concurrency assessment: the hold is managed by the JHDB runtime, and isolation is provided by the runtime plus the enclosing database transaction — it is not a raw SQL `SELECT ... FOR UPDATE` row lock. Functionally it gives you the DL/I hold-then-update behavior your programs expect (and returns "data unavailable" `BA` if a segment cannot be obtained), but the concurrency/throughput profile under heavy contention should be validated against your workload rather than assumed to match IMS/IRLM exactly. + +Example: