← Back
Home › Systems › Operating systems and runtimes

mainframe-tp-monitor

transaction processing monitor

IBM CICS, IBM IMS TM, Oracle Tuxedo

Open the mainframe-tp-monitor pagemainframe-tp-monitor Cooperative schedulingconcurrency: Green threads/coroutines yielding at await points on a user-space schedulerHdr histogramdata-structures: Log-linear bucketed histograms with bounded relative error for latency percentilesBatch checkpoint restartdistributed: Large batch jobs (end-of-day, settlement, payroll runs) that checkpoint and restart idempotentlyDead-letter queuedistributed: A side queue for messages that keep failing: after N delivery attempts or a permanent error, park them with the reason so the main queue keeps moving.›Deterministic simulationtestingdistributed: Run the whole system in one thread under a seeded scheduler with simulated network, disk and clock, so every failure replays from its seed.›Durable job queuedistributed: Persisted tasks that workers lease for a visibility timeout, ack on success and retry with backoff; at-least-once execution that survives worker and queue crashes.›Primary-backup replicationdistributed: One node orders all writes and ships them to standbys; the acknowledgement rule (none, one, all) sets what a crash loses, and an external arbiter decides who takes over.›Shared data cluster lock cachedistributed: Shared lock and cache structures in a coupling facility: global lock negotiation and cross-invalidation of locally cached pages across cluster membersTwo-phase commitdistributed: Atomic commit across shards: participants durably vote yes, then the coordinator logs and broadcasts one decision; blocks if the coordinator is lost.›Context switchinghardware-os: Handing a core to another task by saving and loading registers, stack and address space; the hidden cache and TLB cost outweighs the direct one.›Process supervisionhardware-os: A parent process starts services, reaps their exits and restarts them under a delay and burst-limit policy, then stops them with SIGTERM before SIGKILL.›Resource usage accountinghardware-os: Cgroup/procfs/GPU counters sampled into per-workload usageAuthorization models (RBAC,ABAC, ReBAC)security: How to decide who may do what to which object; roles for coarse rules, relationships for sharing, and checks on every object.›Coverage-guided fuzzingsecurity: Mutate inputs, run an instrumented target, and keep any input that reaches a new code edge; feedback turns blind guessing into incremental search.›Mutual TLSsecurity: TLS where the client also proves a certificate key, so every connection carries a verified, rotatable machine identity.›ARIES recoverystorage: Three-pass crash recovery (analysis, redo, undo) for steal/no-force buffer pools; repeats history, then rolls back losers with compensation log records.›B+ treestorage: Balanced high-fanout search tree with all values in linked leaves; the default on-disk index for point lookups and range scans.›Buffer poolstorage: The database's own page cache (frames, page table, pin counts, dirty bits, replacement) so it, not the OS, controls eviction, write order and I/O.›Deadlock detectionstorage: Find transactions waiting on each other in a cycle (wait-for graph), abort one, or order lock requests so no cycle can form.›Index-free adjacencystorage: Store each node's edges as direct references to neighbouring records, so a hop costs O(degree) pointer reads instead of an index search; know when plain tables or CSR beat it.›Point-in-time recoverystorage: Periodic base backups plus a continuously archived change log let you rebuild the state as of any instant, then branch from there.›Two-phase lockingstorage: Transactions take shared/exclusive locks and release none until they stop acquiring; strict 2PL holds them to commit and guarantees serializability.›Write-ahead logstorage: Append each change to a checksummed sequential log and fsync it before touching data pages; the basis of crash durability in nearly every database.›Backpressuresystems: Bounded queues and credit-based flow so slow consumers throttle producersCache invalidationsystems: Make writes remove cached copies by key, group tag or prefix, broadcast the removal to every node, and guard refills with tokens so stale values never return.›Connection poolingsystems: Reuse and multiplex backend connections with bounded pools, checkout queues and health evictionGraceful drainingsystems: On a termination signal, stop taking new work, finish in-flight work until a deadline, tell clients to reconnect elsewhere, then exit; clients resume from a token.›Cron schedulingsystems: Cron expression parsing and next-fire-time computation, with catch-up and time-zone rulesIdempotency keysfinance: Client-chosen unique key per logical operation, stored with a request fingerprint and the final response, so retries replay the first result instead of acting twice.›Fault injectiondistributed: Inject latency, errors, kills and partitions via proxies, netem or hooksRecord replaydistributed: Record every nondeterministic input (time, randomness, I/O, model and tool outputs, per-tick player input) and re-execute deterministically for debugging, replays and state rebuildExponential backoff with jittersystems: Retry after delays that grow geometrically and are randomized, so failed clients spread out instead of hammering a recovering service in synchronized waves.›Health checkingsystems: Decide per backend whether to route to it using probes and real-traffic errors, with consecutive-count hysteresis, capped ejection and a panic fallback.›PRNGs (PCG, xoshiro)numerics: Small, fast, statistically strong non-cryptographic generators: PCG32 and xoshiro256**, with seeding, parallel streams and unbiased ranges.›Leasesdistributed: A lock that expires on its own: bounded-time ownership that survives crashes and partitions, given bounded clock drift and fencing tokens on writes.›Code coverage instrumentationcompilers: Insert counters into compiled code to record which blocks, edges or lines ran; a spanning tree of the control-flow graph cuts the counters needed.›Delta debuggingcompilers: Ddmin minimization of failing inputs or change setsFast hash functionsdata-structures: Non-cryptographic hashes built from 64×64→128-bit multiplies and xor-shifts; pick by key size, trust level and whether the hash is persisted.›Sanitizerssecurity: ASan/UBSan/TSan shadow memory and instrumentation to catch memory bugs+ 8 moreCryptographic hashes (SHA-2,BLAKE3)security: Collision-resistant fingerprints of data; SHA-256 for interoperability, BLAKE3 for speed, HMAC/HKDF for keyed uses.›Transparent interceptionnetworking: Redirect traffic to a local proxy (iptables TPROXY/REDIRECT, eBPF) without app changesSyscall interceptionsecurity: Intercept syscalls via ptrace, seccomp user notify or a user-space kernelFencing tokensdistributed: A number that grows with every lock grant and is checked by the protected resource, so a paused ex-holder's late write is rejected.›Control-flow graphcompilers: Split a linear instruction list into basic blocks and connect them by jumps; the graph every optimizer, SSA builder and dataflow pass walks.›Minimum spanning treegraphs: Cheapest set of edges connecting all vertices; Kruskal sorts edges and joins components with union-find, Prim grows one tree, Boruvka merges in parallel rounds.›Failure bisectionsearch-sort: Binary search over commits, batches or inputs to isolate a failure+ 1 moreEbpfhardware-os: Verified in-kernel programs on hooks (kprobes, XDP, tc) with mapsPtrace process controlhardware-os: Ptrace: attach, read and write registers and memory, single-step, intercept signalsSeccomp bpfsecurity: Syscall filtering with seccomp BPF programsBFS and DFSgraphs: The two basic graph traversals; BFS gives hop distances and levels, DFS gives discovery/finish order for cycles, components and topological order.›d-ary heapdata-structures: Array heap with d children per node (d = 4 typical): half the binary heap's depth, siblings in one cache line, faster priority queues.›Union-findgraphs: Disjoint-set forest with union by size and path compression; merges sets and answers same-set queries in effectively constant time.›Sparse matrices (CSR)numerics: Compressed sparse row stores only nonzeros as row pointers, column indices and values; SpMV streams them once, so it is memory-bandwidth bound.›

How it is built

Architecture overview

A transaction processing (TP) monitor is the runtime that sits between thousands of terminals or network clients and a set of data stores, and turns each short request into an all-or-nothing unit of work. IBM CICS and IMS TM on the mainframe, and Oracle Tuxedo on Unix, are the classic examples. The application programmer writes a small program per transaction; the monitor owns everything around it: accepting the request, queuing and routing it to a free worker, giving it a task with its own storage, calling the databases and files it needs, and committing or backing out every change together. IMS TM, for example, stores an incoming transaction on a message queue and its scheduler then starts the application in a message processing region (source: Wikipedia, IBM Information Management System).

The one idea that makes it work is separating the transaction from the process. Operating-system processes and threads are expensive, so the monitor keeps a small pool of long-lived server processes and multiplexes many short transactions over them, each with its own storage and a unit-of-work identity that all data stores honour. Atomicity across several data stores comes from a transaction manager running two-phase commit over a standard interface (X/Open XA). Availability comes from splitting the monitor into several cooperating regions or servers, so that a failure of one application server does not take down the terminal network, and from a shared lock and cache facility when one machine is not enough.

Parts:

 terminals / network clients
        │  authenticate, route
        ▼
 ┌───────────────┐   queue      ┌────────────────────────────────────────┐
 │ front end     │────────────► │ application server(s) / regions        │
 │ (TOR, listener)│  by service  │  task per request, own storage        │
 └───────────────┘              │  program calls: read, update, enqueue  │
        ▲ reply                 └───────┬───────────────────┬────────────┘
        │                          begin│ commit / abort    │ data calls
        │                               ▼                   ▼
        │                      ┌──────────────────┐   ┌─────────────────┐
        └──────────────────────│ transaction mgr  │◄─►│ resource mgrs   │
                               │ 2PC + decision   │XA │ (DB, files, MQ) │
                               │ log              │   │ locks + WAL     │
                               └────────┬─────────┘   └────────┬────────┘
                                        │ recovery log         │ shared locks/cache
                                        ▼                      ▼
                                  standby / restart      cluster coupling

How the parts fit together

Front end: terminal-owning region and listener

The front end holds the network side: terminal sessions, TCP connections, TLS. In CICS this is the terminal-owning region (TOR), which routes transactions to several application-owning regions (AORs), and a typical installation has several TORs for each service (source: Wikipedia, CICS). Keeping the connection state out of the application servers is the design point: an application server can crash or be upgraded while the sessions stay up. Identity arrives here, so Mutual TLS authenticates machine-to-machine links and Authorization models decide which user may start which transaction code. connection-pooling (no page yet) and backpressure (no page yet) are the two controls on the way in: bound the number of open sessions per client and refuse early rather than queue without limit.

Dispatcher and task runtime

The runtime gives each request a task with private working storage and runs many tasks on few operating-system threads. Within a CICS region transactions are cooperatively multitasked: they are expected to yield rather than block, and CICS services do this automatically (source: Wikipedia, CICS). The reason is cost: a Context switching between processes saves registers and address space and disturbs caches, while a yield at a known point in a user-space scheduler (cooperative-scheduling, no page yet) costs little. The price is the failure case in Failure modes: one task that does not yield blocks the whole region. A second price: because of its quasi-reentrant programming model, a CICS address space could use only about 1.5 processors at the time of the early-1990s Sysplex work, so capacity came from more regions, not more threads (same source). Process supervision restarts a failed server under a burst-limit policy, and Graceful draining lets a server finish in-flight tasks before a stop.

Tuxedo does the same job with processes on Unix. Its Bulletin Board is a shared-memory segment holding the configuration and state of a domain (servers, services, transactions, clients), a bulletin board liaison (BBL) process on each machine coordinates updates to it, and a Bridge process passes requests between machines; the BBL and Bridge monitor each other and restart the other on failure (source: Wikipedia, Tuxedo). Requests are queued to servers through memory-based inter-process communication, and the client does not know where or how the server runs (same source).

Service queues and messaging

Between the front end and the application sits a queue per service. IMS TM puts the incoming transaction on a queue, in memory or in a dataset, and the scheduler starts the program in a message processing region (source: Wikipedia, IBM Information Management System). Tuxedo adds a /Q component with transient (in-memory) and persistent queues and an event broker for publish and subscribe (source: Wikipedia, Tuxedo). A persistent queue is a Durable job queue: messages survive a restart, a worker takes a lease and acknowledges on completion, and a failed message is retried with Exponential backoff with jitter and parked in a Dead-letter queue after a limit. Message sequence numbers let a receiver detect loss, duplicates and reordering on a link; Idempotency keys make a retried request return the stored answer instead of repeating the update. An in-process bus (publish-subscribe-event-bus, no page yet) carries events inside a region.

Transaction manager and the XA contract

The contract between the monitor and the data stores is the X/Open DTP model and its XA interface, published by The Open Group. It names the calls the transaction manager uses on a resource manager: xa_start and xa_end to bracket the work of a branch, xa_prepare, xa_commit and xa_rollback for the two phases, xa_recover to list prepared branches after a crash, and xa_forget for heuristic outcomes (source: The Open Group, Distributed Transaction Processing: The XA Specification). The spec also describes a read-only optimisation, a one-phase commit when only one resource manager takes part, and heuristic decisions by a resource manager that has prepared, which it must report to the transaction manager and not forget (same source). XA is based on an interface used in Tuxedo in the 1980s (source: Wikipedia, X/Open XA), and CICS supports XA two-phase commit with Db2, IMS/DB, MQ and VSAM with record-level sharing, as well as SNA LU 6.2 for transactions across address spaces (source: Wikipedia, CICS).

Two-phase commit is the algorithm. Every participant durably records its yes vote before replying, and the coordinator logs its decision before telling anyone; both are forced writes to a Write-ahead log, and the force is the fsync and direct I/O call whose real behaviour per platform decides whether a "committed" transaction survives a power cut. The weak point is known: 2PC blocks. If the transaction manager is down after participants have prepared, they hold their locks until it returns, and if its decision log is lost an operator must resolve branches by hand (source: Wikipedia, X/Open XA).

Resource managers: locks, buffer pool and index

Each resource manager is a database engine or file system in its own right. It reads pages through a Buffer pool that owns eviction (LRU and CLOCK), finds rows through a B+ tree, and isolates transactions with Two-phase locking plus Deadlock detection. The monitor does not look inside; it only needs the XA calls and a lock timeout policy so that a stuck branch does not hold up the others.

Not every resource manager is relational. A hierarchical database of the IMS kind keeps each record's child and sibling addresses inside the record, and Index-free adjacency is what makes a transaction's typical call, "get the next dependent of this parent", a direct pointer read through the Buffer pool instead of an index probe. The transaction manager sees this store through the same prepare/commit calls as any other, and a B+ tree index is added only for the lookups the pointers do not serve.

Recovery and replication

After a crash, ARIES recovery repeats the logged history in the buffer pool and rolls back the transactions that had not committed, which is what the resource manager does on its own restart; the transaction manager then asks it for in-doubt branches (xa_recover) and resolves them from its decision log. CICS regions are restarted in a "warm" mode that uses the checkpoint written at shutdown, or a "cold" mode that reloads definitions and discards the log (source: Wikipedia, CICS). For a lost machine, a standby follows through Primary-backup replication; a Lease decides which node is allowed to be primary, and Health checking decides when to fail over. Point-in-time recovery covers the case replication cannot: a bad batch run or a deleted table is copied to the standby as faithfully as good data.

Cluster data sharing

Splitting one workload over several machines creates the sharing problem: two machines must not update the same record or cached page without knowing about each other. In IBM's Parallel Sysplex the answer is a coupling facility holding lock, list and cache structures that serialise access, pass messages and keep buffers consistent between logical partitions (source: Wikipedia, IBM Parallel Sysplex). The general technique is shared-data-cluster-lock-cache (no page yet). On a commodity cluster the equivalent pieces are Cache invalidation, so a write on one node removes copies on the others, and Fencing tokens, so a node that lost its lock during a pause cannot write afterwards.

Operations and verification

Latency percentiles go into a bounded-error histogram (hdr-histogram, no page yet), CPU and I/O are charged per transaction type (resource-usage-accounting, no page yet), and log records carry a checksum (CRC-32C checksums). Batch jobs (batch-checkpoint-restart, no page yet; cron-scheduling, no page yet) must agree with online work on commit frequency, or a long batch transaction blocks the terminals. The recovery paths are the hardest to test by hand; Deterministic simulation testing replays crashes, delays and disk faults from a seed, and Coverage-guided fuzzing attacks the message and buffer parsers at the front end.

Data and control flow

One transaction, from terminal to reply:

  1. The user sends a transaction code and input. The front end authenticates the session, maps the code to a service and places the request on that service's queue (order of microseconds in memory).
  2. The dispatcher assigns the request to a free server or region; the task gets its own storage and a unit-of-work identity.
  3. The program starts a global transaction. For each data store it touches, the transaction manager calls xa_start; the data store takes locks as it reads and writes, and appends change records to its log.
  4. The program ends its part and asks to commit. The transaction manager calls xa_end, then xa_prepare on every branch. Each branch forces its log and answers yes or no (the dominant cost: one log force per branch).
  5. If all say yes, the transaction manager forces its decision record, then calls xa_commit on each. Locks are released and the reply is sent to the front end, which writes it to the terminal.
  6. The transaction manager forgets the transaction after all acknowledgements; read-only branches skip phase two.

A crash between the phases:

  1. A data store restarts and uses its log to redo committed work and undo unfinished work; branches that had prepared stay in doubt and keep their locks.
  2. The transaction manager restarts, reads its decision log, and calls xa_recover on each resource manager to list in-doubt branches.
  3. For each branch it resends the logged decision (commit if a commit record exists, else rollback). If its log is gone, an operator resolves the branch by hand, which is the heuristic path in the XA specification.

Scaling

In the order you hit them:

  1. Log forces per transaction. Each commit waits for at least one durable log write per participant plus the coordinator. Levers: group commit (many transactions share one force), a battery-backed or NVMe log device, fewer participants per transaction, one-phase commit when only one resource manager is involved, the read-only optimisation.
  2. Lock contention on hot rows. A counter or an account record that every transaction updates serialises them. Levers: shorter transactions, commit earlier, split the hot record, move to optimistic schemes where collisions are rare.
  3. Single dispatcher or region capacity. One CICS address space could not use more than about 1.5 processors in the early 1990s (source: Wikipedia, CICS). Lever: more regions behind the same front end, with transactions routed by the front end to several application regions, which the mainframe world calls dynamic routing.
  4. Shared data across machines. Lock and cache traffic between nodes. Lever: the hardware-assisted coupling facility, or on commodity hardware, routing by key so each record has one home node and cross-node locks are rare.
  5. Front-end connections. Many mostly idle sessions. Lever: terminal-owning regions or listener processes with their own pools, separate from application capacity.
  6. Recovery time. More log means longer restart. Lever: frequent checkpoints, a warm standby that applies the log continuously.

Failure modes

FailureSymptomCauseFix
Coordinator down after preparemany transactions stuck, locks held, other work stalls2PC blocks until the transaction manager returns (source: X/Open XA overview)restart it from its decision log; replicated coordinator log; lock timeouts on the resource side
Decision log lostin-doubt branches that nobody can resolvelog device failure with no copymirrored log; operator tools for heuristic commit or rollback, with a record of the mismatch
One task never yieldswhole region stalls, queue growscooperative scheduling in a region (source: Wikipedia, CICS)task runaway limit, region watchdog, restart via process supervision
Storage overwrite across tasksrandom abends, corrupted control blocksall tasks and the kernel share one protection key (source: Wikipedia, CICS history)storage protection between programs and kernel; code review for reentrancy
Deadlock between transactionsone transaction aborted, retriedlock order differs between programsdeadlock detection, consistent lock order, timeouts
Poison messagesame request fails again and againbug or bad data in one inputretry limit with backoff, dead-letter queue, alert on queue depth
Duplicate executiondouble debit or double orderclient or queue retry after a lost replyidempotency keys; stored reply for repeats
Split brain on failovertwo nodes both accept writesprimary slow, standby promotedleases with bounded clocks, fencing tokens checked by the resource

Real implementations

namewhat it isrepolicencenotes
NarayanaJava transaction manager (JTA, JTS, XTS) used by several application serversjbosstm/narayanaApache-2.0the transaction manager part only; official site narayana.io
Enduro/Xopen-source XATMI and XA middleware for C and C++ with Tuxedo-style APIsendurox-dev/enduroxAGPL-3.0 (dual, commercial licence from Mavimax)uses POSIX queues for local IPC; non-Linux versions are commercial only (README)
PostgreSQLdatabase with prepared transactions, usable as an XA resource managerpostgres/postgresPostgreSQL licence (per COPYRIGHT)PREPARE TRANSACTION is the server side of phase one

The alternative: most new systems avoid distributed transactions. A single database transaction covers one service's data; across services, designs use a durable queue with idempotent consumers or a saga with compensating steps. A TP monitor with XA earns its place when several heterogeneous stores must commit together and the transaction rate is high, which is the profile of banking cores, airline reservation and telecom billing.

Sources

Similar systems

Share the most building blocks with this one.