Skip to content

Directory re-registration resolves DNS on the thread that runs the mix #3934

Description

@mcfnord

🤖 AI: Every 15 minutes a registered server re-resolves its directory address on the thread that runs the mix, and the mix waits for the resolver.

SetRegistered() calls NetworkUtil::ParseNetworkAddress() inline, driven by a SERVLIST_REGIST_INTERV_MINUTES = 15 timer. CServer::OnTimer is serviced by the same thread — CHighPrecisionTimer reaches it through a queued connection — so no audio is mixed while the resolve is outstanding. QHostInfo::fromName blocks with no timeout of its own and pumps no events. The SRV attempt before it spins processEvents for up to DNS_SRV_RESOLVE_TIMEOUT_MS = 500 instead, and the last row below is that spin costing nothing: only fromName reaches the mix.

Two servers, one connected client each, registered to a directory answering SRR_REGISTERED through a stub resolver with a per-name latency. Each server's own maximum audio-timer lateness, in the record before its re-registration and the record covering it:

build resolver latency that server the other server, same run
unpatched 300 ms 87.0 -> 303.5 ms 218.8 -> 218.8 ms
unpatched 1500 ms 192.5 -> 1506.5 ms 150.5 -> 150.5 ms
unpatched 1500 ms 115.9 -> 1538.6 ms 164.0 -> 164.0 ms
patched 1500 ms 131.2 -> 131.2 ms 144.9 -> 154.0 ms
unpatched SRV timed out at 498 ms, A/AAAA instant 94.6 -> 94.6 ms 145.9 -> 145.9 ms

The patched build reuses the address resolved earlier for that directory string and refreshes it with an asynchronous QHostInfo::lookupHost. It still performed the lookup: the registration went out at 23:14:12.207Z and its answer arrived at 23:14:13.711Z. The first registration after startup still resolves inline, since nothing is cached yet.

In the third row the unstalled server was given -e <ip>:<port> rather than a hostname, with every name the stub resolver did not recognise also delayed 1500 ms; it registered on its 15-minute schedule and issued no DNS query at all. An address literal is a workaround where the directory address is stable.

The last row used a port-less address, the only form that reaches the SRV path; its own A/AAAA lookup answered instantly, so the 498 ms spent waiting for a deliberately unanswerable SRV record is all that row measures.

The refresh timer is not the only entry to this resolve. On a live server, SetDirectoryAddress() and SetDirectoryType() each call Unregister() then Register() — the old address is resolved, then the new one — reachable mid-session from the server GUI and from jamulusserver/setDirectory. Measured on a main build at this commit (3.12.5dev-c1ceb104), reading the server's own outbound packet stream with a client connected, old name at 300 ms and new name at 1500 ms: outbound audio halts for 301.6 ms, the unregister message leaves for the directory, and audio halts again for 1502.5 ms — 1.8 s of mix outage for one settings change. On quit it resolves once more, and the list manager's handler runs before the one that tells the clients: with a player still connected and --discononquit set, SIGTERM stops the mix and the next packet of any kind leaves at +1.506 s on the delayed server against +0.005 s on the control — the directory's unregister and the player's own CLDisconnection both waiting behind the resolver. A packet that needs no resolver leaves at +0.002 s on both. A cached address cannot remove the change-path stall, because the new directory string has no cached answer by construction.

Fix: resolve asynchronously and register when the answer arrives. Reusing the last resolved address (the patched build above) removes the periodic stall but not the change-path one.


🤖 This message was written by AI and reviewed by @mcfnord.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions