Using HashMap and multithreading server in rust

Viewed 47

I have a multi-thread server which can handle many connections at the same time.

In each connection i would like to write or read in a single hashmap (i tried to implement a basic redis).

The problem is that the connection may never end (client can send many data before close connection) so the lock never drop, so another client cannot take it.

Without the arc mutex hashmap my multi-thread server work, but with it my server can't respond to a second client for the reason mentionned below.

the entire code

#[allow(unused_imports)]
use std::env;
use std::fs;
//use std::io::Write;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;
#[allow(unused_imports)]
use std::{
    io::{prelude::*, BufReader},
    net::{TcpListener, TcpStream},
};

//aa
fn main() {
    // You can use print statements as follows for debugging, they'll be visible when running tests.
    println!("Logs from your program will appear here!");
    let store = Arc::new(Mutex::new(HashMap::new()));
    // Uncomment this block to pass the first stage
    let listener = TcpListener::bind("127.0.0.1:6379").unwrap();
    let mut handles = vec![];
    for stream in listener.incoming() {
        println!("on request");
        let stream = stream.unwrap();
        let store = store.clone();
        let handle = thread::spawn(|| {
            handle_client(stream, store);
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
}

fn handle_client(mut stream: TcpStream, store: Arc<Mutex<HashMap<String, String>>>) {
    let mut store = store.lock().unwrap(); // this store never drop due to the infinte loop so i can only have one connection 
    println!("handle_client");
    let mut cloned_stream = stream.try_clone().unwrap();
    let buf_reader = BufReader::new(&mut stream);
    let mut command = "".to_string();
    let mut response = "+PONG\r\n".to_string();
    let mut key = "".to_string();

    for (index, line) in buf_reader.lines().map(|result| result.unwrap()).enumerate() {
        dbg!(&line);
        dbg!(index);
        if line == "ping" {
            cloned_stream.write_all(response.as_bytes()).unwrap();
        }

        if index == 2 && line == "echo" {
            command = "echo".to_string();
        }

        if index == 2 && line == "set" {
            command = "set".to_string();
        }

        if index == 2 && line == "get" {
            command = "get".to_string();
        }

        dbg!(&command);

        if index == 4 && command == "echo" {
            response = format!("+{}\r\n", line);
            cloned_stream.write_all(response.as_bytes()).unwrap();
        }

        if index == 4 && command == "set" {
            dbg!(&response);
            key = line.to_string();
        }

        if index == 4 && command == "get" {
            let value = store.get(&key.to_string()).unwrap().to_string();
            response = format!("+{}\r\n", value);
            cloned_stream.write_all(response.as_bytes()).unwrap();
        }

        if index == 6 && command == "set" {
            let clone_line = line.clone();
            store.insert(key.clone(), clone_line);
            response = format!("+{}\r\n", line);
            cloned_stream.write_all(response.as_bytes()).unwrap();
        }
    }
}
0 Answers
Related