mirror of
https://github.com/hickory-dns/hickory-dns.git
synced 2026-04-25 03:05:51 +03:00
[GH-ISSUE #227] Synchronous resolver is not Send + Sync #402
Labels
No labels
blocked
breaking-change
bug
bug:critical
bug:tests
cleanup
compliance
compliance
compliance
crate:all
crate:client
crate:native-tls
crate:proto
crate:recursor
crate:resolver
crate:resolver
crate:rustls
crate:server
crate:util
dependencies
docs
duplicate
easy
easy
enhance
enhance
enhance
feature:dns-over-https
feature:dns-over-quic
feature:dns-over-tls
feature:dnsssec
feature:global_lb
feature:mdns
feature:tsig
features:edns
has workaround
ops
perf
platform:WASM
platform:android
platform:fuchsia
platform:linux
platform:macos
platform:windows
pull-request
question
test
tools
tools
trust
unclear
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/hickory-dns#402
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @mathstuf on GitHub (Oct 12, 2017).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/227
This is due to its embedding of the async Reactor from Tokio. This means that for my
Send + Syncstructure, I need to instead create a resolver on each call instead of being able to amortize it to be constructed just once.@mathstuf commented on GitHub (Oct 12, 2017):
Yeah…even the base
trust-dnssynchronous client isn'tSend + Sync.@bluejekyll commented on GitHub (Oct 12, 2017):
It is cloneable. Does clone not facilitate your needs?
@mathstuf commented on GitHub (Oct 12, 2017):
No,
Clonedoesn't suffice. I have a setup which runs things viarayon. One of these things happens to do DNS lookups (usingdigviafork/execright now). The structure that does the lookups cannot store aClientin it becauserayonrequiresSendat least which is not possible with tokio'sCorestructure.@mathstuf commented on GitHub (Oct 12, 2017):
FWIW, we require
Synchere for other reasons, but it's not something that's easily fixable without making everything single threaded again.@bluejekyll commented on GitHub (Oct 12, 2017):
So you may be bumping into some areas where I haven't had any strong use cases, and so don't have any good examples at the moment. We don't have any yet, but perhaps you wouldn't mind creating an example that we could put into
resolver/examples(doesn't exist yet, but it would be cool to start a set of examples there).To your specific issue. You may need to use
ResolverFuturedirectly. I have an example here: https://docs.rs/trust-dns-resolver/0.6.0/trust_dns_resolver/#using-the-tokioasync-resolver . As of now, theResolverFutureisn't multi-Coreaware. It spawns itself and returns a *Handle(basically aSinkin properTokioparlance) which can be used to send messages to the spawned instance of theFuture. TheResolverFutureshould shutdown once all outstanding *Handles are dropped. I think in your case, you'd want to initialize aResolverFutureon oneCorethen, clone eachHandleinto the new threads. To run, you'd end up with aCoreper thread as well.I haven't worked much with
rayonyet. But it would be really awesome to prove out the best method for working with it! It's also very possible you're going to bump into some limitations we're going to have to fix.@mathstuf commented on GitHub (Oct 12, 2017):
Basically, the synchronous and asynchronous implementations can't share "business logic" code. They can share parsers and other pure logic, but the internal
Corerequired to use the async code via a sync interface blocks concurrency via thread workers due to the sharing restrictions. And async can't use sync business logic due to the blocking nature of it.@mathstuf commented on GitHub (Oct 12, 2017):
I've filed tokio-rs/tokio-core#265 to help improve Tokio's documentation about this problem.
@bluejekyll commented on GitHub (Oct 12, 2017):
We might be able to "fix" the SyncClient to use a thread-local Core, https://github.com/tokio-rs/tokio-core/pull/212 , or something similar. If we remove
Corefrom theSyncClient, then we might have some options here. This is meant to exist as an ease of use option so that people don't necessarily have to get involved with Tokio, obviously making it more flexible for cases like threading, etc. would be nice, but I also see that as slightly more advanced, and therefor pushing towards Tokio at that point doesn't seem inappropriate to me.btw, is my above post about using
ResolverFuturean option for you?@mathstuf commented on GitHub (Oct 12, 2017):
I'm not thrilled about those changes to tokio…Rust the language doesn't have a runtime that needs initialized (IIRC, the main reason green threads were dropped pre-1.0) and I don't think a lazily initialized one is good either. Crates certainly shouldn't be relying on such global, implicit behavior IMO.
Possibly, I'll need to test it. I also might not be able to practically use it if creating and destroying
Cores all the time is an issue.@bluejekyll commented on GitHub (Oct 12, 2017):
You could potentially (I haven't done this) just stick the
Corein a thread local, then you'd only ever create one per thread.@mathstuf commented on GitHub (Oct 13, 2017):
Eh, the extra complexity there probably makes it easier to just stick with
digbehindforkandexec.@bluejekyll commented on GitHub (Oct 13, 2017):
I think it's reasonable to put thread-local
Cores into the synchronous variants of the library. I'll open a separate issue for that.@mathstuf commented on GitHub (Oct 13, 2017):
I'd really rather not have a library setting up threads underneath me.
@mathstuf commented on GitHub (Oct 13, 2017):
(Without it being something the library is meant to do, like
rayon.)@bluejekyll commented on GitHub (Oct 13, 2017):
Thread locals don’t set up a new thread, they associate static context to the current thread. This would allow a single Core per thread to exist, without any work by the user of the lib.
No new thread creation at all.
edit: the #245 doesn't use ThreadLocal, but does create a new Core on each Sync request.
@briansmith commented on GitHub (Oct 24, 2017):
Do you really need the sync resolver to be
Send? If it is madeSync, then you can useArc<...>to reference the resolver in yourSend + Syncstructure. IMO, that's quite a reasonable trade-off. If you can't useArc<...>to reference the sync resolver then it would be good to know why.[Edit: s/
Rc/Arc]@bluejekyll commented on GitHub (Oct 24, 2017):
I think I should be able to achieve both with the current implementation...
@mathstuf commented on GitHub (Oct 24, 2017):
Using
Rcto make aSyncthing intoSendwhere sharing isn't necessary is, IMNSHO, a hack and shouldn't be necessary.@briansmith commented on GitHub (Oct 24, 2017):
When making a complex type
Sendinternally, we tend to end up either needing to either clone internal stuff or wrap it inArcorRc. So actually, asking the few users who need theSendfunctionality to implement it themselves in terms ofArcends up making the internals simpler and more efficient for the users that don't need it. (In this case, I think it's mostly a non-issue since we can just wrap a couple of internal things inArcand be done with it.)@bluejekyll commented on GitHub (Oct 24, 2017):
Though, the point is good. I'd love to be able to remove
Arcwhere possible to reduce the overhead on the pointer type in cases where possible. So if we did only supportSyncthat might be more efficient, and thus allow the async variants to not incur the cost of theArc.@briansmith commented on GitHub (Oct 24, 2017):
First, I mixed up
SendandSync. The extra cloning in the current PR for this is to make thingsSync, not to make thingsSend.Second, I think I was confused about whether
Archelps us getSyncorSendfor free.Mutexactually gives usSyncfor almost free for any time that is alreadySend. That has nothing to do withArc. Sorry.I think it shouldn't cost much (nothing?) to make the async types
Sendand that's probably necessary for good Tokio support.It is reasonable to either ask the users of the synchronous API to use
Mutexwhen they needSync, or it would be reasonable to implement the synchronous API in a way that uses aMutexaround the async API for those users, but I don't think it's reasonable to addArcor do extra cloning/copying in the async code just to support aSyncsynchronous API. Using aMutexwould be cheaper anyway.@briansmith commented on GitHub (Oct 24, 2017):
Also, if we make the async API
Syncnow, then we'll have to addMutexinternally later if/when we support things like PKCS#11 or other things that aren't as nicely thread-safe as Rust. That seems like a high long-term cost, even if we can avoid it straightforwardly now.@bluejekyll commented on GitHub (Oct 24, 2017):
Let me fix the current issues in the PR, which is just to make it Send at the moment, if it ends up looking like it's too much cost internally, then we can decide what other options we have.
@bluejekyll commented on GitHub (Oct 27, 2017):
I've run into some issues with OpenSSL in the current PR. It will most likely effect NativeTLS as well.
There are two options moving forward, only support Rustls for client TLS, or requrie
Arc<Mutex<Resolver>>.I'm also not a fan of the implementation in that PR at the moment, especially for TCP, which will require re-connections for each DNS request. I might try a different direction tomorrow.
@bluejekyll commented on GitHub (Oct 31, 2017):
Ok, #245 is the path forward on this.
If anyone is interested in the changes, please look at that PR. It makes the Resolver and Client Send+Sync, without any static information or shared Core's. If you have feedback please file it soon, otherwise I'll merge this in, and it will be incorporated in the next release.
By the way, the only supported SyncClient TLS implementation will be Rustls after this change. For the others, the tokio variants will be required.