Actix-web updating web::Data

I'm trying to learn how to update state in an actix-web server.
See my questions in the comments here:

As a first commentary: you do not need to use Arc here. The type annotation for your line look like this:

let state: Arc<_> = Arc::clone(&state);

But, you could do

let state: web::Data<_> = state.clone();

And the result should be almost identical :slightly_smiling_face:
In fact you can then always get back a reference to Arc, since web::Data implements Deref<Target = Arc>.
I am not sure why you want that in this case though: using the state you give as argument should work just fine.

For your second question: you do not, in fact, mutate state.dog_map (at least not directly from what I can see), but a reference to it. The mut in let mut dog_map = &state.dog_map means that dog_map can be reassigned to point at something else (since it is a reference), like

let mut dog_map = &state.dog_map;
dog_map = &other_state.dog_map;

Are you suggesting that I can just modify state.dog_map directly?
This does not work: state.dog_map.insert(id, dog.clone());
The error is "cannot borrow data in an Arc as mutable trait DerefMut is required to modify through a dereference, but it is not implemented for Arc<AppState>"

To be able to mutate data stored in an Arc (or a Data, which is just a wrapper for an Arc), you need some way of making those mutations thread-safe.

The simplest way of doing this would be to wrap AppState (or individual fields of AppState, if you want to be more fine grained) in a Mutex, which allows you to 'lock' the data so that only one thread can access it at a time. There's also RwLock, which allows multiple readers or one writer, but never both.

However, since you're specifically using a HashMap, you might want to look into concurrent data structures like dashmap, which are specifically designed to be concurrently accessed.

The example for Data in the Actix docs shows the Mutex approach. There's also a chapter on Arc/Mutex in the book.

2 Likes

Okay, I'm trying the approach of using a Mutex. It works for everything but the post handler.
See this comment: rust-actix-web-demo/main.rs at master · mvolkmann/rust-actix-web-demo · GitHub

You can't mutate via a & reference - either change it to &mut or just call the method directly via lock.dog_map.

1 Like

I'm guessing the line with insert is also emitting an error about the immutable reference.

1 Like

That fixed my post route. Thanks! But it also broke my GET routes. They still return a 200 status, but no response body. All I did was add use of Mutex. See rust-actix-web-demo/main.rs at master · mvolkmann/rust-actix-web-demo · GitHub.

I added println!("{:?}", dogs); in the get_dogs function to verify that it is getting the data from the HashMap and it is. So I don't know why it is no longer being returned in the response body.

I finally got time to look at this again. Turns out it was working, but I had clicked the "Visualize" button in Postman and that causes it to not render the JSON that came back. So sorry for the noise and thanks so much for the help!

2 Likes