Skip to content

feat: query-on-zoom for stored session viewer #459

@tylerkron

Description

@tylerkron

Problem

When viewing stored logging sessions with large datasets (e.g., 48 hours at 1000hz = 172M+ samples per channel), the app loads all samples into memory before rendering. This doesn't scale — it causes excessive memory usage and slow load times.

After #457 and #458, the app decimates and displays a minimap overview, but still loads everything into memory first.

Goal

  • Initial load: Stream through DB rows once, building a low-resolution overview without holding all data in memory
  • Zoom in: Re-query the DB for only the visible time window, LTTB-decimate to ~5000 points — full fidelity in small windows (e.g., 5 seconds of a 48-hour session shows all 5000 data points)
  • Memory stays bounded regardless of session size

Prior work

Implementation plan

1. Add composite DB index

Add (LoggingSessionID, TimestampTicks) index to DataSamples for efficient range queries. Use CREATE INDEX IF NOT EXISTS since the app uses Database.EnsureCreated(). If index creation fails, log a warning and continue — queries still work, just slower.

2. New SessionDataService

DB query abstraction using IDbContextFactory<LoggingContext>:

  • GetChannelMetadata(sessionId) — distinct channels with color/type
  • GetSessionBounds(sessionId) — total count, min/max ticks
  • StreamSamples(sessionId)IEnumerable via AsEnumerable() for streaming (no ToList())
  • QueryTimeWindow(sessionId, minTicks, maxTicks, CancellationToken) — range query for zoom

Failed zoom queries should log the error and keep displaying current data — not crash.

3. New StreamingOverviewBuilder

Fed row-by-row during initial streaming pass, accumulates in bounded memory:

  • 800-bucket MinMax per channel for minimap (~1600 points)
  • Every-Nth-sample pre-filter → LTTB to 5000 points for main plot overview

4. Rewrite DisplayLoggingSession

  • Small sessions (< 50K total samples across all channels): Load directly as today
  • Large sessions: Stream once through StreamingOverviewBuilder, populate minimap + main plot from builder output. Eliminates _allSessionPoints.

5. Debounced zoom re-query

Extend OnMainTimeAxisChanged (from #458):

  • 200ms debounce timer on axis changes
  • Convert visible range (ms) back to ticks
  • Query visible window via SessionDataService.QueryTimeWindow()
  • LTTB-decimate result to 5000 points per channel
  • Cancel stale queries via CancellationTokenSource — dispose previous CTS when creating a new one on each zoom

6. Reset zoom → instant overview

Use cached overview data immediately, no DB query needed.

Acceptance criteria

  • 1M+ sample session loads quickly with bounded memory
  • Zooming into a 5-second window of a large session shows ~5000 points at full resolution
  • Minimap interaction (drag/resize) triggers zoom re-query
  • Reset zoom instantly restores overview
  • Rapid mouse-wheel zoom debounces correctly (no UI freeze)
  • Small sessions (< 50K samples) still load normally
  • Unit tests for StreamingOverviewBuilder and SessionDataService

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions