Search code examples
rustcontainersshared-ptr

Rust: how to make a separate reference to an item, which is already in a container?


My server is handling approximately 50-100 clients, which connect with websocket, I'm using the simple_websockets library.

Clients can connect any time, and also they disconnect randomly. When a client connects, it gets a u64 identifier from simple_websockets, I use this ID as the key for my container, which looks like:

pub type ClientList = Arc<RwLock<HashMap<u64, Client>>>;

I have a suspect, that it's not optimal, I'm not sure, maybe I'm wrong, but if I get a Client from it, it will be locked until the scope ends, in the example, process_stuff() finishes.

// self.clients: ClientList (defined elsewhere)
let mut hash_map = self.clients.write().unwrap();
let client: &mut Client = hash_map.get_mut(&client_id).unwrap();
client.process_stuff();

One of the clients is a special one. It is not connected when the server starts, it will connect just as other clients, the server will detect whether it's the special client or not. It should be put into the container as well, because it must behave as other clients, it has only a few special tasks. Also, there should be a quick access to it, e.g. a dedicated pointer. I would avoid pointer by storing its ID only, and pick it from the container every time, but it would be slow.

I can't use a simple pointer, because the special client is not present from the server's startup, it must be wrapped into Option or similar. This is the point, where my question comes: what type of pointer should I use for the special client, maybe I need to modify my container to be able to point to the same object from two pointers (a dedicated and the one in the container)?


Solution

  • I've solved the container part. It looks "too nested", but this is the truth.

    pub type SharedClient = Arc<RwLock<Client>>;
    pub type SharedClientList = Arc<RwLock<HashMap<u64, SharedClient>>>;
    

    Plus reward: I can now get a Client both write/mutable and read/immutable, depending on if the program, who picked it from the container, should change it.

    Comment: high five to Rust for this, probably I've been never would use different access from a container, if I'm not forced to.

    Edit: the special client is also must be protected by lock, as it get its value during the operation, when potentially multiple clients may set it. It will never happened, but only because the clients' behaviour, there's no hard guarantee for that.

    special_client: Arc<RwLock<Option<SharedClient>>>,
    

    It will be used once under write lock, then always with read lock.

    Please, comment, if I'm doing the wrong way.