This is an automated email from the ASF dual-hosted git repository.

hubcio pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new 92aee83c4 fix(server): skip NUMA memory binding on a single-node host 
(#4243)
92aee83c4 is described below

commit 92aee83c40f91fcc955e50ad5aaf8f3f6e07bfc9
Author: Justin Mclean <[email protected]>
AuthorDate: Mon Sep 21 16:27:52 2026 +1000

    fix(server): skip NUMA memory binding on a single-node host (#4243)
---
 core/server/src/shard_allocator.rs | 44 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/core/server/src/shard_allocator.rs 
b/core/server/src/shard_allocator.rs
index 606e64881..667b0fb36 100644
--- a/core/server/src/shard_allocator.rs
+++ b/core/server/src/shard_allocator.rs
@@ -100,7 +100,11 @@ impl NumaTopology {
     pub fn detect() -> Result<Self, ShardingError> {
         let topology =
             Topology::new().map_err(|e| ShardingError::TopologyDetection { 
msg: e.to_string() })?;
+        Self::from_topology(topology)
+    }
 
+    /// Split from [`Self::detect`] so tests can pass a synthetic topology.
+    fn from_topology(topology: Topology) -> Result<Self, ShardingError> {
         let numa_nodes: Vec<_> = 
topology.objects_with_type(NUMANode).collect();
 
         let node_count = numa_nodes.len();
@@ -481,6 +485,9 @@ impl ShardAllocator {
             numa.cores_per_node
         };
 
+        // Binding to the only node gains nothing, and some VMs reject it.
+        let pin_memory = topology.node_count > 1;
+
         let mut shard_infos = Vec::new();
 
         let node_cpus: Vec<Vec<usize>> = nodes
@@ -511,7 +518,7 @@ impl ShardAllocator {
             for cpu_id in cores_to_use {
                 shard_infos.push(ShardInfo {
                     cpu_set: HashSet::from([cpu_id]),
-                    numa_node: Some(node_id),
+                    numa_node: pin_memory.then_some(node_id),
                 });
             }
         }
@@ -600,6 +607,41 @@ mod tests {
         }
     }
 
+    fn synthetic_topology(description: &str) -> NumaTopology {
+        let topology = hwlocality::topology::builder::TopologyBuilder::new()
+            .from_synthetic(description)
+            .expect("valid synthetic description")
+            .build()
+            .expect("synthetic topology builds");
+        NumaTopology::from_topology(topology).expect("synthetic topology has 
NUMA nodes")
+    }
+
+    #[test]
+    fn a_single_numa_node_is_not_bound() {
+        let topology = synthetic_topology("node:1 core:4 pu:1");
+        let shards =
+            ShardAllocator::compute_numa_assignments(&topology, 
&NumaConfig::default()).unwrap();
+
+        assert_eq!(shards.len(), 4);
+        assert!(
+            shards.iter().all(|shard| shard.numa_node.is_none()),
+            "a single-node topology must not pin shard memory"
+        );
+    }
+
+    #[test]
+    fn several_numa_nodes_are_still_bound() {
+        let topology = synthetic_topology("node:2 core:2 pu:1");
+        let shards =
+            ShardAllocator::compute_numa_assignments(&topology, 
&NumaConfig::default()).unwrap();
+
+        assert_eq!(shards.len(), 4);
+        assert!(
+            shards.iter().all(|shard| shard.numa_node.is_some()),
+            "a multi-node topology must keep pinning shard memory"
+        );
+    }
+
     #[test]
     fn bind_cpu_with_empty_set_is_a_no_op() {
         let shard = ShardInfo {

Reply via email to