VSAM ESDS Logical Delete Patterns

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.

What Is Logical Delete?

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.

Common Patterns

Common logical delete patterns
PatternDescription
Status fieldOne byte (or more) in each record: e.g. A=active, D=deleted. On delete, REWRITE with D. On read, skip D.
Tombstone contentREWRITE the whole record with a fixed pattern (e.g. all spaces, or a special code). Reader recognizes and skips.
Date or sequenceA "deleted at" or "version" field; deleted records get a sentinel value. Reader skips by that value.

Status Field Pattern

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.

Tombstone and Sentinel Patterns

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.

Implementation Steps

Steps to implement logical delete
StepDescription
DesignAdd a status (or equivalent) field to the record layout; define values for active and deleted.
DeleteRead the record, set the status to deleted, REWRITE. Record stays at same RBA.
ReadWhen reading (sequential or by RBA), check status; skip or ignore records marked deleted.
Optional reuseTo reuse an inactive slot: find a deleted record of same length, REWRITE with new data and active status.

COBOL Example (Conceptual)

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.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
01 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.

Reusing Logically Deleted Slots

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 to Run REPRO to Reclaim Space

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.

Key Takeaways

  • Logical delete = record stays on disk; a field or pattern in the record marks it as deleted; the application skips it on read.
  • Common pattern: status byte (e.g. A/D); on delete, REWRITE with status = D; on read, skip when status = D.
  • You can reuse a deleted slot by REWRITing new data and active status into it (same length).
  • To reclaim space, REPRO to a new ESDS with only active records; then RBAs change and stored references must be updated.
  • Logical delete is the standard workaround for ESDS because physical delete is not supported.

Explain Like I'm Five

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).

Test Your Knowledge

Test Your Knowledge

1. What does logical delete do to the record on disk?

  • Removes it
  • Overwrites it with zeros
  • Leaves it in place but marks it (e.g. status field) so the application skips it
  • Moves it to the end

2. How do you "delete" a record when using a status-field pattern?

  • Issue DELETE verb
  • REWRITE the record with the status byte set to deleted
  • Remove the key
  • Use REPRO

3. Why might you run REPRO to copy only active records to a new ESDS?

  • To change the key
  • To reclaim space and reduce file size when many records are logically deleted
  • To enable physical delete
  • To change CI size
Published
Updated
Read time4 min
AuthorMainframeMaster
Reviewed by MainframeMaster teamVerified: IBM z/OS 2.5 documentationSources: IBM DFSMS Access Method Services, z/OS VSAM documentationApplies to: z/OS 2.5