cached_resolve_t expiration is overengineered
There are two misfeatures in the way we expire pending and cached DNS requests—maybe three.
We schedule expiration with a priority queue. That's probably over-engineered. Instead, we could just walk the hash table periodically and remove expired entries. If we choose an appropriate interval, we shouldn't lose too much CPU to walking the hash table.
We can't remove or re-order entries in the priority queue before they expire. That means that when a pending cached_resolve_t gets its answers/errors and becomes done, we don't currently remove it: instead we make a copy of it to represent the done cached_resolve_t, put that in the priority queue too, and wait for the pending one to expire on its own. How silly.
Pending DNS requests probably don't need to be scheduled for expiration at all: we already have timeout logic in evdns.c to ensure that a DNS request that doesn't complete will get treated as an error. I don't think we need a separate means to expire them.