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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//! Caller-owned scan cursors with lock-free per-batch advance.
//!
//! Each cursor handle (`RocksDbKeysCursor` / `RocksDbValsCursor`) owns
//! its iteration state directly — there is no per-transaction map and no
//! per-batch mutex acquisition on the hot path. The cursor's
//! `next_batch` advances the iterator inline; the only synchronisation
//! is a `Transaction::done` atomic load at entry (SeqCst) so cursors
//! bail cleanly if the transaction is being committed/cancelled.
//!
//! Each `next_batch` returns a [`KeysBatch`] / [`ValsBatch`] borrowing
//! from the cursor's own internal buffer for the duration of the
//! `&mut self` borrow. One allocation per batch (the result `Vec<&[u8]>`);
//! the buffer itself is reused across batches. Per-item heap allocations
//! are zero.
//!
//! # Lifetime
//!
//! The handle's `'tx` lifetime is the borrow into the parent
//! `Transaction`. Cursors cannot outlive the transaction at the type
//! level. The iterator inside `ScanState` is `'static`-erased (same
//! pattern as `TransactionInner`'s `tx`/`snapshot`) because Rust can't
//! express the self-referential borrow into the boxed
//! `rocksdb::Transaction` or `Pin<Arc<DB>>` without a helper crate.
//!
//! # Safety vs commit/cancel
//!
//! `commit`/`cancel` need to drop the snapshot (and, for writable
//! transactions, consume the boxed `rocksdb::Transaction`) before any
//! cursor's iterator destructor runs — RocksDB's
//! `rocksdb_iter_destroy` decrements the parent's internal refcount, so
//! freeing it on a dropped parent is use-after-free.
//!
//! Two invariants close that race:
//!
//! 1. `Transaction::cursors_alive` counts live cursors. `open_*_cursor` increments after passing
//! the `done` check (SeqCst); the cursor's drop guard decrements (Release).
//! 2. `commit`/`cancel` set `done = true` (SeqCst), then `yield_now`-loop until `cursors_alive ==
//! 0` (SeqCst) before consuming `inner`. With SeqCst on both atomics, a cursor that successfully
//! passes its `done` check has its `cursors_alive` increment globally ordered before commit's
//! load, so commit will wait for it. Conversely, a cursor that opens after commit's `done` store
//! sees `done == true` and aborts before allocating its iterator.
//!
//! # Drop ordering on the cursor handle
//!
//! The cursor handle is laid out as:
//!
//! ```text
//! struct RocksDbKeysCursor<'tx> {
//! tx: &'tx Transaction,
//! state: ScanState, // contains iter + reusable buffers
//! _alive_guard: AliveGuard, // decrements cursors_alive on drop
//! }
//! ```
//!
//! Fields drop in declaration order (Rust reference). So on cursor
//! drop: `tx` (no-op), then `state` (iterator destroyed, snapshot
//! refcount decremented while parent still alive), then `_alive_guard`
//! (counter decrement → unblocks commit's drain). The iterator is
//! destroyed **before** commit is allowed to proceed; commit can then
//! safely drop the snapshot.
use Ordering;
use ;
use ;
use crateKey;
use crate;
use crateResult;
/// Which underlying object the iterator borrows from. Decided at open
/// time by whether the transaction is writable: writable scans iterate
/// on the rocksdb `Transaction` so pending writes in the same logical
/// tx are visible (via `BaseDeltaIterator`); read-only scans iterate on
/// the underlying database directly, which avoids the BaseDeltaIterator
/// wrapper.
pub
/// Per-keys-cursor state. Owned directly by `RocksDbKeysCursor` — no
/// per-transaction map, no per-batch lock lookup.
///
/// Visibility is `pub(in crate::kvs)` so the `cursor_*` helpers in
/// `mod.rs` can reference it in their signatures.
pub
/// Per-vals-cursor state. See [`ScanStateKeys`].
pub
/// RAII guard that decrements `Transaction::cursors_alive` on drop.
/// Declared as the **last** field of each cursor handle so it drops
/// **after** the iterator (declared earlier in the struct) — see the
/// module-level comment for why ordering matters.
pub
/// Caller-owned handle for a keys-only scan.
///
/// Field order is load-bearing (see module-level comment): `tx` first
/// (no-op drop), `state` second (drops the iterator while parent
/// snapshot is still alive), `_alive_guard` last (decrement signals
/// `commit`/`cancel` that this cursor has finished tearing down).
pub
/// Caller-owned handle for a key+value scan. See [`RocksDbKeysCursor`].
pub