# win-numa-sys
Memory-safe Rust over the Windows NUMA APIs.
Windows provides some NUMA concepts; this crate builds library notions on top of them. Whether a
client uses them is up to the client.
## What is here
- **`NumaNode`** -- a node number, as Windows numbers them. A newtype because a node *number* and a
*count* of nodes are both small integers and are trivially swapped at a call site.
- **`NumaBuffer`** -- an owned allocation made with `VirtualAllocExNuma` and released with
`VirtualFree`, so a buffer can be placed on a chosen node rather than wherever the default
allocator lands it.
- **`highest_numa_node()`** and **`volume_numa_node(handle)`** -- the two questions Windows will
answer about nodes, wrapped so a caller can find a node to pass without writing the FFI.
## What is not here, and will not be
**Any opinion about which node anything should use.** This crate reports what Windows says and
allocates where it is told. It does not map a file to a node, does not shard anything, and does not
choose a node on a caller's behalf.
The `-sys` suffix is that promise. In this workspace the suffix means thin over Win32, memory-safe,
adding no policy -- see the repository's
[DESIGN-NOTES.md](../../DESIGN-NOTES.md#the-waitable-queues-crate-is-named-plural-and-carries-no-sys-suffix),
where a sibling crate drops the suffix for failing exactly that test.
## The name
The first crate here to take `win-` rather than `windows-`. `windows` is Microsoft's namespace, and
a crate published as `windows-numa-sys` today is a name they may reasonably want tomorrow; see
[DESIGN-NOTES.md](../../DESIGN-NOTES.md#new-crates-take-the-win-prefix). Existing crates keep their
names for now.
## A node argument is a preference, not an instruction
`VirtualAllocExNuma`'s parameter is `nndPreferred`, and the name is the contract. A successful
allocation is **not** evidence that the pages landed on the node that was asked for. Two things
follow, both of which have already caught someone in this workspace:
- Committed pages are demand-zero, so until something writes to them no physical page has been drawn
from the preferred node at all. Measuring placement means faulting the pages in first.
- An *invalid* node is refused -- but `u32::MAX` is not a test of that, because it is the API's own
no-preference sentinel and is accepted by design. A measurement that asks for `u32::MAX` and sees
it succeed has measured the sentinel, not a range check.
Observing where pages actually landed needs `QueryWorkingSetEx`, which lives in
`windows-placement-probe` today; whether it moves here is [CHECKLIST.md](CHECKLIST.md) `N-1.2`.
## Buffer traits
`NumaBuffer` implements `io-buffers`' `IoBuf` and `IoBufMut`, so a ring takes it as a buffer as it
is. This crate defines no buffer trait of its own: the traits belong to `io-buffers`, which is
portable and so cannot depend on a Windows allocator, and the orphan rule lets only the crate that
owns the trait or the type implement it, which is why the implementations are here.
A crate that owns a buffer trait of its own implements it for `NumaBuffer` the same way, over the
inherent `as_ptr`, `as_mut_ptr` and `len`. See [DESIGN-NOTES.md](DESIGN-NOTES.md) `N-D-2`.