Tombstone *slot* in the roster file with an in-place 4-byte overwrite. **Fast path** (same-process delete after a ``put``): the byte offset of the entry was recorded by ``_roster_append`` in ``_roster_slot_offsets``. We seek directly and write the tombstone
(self, slot)
| 532 | self._roster_invalidate() |
| 533 | |
| 534 | def _roster_remove(self, slot): |
| 535 | """ |
| 536 | Tombstone *slot* in the roster file with an in-place 4-byte overwrite. |
| 537 | |
| 538 | **Fast path** (same-process delete after a ``put``): the byte offset |
| 539 | of the entry was recorded by ``_roster_append`` in |
| 540 | ``_roster_slot_offsets``. We seek directly and write the tombstone |
| 541 | using the persistent write fd — zero extra opens. |
| 542 | |
| 543 | **Slow path** (cross-process or after restart): scan the file for the |
| 544 | entry and overwrite it. |
| 545 | |
| 546 | ``_roster_read`` skips ``_ROSTER_TOMBSTONE`` entries; they are |
| 547 | compacted on the next ``atomic_rebuild``. |
| 548 | """ |
| 549 | tombstone = struct.pack(_ROSTER_ENTRY_FMT, _ROSTER_TOMBSTONE) |
| 550 | |
| 551 | byte_offset = self._roster_slot_offsets.pop(slot, None) |
| 552 | if byte_offset is not None: |
| 553 | # Fast path: reuse the write fd, seek to known offset |
| 554 | wfd = self._roster_wfd_open() |
| 555 | if wfd is not None: |
| 556 | try: |
| 557 | wfd.seek(byte_offset) |
| 558 | wfd.write(tombstone) |
| 559 | wfd.flush() |
| 560 | _fsync_fd_maybe(wfd.fileno()) |
| 561 | # seek back to end so next append lands correctly |
| 562 | wfd.seek(0, 2) |
| 563 | self._roster_invalidate() |
| 564 | return |
| 565 | except OSError as exc: |
| 566 | log.error( |
| 567 | "Error tombstoning roster (fast) %s: %s", |
| 568 | self.roster_path, |
| 569 | exc, |
| 570 | ) |
| 571 | try: |
| 572 | wfd.close() |
| 573 | except OSError: |
| 574 | pass |
| 575 | self._roster_wfd = None |
| 576 | # fall through to slow path |
| 577 | |
| 578 | # Slow path: open+scan+overwrite |
| 579 | try: |
| 580 | with salt.utils.files.fopen(self.roster_path, "r+b") as f: |
| 581 | data = f.read() |
| 582 | entry = struct.pack(_ROSTER_ENTRY_FMT, slot) |
| 583 | idx = data.find(entry) |
| 584 | if idx == -1: |
| 585 | return |
| 586 | f.seek(idx) |
| 587 | f.write(tombstone) |
| 588 | f.flush() |
| 589 | _fsync_fd_maybe(f.fileno()) |
| 590 | except OSError as exc: |
| 591 | log.error("Error tombstoning roster %s: %s", self.roster_path, exc) |
no test coverage detected