Skip to content

Commit 45075bc

Browse files
committed
Addressing lock panics in Client
We actually should keep the connections locked until we send the packet so the list doesn't change, as that will avoid the potential for a panic while holding the lock. We are changing all of the unwraps here to expects as we have reviewed all of the execution paths from the lock and they don't have known panics. This is but one of many changes needed to address issue #4
1 parent 28c29f1 commit 45075bc

File tree

2 files changed

+31
-20
lines changed

2 files changed

+31
-20
lines changed

rustygear/src/client.rs

+29-20
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ impl Client {
298298
// Active servers will have a writer and a reader
299299
self.conns
300300
.lock()
301-
.unwrap()
301+
.expect("All lock holders should not panic")
302302
.active_servers()
303303
.map(|hostname| hostname.clone())
304304
.collect()
@@ -522,19 +522,23 @@ impl Client {
522522
/// Returns an error if there aren't any connected servers, or no ECHO_RES comes back
523523
pub async fn echo(&mut self, payload: &[u8]) -> Result<(), io::Error> {
524524
let packet = new_req(ECHO_REQ, Bytes::copy_from_slice(payload));
525-
if self.conns.lock().unwrap().len() < 1 {
526-
return Err(io::Error::new(
527-
io::ErrorKind::Other,
528-
"No connections for echo!",
529-
));
530-
}
531-
self.conns
532-
.lock()
533-
.unwrap()
534-
.get(0)
535-
.unwrap()
536-
.send_packet(packet)
537-
.await?;
525+
{
526+
let conns = self
527+
.conns
528+
.lock()
529+
.expect("All lock holders should not panic");
530+
if conns.len() < 1 {
531+
return Err(io::Error::new(
532+
io::ErrorKind::Other,
533+
"No connections for echo!",
534+
));
535+
}
536+
conns
537+
.get(0)
538+
.expect("Conns is locked by mutex and we checked length above")
539+
.send_packet(packet)
540+
.await?;
541+
} // Unlock conns
538542
debug!("Waiting for echo response");
539543
match self.client_data.receivers().echo_rx.recv().await {
540544
Some(res) => info!("echo received: {:?}", res),
@@ -607,7 +611,10 @@ impl Client {
607611
data.extend(payload);
608612
let packet = new_req(ptype, data.freeze());
609613
{
610-
let mut conns = self.conns.lock().unwrap();
614+
let mut conns = self
615+
.conns
616+
.lock()
617+
.expect("All lock holders should not panic");
611618
let conn = match conns.get_hashed_conn(&unique.iter().map(|b| *b).collect()) {
612619
None => {
613620
return Err(io::Error::new(
@@ -640,9 +647,14 @@ impl Client {
640647

641648
/// Sends a GET_STATUS packet and then returns the STATUS_RES in a [JobStatus]
642649
pub async fn get_status(&mut self, handle: &ServerHandle) -> Result<JobStatus, io::Error> {
643-
// TODO: mapping?
650+
let mut payload = BytesMut::with_capacity(handle.handle().len());
651+
payload.extend(handle.handle());
652+
let status_req = new_req(GET_STATUS, payload.freeze());
644653
{
645-
let conns = self.conns.lock().unwrap();
654+
let conns = self
655+
.conns
656+
.lock()
657+
.expect("All lock holders should not panic");
646658
let conn = match conns.get_by_server(handle.server()).and_then(|conn| {
647659
if conn.is_active() {
648660
Some(conn)
@@ -653,9 +665,6 @@ impl Client {
653665
None => return Err(io::Error::new(ErrorKind::Other, "No connection for job")),
654666
Some(conn) => conn,
655667
};
656-
let mut payload = BytesMut::with_capacity(handle.handle().len());
657-
payload.extend(handle.handle());
658-
let status_req = new_req(GET_STATUS, payload.freeze());
659668
conn.send_packet(status_req).await?;
660669
}
661670
debug!("Waiting for STATUS_RES for {}", handle);

rustygear/src/conn.rs

+2
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ impl Connections {
389389

390390
// TODO: Make this a client configurable
391391
const HASH_RING_REPLICAS: usize = 1;
392+
393+
// This is run with locks held so it is very important that it not panic!
392394
pub fn get_hashed_conn(&mut self, hashable: &Vec<u8>) -> Option<&mut ConnHandler> {
393395
match self
394396
.ring

0 commit comments

Comments
 (0)