codex/file-system-journal-transaction-timeline.py

file-system-journal-transaction-timeline.py
"""Draw a full-data redo journal timeline; tested with Python 3.14,
matplotlib 3.10.7 and numpy 2.3.5. Run from _media to write the PNG there.
The horizontal positions express dependencies, not measured durations.
"""

from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch


def main():
    fig, ax = plt.subplots(figsize=(12, 6.1), dpi=100, facecolor="white")
    ax.set(xlim=(-0.25, 12), ylim=(-0.6, 5.5))
    ax.axis("off")
    fig.subplots_adjust(left=0.015, right=0.985, top=0.93, bottom=0.09)
    ax.text(5.8, 5.3, "Full-data journaling: commit before checkpoint", ha="center",
            fontsize=18, weight="bold", color="#15354a")
    ax.text(5.8, 4.91, "One append • atomic records • honored flushes • no other writer",
            ha="center", fontsize=12, color="#435667")

    def box(x, y, width, text, color, fontsize=12):
        ax.add_patch(FancyBboxPatch((x, y), width, 0.75, boxstyle="round,pad=0.07",
                                   facecolor=color, edgecolor="#365466", linewidth=1.2))
        ax.text(x + width / 2, y + 0.375, text, ha="center", va="center",
                fontsize=fontsize, color="#132e3e")

    for y, label in [(3.75, "Journal"), (2.55, "Final locations"), (1.25, "Crash outcome")]:
        ax.text(0, y, label, fontsize=12, weight="bold", va="center")

    box(1.6, 3.4, 2.0, "Write payload\nI + B + D", "#dcecf7")
    box(4.0, 3.4, 1.75, "Write commit\nmarker", "#c8e9e4")
    box(9.65, 3.4, 1.8, "Retire journal\nspace reusable", "#e4e7ec", 11)
    box(6.1, 2.2, 2.75, "Checkpoint I + B + D\n(any write order)", "#f7e3bb")
    ax.plot([1.6, 5.75], [2.58, 2.58], color="#7d94a1", lw=2)
    ax.text(3.65, 2.82, "Keep final records old", ha="center", fontsize=11)
    ax.annotate("", xy=(9.6, 2.58), xytext=(8.9, 2.58),
                arrowprops={"arrowstyle": "->", "color": "#365466", "lw": 1.5})

    for x, label in [(3.8, "Payload\nflush"), (5.95, "Commit\nflush"), (9.2, "Checkpoint\nflush")]:
        ax.plot([x, x], [1.85, 4.3], color="#b84c35", lw=1.6, linestyle="--")
        ax.text(x, 4.48, label, ha="center", va="center", fontsize=11,
                color="#a13d2d", weight="bold")

    ax.annotate("", xy=(6.06, 2.92), xytext=(5.72, 3.39),
                arrowprops={"arrowstyle": "->", "color": "#365466", "lw": 1.5})
    ax.text(6.25, 3.65, "Durable decision:\nacknowledgment may follow", fontsize=11,
            color="#126b5c", va="center")
    box(1.6, 0.85, 4.1, "No durable commit → old file\nIgnore incomplete payload", "#edf3f8", 11)
    box(6.05, 0.85, 3.25, "Durable commit → new file\nReplay any missing copies", "#e3f2ee", 11)
    box(9.65, 0.85, 1.8, "New file\nalready durable", "#edf0f3", 11)
    ax.annotate("", xy=(11.7, 0.47), xytext=(1.6, 0.47),
                arrowprops={"arrowstyle": "->", "color": "#365466", "lw": 1.4})
    ax.text(6.6, 0.2, "Persistence dependencies (not elapsed time)", ha="center", fontsize=11)
    fig.text(0.5, 0.025, "I: inode size 4 → 8, references 7 → 7 & 9    B: block 9 free → allocated    D: block 9 → EFGH",
             ha="center", fontsize=11, color="#435667")
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()