Because an ESDS does not support physical delete, applications that need to "remove" records use logical delete: the record stays on disk but is marked as inactive so that the program ignores it when reading. You implement this with a pattern that fits your record layout—typically a status field, a tombstone value, or a sentinel in the record. When a record is "deleted," you update it (REWRITE) to set the mark; when you read, you check the mark and skip deleted records. Optionally you can reuse the slot by REWRITing a new active record into a previously deleted one. This page explains common logical delete patterns, how to design the record layout, how to handle read and delete in code, and when to consider REPRO to reclaim space.
Logical delete means that the record is not removed from the file. Instead, something in the record (or about the record) indicates that it should be treated as deleted. The application is responsible for setting that indicator when deletion is requested and for checking it when reading. The access method does not remove the record; it only stores and retrieves it. So logical delete is a convention between the record layout and the application code. The most common approach is to reserve one or more bytes in every record as a "status" or "record type" field. When the value means "deleted," the application skips the record or does not use it.
| Pattern | Description |
|---|---|
| Status field | One byte (or more) in each record: e.g. A=active, D=deleted. On delete, REWRITE with D. On read, skip D. |
| Tombstone content | REWRITE the whole record with a fixed pattern (e.g. all spaces, or a special code). Reader recognizes and skips. |
| Date or sequence | A "deleted at" or "version" field; deleted records get a sentinel value. Reader skips by that value. |
The status field pattern is the most common. In your record layout you define a field that can take at least two values: for example, "A" for active and "D" for deleted, or 0 for active and 1 for deleted. When the user or process requests deletion, you read the record (if you don't already have it), set the status field to the deleted value, and REWRITE the record. The record length must not increase; usually the status is a fixed position and length. When you read the file—either sequentially with READ NEXT or by RBA—you check the status after each read. If it is deleted, you skip the record (do not process it, and optionally read the next). So from the application's point of view, deleted records are invisible even though they still exist on disk.
The status field should be at a fixed position (e.g. first byte or first two bytes) so that every record has it. If you have variable-length records, the status is usually in a fixed prefix. Choose values that cannot be confused with valid data; for example, use a byte that is only ever "A" or "D", or a numeric code that is only 0 or 1.
Instead of a dedicated status byte, you can use the record content itself as the indicator. For example, you might REWRITE the entire record with spaces or with a special value in the first field (e.g. a key field set to low-values or a code that means "deleted"). When you read, you check for that pattern and skip. This is a "tombstone" or sentinel pattern. It works when you have a fixed record length and a field that would never normally have that value for a valid record. The downside is that you must ensure the tombstone value is unambiguous and that your read logic always checks for it.
| Step | Description |
|---|---|
| Design | Add a status (or equivalent) field to the record layout; define values for active and deleted. |
| Delete | Read the record, set the status to deleted, REWRITE. Record stays at same RBA. |
| Read | When reading (sequential or by RBA), check status; skip or ignore records marked deleted. |
| Optional reuse | To reuse an inactive slot: find a deleted record of same length, REWRITE with new data and active status. |
Suppose the record has a 1-byte status at the start: 01 REC. 05 REC-STATUS PIC X. 05 REC-DATA PIC X(79). When active, REC-STATUS is "A"; when deleted, "D". To delete: read the record, move "D" to REC-STATUS, REWRITE REC. To read and skip deleted: in the read loop, after READ NEXT, if REC-STATUS = "D" then continue to the next READ; else process REC-DATA. To "insert" by reusing a deleted slot: you would need a way to find a deleted record (e.g. scan for one with REC-STATUS = "D" and same length), then REWRITE with new data and REC-STATUS = "A". Often applications do not reuse; they just append new records and leave deleted ones in place until a REPRO run.
12345678910111213141501 LOG-REC. 05 LOG-STATUS PIC X VALUE 'A'. *> A=active, D=deleted 05 LOG-KEY PIC X(10). 05 LOG-BODY PIC X(69). ... *> To logically delete: after reading the record MOVE 'D' TO LOG-STATUS REWRITE LOG-REC ... *> When reading sequentially: skip deleted READ LOGFILE NEXT IF LOG-STATUS = 'D' GO TO read-next-record END-IF PERFORM process-record.
If you want to reuse the space of a deleted record (same RBA), you can REWRITE that record with new content and active status. That requires finding a record that is marked deleted and has the same length as the new record. You might scan sequentially or maintain a list of RBAs of deleted records. Reuse keeps the file from growing when you have a mix of deletes and inserts, but it adds complexity. Many applications simply append new records and do not reuse; they accept that the file grows and run REPRO periodically to build a new file with only active records.
When a large proportion of records are logically deleted, the file still occupies space for those records. To reclaim space you can REPRO the ESDS to a new cluster, copying only records that are not marked deleted. The new file is smaller and has no logical deletes. After switching to the new file, all RBAs change. Any stored RBA (e.g. in a separate index or control file) must be updated or rebuilt. So REPRO is a maintenance step, not something you do on every delete. Run it when the percentage of deleted records is high enough to justify the job and the RBA change.
You have a list of names on a piece of paper. You can't erase (physical delete). So when someone leaves, you put a line through their name (logical delete). When you read the list, you skip the names that have a line through them. The name is still there, but you pretend it's gone. If you want a clean list, you copy the list onto a new paper and only write the names that are not crossed out (REPRO).
1. What does logical delete do to the record on disk?
2. How do you "delete" a record when using a status-field pattern?
3. Why might you run REPRO to copy only active records to a new ESDS?