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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Concurrent index build coordination.
//!
//! Concurrent `DEFINE INDEX` can run asynchronously while user writes continue.
//! In a multi-node deployment every node must make the same decisions about
//! which builder owns the work, whether writers should queue mutations, and
//! when queries may use the index. This module keeps those decisions in durable
//! table-scoped keys instead of process-local memory.
//!
//! The durable protocol uses four key families:
//!
//! - `!bs`: one build-state record per index, including phase, owner, generation, report counters,
//! the initial-scan continuation checkpoint, and error reason.
//! - `!bg`: generation-scoped queued mutations that the builder replays.
//! - `!bp`: per-record pointers to the first queued mutation seen during the initial scan, so the
//! scan indexes the writer-observed old state.
//! - `!br`: writer reservations that keep `Closing` from publishing `Online` until every admitted
//! writer has either committed its `!bg` entry, released its ticket after transaction close, or
//! died.
//!
//! Generation numbers fence stale queued work. Builder owner heartbeats fence
//! stale builders. Query planning only sees durable-`Online` indexes, while
//! document writes still see building indexes so they can enqueue mutations.
//! A build in durable `Error` keeps admitting writes the same way, so a failed
//! background build never blocks user writes: the errored generation's queue
//! is never replayed — `REBUILD INDEX` wipes it and rescans the table.
//! Legacy `!ig`/`!ip` appendings are still drained for committed work from older
//! code paths, but new writes use the durable queue.
use Duration;
pub use ;
pub use ;
pub use ;
use crateIndexBuildReservationRelease;
/// Monotonically increasing build epoch for a table index.
///
/// Durable appendings, primary appending sentinels, and reservations all carry
/// this value so a replacement build never consumes work left behind by an
/// older build attempt.
pub type BuildGeneration = u64;
/// Per-generation ordering token assigned to a writer admitted during a build.
///
/// A single user transaction reserves one `BuildTicket` per index it writes to;
/// every indexed mutation in that transaction shares the ticket and is
/// disambiguated by `BuildTicketMutationSeq`.
pub type BuildTicket = u64;
/// Per-ticket index of an admitted mutation, distinguishing the different
/// `!bg` entries that share the same `(generation, ticket)` reservation.
///
/// The first mutation in a user transaction's batch uses `0`; subsequent
/// mutations use `1`, `2`, ... A `u32` gives a per-user-transaction cap of
/// ~4.3B mutations per index, which is well above any realistic single-txn
/// indexed write count.
pub type BuildTicketMutationSeq = u32;
/// How long a writer admission reservation is considered owned by the writer.
const BUILD_RESERVATION_TTL_SECS: i64 = 30;
/// How long a builder may go without heartbeating its durable state before
/// another builder may take ownership of the same generation. This assumes
/// bounded clock skew between nodes; ownership transitions are still fenced by
/// CAS on `(generation, owner)`, so a stale owner cannot publish progress after
/// takeover.
const BUILD_OWNER_LEASE_SECS: i64 = 60;
/// Poll cadence while writer admission waits for `Closing` to become `Online`
/// or `Error`. The caller's context deadline is the only timeout budget.
const BUILD_CLOSING_SLEEP: Duration = from_millis;
type IndexBuilding = Arc;
pub
pub type BatchId = u32;
pub type AppendingId = u32;
const LEGACY_BATCH_ID: BatchId = 0;