Module 10
Rocket Data Replicate and Sync on IDMS
Everything in the previous nine modules exists to make this one make sense. A replication product is not magic: it reads a change log, decodes the bytes using a description you gave it, and writes rows somewhere else. Every hard problem in the project is one of the behaviours you have already studied, arriving at the wrong moment.
Putting it together. The software doing the copying has four jobs, and almost every incident you will ever have is one of those four.
Capture — read the change log as changes happen. Decode — turn mainframe bytes into real values, using the record layouts. Stage — hold changes safely, grouped by transaction, until they are known to be final. Apply — write them to the target in the right order, in a way that is safe to repeat.
Knowing which of the four is failing is most of the diagnosis. This module gives you the architecture, the modelling decisions, and a failure catalogue you can work down when the lag graph starts climbing.
New words on this page, one line each
- CDC
- Change data capture — continuously reading the change log to copy changes as they happen.
- bulk transfer
- Reading the whole database once to populate the target the first time.
- watermark
- The exact position in the change log where the bulk copy ended and continuous copying must start.
- staging
- A durable buffer between reading and writing, where changes are assembled into whole transactions.
- idempotent
- Safe to repeat. Applying the same change twice leaves the same result as applying it once.
- lag
- How far behind the copy is, in unapplied changes or in time.
- back-pressure
- What happens when the buffer fills: reading has to stop, and the change log becomes your only remaining buffer.
- reconciliation
- Actually checking that the copy matches, rather than trusting that nothing errored.
- full refresh
- Throwing the copy away and rebuilding it, because the changes needed to catch up no longer exist.
The four jobs the software has to do
Four ways to move data, and when each is right
The architecture is the one you already know: read the log, decode, buffer by transaction, apply on commit. Two things differ.
First, decoding is not free — the log holds raw mainframe bytes and needs the record layouts supplied separately, so a source schema change that nobody told you about produces wrong data rather than an error.
Second, the log is not kept indefinitely. It is recycled on a fixed schedule sized for disaster recovery, not for you, so an outage longer than that window is unrecoverable without a full reload.
| Mode | What it does | Use it for | Cost |
|---|---|---|---|
| Bulk transfer | Reads the source in full and loads the target | Initial load, full refresh after an unrecoverable gap, rebuilding after a reorg | Highest mainframe CPU and elapsed time; may need a quiesce window |
| Log/journal CDC | Reads the journal stream and replicates committed change continuously | Steady-state replication — everything after the initial load | Low and roughly proportional to change volume, not data volume |
| Compare & sync | Compares source and target and generates the delta to repair the difference | Validation, drift detection, cheap recovery from a small gap | A full read of both sides; schedule it, do not run it casually |
| Real-time / exit-based capture | Sees changes as they happen rather than as they are journalled | Lowest achievable latency where the platform supports it | Tighter coupling to the source; availability and support implications to confirm |
A real project uses at least three of them: bulk for the initial load, CDC for steady state, and compare for periodic assurance. Design all three from the start — retro-fitting reconciliation after go-live is how teams end up unable to answer "is the target correct?" with anything better than an opinion.
The record layouts are the product
The software cannot decode a single change without being told that record type 415 is an employee, that bytes 5 to 14 are a first name in mainframe text, and that bytes 60 to 64 are a salary packed two digits per byte.
If someone adds a field to the source and nobody updates that description, the decoder happily keeps reading the old byte positions. No error is raised. The data is simply wrong from that moment on. Generate the description from the blueprint, keep it in version control, and compare every regeneration.
The pipeline cannot decode a single journal image without knowing that record ID 415 is an
EMPLOYEE, that bytes 5–14 are EMP-FIRST-NAME-0415 in EBCDIC, and that bytes
60–64 are SALARY-AMOUNT-0420 packed with two implied decimals. That knowledge lives in the
mapping repository, and it comes from the artefacts you gathered in Module 04.
| Source artefact | Feeds |
|---|---|
Schema punch (DISPLAY SCHEMA … WITH ALL) | Record types, record IDs, elements, pictures, sets, membership options |
| COBOL copybooks | Physical layouts including REDEFINES and OCCURS that the schema states less explicitly |
| DMCL | Page groups, radix, area-to-file mapping, journal configuration |
| SQL catalog (if the option is installed) | An independent cross-check on column types and lengths |
| Application source | REDEFINES discriminators, sentinel meanings, ERASE options actually used |
Turning pointer-linked records into tables
This is where the CODASYL model meets the relational one, and it is a series of decisions with no default right answer. Work through them.
The decision rules, collected
| Source construct | Target construct | Decision you must make |
|---|---|---|
CALC record, DUPLICATES NOT ALLOWED | Table with a natural primary key | None — take the key |
| CALC record, duplicates allowed | Table with a non-unique index | What actually makes a row unique? Often owner + key. |
| VIA record | Child table | Key strategy: composite (owner + sort key) if the sorted set forbids duplicates, otherwise a generated sequence assigned at capture |
| One-to-many set | Foreign key on the member table | Nullable if OPTIONAL, NOT NULL if MANDATORY |
| Junction record (member of two sets, owns none) | Associative table | Composite key from both foreign keys, plus payload columns |
| Multi-member set | Several child tables, or one with a type discriminator | Whether consumers want them unified |
| Recursive structure record | Self-referencing FK or a closure/edge table | Depth of query the consumers need |
| Set order that carries meaning | An explicit column: sequence, valid-from, current flag | Which semantic the order was encoding |
| Orphaned optional members | Rows with a null FK, or excluded, or attached to a synthetic parent | What the business says an orphan means |
OCCURS group | Child table with a sequence number | Whether a wide flattened row is genuinely better for the consumer |
| Sentinel values | NULL, or a preserved distinct value | Signed off by the business, in writing, per field |
| Db-key | Optional technical column, never the primary key | Whether you need it at all for debugging |
The first copy, and the handover point
You are photographing a filing cabinet that people keep using while you work. By the time you reach the last drawer, the first one has changed.
The fix is not to work faster. It is to have a colleague writing down every change from the moment you started, and then apply that list over your photographs afterwards.
Which is why the rule is: start recording changes before you start copying. Overlap costs nothing if applying a change twice is harmless. A gap cannot be fixed by anything except doing it all again.
The most delicate five minutes of the project. The sequence that works:
- Start capture first. It begins accumulating change into staging; nothing is applied yet.
- Record the journal position at which capture started. This is the watermark.
- Run the bulk extract. It reads a source that is being modified concurrently, so what it produces is fuzzy — a mixture of states.
- Load the target.
- Replay staged change from the watermark forward, applying every operation as an upsert.
- Reconcile. Once replay catches up, run a compare on a sample or on everything.
The fuzziness in step 3 is cured by step 5 precisely because the changes are re-applied over whatever the extract happened to catch. This only works if apply is idempotent: an insert of a row that exists must become an update, a delete of a row that is absent must be a no-op. Write it that way from the beginning.
Why the copy falls behind
For some period, the source produced changes faster than the slowest stage could drain them.
That is the whole explanation, and it means the useful question is never “why is replication slow?” but “which stage is the bottleneck, and was it sized against peak or against average?” The simulator below lets you create each failure shape deliberately.
Lag is the number the business will ask about, and it has exactly one cause: for some interval, the source produced change faster than the slowest stage could drain it. Play with the pipeline and find the failure shapes.
Read the simulator's behaviour as four distinct situations:
- Steady state. Apply throughput exceeds change rate; lag hovers near zero and recovers from spikes.
- Batch spike. A nightly job produces more change in ten minutes than the day does in eight hours. Lag climbs, then drains. Acceptable if it drains before the next spike — that is your real capacity test, not the average.
- Target outage. Capture keeps reading, staging absorbs. This is what a durable staging area is for. When staging fills, back-pressure stops capture and the journal becomes your buffer — and now journal retention is the clock you are racing.
- Structural under-capacity. Apply is simply slower than the change rate. Lag grows monotonically and no amount of waiting fixes it. The remedies are all upstream: filter what you replicate, batch the applies, parallelise by table, or reduce source change.
What goes wrong, and what to check first
| Symptom | Likely cause | First check |
|---|---|---|
| Lag climbing steadily, no spike | Apply under-capacity, or a target index making every write expensive | Apply rate versus source change rate; target write latency |
| Lag flat then a cliff | One enormous uncommitted source transaction | Long-running run units on the source; ERASE … ALL cascades |
| Target row counts diverge, no errors | Db-key-based keying and a reorg; or orphans excluded by an owner-down extract | Whether an unload/reload happened; the key strategy |
| Some columns wrong, others fine | Whole-record code page conversion destroying packed and binary fields | Conversion configuration; test with a negative packed value |
| Values wrong only for negative numbers | Zoned decimal sign overpunch mishandled | The field's PIC and whether it is COMP-3 or DISPLAY |
| Fields wrong after a certain position, in some rows only | OCCURS DEPENDING ON parsed at fixed offsets | The count field and the parser's variable-length handling |
| Rows that were later rolled back appear in the target | Applying on arrival rather than on commit | Transaction assembly in staging |
| Capture cannot resume after an outage | Required archive journals have been recycled | Retention policy versus outage duration; declare a full refresh |
| Unexplained divergence after a source incident | Cold start, area restore, or a local-mode unjournalled job | The source operations log for that window |
| Enormous change volume with no business activity | Structural journal activity — index maintenance, pointer updates from sorted-set reordering | Whether capture filters structural images |
Proving the copy is actually right
Row counts catch gross failures and prove nothing about correctness. Column checksums catch the byte-level decoding bugs that counts never will. A full comparison catches everything — expensively.
Then add one more: run five reports the business already trusts against both systems and compare numbers a human recognises. That is the only check that catches a modelling mistake, where every technical test passes and the answer is still wrong.
"The pipeline reports no errors" is not evidence. Build three layers of assurance and run them on a schedule.
1. Counts
Row counts per table, per day. Cheap, continuous, catches gross failures — and catches nothing about correctness of values.
2. Checksums
Sum or hash a numeric and a character column per key range. This is what catches packed-decimal and code-page bugs that counts never will.
3. Full compare
A compare-and-sync run across everything. Expensive; schedule it weekly or after any source incident, and always after a reorg or cold start.
Add one non-technical layer: a business check. Pick five reports the business already trusts, run them against source and target, and compare the numbers a human recognises. That is the check that finds modelling errors, which no checksum can.
Cutover patterns
- Read-only replica. The target serves reporting and analytics; the mainframe remains the system of record. Lowest risk, and often the whole project. One-way replication, no conflict resolution.
- Parallel run. New applications are built against the target while the mainframe still runs. Both are live for reads; only the mainframe is written. Divergence is visible and cheap to fix.
- Phased write migration. Ownership of specific entities moves to the new platform, one at a time. Requires replication in the other direction for anything the mainframe still reads, and therefore requires conflict rules.
- Bi-directional sync. Both platforms write. Only do this with a defined ownership model per entity or per field, loop prevention, and an agreed conflict resolution rule. It is the most capable and by a wide margin the most dangerous configuration.
The non-functional conversation
- Mainframe CPU. Capture consumes it, and mainframe CPU is expensive and metered. Ask what portion of the work is zIIP-eligible and get a measured figure from a proof of concept, not a brochure figure.
- External run units. Anything connecting as an ERU counts against
MAXERUS. Get an allocation agreed. - Network. Sustained throughput and, more importantly, behaviour under a link failure — does capture stall gracefully and resume from its position?
- Security. Journal and database access is authorised by RACF, ACF2 or Top Secret. The capture identity needs specific, minimal, documented authority. Encryption in transit is a requirement, not an option.
- Auditability. Some regulated environments need to prove what was replicated and when. Decide early whether the pipeline is in scope for audit, because it changes what you retain.
The project checklist
Everything this course says to establish before design freeze
- Complete list of segments, areas and record types in scope, with the DBNAME that groups them.
- Schema punch and DMCL source, with version numbers recorded.
- COBOL copybooks, diffed against the schema element list.
- Every
REDEFINESdiscriminator, traced in application source. - Every
OCCURS DEPENDING ONand its count field. - Sentinel-to-null mapping, per field, signed off by the business.
- Key strategy per record type, especially every VIA record.
- Set-to-relational mapping, with nullability derived from membership options.
- Orphan policy.
- Which
ERASEoptions the applications actually use, and the worst-case cascade size. - Inventory of every writer: online, batch under CV, local mode, ADS, ASF, SQL. Which journal.
- Journal retention, archive cycle, and the agreed minimum.
- Notification agreement: reorg, cold start, restore, schema change, DMCL change.
MAXERUSheadroom and the allocation for replication.- Consistency strategy for the initial load and the watermark mechanism.
- Idempotent apply semantics, written down.
- Reconciliation: counts, checksums, full compare, business reports — each with a schedule and an owner.
- Full refresh procedure, timed on real data volumes.
- Latency target, alert thresholds set well inside journal retention, and an escalation path.
- Cutover pattern chosen, with the conflict model if writes ever go both ways.