Wiki — Sticky TOC + Scrollspy
A clean knowledge-base article layout for the fictional Aurora DB storage engine, pairing a readable serif body column with a sticky right-rail table of contents. The TOC is generated from the article headings, nests h3 anchors under their h2 sections, and highlights the section you are reading via an IntersectionObserver, auto-scrolling to keep the active entry in view. A top reading bar and a TOC meter track scroll depth, clicks smooth-scroll and move focus, and the rail collapses on narrow screens. Built with Inter, Source Serif 4 and vanilla JS only.
MCP
程式碼
:root {
--bg: #ffffff;
--bg-2: #f7f8fa;
--panel: #ffffff;
--ink: #1a1a1f;
--ink-2: #3a3a42;
--muted: #6b7280;
--line: rgba(20, 20, 30, 0.10);
--line-2: rgba(20, 20, 30, 0.18);
--link: #2563eb;
--link-hover: #1d4ed8;
--accent: #2563eb;
--note: #2563eb;
--tip: #16a34a;
--warn: #d97706;
--danger: #dc2626;
--code-bg: #f4f4f6;
--kbd-bg: #eceef2;
--r-sm: 6px;
--r-md: 10px;
--r-lg: 14px;
--topbar-h: 56px;
--nav-w: 248px;
--toc-w: 244px;
--ui: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--serif: "Source Serif 4", Georgia, "Times New Roman", serif;
--mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--topbar-h) + 18px); }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: var(--ui);
font-size: 15px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; }
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 3px;
}
/* ---------- top reading progress bar ---------- */
.reading-bar {
position: fixed;
inset: 0 0 auto 0;
height: 3px;
background: transparent;
z-index: 60;
pointer-events: none;
}
.reading-bar span {
display: block;
height: 100%;
width: 0%;
background: linear-gradient(90deg, var(--accent), #60a5fa);
transition: width 0.08s linear;
}
/* ---------- top bar ---------- */
.topbar {
position: sticky;
top: 0;
z-index: 50;
height: var(--topbar-h);
display: flex;
align-items: center;
gap: 14px;
padding: 0 18px;
background: rgba(255, 255, 255, 0.86);
backdrop-filter: saturate(1.4) blur(8px);
border-bottom: 1px solid var(--line);
}
.hamburger {
display: none;
align-items: center;
justify-content: center;
width: 38px;
height: 38px;
border: 1px solid var(--line);
background: var(--panel);
color: var(--ink-2);
border-radius: var(--r-sm);
cursor: pointer;
}
.hamburger:hover { background: var(--bg-2); }
.brand {
display: inline-flex;
align-items: center;
gap: 9px;
color: var(--ink);
font-weight: 700;
letter-spacing: -0.01em;
}
.brand:hover { text-decoration: none; }
.brand-mark { color: var(--accent); font-size: 19px; }
.brand-name em { color: var(--muted); font-style: normal; font-weight: 600; }
.topsearch {
flex: 1;
max-width: 420px;
margin: 0 auto 0 8px;
display: flex;
align-items: center;
gap: 8px;
padding: 0 10px;
height: 36px;
background: var(--bg-2);
border: 1px solid var(--line);
border-radius: var(--r-md);
color: var(--muted);
}
.topsearch:focus-within { border-color: var(--link); background: #fff; }
.topsearch input {
flex: 1;
border: 0;
background: transparent;
font: inherit;
font-size: 14px;
color: var(--ink);
outline: none;
}
.topsearch input::placeholder { color: var(--muted); }
kbd {
font-family: var(--mono);
font-size: 11px;
line-height: 1;
padding: 3px 6px;
background: var(--kbd-bg);
border: 1px solid var(--line-2);
border-bottom-width: 2px;
border-radius: 5px;
color: var(--ink-2);
}
.ver-pill {
font-size: 12px;
font-weight: 600;
color: var(--tip);
background: color-mix(in srgb, var(--tip) 12%, #fff);
border: 1px solid color-mix(in srgb, var(--tip) 30%, transparent);
padding: 4px 9px;
border-radius: 999px;
white-space: nowrap;
}
/* ---------- shell grid ---------- */
.shell {
display: grid;
grid-template-columns: var(--nav-w) minmax(0, 1fr) var(--toc-w);
gap: 0;
max-width: 1320px;
margin: 0 auto;
}
/* ---------- left sidebar ---------- */
.sidenav {
border-right: 1px solid var(--line);
background: var(--bg);
}
.sidenav-scroll {
position: sticky;
top: var(--topbar-h);
max-height: calc(100vh - var(--topbar-h));
overflow-y: auto;
padding: 22px 16px 40px;
}
.nav-group {
margin: 18px 8px 6px;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted);
}
.nav-group:first-child { margin-top: 0; }
.nav-list { list-style: none; margin: 0 0 4px; padding: 0; }
.nav-list a {
display: block;
padding: 6px 10px;
border-radius: var(--r-sm);
color: var(--ink-2);
font-size: 13.5px;
font-weight: 500;
}
.nav-list a:hover { background: var(--bg-2); color: var(--ink); text-decoration: none; }
.nav-list a code { font-family: var(--mono); font-size: 12px; }
.nav-list a.is-current {
background: color-mix(in srgb, var(--accent) 10%, #fff);
color: var(--link-hover);
font-weight: 600;
box-shadow: inset 2px 0 0 var(--accent);
}
.scrim {
position: fixed;
inset: 0;
background: rgba(15, 18, 26, 0.42);
z-index: 39;
}
/* ---------- main article ---------- */
.article {
min-width: 0;
padding: 28px clamp(20px, 4vw, 52px) 80px;
}
.breadcrumbs {
font-size: 12.5px;
color: var(--muted);
display: flex;
flex-wrap: wrap;
gap: 7px;
align-items: center;
margin-bottom: 18px;
}
.breadcrumbs a { color: var(--muted); }
.breadcrumbs a:hover { color: var(--link); }
.breadcrumbs span[aria-current] { color: var(--ink-2); font-weight: 600; }
.article-head h1 {
font-family: var(--ui);
font-size: clamp(28px, 4vw, 38px);
line-height: 1.12;
letter-spacing: -0.02em;
font-weight: 800;
margin: 0 0 14px;
}
.lede {
font-family: var(--serif);
font-size: 18px;
line-height: 1.6;
color: var(--ink-2);
margin: 0 0 18px;
max-width: 62ch;
}
.lede em { font-style: italic; color: var(--ink); }
.meta-row { display: flex; flex-wrap: wrap; gap: 8px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }
.meta-pill {
font-size: 12px;
font-weight: 500;
color: var(--ink-2);
background: var(--bg-2);
border: 1px solid var(--line);
padding: 4px 10px;
border-radius: 999px;
}
.meta-pill.author { display: inline-flex; align-items: center; gap: 7px; }
.meta-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--tip); }
/* ---------- prose ---------- */
.prose {
max-width: 740px;
padding-top: 26px;
font-family: var(--serif);
font-size: 17px;
line-height: 1.65;
color: var(--ink);
}
.prose section { scroll-margin-top: calc(var(--topbar-h) + 18px); }
.prose section + section { margin-top: 14px; }
.prose h2 {
font-family: var(--ui);
font-size: 23px;
font-weight: 700;
letter-spacing: -0.01em;
line-height: 1.25;
margin: 34px 0 12px;
padding-bottom: 8px;
border-bottom: 1px solid var(--line);
scroll-margin-top: calc(var(--topbar-h) + 18px);
}
.prose h3 {
font-family: var(--ui);
font-size: 17.5px;
font-weight: 700;
margin: 26px 0 8px;
scroll-margin-top: calc(var(--topbar-h) + 18px);
}
.prose p { margin: 0 0 16px; }
.prose strong { font-weight: 700; color: var(--ink); }
.prose em { font-style: italic; }
.prose blockquote {
margin: 20px 0;
padding: 4px 18px;
border-left: 3px solid var(--accent);
color: var(--ink-2);
font-style: italic;
}
.prose blockquote p { margin: 8px 0; }
.prose :not(pre) > code {
font-family: var(--mono);
font-size: 0.84em;
background: var(--code-bg);
border: 1px solid var(--line);
padding: 1px 5px;
border-radius: 5px;
color: #b91c5c;
}
.prose pre {
font-family: var(--mono);
background: var(--code-bg);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 14px 16px;
overflow-x: auto;
margin: 0 0 18px;
line-height: 1.6;
}
.prose pre code { font-family: var(--mono); font-size: 13px; color: var(--ink); }
.prose pre .cm { color: var(--muted); }
/* tables */
.table-wrap { overflow-x: auto; margin: 0 0 18px; border: 1px solid var(--line); border-radius: var(--r-md); }
.prose table {
width: 100%;
border-collapse: collapse;
font-family: var(--ui);
font-size: 13.5px;
}
.prose thead th {
text-align: left;
background: var(--bg-2);
color: var(--ink-2);
font-weight: 600;
padding: 10px 14px;
border-bottom: 1px solid var(--line-2);
}
.prose tbody td { padding: 9px 14px; border-bottom: 1px solid var(--line); color: var(--ink-2); }
.prose tbody tr:last-child td { border-bottom: 0; }
.prose tbody tr:hover { background: var(--bg-2); }
.prose td code { background: var(--code-bg); }
/* callouts */
.callout {
font-family: var(--ui);
font-size: 14px;
line-height: 1.6;
border: 1px solid var(--line);
border-left-width: 4px;
border-radius: var(--r-sm);
padding: 12px 14px;
background: var(--bg-2);
}
.callout.note { border-left-color: var(--note); background: color-mix(in srgb, var(--note) 6%, #fff); }
.callout.warn { border-left-color: var(--warn); background: color-mix(in srgb, var(--warn) 8%, #fff); }
.callout strong { color: var(--ink); }
.page-foot {
font-family: var(--ui);
font-size: 12.5px;
color: var(--muted);
margin-top: 40px;
padding-top: 18px;
border-top: 1px solid var(--line);
}
/* ---------- right rail TOC ---------- */
.toc { padding: 28px 18px 40px; }
.toc-sticky {
position: sticky;
top: calc(var(--topbar-h) + 18px);
max-height: calc(100vh - var(--topbar-h) - 36px);
display: flex;
flex-direction: column;
}
.toc-title {
font-family: var(--ui);
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted);
margin: 0 0 10px;
}
.toc-progress {
height: 3px;
background: var(--line);
border-radius: 99px;
overflow: hidden;
margin-bottom: 12px;
}
.toc-progress span {
display: block;
height: 100%;
width: 0%;
background: var(--accent);
transition: width 0.1s linear;
}
.toc-nav {
overflow-y: auto;
font-family: var(--ui);
border-left: 1px solid var(--line);
}
.toc-nav a {
position: relative;
display: block;
padding: 5px 12px;
margin-left: -1px;
border-left: 2px solid transparent;
color: var(--muted);
font-size: 13px;
font-weight: 500;
line-height: 1.4;
}
.toc-nav a:hover { color: var(--ink); text-decoration: none; }
.toc-nav a.sub { padding-left: 24px; font-size: 12.5px; }
.toc-nav a.active {
color: var(--link-hover);
border-left-color: var(--accent);
font-weight: 600;
}
.toc-top {
font-family: var(--ui);
font-size: 12.5px;
font-weight: 500;
color: var(--muted);
margin-top: 14px;
padding-top: 12px;
border-top: 1px solid var(--line);
opacity: 0;
transform: translateY(-4px);
transition: opacity 0.2s, transform 0.2s;
pointer-events: none;
}
.toc-top.show { opacity: 1; transform: none; pointer-events: auto; }
/* ---------- toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 24px;
transform: translate(-50%, 16px);
background: var(--ink);
color: #fff;
font-family: var(--ui);
font-size: 13px;
font-weight: 500;
padding: 9px 16px;
border-radius: var(--r-md);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
opacity: 0;
pointer-events: none;
transition: opacity 0.22s, transform 0.22s;
z-index: 70;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- responsive ---------- */
@media (max-width: 1080px) {
.shell { grid-template-columns: var(--nav-w) minmax(0, 1fr); }
.toc { display: none; }
}
@media (max-width: 820px) {
.shell { grid-template-columns: minmax(0, 1fr); }
.hamburger { display: inline-flex; }
.ver-pill { display: none; }
.sidenav {
position: fixed;
top: var(--topbar-h);
left: 0;
bottom: 0;
width: min(86vw, 300px);
z-index: 40;
background: var(--panel);
border-right: 1px solid var(--line-2);
box-shadow: 4px 0 24px rgba(0, 0, 0, 0.12);
transform: translateX(-105%);
transition: transform 0.24s ease;
}
.sidenav.open { transform: none; }
.sidenav-scroll { position: static; max-height: none; height: 100%; }
}
@media (max-width: 520px) {
body { font-size: 14.5px; }
.topsearch { display: none; }
.article { padding: 20px 16px 64px; }
.prose { font-size: 16px; }
.prose pre { font-size: 12px; }
.lede { font-size: 16.5px; }
.article-head h1 { font-size: 26px; }
.brand-name { display: none; }
}(function () {
"use strict";
var prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 1800);
}
/* ---------- build the TOC from article headings ---------- */
var article = document.querySelector(".prose");
var tocNav = document.getElementById("tocNav");
var headings = article
? Array.prototype.slice.call(article.querySelectorAll("section[id] h2, h3[id]"))
: [];
// Map each heading to its TOC link
var linkFor = {};
headings.forEach(function (h) {
var id = h.id || (h.closest("section") && h.closest("section").id);
if (!id) return;
if (!h.id) h.id = id;
var label =
h.getAttribute("data-toc") ||
(h.closest("section") && h.closest("section").getAttribute("data-toc")) ||
h.textContent.trim();
var a = document.createElement("a");
a.href = "#" + id;
a.textContent = label;
a.setAttribute("data-target", id);
if (h.tagName === "H3") a.classList.add("sub");
tocNav.appendChild(a);
linkFor[id] = a;
});
/* ---------- smooth-scroll + focus on TOC click ---------- */
function goTo(id, announce) {
var target = document.getElementById(id);
if (!target) return;
target.scrollIntoView({
behavior: prefersReduced ? "auto" : "smooth",
block: "start",
});
// move focus for accessibility without an extra visible jump
target.setAttribute("tabindex", "-1");
target.focus({ preventScroll: true });
if (announce) {
var lbl = linkFor[id] ? linkFor[id].textContent : id;
toast("Jumped to “" + lbl + "”");
}
}
tocNav.addEventListener("click", function (e) {
var a = e.target.closest("a[data-target]");
if (!a) return;
e.preventDefault();
var id = a.getAttribute("data-target");
history.replaceState(null, "", "#" + id);
goTo(id, true);
});
/* ---------- scrollspy via IntersectionObserver ---------- */
var activeId = null;
var visible = new Map();
function setActive(id) {
if (id === activeId) return;
activeId = id;
Object.keys(linkFor).forEach(function (key) {
linkFor[key].classList.toggle("active", key === id);
});
var link = linkFor[id];
if (link) {
link.setAttribute("aria-current", "true");
// keep the active TOC entry visible within the (scrollable) TOC nav
var top = link.offsetTop;
var nav = tocNav;
if (top < nav.scrollTop || top > nav.scrollTop + nav.clientHeight - 28) {
nav.scrollTo({
top: Math.max(0, top - nav.clientHeight / 2),
behavior: prefersReduced ? "auto" : "smooth",
});
}
}
Object.keys(linkFor).forEach(function (key) {
if (key !== id) linkFor[key].removeAttribute("aria-current");
});
}
function pickActive() {
if (!visible.size) return;
// choose the visible heading nearest the top of the viewport
var best = null;
var bestTop = Infinity;
visible.forEach(function (rectTop, id) {
if (rectTop < bestTop) {
bestTop = rectTop;
best = id;
}
});
if (best) setActive(best);
}
if ("IntersectionObserver" in window && headings.length) {
var spy = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
var id =
entry.target.id ||
(entry.target.closest("section") && entry.target.closest("section").id);
if (!id) return;
if (entry.isIntersecting) {
visible.set(id, entry.boundingClientRect.top);
} else {
visible.delete(id);
}
});
pickActive();
},
{
// activation band: a bit below the sticky header, well above the fold
rootMargin: "-78px 0px -65% 0px",
threshold: 0,
}
);
headings.forEach(function (h) {
spy.observe(h);
});
}
/* ---------- reading progress (top bar + TOC meter) ---------- */
var readingFill = document.getElementById("readingFill");
var tocFill = document.getElementById("tocFill");
var tocTop = document.getElementById("tocTop");
var ticking = false;
function updateProgress() {
var doc = document.documentElement;
var scrollTop = window.scrollY || doc.scrollTop;
var max = doc.scrollHeight - window.innerHeight;
var pct = max > 0 ? Math.min(100, Math.max(0, (scrollTop / max) * 100)) : 0;
if (readingFill) readingFill.style.width = pct + "%";
if (tocFill) tocFill.style.width = pct + "%";
if (tocTop) tocTop.classList.toggle("show", scrollTop > 600);
ticking = false;
}
window.addEventListener(
"scroll",
function () {
if (!ticking) {
ticking = true;
window.requestAnimationFrame(updateProgress);
}
},
{ passive: true }
);
window.addEventListener("resize", updateProgress);
updateProgress();
if (tocTop) {
tocTop.addEventListener("click", function (e) {
e.preventDefault();
window.scrollTo({ top: 0, behavior: prefersReduced ? "auto" : "smooth" });
toast("Back to top");
});
}
/* ---------- mobile nav drawer ---------- */
var navToggle = document.getElementById("navToggle");
var sidenav = document.getElementById("sidenav");
var scrim = document.getElementById("scrim");
function setNav(open) {
if (!sidenav) return;
sidenav.classList.toggle("open", open);
navToggle.setAttribute("aria-expanded", String(open));
navToggle.setAttribute("aria-label", open ? "Close navigation" : "Open navigation");
if (scrim) scrim.hidden = !open;
}
if (navToggle) {
navToggle.addEventListener("click", function () {
setNav(!sidenav.classList.contains("open"));
});
}
if (scrim) scrim.addEventListener("click", function () { setNav(false); });
if (sidenav) {
sidenav.addEventListener("click", function (e) {
if (e.target.closest("a")) setNav(false);
});
}
/* ---------- keyboard shortcuts ---------- */
document.addEventListener("keydown", function (e) {
var tag = (e.target && e.target.tagName) || "";
var typing = tag === "INPUT" || tag === "TEXTAREA" || e.target.isContentEditable;
if (e.key === "Escape") setNav(false);
if (typing || e.metaKey || e.ctrlKey || e.altKey) {
if (e.key === "/" && !typing) {
e.preventDefault();
var s = document.querySelector(".topsearch input");
if (s) s.focus();
}
return;
}
if (e.key === "/") {
e.preventDefault();
var search = document.querySelector(".topsearch input");
if (search) search.focus();
} else if (e.key === "t" || e.key === "T") {
e.preventDefault();
window.scrollTo({ top: 0, behavior: prefersReduced ? "auto" : "smooth" });
toast("Back to top");
}
});
/* ---------- honor an incoming hash on load ---------- */
if (location.hash) {
var initial = location.hash.slice(1);
if (document.getElementById(initial)) {
requestAnimationFrame(function () { goTo(initial, false); });
}
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Aurora DB — Storage Engine · Verdant Knowledge Base</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Source+Serif+4:opsz,[email protected],400;8..60,500;8..60,600;8..60,700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- top reading progress bar -->
<div class="reading-bar" aria-hidden="true"><span id="readingFill"></span></div>
<header class="topbar">
<button class="hamburger" id="navToggle" aria-label="Open navigation" aria-expanded="false" aria-controls="sidenav">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
</button>
<a class="brand" href="#top">
<span class="brand-mark" aria-hidden="true">◭</span>
<span class="brand-name">Verdant <em>KB</em></span>
</a>
<div class="topsearch">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.2-3.2"/></svg>
<input type="search" placeholder="Search the knowledge base…" aria-label="Search the knowledge base" />
<kbd>/</kbd>
</div>
<span class="ver-pill">v3.2 · stable</span>
</header>
<div class="shell">
<!-- LEFT SIDEBAR NAV -->
<nav class="sidenav" id="sidenav" aria-label="Documentation sections">
<div class="sidenav-scroll">
<p class="nav-group">Aurora DB</p>
<ul class="nav-list">
<li><a href="#top">Overview</a></li>
<li><a href="#install">Getting started</a></li>
<li><a class="is-current" href="#top" aria-current="page">Storage engine</a></li>
<li><a href="#install">Query planner</a></li>
<li><a href="#install">Replication</a></li>
</ul>
<p class="nav-group">Operations</p>
<ul class="nav-list">
<li><a href="#install">Backups & PITR</a></li>
<li><a href="#install">Observability</a></li>
<li><a href="#install">Capacity planning</a></li>
</ul>
<p class="nav-group">Reference</p>
<ul class="nav-list">
<li><a href="#install">CLI: <code>aurora</code></a></li>
<li><a href="#install">Config keys</a></li>
<li><a href="#install">Error codes</a></li>
</ul>
</div>
</nav>
<div class="scrim" id="scrim" hidden></div>
<!-- MAIN ARTICLE -->
<main class="article" id="top">
<nav class="breadcrumbs" aria-label="Breadcrumb">
<a href="#top">Docs</a><span aria-hidden="true">/</span>
<a href="#top">Aurora DB</a><span aria-hidden="true">/</span>
<span aria-current="page">Storage engine</span>
</nav>
<header class="article-head">
<h1>The Aurora DB Storage Engine</h1>
<p class="lede">
Aurora DB is a distributed, log-structured database built for the
<em>Verdant</em> platform. This page is the canonical reference for how the
storage engine persists, compacts, and recovers data on disk — from the write path
down to the on-disk segment format.
</p>
<div class="meta-row">
<span class="meta-pill">Updated Jun 8, 2026</span>
<span class="meta-pill">~9 min read</span>
<span class="meta-pill author"><span class="dot" aria-hidden="true"></span>Maintained by the Storage team</span>
</div>
</header>
<article class="prose">
<section id="overview" data-toc="Overview">
<h2>Overview</h2>
<p>
The storage engine — codenamed <strong>Project Nimbus</strong> — is the lowest layer of
Aurora DB. It owns everything below the query planner: the write-ahead log, in-memory
memtables, immutable on-disk segments, and the background compaction that keeps read
amplification bounded. Every higher subsystem, from the planner to replication, ultimately
speaks to Nimbus through a narrow key/value interface.
</p>
<p>
Nimbus is a <em>log-structured merge</em> (LSM) engine. Writes are always sequential:
they land in the log first, then in a sorted in-memory buffer, and are only ever rewritten
in bulk during compaction. This trades a little read complexity for write throughput that
scales close to raw disk bandwidth.
</p>
<blockquote>
<p>
Nimbus never updates a record in place. A “delete” is just another append — a tombstone
that shadows older versions until compaction reclaims the space.
</p>
</blockquote>
</section>
<section id="write-path" data-toc="The write path">
<h2>The write path</h2>
<p>
A write travels through three stages before it is durable and queryable. Understanding the
order of these stages explains nearly every latency characteristic of the engine.
</p>
<h3 id="wal" data-toc="Write-ahead log">Write-ahead log</h3>
<p>
Each mutation is first appended to the <strong>write-ahead log</strong> (WAL), a single
sequential file per shard. The WAL is the durability boundary: once an entry is
<code>fsync</code>-ed, the write is considered committed even if the process crashes a
microsecond later. Recovery replays the tail of the WAL into fresh memtables.
</p>
<pre><code>aurora write \
--shard 7 \
--key "verdant:user:8821" \
--value @profile.json \
--durability sync <span class="cm"># fsync before ack</span></code></pre>
<p>
Set <code>--durability async</code> only for workloads that can tolerate losing the last
few milliseconds of writes on an unclean shutdown.
</p>
<h3 id="memtable" data-toc="Memtables">Memtables</h3>
<p>
After the WAL, the mutation is inserted into the active <strong>memtable</strong>, a
concurrent sorted map kept entirely in RAM. Reads check the memtable first, so freshly
written keys are served without touching disk. When a memtable exceeds
<code>nimbus.memtable.max_bytes</code> it is sealed, made read-only, and queued for flush.
</p>
<h3 id="flush" data-toc="Flush to segments">Flush to segments</h3>
<p>
A background flusher streams each sealed memtable to disk as an immutable
<strong>segment</strong>. Because the memtable is already sorted, the flush is a single
sequential pass — no random I/O. The original WAL entries become eligible for truncation
once their segment is fully persisted.
</p>
</section>
<section id="segment-format" data-toc="On-disk segments">
<h2>On-disk segments</h2>
<p>
A segment is a self-describing, immutable file. Its layout is designed so a single segment
can be opened, validated, and range-scanned without consulting any external index.
</p>
<div class="table-wrap">
<table>
<thead>
<tr><th>Block</th><th>Purpose</th><th>Typical size</th></tr>
</thead>
<tbody>
<tr><td><code>header</code></td><td>Magic, format version, shard id, key range</td><td>4 KB</td></tr>
<tr><td><code>data</code></td><td>Sorted, prefix-compressed key/value pairs</td><td>up to 256 MB</td></tr>
<tr><td><code>filter</code></td><td>Bloom filter for negative lookups</td><td>~1.2% of data</td></tr>
<tr><td><code>index</code></td><td>Sparse index: one entry per data block</td><td>~0.4% of data</td></tr>
<tr><td><code>footer</code></td><td>Block offsets, full-file CRC32C</td><td>512 B</td></tr>
</tbody>
</table>
</div>
<p>
Lookups consult the <code>filter</code> block before any disk read. A miss in the Bloom
filter is a guaranteed “not present,” which is what keeps point reads cheap even when a key
is spread across dozens of segments.
</p>
</section>
<section id="compaction" data-toc="Compaction">
<h2>Compaction</h2>
<p>
Left alone, an LSM engine accumulates overlapping segments and read amplification climbs.
<strong>Compaction</strong> merges segments together, drops shadowed versions and
tombstones, and rewrites the survivors into a smaller, non-overlapping set.
</p>
<h3 id="leveling" data-toc="Leveled strategy">Leveled strategy</h3>
<p>
Nimbus uses <em>leveled</em> compaction by default. Level 0 holds raw flushed segments that
may overlap; every deeper level holds non-overlapping, size-tiered segments. A level fills
up, spills into the next, and the cascade keeps the worst-case read bounded to roughly one
segment per level.
</p>
<p class="callout note">
<strong>Note —</strong> Compaction is I/O-bound. On busy shards, cap it with
<code>nimbus.compaction.rate_limit_mb</code> so background work never starves foreground
queries.
</p>
<p class="callout warn">
<strong>Warning —</strong> Disabling compaction entirely will <em>not</em> reclaim deleted
space. Tombstones live forever until a compaction sweeps them, and disk usage grows without
bound.
</p>
</section>
<section id="recovery" data-toc="Crash recovery">
<h2>Crash recovery</h2>
<p>
On startup, Nimbus scans the segment directory, verifies each footer CRC, and replays any
WAL entries written after the newest durable segment. Segments with a torn footer are
quarantined rather than trusted — a partially written file is treated as if the flush never
happened.
</p>
<pre><code>aurora recover --shard 7 --verify-crc <span class="cm"># dry run, reports torn segments</span>
aurora recover --shard 7 --apply <span class="cm"># replay WAL, reopen for writes</span></code></pre>
<p>
Recovery time is proportional to the size of the un-flushed WAL tail, not the size of the
dataset — typically well under a second per gigabyte of pending writes.
</p>
</section>
<section id="tuning" data-toc="Tuning & limits">
<h2>Tuning & limits</h2>
<p>
The defaults are tuned for a balanced read/write mix on NVMe storage. The keys below are the
ones worth touching first when a workload skews heavily in one direction.
</p>
<div class="table-wrap">
<table>
<thead><tr><th>Config key</th><th>Default</th><th>Notes</th></tr></thead>
<tbody>
<tr><td><code>nimbus.memtable.max_bytes</code></td><td>64 MiB</td><td>Bigger = fewer, larger segments</td></tr>
<tr><td><code>nimbus.compaction.rate_limit_mb</code></td><td>128</td><td>Throttle background I/O</td></tr>
<tr><td><code>nimbus.bloom.bits_per_key</code></td><td>10</td><td>Higher = fewer false positives</td></tr>
<tr><td><code>nimbus.block.target_kb</code></td><td>32</td><td>Smaller = faster point reads</td></tr>
</tbody>
</table>
</div>
</section>
<section id="install" data-toc="Next steps">
<h2>Next steps</h2>
<p>
With the storage layer understood, the natural next reads are the
<a href="#top">Query planner</a> (how scans turn into segment reads) and
<a href="#top">Replication</a> (how segments stream to followers). For day-two operations,
see <a href="#top">Backups & PITR</a>, which builds directly on the immutable-segment
model described above.
</p>
<p>
Press <kbd>T</kbd> at any time to jump back to the top of this page.
</p>
</section>
<p class="page-foot">Last reviewed by the Storage team · Verdant Knowledge Base · CC BY 4.0</p>
</article>
</main>
<!-- RIGHT RAIL: STICKY TOC + SCROLLSPY -->
<aside class="toc" aria-label="Table of contents">
<div class="toc-sticky">
<p class="toc-title">On this page</p>
<div class="toc-progress" aria-hidden="true"><span id="tocFill"></span></div>
<nav id="tocNav" class="toc-nav"><!-- built by script.js --></nav>
<a class="toc-top" href="#top" id="tocTop">↑ Back to top</a>
</div>
</aside>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Sticky TOC + Scrollspy
A complete knowledge-base reading view for Aurora DB, a fictional distributed database, laid out in a crisp white docs palette with a persistent left sidebar, a centered serif body column capped at a comfortable measure, and a sticky right-rail table of contents. The article runs through real-feeling technical sections — the write path, on-disk segment format, compaction, recovery and tuning — with headings, code blocks, tables, callouts and keyboard hints.
The TOC builds itself from the article’s h2 and h3 elements, nesting sub-headings under their
parent sections. As you scroll, an IntersectionObserver watches every heading and highlights the one
that currently owns the viewport; the rail auto-scrolls so the active entry never drifts out of sight.
A thin progress bar across the top of the page and a matching meter in the TOC both track overall
reading position.
Clicking a TOC entry smooth-scrolls to its section and moves keyboard focus there for accessibility,
updating the URL hash as it goes. A back-to-top link fades in once you are well into the page, the left
nav collapses into a drawer below 820px, and shortcuts (/ to search, T to jump to the top) round
it out. Everything runs on vanilla JS — no frameworks, no build step, and reduced-motion preferences
are respected.
Illustrative UI only — fictional articles, products, and data.