File size: 4,932 Bytes
4e23b01
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// src/stats.ts
//
// The MiniDb stats object (observability counters) as a factory: same shape
// and initial values as the historical inline literal, shared by reference
// with every facet's structural subset view.

/** Create the MiniDb stats object (all counters zeroed). */
export function createMiniDbStats() {
  return {

    compactions: 0,
    compactErrors: 0,
    walBytesWritten: 0,
    walFsyncs: 0,
    /** Failed writev-class attempts on the WAL write path. Each one poisons
     *  the WAL and triggers an in-place recovery (truncate + resume). */
    walWriteErrors: 0,
    /** Failed fsync attempts; a background everysec failure never rejects a
     *  write — it surfaces only here and in lastWalFsyncError. A write-path
     *  ('always') fsync failure rejects its batch and poisons the WAL. */
    walFsyncErrors: 0,
    /** Sticky copy of the most recent fsync failure (never cleared). */
    lastWalFsyncError: null as unknown,
    /** Bytes currently queued in the live WAL's in-memory append buffer. */
    walQueuedBytes: 0,
    /** High-water mark of walQueuedBytes. */
    walMaxQueuedBytes: 0,
    /** WAL group commits (one per flushed batch) and the frames they carried. */
    walGroupCommits: 0,
    walGroupCommitFrames: 0,
    snapshotBytesWritten: 0,
    evictions: 0,
    maxMemoryRejections: 0,
    queryIndexHits: 0,
    // ---- lifecycle phase metrics (cumulative wall-clock ms / counts) ----
    /** Bytes and frames recovery scanned at open (snapshot + WAL). */
    recoveryBytes: 0,
    recoveryFrames: 0,
    recoveryDurationMs: 0,
    /** Open-time derived-index rebuilds (secondary + dt + compound). */
    indexRebuildDurationMs: 0,
    /** Values decoded by the open-time shared rebuild walk (0 when no
     *  value-derived index exists: the walk is metadata-only then). */
    indexRebuildDecoded: 0,
    /** Text-index (re)builds: at open and after each compaction. */
    textRebuildDurationMs: 0,
    /** Whole successful compactions, hook included. */
    compactionDurationMs: 0,
    /** The non-blocking snapshot phase of compaction. */
    compactionSnapshotDurationMs: 0,
    /** The rotation critical section of compaction (writes park meanwhile). */
    compactionRotationDurationMs: 0,
    /** Text-postings rebuild after a compaction rotation. */
    compactionPostingsDurationMs: 0,
    /** Cumulative time write ops spent parked on a compaction rotation. */
    compactionRotationPauseMs: 0,
    /** Set once a rotation's directory fsync reported EINVAL/ENOTSUP: this
     *  platform cannot make renames durable via the directory, so rotation
     *  durability is knowingly degraded (warned once), never silently. */
    dirFsyncUnsupported: false,
    /** Candidate keys iterated / values decoded / rows fed to a sort in query(). */
    queryCandidates: 0,
    queryDecoded: 0,
    querySortedRows: 0,
    // ---- persistent index generations (stage 5) ----
    /** Successful generation builds (published under generations/ + CURRENT). */
    generationBuilds: 0,
    /** Builds that failed with a real error (I/O, corruption). */
    generationBuildErrors: 0,
    /** Builds discarded because the ground shifted under them (rotation, WAL
     *  rollback, queue overflow, close) — expected churn, not an error. */
    generationBuildAborts: 0,
    generationBuildDurationMs: 0,
    /** Opens served by a published generation (no full index rebuild). */
    generationLoads: 0,
    /** Opens that fell back to the legacy full recovery (no/invalid
     *  generation); the sticky reason is in lastGenerationFallback. */
    generationLoadFallbacks: 0,
    lastGenerationFallback: null as string | null,
    generationLoadDurationMs: 0,
    /** Individual index images rejected at generation load (definition hash
     *  mismatch, corrupt file) and rebuilt from the loaded store. */
    generationIndexRebuilds: 0,
    // ---- stage 6: workerized maintenance ----
    /** Successful bounded text builds actually hosted by a worker thread. */
    textWorkerBuilds: 0,
    /** Bounded text builds hosted inline because worker startup was unavailable. */
    textWorkerFallbacks: 0,
    /** Sticky reason for the most recent inline fallback. */
    lastTextWorkerFallback: null as string | null,
    /** Worker runs that failed after the ready handshake (crash/OOM/ENOSPC).
     *  Expected owner/shutdown cancellation is not an error. */
    textWorkerErrors: 0,
    /** Deferred open-time text base builds (no-generation fallback path):
     *  bases committed by the background maintenance task, and builds that
     *  finally failed after every retry (their indexes keep raising
     *  TextIndexBuildingError until a later build attaches a base). */
    textDeferredBuilds: 0,
    textDeferredBuildErrors: 0,
  };
}

/** The MiniDb stats object shape (all facets take structural subsets). */
export type MiniDbStats = ReturnType<typeof createMiniDbStats>;