The current thread is pinned by calling pin
, which returns a new guard:
What i understand from the above documentation is, you data will not be garbage collected as long as Guard
is pinned to the current thread.
Let's consider the following situations
I have a struct Config
and HttpRequest
struct Config{
version: u32
// really complex to represent here
}
struct HttpRequest{
config: Arc<Config>
// others
}
I have to process http request in multiple phases, for example
- Getting request header, body
- Talking with database
- Talking with file system if needed
- Talking with external system if needed
- Sending response
All phases of any request, must be processed with same config version. There shouldn’t be any request getting version x
config in phase 1 and getting version x+y
config in next phases.
Every phase will be scheduled on different tokio tasks(So on different threads possibly). Due to which, HttpRequest
struct will be move across threads using move
keyword in every next phase.
My question is, if i keep a reference of crossbeam epoch Guard
in HttpRequest
, will there be any guarantee that memory won’t be reclaimed until the guard is dropped. Considering HttpRequest
will be moved across thread and cross beam guards are pinned the calling thread?
Considering that Guard: !Send + !Sync
, it wouldn't even be possible for a Guard
or &Guard
to be sent between threads. Directly addressing your question:
No, it wouldn't be able to, because (&)Guard
can't be (because it pins the calling thread).
Yes, the memory will be used correctly. But as said before, that will make HttpRequest
impossible to send between threads.
To solve this, consider using tokio::task::LocalSet
, or not using crossbeam_epoch
at all.
1 Like
I'd expect the attempt would make the created future !Send
and give you a somewhat confusing error.
1 Like
Any other data structures that can fit into this situation? checked arc-swap
, but that also has similar limitations
I don't see what would be wrong with arc-swap
, it actually seems right for your use case. When you initialize an HttpRequest
, provide a &ArcSwap<Config>
, then load_full
the Arc<Config>
and store it in HttpRequest
. Don't try to use load
, as the docs say: "this is suited for local variables on stack, but not in long-living data structures." (emphasis and footnotes mine)
Whenever you need to change the config, you can just do a store
to change it for all future requests.
ArcSwapAny in arc_swap - Rust
The method is lock-free and wait-free, but usually more expensive than load
.
This was concerning for me, but will benchmark that how much slower it is. Thanks for suggestions