perf: batch NIO dispatch on project open (one HTTP per compute)

Project open used to create each link by issuing two NIO POSTs from the
controller to the compute — ~5000 HTTP round-trips for a 2500-link
topology, all funnelling through the single shared controller/compute
event loop and capping throughput near 12 links/s.

Replace it with a bulk path:
- UDPLink split into _prepare() (local: ports, peer addrs, link_data)
  and _commit_nios() (dispatch). create() = prepare + commit (interactive).
- Link.add_node gains batch=True: attach both nodes without triggering
  per-link NIO HTTP.
- compute: new POST /projects/{id}/nios/batch endpoint with a unified
  _add_nio_binding dispatch across node types (docker/qemu/iou/vpcs/
  builtin differ in signature).
- project.open: prepare all links locally, group NIO entries by compute,
  send each compute a single /nios/batch, then finalise (wire node/port
  refs, mark created, notify, apply marker defs) in parallel.

Cuts controller->compute HTTP from O(links) to O(computes). Test added
for the batch endpoint.
This commit is contained in:
YueGuobin committed 2026-08-10 23:42:50 +08:00
1 parent 96d4d82716
commit 38c49a655c
7 files changed
+280 -29

No files matched your search

+5 -2
View File
@@ -257,11 +257,14 @@ class Link:
"""
return self._created
async def add_node(self, node, adapter_number, port_number, label=None, dump=True):
async def add_node(self, node, adapter_number, port_number, label=None, dump=True, batch=False):
"""
Add a node to the link
:param dump: Dump project on disk
:param batch: When True, do not create the link on the computes once
both nodes are attached — the caller drives creation via the
project-open bulk path. Used to avoid one HTTP round-trip per link.
"""
port = node.get_port(adapter_number, port_number)
@@ -305,7 +308,7 @@ class Link:
{"node": node, "adapter_number": adapter_number, "port_number": port_number, "port": port, "label": label}
)
if len(self._nodes) == 2:
if len(self._nodes) == 2 and not batch:
await self.create()
for n in self._nodes:
n["node"].add_link(self)