Files
vdm/daemon/src/store/segments.hpp
T
samiandClaude Sonnet 5 a967eca669 daemon: persist engine progress/probe to the store — segments:0 no longer leaks
Engine numbers never reached the store: download.get after a correctly-finished
download reported sizeBytes: null, downloadedBytes: 0, speedBps: 0, resumable:
false, segments: 0, segmentDetail: [] — segments: 0 breaks the frozen contract
(TaskSummary.segments is minimum:1, required).

- Scheduler::tick() now probes (EnginePort::probe) before every start(), persisting
  sizeBytes/resumable/validators via Tasks::set_probe_result before a byte moves,
  then starts the engine with that ProbeResult as probe_hint.
- Scheduler::persist_progress() (new) writes downloadedBytes/speedBps/segments/
  segmentDetail from the engine's Progress. Called from progress_snapshot() (the
  250ms tick) *and* once more from on_engine_state right before release()/unmap on
  every terminal transition, so a task that finishes between two ticks — the common
  case for anything small or fast — still leaves real numbers instead of the
  pre-persistence defaults.
- TaskSummary.segments is sourced from segments.size() when the task has any
  (matching what actually lands in segmentDetail, per the schema's "exactly
  segments entries"), falling back to the engine's effective_segments (budget
  slots *held*, not necessarily physical range count) only pre-segmentation.
- Tasks::set_final_bytes tops up on_finished's byte count as a last-resort
  backstop.
- store/segments.{cpp,hpp}: read/write access to the segments table behind
  TaskDetail.segmentDetail. Wired into daemon/CMakeLists.txt.
- migrations/0002: speed_bps on tasks and segments; fixes segments.state's CHECK
  to include 'pending' (0001 omitted it, so a pre-connect snapshot could never be
  written).
- store_migrations_test's forward-only loop faked "released version N" by setting
  the user_version pragma alone, with no real schema underneath — never exercised
  until 0002 existed. Fixed to actually build the db through migrations 1..N first.

Verified against real veloxd + tools/testserver (not just unit tests):
download.list/download.get correct immediately after completion and after a
daemon restart, with saveTo.allowedRoots pointed at an isolated dir.

Observed but not fixed (CORE, not this lane, noted in deferrals.md): Progress.
speed_bps reads back 0 for the whole lifetime of a live throttled download in the
same E2E check, despite downloadedBytes visibly advancing. DAEMON passes it
through unmodified; filed rather than worked around.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GRDjHGgpYmMoPE2UFbe7pP
2026-09-11 12:11:19 +04:00

46 lines
1.4 KiB
C++

#pragma once
// Read/write access to the `segments` table — the per-connection detail behind
// TaskDetail.segmentDetail (download.get) and the segment-bars widget. Written from an
// engine progress tick (Scheduler::progress_snapshot); read back on download.get.
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
#include "store/sqlite.hpp"
#include "velox_proto.hpp"
namespace velox::daemon::store {
// One segment's live counters, as read off vdm::task::SegmentProgress. `state` is a wire
// SegmentState spelling ("pending"/"connecting"/.../"failed") — the caller maps the
// engine's own enum, this module stays generic like the others.
struct SegmentSnapshot {
std::uint32_t index;
std::int64_t start_byte;
std::int64_t end_byte; // inclusive (ADR 0010)
std::int64_t completed_bytes;
std::int64_t speed_bps;
std::string state;
};
class Segments {
public:
explicit Segments(Db& db) : db_(db) {}
// Replaces every row for `task_id` with `segs` in one transaction. Simpler than a
// per-index upsert and cheap at <=32 rows, <=4 Hz.
DbResult<void> replace_all(std::string_view task_id, const std::vector<SegmentSnapshot>& segs);
// In index order. Empty if the task has never been segmented (TaskDetail's own
// description permits this).
DbResult<std::vector<velox::proto::Segment>> list(std::string_view task_id);
private:
Db& db_;
};
} // namespace velox::daemon::store