Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/knut

.nornir/assets/thund-checkpoint-recovery.svg

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 640" font-family="'DejaVu Sans', 'Segoe UI', sans-serif">
  <defs>
    <linearGradient id="board" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#0b1c2e"/>
      <stop offset="1" stop-color="#06111d"/>
    </linearGradient>
    <linearGradient id="chip" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#14384f"/>
      <stop offset="1" stop-color="#0e2a3e"/>
    </linearGradient>
    <linearGradient id="rail" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#173d57"/>
      <stop offset="1" stop-color="#0c2438"/>
    </linearGradient>
    <linearGradient id="slot" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#123448"/>
      <stop offset="1" stop-color="#0a2032"/>
    </linearGradient>
    <linearGradient id="commit" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#12463a"/>
      <stop offset="1" stop-color="#0a2c26"/>
    </linearGradient>
    <marker id="arw" markerWidth="10" markerHeight="10" refX="7" refY="3.2" orient="auto">
      <path d="M0,0 L7,3.2 L0,6.4 Z" fill="#6fd3f5"/>
    </marker>
    <marker id="barw" markerWidth="10" markerHeight="10" refX="7" refY="3.2" orient="auto">
      <path d="M0,0 L7,3.2 L0,6.4 Z" fill="#7fb0cc"/>
    </marker>
    <marker id="grn" markerWidth="10" markerHeight="10" refX="7" refY="3.2" orient="auto">
      <path d="M0,0 L7,3.2 L0,6.4 Z" fill="#57d9a3"/>
    </marker>
    <marker id="cor" markerWidth="10" markerHeight="10" refX="7" refY="3.2" orient="auto">
      <path d="M0,0 L7,3.2 L0,6.4 Z" fill="#ff7a7a"/>
    </marker>
  </defs>

  <rect x="0" y="0" width="1180" height="640" fill="url(#board)"/>
  <g stroke="#143a52" stroke-width="1">
    <line x1="0" y1="72" x2="1180" y2="72"/>
    <line x1="0" y1="596" x2="1180" y2="596"/>
  </g>

  <!-- title -->
  <text x="40" y="42" fill="#eaf6ff" font-size="22" font-weight="700">&#222;und &#183; barrier / epoch checkpoint + crash recovery</text>
  <text x="40" y="63" fill="#9fc9e0" font-size="13.5">one epoch = one trigger &#8226; commit-by-manifest &#8226; restore from the latest <tspan fill="#bfe6ff" font-weight="700">COMMITTED</tspan> epoch and resume from its offset (phases 3-4)</text>

  <!-- legend -->
  <g font-size="11.5">
    <line x1="748" y1="38" x2="782" y2="38" stroke="#7fb0cc" stroke-width="2.5" stroke-dasharray="6 4" marker-end="url(#barw)"/>
    <text x="790" y="42" fill="#cfe6f5">barrier &#8594; snapshot</text>
    <line x1="946" y1="38" x2="980" y2="38" stroke="#57d9a3" stroke-width="2.5" marker-end="url(#grn)"/>
    <text x="988" y="42" fill="#cfe6f5">restore &amp; resume</text>
  </g>

  <!-- ===== stream timeline: 4 triggers ===== -->
  <text x="40" y="108" fill="#9fc9e0" font-size="12" font-weight="700">stream &#8594; triggers (epochs)</text>
  <g stroke="#6fd3f5" stroke-width="3" fill="none">
    <path d="M40 150 H1120" marker-end="url(#arw)"/>
  </g>

  <!-- trigger chips -->
  <g>
    <!-- t0 -->
    <rect x="70" y="122" width="180" height="56" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="1.8"/>
    <text x="160" y="146" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">trigger 0 &#183; epoch 0</text>
    <text x="160" y="166" fill="#9fc9e0" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">observe W &#183; drop late &#183; window</text>
    <!-- t1 -->
    <rect x="290" y="122" width="180" height="56" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="1.8"/>
    <text x="380" y="146" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">trigger 1 &#183; epoch 1</text>
    <text x="380" y="166" fill="#9fc9e0" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">offset = 2 committed</text>
    <!-- crash gap -->
    <rect x="510" y="118" width="150" height="64" rx="9" fill="#2a1420" stroke="#ff7a7a" stroke-width="1.8" stroke-dasharray="5 4"/>
    <text x="585" y="146" fill="#ff9a9a" font-size="14" font-weight="700" text-anchor="middle">&#128165; CRASH</text>
    <text x="585" y="166" fill="#c99" font-size="9.5" text-anchor="middle">state lost from heap</text>
    <!-- t2 (resumed) -->
    <rect x="700" y="122" width="180" height="56" rx="9" fill="url(#chip)" stroke="#57d9a3" stroke-width="1.8"/>
    <text x="790" y="146" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">trigger 2 &#183; epoch 2</text>
    <text x="790" y="166" fill="#9fc9e0" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">resumed at offset 2</text>
    <!-- t3 -->
    <rect x="920" y="122" width="180" height="56" rx="9" fill="url(#chip)" stroke="#57d9a3" stroke-width="1.8"/>
    <text x="1010" y="146" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">trigger 3 &#183; epoch 3</text>
    <text x="1010" y="166" fill="#9fc9e0" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">windows close once</text>
  </g>

  <!-- barrier arrows down to store (t0, t1) -->
  <g stroke="#7fb0cc" stroke-width="2.4" fill="none" stroke-dasharray="6 4">
    <path d="M160 178 V300" marker-end="url(#barw)"/>
    <path d="M380 178 V300" marker-end="url(#barw)"/>
  </g>
  <!-- barrier arrows down (t2, t3) -->
  <g stroke="#7fb0cc" stroke-width="2.4" fill="none" stroke-dasharray="6 4">
    <path d="M790 178 V300" marker-end="url(#barw)"/>
    <path d="M1010 178 V300" marker-end="url(#barw)"/>
  </g>

  <!-- ===== checkpoint state store row ===== -->
  <rect x="40" y="308" width="1080" height="150" rx="12" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2.2"/>
  <text x="60" y="334" fill="#eaf6ff" font-size="15" font-weight="700">checkpoint state store</text>
  <text x="60" y="353" fill="#9fc9e0" font-size="11">{state_root}/{pipeline}/{flow_target}/ &#183; parquet-rs ArrowWriter over datafusion::object_store (== graphar ChunkStore substrate)</text>

  <!-- committed epoch dirs -->
  <g font-family="'DejaVu Sans Mono', monospace" font-size="9">
    <rect x="70" y="368" width="180" height="72" rx="7" fill="url(#commit)" stroke="#57d9a3" stroke-width="1.6"/>
    <text x="160" y="386" fill="#bfeede" font-size="10" text-anchor="middle" font-weight="700">epoch=000000/ &#10003;</text>
    <text x="80" y="404" fill="#cfe6f5">operator-state.parquet</text>
    <text x="80" y="418" fill="#cfe6f5">_thund_checkpoint.json</text>
    <text x="80" y="432" fill="#9fd8bf">status: COMMITTED</text>

    <rect x="290" y="368" width="180" height="72" rx="7" fill="url(#commit)" stroke="#57d9a3" stroke-width="1.6"/>
    <text x="380" y="386" fill="#bfeede" font-size="10" text-anchor="middle" font-weight="700">epoch=000001/ &#10003;</text>
    <text x="300" y="404" fill="#cfe6f5">W, input_maxima</text>
    <text x="300" y="418" fill="#cfe6f5">offset = 2</text>
    <text x="300" y="432" fill="#cfe6f5">emitted_windows[]</text>

    <rect x="700" y="368" width="180" height="72" rx="7" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
    <text x="790" y="386" fill="#bfe6ff" font-size="10" text-anchor="middle" font-weight="700">epoch=000002/</text>
    <text x="710" y="404" fill="#cfe6f5">operator-state.parquet</text>
    <text x="710" y="418" fill="#cfe6f5">offset = 3</text>

    <rect x="920" y="368" width="180" height="72" rx="7" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.3"/>
    <text x="1010" y="386" fill="#bfe6ff" font-size="10" text-anchor="middle" font-weight="700">epoch=000003/</text>
    <text x="930" y="404" fill="#cfe6f5">offset = 4</text>
    <text x="930" y="418" fill="#cfe6f5">_thund_latest.json &#8594;</text>
  </g>

  <!-- latest pointer callout -->
  <rect x="500" y="386" width="170" height="40" rx="7" fill="url(#slot)" stroke="#7fb0cc" stroke-width="1.3"/>
  <text x="585" y="404" fill="#bfe6ff" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">_thund_latest.json</text>
  <text x="585" y="418" fill="#86b3cc" font-size="8.5" text-anchor="middle">flip = publish (last write)</text>

  <!-- ===== recovery arrow: latest committed epoch -> resumed trigger ===== -->
  <g stroke="#57d9a3" stroke-width="2.6" fill="none">
    <path d="M470 404 H500" />
    <path d="M380 368 V330 H705 V178" marker-end="url(#grn)"/>
  </g>
  <text x="548" y="256" fill="#9fe6c9" font-size="11" font-weight="700" text-anchor="middle">restore latest COMMITTED (epoch 1)</text>
  <text x="548" y="272" fill="#86b3cc" font-size="9.5" text-anchor="middle">open rows + W + maxima + emitted set + offset &#8594; resume, no double-emit / no loss</text>

  <!-- ===== ground rail ===== -->
  <rect x="40" y="500" width="1080" height="78" rx="11" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
  <text x="64" y="524" fill="#dff1ff" font-size="13" font-weight="700">guarantees</text>
  <text x="64" y="544" fill="#bcd9ec" font-size="10.5">state exactly-once w.r.t. the checkpoint (restore == state as of the committed epoch) &#8226; output at-least-once, exactly-once with a keyed _gar_id MERGE sink</text>
  <text x="64" y="562" fill="#7fa8c4" font-size="10" font-family="'DejaVu Sans Mono', monospace">single-node sequential (trivial barrier alignment) &#183; replayable source &#183; commit order: state.parquet &#8594; manifest (COMMITTED) &#8594; latest &#183; partial epoch ignored</text>

  <text x="40" y="618" fill="#7fa8c4" font-size="10">Additive: Recompute stays the default; this is the opt-in Incremental path with a state_root. Restart boundary in tests/benches = NativeBackend::with_max_triggers.</text>
</svg>