cubelinux: CUBE_OP_RANGE — a region walk that seeks on the box's key span
The seventh operation: `cube(2)` gains CUBE_OP_RANGE, a bounded walk of one space's records that lie in a box. Its argument block is its own (`cube_range_args`, versioned by `size` like the walk's), and the box travels as its six numbers for the reason a coordinate does — the key it has to become is the driver's business. The operation rests on the span that the shared file already owns. `key_span(lo, hi)` bounds every key in the box because the interleave is monotone on each axis, so a v3 image is **sought**: the fixed-stride index is binary-searched for the span's foot (`Addressed::lower_bound`) and read forward to its head, merging the log's edits exactly as a walk does. A packed v1/v2 image has no index to search, so its space is walked with the same span used only to stop early — and the contract is the same either way, so a caller is not told which path it got. The trap that shaped the code, and the reason it is written the way it is: **the span is a bound, not the set.** Keys of points outside the box fall inside it (Z-order amplification), so every candidate is decoded and tested against the box before it is returned — which is what `morton_decode`, the interleave's inverse, is for, now in the shared file with the same kind of hand-pinned tests the interleave has. And the cursor counts the records *in the box*, not the records of the space, because those are the records the walk returns. The over-coverage — records examined versus records returned — is the number this operation is meant to publish, and it is not wired to the caller yet: the cost gate measures it by comparing against the userspace store, which counts the same thing.
This commit is contained in:
@@ -468,9 +468,29 @@ pub fn morton_key(x: u64, y: u64, z: u64) -> [u8; RAW_KEY_LEN] {
|
||||
k
|
||||
}
|
||||
|
||||
/// The point a key encodes — the inverse of [`morton_key`].
|
||||
///
|
||||
/// Bit `n` of the key is bit `n / 3` of axis `n % 3`, which is the interleave read backwards.
|
||||
///
|
||||
/// Why the kernel needs it: a region walk is handed a **key span**, not a set of keys. A span is a
|
||||
/// bound, not the set — keys of points *outside* the box also fall inside it (Z-order
|
||||
/// amplification) — so every candidate found in the span has to be turned back into a point and
|
||||
/// tested for membership. Without this, the walk would return records that are outside the region
|
||||
/// the caller asked for, which is exactly the mistake the span's own doc warns about.
|
||||
pub fn morton_decode(k: &[u8; RAW_KEY_LEN]) -> [u64; 3] {
|
||||
let mut out = [0u64; 3];
|
||||
let mut n = 0;
|
||||
while n < RAW_KEY_LEN * 8 {
|
||||
if k[RAW_KEY_LEN - 1 - (n / 8)] & (1 << (n % 8)) != 0 {
|
||||
out[n % 3] |= 1u64 << (n / 3);
|
||||
}
|
||||
n += 1;
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Compare two keys as the 192-bit numbers they are. `a < b` means `a` sorts first.
|
||||
pub fn key_cmp(a: &[u8; RAW_KEY_LEN], b: &[u8; RAW_KEY_LEN]) -> core::cmp::Ordering {
|
||||
let mut i = 0;
|
||||
pub fn key_cmp(a: &[u8; RAW_KEY_LEN], b: &[u8; RAW_KEY_LEN]) -> core::cmp::Ordering { let mut i = 0;
|
||||
while i < RAW_KEY_LEN {
|
||||
if a[i] != b[i] {
|
||||
return if a[i] < b[i] {
|
||||
|
||||
Reference in New Issue
Block a user