varvedb 0.4.2

A high-performance, embedded, append-only event store for Rust.
Documentation
---
import BaseLayout from '../layouts/BaseLayout.astro';
import '../styles/css/sections/hero.css';
import '../styles/css/sections/features.css';
import '../styles/css/sections/architecture.css';
import '../styles/css/sections/code-window.css';
---

<BaseLayout>
  <section class="hero varve-layer layer-1">
    <div id="hero-canvas"></div>
    <div class="container hero-content">
      <img src="/logo.svg" alt="VarveDB Logo" class="hero-logo" />
      <h1>The Embedded <br/><span class="highlight">Event Store</span></h1>
      <p class="tagline">Zero-copy event storage with sub-microsecond reads and 1M+ events/sec batch writes.</p>
      <div class="cta-group">
        <a href="/docs/quick_start" class="btn btn-primary">Get Started</a>
        <a href="/docs/introduction" class="btn btn-secondary">Read the Docs</a>
      </div>
      <div class="install-cmd">
        <span class="prefix">$</span> cargo add varvedb
        <button class="copy-btn" aria-label="Copy command">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
        </button>
      </div>
    </div>
  </section>

  <section id="features" class="features varve-layer layer-2">
    <div class="container">
      <h2>Built for Speed and Reliability</h2>
      <div class="features-grid">
        <div class="feature-card fade-in-section">
          <div class="feature-icon">
            <svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
          </div>
          <h3>Zero-Copy Reads</h3>
          <p>Leverages <a href="https://rkyv.org/" class="tech-link">rkyv</a> to map data directly from disk. No deserialization means reads complete in nanoseconds.</p>
        </div>
        <div class="feature-card fade-in-section">
          <div class="feature-icon">
            <svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg>
          </div>
          <h3>Batch Writes</h3>
          <p>Achieve 700x throughput gains by batching events. Single transaction overhead amortized across thousands of events.</p>
        </div>
        <div class="feature-card fade-in-section">
          <div class="feature-icon">
            <svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" /></svg>
          </div>
          <h3>Append-Only Log</h3>
          <p>Immutable event stream ensures data integrity and simplifies replication. Perfect for Event Sourcing and CQRS.</p>
        </div>
      </div>
    </div>
  </section>

  <section id="architecture" class="architecture varve-layer layer-3">
    <div class="container">
      <h2>Architecture</h2>
      <p class="section-desc">Memory-mapped storage for maximum throughput. Built on LMDB for ACID guarantees.</p>
      
      <div class="arch-container">
        <!-- Diagram Side -->
        <div class="arch-diagram">
          <div class="data-packet packet-write"></div>
          <div class="data-packet packet-read"></div>
          <div class="arch-box user" data-id="user">User Application</div>
          
          <div class="arch-flow">
            <span class="arch-icon">⬇</span>
            <span>Zero-Copy Read / Batch Append</span>
          </div>

          <div class="arch-box varvedb" data-id="varvedb">
            <div class="arch-title">VarveDB Engine</div>
            <div class="arch-inner">
              <div class="arch-component" data-id="stream">Stream Handler</div>
              <div class="arch-component" data-id="indexer">Index Manager</div>
              <div class="arch-component" data-id="cache">Page Cache</div>
            </div>
            
            <div class="arch-flow internal">
              <span class="arch-icon">⬇</span>
              <span>mmap / fsync</span>
            </div>

            <div class="arch-box storage" data-id="storage">LMDB / Disk</div>
          </div>
        </div>

        <!-- Code Side -->
        <div class="code-window fade-in-section">
          <div class="code-header">
            <div class="code-dots"><span></span><span></span><span></span></div>
            <div class="code-title">src/main.rs</div>
          </div>
          <pre is:raw><code><span class="keyword">use</span> varvedb::{Varve, StreamId};

<span class="keyword">fn</span> <span class="function">main</span>() -> <span class="type">Result</span><(), <span class="type">Error</span>> {
<span class="code-line" data-related-id="varvedb">  <span class="comment">// Initialize the event store</span></span>
<span class="code-line" data-related-id="varvedb">  <span class="keyword">let</span> <span class="keyword">mut</span> varve = <span class="type">Varve</span>::<span class="function">new</span>(<span class="string">"./data"</span>)?;</span>

<span class="code-line" data-related-id="stream">  <span class="comment">// Create a typed stream</span></span>
<span class="code-line" data-related-id="stream">  <span class="keyword">let</span> <span class="keyword">mut</span> stream = varve.<span class="function">stream</span>::<<span class="type">Event</span>, <span class="number">256</span>>(<span class="string">"orders"</span>)?;</span>

<span class="code-line" data-related-id="stream">  <span class="comment">// Append events (zero-copy on read)</span></span>
<span class="code-line" data-related-id="stream">  <span class="keyword">let</span> (seq, _) = stream.<span class="function">append</span>(<span class="type">StreamId</span>(<span class="number">1</span>), &event)?;</span>

<span class="code-line" data-related-id="indexer">  <span class="comment">// Read back instantly</span></span>
<span class="code-line" data-related-id="indexer">  <span class="keyword">let</span> bytes = stream.<span class="function">get_bytes</span>(<span class="type">StreamId</span>(<span class="number">1</span>), seq)?;</span>

  <span class="keyword">Ok</span>(())
}</code></pre>
        </div>
      </div>
    </div>
  </section>
</BaseLayout>

<script>
  import { initHero3D } from '../js/hero-3d.js';

  // Initialize 3D Hero
  initHero3D();

  // Simple intersection observer for fade-in animations
  const observerOptions = {
    root: null,
    rootMargin: '0px',
    threshold: 0.1
  };

  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        entry.target.classList.add('visible');
      }
    });
  }, observerOptions);

  document.querySelectorAll('.fade-in-section').forEach(el => observer.observe(el));

  // Copy to clipboard
  const copyBtn = document.querySelector('.copy-btn');
  if (copyBtn) {
    copyBtn.addEventListener('click', () => {
      navigator.clipboard.writeText('cargo add varvedb');
      
      const originalIcon = copyBtn.innerHTML;
      copyBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
      
      setTimeout(() => {
        copyBtn.innerHTML = originalIcon;
      }, 2000);
    });
  }

  // Interactive Diagram
  const components = document.querySelectorAll('.arch-component, .arch-box');
  const codeLines = document.querySelectorAll('.code-line');

  components.forEach(comp => {
    comp.addEventListener('mouseenter', (e) => {
      e.stopPropagation();
      
      const id = comp.getAttribute('data-id');
      if (!id) return;
      
      // Determine highlight color
      let color = '#38bdf8'; // Default Cyan
      if (comp.classList.contains('storage')) color = '#fbbf24'; // Yellow
      
      // Set CSS variable for highlight color
      document.documentElement.style.setProperty('--highlight-color', color);

      // Highlight Diagram Components
      components.forEach(c => {
        c.classList.remove('highlight', 'dim'); // Reset state
        
        if (c === comp || c.getAttribute('data-id') === id) {
          c.classList.add('highlight');
        } else if (c.contains(comp)) {
          // If this component contains the hovered one (e.g. Engine contains Stream),
          // do NOT dim it, but don't highlight it either.
          // This ensures the parent doesn't fade out, which would fade out the child too.
        } else {
          c.classList.add('dim');
        }
      });

      // Highlight Code Lines
      codeLines.forEach(line => {
        line.classList.remove('highlight', 'dim'); // Reset state
        if (line.getAttribute('data-related-id') === id) {
          line.classList.add('highlight');
        } else {
          line.classList.add('dim');
        }
      });
    });

    comp.addEventListener('mouseleave', () => {
      // Reset Diagram
      components.forEach(c => {
        c.classList.remove('highlight', 'dim');
      });

      // Reset Code
      codeLines.forEach(line => {
        line.classList.remove('highlight', 'dim');
      });
    });
  });
</script>