archlinux / alpm.rs

Rust bindings for libalpm
GNU General Public License v3.0
112 stars 21 forks source link

`Alpm` handles and Concurrency #28

Closed fosskers closed 2 years ago

fosskers commented 2 years ago

Related to #6 . We've talked in the past about sharing a single Alpm handle across threads, and now I've come to a point in my coding where it's finally (seeming) necessary.

There are a number of read-only operations I'd like to perform, namely native package lookups, and I'd like to do so concurrently. In my particular case I'm using rayon, and as a rule am keeping all usage of async of out this code base:

pkgs.into_par_iter()
        .map(|p| resolve_one(alpm, res.clone(), p))
        .collect::<Validated<(), Error>>();

Here alpm is passed in by the caller as &'a Alpm. References are normally fine to send across threads without any other Arcing or Mutexing, and I intend nothing mutable. Unfortunately this doesn't seem possible at the moment, with the compiler telling me:

error[E0277]: `UnsafeCell<std::option::Option<Box<(dyn alpm::cb::QuestionCbTrait + 'static)>>>` cannot be shared between threads safely

Wrapping the handle in Arcs, etc., doesn't solve it. So:

  1. Is there a way to do this already that I'm not seeing?
  2. If not, is there a reasonable change that could be made to allow this?

I suppose I could open a handle per thread, but that's really not ideal. I could also using the r2d2 pooling strategy that I figured out in the original Rust PoC. Although maybe that would fail now for the same reason? I will check.

Anyway, let me know your thoughts. Thank you kindly.

fosskers commented 2 years ago

Alright the r2d2 approach appears to work when the caller passes a Pool<M> where M: ManageConnection<Connection = Alpm>. I'm able to use rayon's map_with to auto-clone the Pool handle as it passes to each thread, then within each thread grab a pre-opened Alpm from the pool and work as I intended.

That's probably sufficient for my use-case for the moment, but do you still have anything thoughts about the native Sending from above?

Morganamilo commented 2 years ago

There are a number of read-only operations I'd like to perform

So as alpm lazy loads, nothing is really read only. A call to .install_size() or anything will trigger interior mutability.

Alpm isnt send because the callbacks don't have a send bound. That could be added but then would make you unable to rc in callbacks.

fosskers commented 2 years ago

In that case I'll move forward with the Connection Pool approach. Do you foresee any problems with having multiple handles to ALPM open at the same time?

Morganamilo commented 2 years ago

Should be fine. But I also don't really see the need for concurrency.

fosskers commented 2 years ago

Cool, then this can be closed.