Skip to content

Commit bf0a314

Browse files
committed
Order NextItem subquery results predictably
- Fixes #5055 - Add a new column, `index` to the `NextItem` subquery, which indexes the shifts from 0..n. - Add an `ORDER BY index` clause to guarantee order. - Add test Ensure MAC address shift is correct Simplify MAC shift logic Clippy, and remove local env files Review feedback
1 parent 475fb62 commit bf0a314

File tree

4 files changed

+331
-54
lines changed

4 files changed

+331
-54
lines changed

nexus/db-queries/src/db/queries/disk.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,12 @@ struct NextDiskSlot {
4646

4747
impl NextDiskSlot {
4848
fn new(instance_id: Uuid) -> Self {
49-
let generator = DefaultShiftGenerator {
50-
base: 0,
51-
max_shift: i64::try_from(MAX_DISKS_PER_INSTANCE).unwrap(),
52-
min_shift: 0,
53-
};
49+
let generator = DefaultShiftGenerator::new(
50+
0,
51+
i64::try_from(MAX_DISKS_PER_INSTANCE).unwrap(),
52+
0,
53+
)
54+
.expect("invalid min/max shift");
5455
Self { inner: NextItem::new_scoped(generator, instance_id) }
5556
}
5657
}

nexus/db-queries/src/db/queries/network_interface.rs

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,8 @@ impl NextIpv4Address {
516516
let subnet = IpNetwork::from(subnet);
517517
let net = IpNetwork::from(first_available_address(&subnet));
518518
let max_shift = i64::from(last_address_offset(&subnet));
519-
let generator =
520-
DefaultShiftGenerator { base: net, max_shift, min_shift: 0 };
519+
let generator = DefaultShiftGenerator::new(net, max_shift, 0)
520+
.expect("invalid min/max shift");
521521
Self { inner: NextItem::new_scoped(generator, subnet_id) }
522522
}
523523
}
@@ -575,12 +575,13 @@ pub struct NextNicSlot {
575575

576576
impl NextNicSlot {
577577
pub fn new(parent_id: Uuid) -> Self {
578-
let generator = DefaultShiftGenerator {
579-
base: 0,
580-
max_shift: i64::try_from(MAX_NICS_PER_INSTANCE)
578+
let generator = DefaultShiftGenerator::new(
579+
0,
580+
i64::try_from(MAX_NICS_PER_INSTANCE)
581581
.expect("Too many network interfaces"),
582-
min_shift: 0,
583-
};
582+
0,
583+
)
584+
.expect("invalid min/max shift");
584585
Self { inner: NextItem::new_scoped(generator, parent_id) }
585586
}
586587
}
@@ -607,25 +608,62 @@ pub struct NextMacAddress {
607608
>,
608609
}
609610

611+
// Helper to ensure we correctly compute the min/max shifts for a next MAC
612+
// query.
613+
#[derive(Copy, Clone, Debug)]
614+
struct NextMacShifts {
615+
base: MacAddr,
616+
min_shift: i64,
617+
max_shift: i64,
618+
}
619+
620+
impl NextMacShifts {
621+
fn for_guest() -> Self {
622+
let base = MacAddr::random_guest();
623+
Self::shifts_for(base, MacAddr::MIN_GUEST_ADDR, MacAddr::MAX_GUEST_ADDR)
624+
}
625+
626+
fn for_system() -> NextMacShifts {
627+
let base = MacAddr::random_system();
628+
Self::shifts_for(
629+
base,
630+
MacAddr::MIN_SYSTEM_ADDR,
631+
MacAddr::MAX_SYSTEM_ADDR,
632+
)
633+
}
634+
635+
fn shifts_for(base: MacAddr, min: i64, max: i64) -> NextMacShifts {
636+
let x = base.to_i64();
637+
638+
// The max shift is the distance to the last value. This min shift is
639+
// always expressed as a negative number, giving the largest leftward
640+
// shift, i.e., the distance to the first value.
641+
let max_shift = max - x;
642+
let min_shift = min - x;
643+
Self { base, min_shift, max_shift }
644+
}
645+
}
646+
610647
impl NextMacAddress {
611648
pub fn new(vpc_id: Uuid, kind: NetworkInterfaceKind) -> Self {
612649
let (base, max_shift, min_shift) = match kind {
613650
NetworkInterfaceKind::Instance => {
614-
let base = MacAddr::random_guest();
615-
let x = base.to_i64();
616-
let max_shift = MacAddr::MAX_GUEST_ADDR - x;
617-
let min_shift = x - MacAddr::MIN_GUEST_ADDR;
651+
let NextMacShifts { base, min_shift, max_shift } =
652+
NextMacShifts::for_guest();
618653
(base.into(), max_shift, min_shift)
619654
}
620655
NetworkInterfaceKind::Service => {
621-
let base = MacAddr::random_system();
622-
let x = base.to_i64();
623-
let max_shift = MacAddr::MAX_SYSTEM_ADDR - x;
624-
let min_shift = x - MacAddr::MAX_SYSTEM_ADDR;
656+
let NextMacShifts { base, min_shift, max_shift } =
657+
NextMacShifts::for_system();
625658
(base.into(), max_shift, min_shift)
626659
}
627660
};
628-
let generator = DefaultShiftGenerator { base, max_shift, min_shift };
661+
let generator = DefaultShiftGenerator::new(base, max_shift, min_shift)
662+
.unwrap_or_else(|| {
663+
panic!(
664+
"invalid min shift ({min_shift}) or max_shift ({max_shift})"
665+
)
666+
});
629667
Self { inner: NextItem::new_scoped(generator, vpc_id) }
630668
}
631669
}
@@ -1713,6 +1751,7 @@ mod tests {
17131751
use crate::db::model::NetworkInterface;
17141752
use crate::db::model::Project;
17151753
use crate::db::model::VpcSubnet;
1754+
use crate::db::queries::network_interface::NextMacShifts;
17161755
use async_bb8_diesel::AsyncRunQueryDsl;
17171756
use dropshot::test_util::LogContext;
17181757
use ipnetwork::Ipv4Network;
@@ -2801,4 +2840,37 @@ mod tests {
28012840
"fd00::5".parse::<IpAddr>().unwrap(),
28022841
);
28032842
}
2843+
2844+
#[test]
2845+
fn test_next_mac_shifts_for_system() {
2846+
let NextMacShifts { base, min_shift, max_shift } =
2847+
NextMacShifts::for_system();
2848+
assert!(base.is_system());
2849+
assert!(
2850+
min_shift <= 0,
2851+
"expected min shift to be negative, found {min_shift}"
2852+
);
2853+
assert!(max_shift >= 0, "found {max_shift}");
2854+
let x = base.to_i64();
2855+
assert_eq!(x + min_shift, MacAddr::MIN_SYSTEM_ADDR);
2856+
assert_eq!(x + max_shift, MacAddr::MAX_SYSTEM_ADDR);
2857+
}
2858+
2859+
#[test]
2860+
fn test_next_mac_shifts_for_guest() {
2861+
let NextMacShifts { base, min_shift, max_shift } =
2862+
NextMacShifts::for_guest();
2863+
assert!(base.is_guest());
2864+
assert!(
2865+
min_shift <= 0,
2866+
"expected min shift to be negative, found {min_shift}"
2867+
);
2868+
assert!(
2869+
max_shift >= 0,
2870+
"expected max shift to be positive, found {max_shift}"
2871+
);
2872+
let x = base.to_i64();
2873+
assert_eq!(x + min_shift, MacAddr::MIN_GUEST_ADDR);
2874+
assert_eq!(x + max_shift, MacAddr::MAX_GUEST_ADDR);
2875+
}
28042876
}

0 commit comments

Comments
 (0)