Skip to content

Commit c453fe9

Browse files
authored
Remove IOState::New (#1467)
At long last, we're no longer using `IOState::New`; jobs are immediately sent to the IO worker tasks when they are created, so we can remove this variant. Reconciliation jobs – which _do_ use `IOState::New` but never used `IOState::Error` – now get their own `enum ReconcileIOState`, limited to their subset of states.
1 parent 0d60de8 commit c453fe9

File tree

3 files changed

+81
-78
lines changed

3 files changed

+81
-78
lines changed

upstairs/src/client.rs

+29-29
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use crate::{
44
live_repair::ExtentInfo, upstairs::UpstairsConfig, upstairs::UpstairsState,
55
ClientIOStateCount, ClientId, CrucibleDecoder, CrucibleError, DownstairsIO,
66
DsState, EncryptionContext, IOState, IOop, JobId, Message, RawReadResponse,
7-
ReconcileIO, RegionDefinitionStatus, RegionMetadata, Validation,
7+
ReconcileIO, ReconcileIOState, RegionDefinitionStatus, RegionMetadata,
8+
Validation,
89
};
910
use crucible_common::{
1011
deadline_secs, verbose_timeout, x509::TLSContext, ExtentId,
@@ -344,12 +345,10 @@ impl DownstairsClient {
344345
job: &mut DownstairsIO,
345346
new_state: IOState,
346347
) -> IOState {
347-
let is_running =
348-
matches!(new_state, IOState::New | IOState::InProgress);
348+
let is_running = matches!(new_state, IOState::InProgress);
349349
self.io_state_count.incr(&new_state);
350350
let old_state = job.state.insert(self.client_id, new_state);
351-
let was_running =
352-
matches!(old_state, IOState::New | IOState::InProgress);
351+
let was_running = matches!(old_state, IOState::InProgress);
353352
self.io_state_count.decr(&old_state);
354353

355354
// Update our bytes-in-flight counter
@@ -414,32 +413,28 @@ impl DownstairsClient {
414413
job
415414
}
416415

417-
/// Ensures that the given job is in the job queue and in `IOState::New`
416+
/// Sets the given job's state to [`IOState::InProgress`]
417+
///
418+
/// # Panics
419+
/// If the job's state is [`IOState::Done`] but the job has not been acked
418420
pub(crate) fn replay_job(&mut self, job: &mut DownstairsIO) {
419-
// If the job is InProgress, then we can just go back to New and no
420-
// extra work is required.
421421
// If it's Done, then by definition it has been acked; test that here
422422
// to double-check.
423423
if IOState::Done == job.state[self.client_id] && !job.acked {
424424
panic!("[{}] This job was not acked: {:?}", self.client_id, job);
425425
}
426426

427-
let old_state = self.set_job_state(job, IOState::InProgress);
427+
self.set_job_state(job, IOState::InProgress);
428428
job.replay = true;
429-
assert_ne!(
430-
old_state,
431-
IOState::New,
432-
"IOState::New is transitory and should not be seen"
433-
);
434429
}
435430

436431
/// Sets this job as skipped and moves it to `skipped_jobs`
437432
///
438433
/// # Panics
439-
/// If the job is not new or in-progress
434+
/// If the job's state is not [`IOState::InProgress`]
440435
pub(crate) fn skip_job(&mut self, job: &mut DownstairsIO) {
441436
let prev_state = self.set_job_state(job, IOState::Skipped);
442-
assert!(matches!(prev_state, IOState::New | IOState::InProgress));
437+
assert!(matches!(prev_state, IOState::InProgress));
443438
self.skipped_jobs.insert(job.ds_id);
444439
}
445440

@@ -2172,8 +2167,10 @@ impl DownstairsClient {
21722167
if self.state != DsState::Reconcile {
21732168
panic!("[{}] should still be in reconcile", self.client_id);
21742169
}
2175-
let prev_state = job.state.insert(self.client_id, IOState::InProgress);
2176-
assert_eq!(prev_state, IOState::New);
2170+
let prev_state = job
2171+
.state
2172+
.insert(self.client_id, ReconcileIOState::InProgress);
2173+
assert_eq!(prev_state, ReconcileIOState::New);
21772174

21782175
// Some reconciliation messages need to be adjusted on a per-client
21792176
// basis, e.g. not sending ExtentRepair to clients that aren't being
@@ -2191,9 +2188,10 @@ impl DownstairsClient {
21912188
} else {
21922189
// Skip this job for this Downstairs, since only the target
21932190
// clients need to do the reconcile.
2194-
let prev_state =
2195-
job.state.insert(self.client_id, IOState::Skipped);
2196-
assert_eq!(prev_state, IOState::InProgress);
2191+
let prev_state = job
2192+
.state
2193+
.insert(self.client_id, ReconcileIOState::Skipped);
2194+
assert_eq!(prev_state, ReconcileIOState::InProgress);
21972195
debug!(self.log, "no action needed request {repair_id:?}");
21982196
}
21992197
}
@@ -2209,9 +2207,10 @@ impl DownstairsClient {
22092207
debug!(self.log, "skipping flush request {repair_id:?}");
22102208
// Skip this job for this Downstairs, since it's narrowly
22112209
// aimed at a different client.
2212-
let prev_state =
2213-
job.state.insert(self.client_id, IOState::Skipped);
2214-
assert_eq!(prev_state, IOState::InProgress);
2210+
let prev_state = job
2211+
.state
2212+
.insert(self.client_id, ReconcileIOState::Skipped);
2213+
assert_eq!(prev_state, ReconcileIOState::InProgress);
22152214
}
22162215
}
22172216
Message::ExtentReopen { .. } | Message::ExtentClose { .. } => {
@@ -2230,12 +2229,13 @@ impl DownstairsClient {
22302229
reconcile_id: ReconciliationId,
22312230
job: &mut ReconcileIO,
22322231
) -> bool {
2233-
let old_state = job.state.insert(self.client_id, IOState::Done);
2234-
assert_eq!(old_state, IOState::InProgress);
2232+
let old_state =
2233+
job.state.insert(self.client_id, ReconcileIOState::Done);
2234+
assert_eq!(old_state, ReconcileIOState::InProgress);
22352235
assert_eq!(job.id, reconcile_id);
2236-
job.state
2237-
.iter()
2238-
.all(|s| matches!(s, IOState::Done | IOState::Skipped))
2236+
job.state.iter().all(|s| {
2237+
matches!(s, ReconcileIOState::Done | ReconcileIOState::Skipped)
2238+
})
22392239
}
22402240

22412241
pub(crate) fn total_live_work(&self) -> usize {

upstairs/src/downstairs.rs

+30-30
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ impl Downstairs {
610610
*/
611611
for (id, job) in &self.ds_active {
612612
let state = &job.state[client_id];
613-
if state == &IOState::New || state == &IOState::InProgress {
613+
if state == &IOState::InProgress {
614614
info!(
615615
self.log,
616616
"[{}] cannot deactivate, job {} in state {:?}",
@@ -2531,7 +2531,7 @@ impl Downstairs {
25312531
self.ds_active.for_each(|ds_id, job| {
25322532
let state = &job.state[client_id];
25332533

2534-
if matches!(state, IOState::InProgress | IOState::New) {
2534+
if matches!(state, IOState::InProgress) {
25352535
self.clients[client_id].skip_job(job);
25362536
number_jobs_skipped += 1;
25372537

@@ -4262,7 +4262,7 @@ pub(crate) mod test {
42624262
upstairs::UpstairsState,
42634263
ClientId, CrucibleError, DownstairsIO, DsState, ExtentFix, IOState,
42644264
IOop, ImpactedAddr, ImpactedBlocks, JobId, RawReadResponse,
4265-
ReconcileIO, ReconciliationId, SnapshotDetails,
4265+
ReconcileIO, ReconcileIOState, ReconciliationId, SnapshotDetails,
42664266
};
42674267

42684268
use bytes::BytesMut;
@@ -5877,9 +5877,9 @@ pub(crate) mod test {
58775877
panic!("{:?} not ExtentFlush()", m);
58785878
}
58795879
}
5880-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
5881-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
5882-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
5880+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
5881+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
5882+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
58835883

58845884
// Second task, close extent
58855885
let rio = ds.reconcile_task_list.pop_front().unwrap();
@@ -5896,9 +5896,9 @@ pub(crate) mod test {
58965896
panic!("{:?} not ExtentClose()", m);
58975897
}
58985898
}
5899-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
5900-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
5901-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
5899+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
5900+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
5901+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
59025902

59035903
// Third task, repair extent
59045904
let rio = ds.reconcile_task_list.pop_front().unwrap();
@@ -5924,9 +5924,9 @@ pub(crate) mod test {
59245924
panic!("{:?} not ExtentRepair", m);
59255925
}
59265926
}
5927-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
5928-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
5929-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
5927+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
5928+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
5929+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
59305930

59315931
// Third task, close extent
59325932
let rio = ds.reconcile_task_list.pop_front().unwrap();
@@ -5943,9 +5943,9 @@ pub(crate) mod test {
59435943
panic!("{:?} not ExtentClose()", m);
59445944
}
59455945
}
5946-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
5947-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
5948-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
5946+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
5947+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
5948+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
59495949
}
59505950

59515951
#[test]
@@ -5996,9 +5996,9 @@ pub(crate) mod test {
59965996
panic!("{:?} not ExtentFlush()", m);
59975997
}
59985998
}
5999-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
6000-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
6001-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
5999+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
6000+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
6001+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
60026002

60036003
// Second task, close extent
60046004
let rio = ds.reconcile_task_list.pop_front().unwrap();
@@ -6015,9 +6015,9 @@ pub(crate) mod test {
60156015
panic!("{:?} not ExtentClose()", m);
60166016
}
60176017
}
6018-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
6019-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
6020-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
6018+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
6019+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
6020+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
60216021

60226022
// Third task, repair extent
60236023
let rio = ds.reconcile_task_list.pop_front().unwrap();
@@ -6043,9 +6043,9 @@ pub(crate) mod test {
60436043
panic!("{:?} not ExtentRepair", m);
60446044
}
60456045
}
6046-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
6047-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
6048-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
6046+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
6047+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
6048+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
60496049

60506050
// Third task, close extent
60516051
let rio = ds.reconcile_task_list.pop_front().unwrap();
@@ -6062,9 +6062,9 @@ pub(crate) mod test {
60626062
panic!("{:?} not ExtentClose()", m);
60636063
}
60646064
}
6065-
assert_eq!(IOState::New, rio.state[ClientId::new(0)]);
6066-
assert_eq!(IOState::New, rio.state[ClientId::new(1)]);
6067-
assert_eq!(IOState::New, rio.state[ClientId::new(2)]);
6065+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(0)]);
6066+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(1)]);
6067+
assert_eq!(ReconcileIOState::New, rio.state[ClientId::new(2)]);
60686068
}
60696069

60706070
// Tests for reconciliation
@@ -6333,9 +6333,9 @@ pub(crate) mod test {
63336333
let Some(job) = &ds.reconcile_current_work else {
63346334
panic!("failed to find current work");
63356335
};
6336-
assert_eq!(job.state[ClientId::new(0)], IOState::Skipped);
6337-
assert_eq!(job.state[ClientId::new(1)], IOState::InProgress);
6338-
assert_eq!(job.state[ClientId::new(2)], IOState::InProgress);
6336+
assert_eq!(job.state[ClientId::new(0)], ReconcileIOState::Skipped);
6337+
assert_eq!(job.state[ClientId::new(1)], ReconcileIOState::InProgress);
6338+
assert_eq!(job.state[ClientId::new(2)], ReconcileIOState::InProgress);
63396339

63406340
let msg = Message::RepairAckId { repair_id: rep_id };
63416341
assert!(!ds.on_reconciliation_ack(

upstairs/src/lib.rs

+22-19
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ impl DownstairsIO {
972972

973973
for state in self.state.iter() {
974974
match state {
975-
IOState::New | IOState::InProgress => wc.active += 1,
975+
IOState::InProgress => wc.active += 1,
976976
IOState::Error(_) => wc.error += 1,
977977
IOState::Skipped => wc.skipped += 1,
978978
IOState::Done => wc.done += 1,
@@ -1102,15 +1102,15 @@ struct WorkSummary {
11021102
struct ReconcileIO {
11031103
id: ReconciliationId,
11041104
op: Message,
1105-
state: ClientData<IOState>,
1105+
state: ClientData<ReconcileIOState>,
11061106
}
11071107

11081108
impl ReconcileIO {
11091109
fn new(id: ReconciliationId, op: Message) -> ReconcileIO {
11101110
ReconcileIO {
11111111
id,
11121112
op,
1113-
state: ClientData::new(IOState::New),
1113+
state: ClientData::new(ReconcileIOState::New),
11141114
}
11151115
}
11161116
}
@@ -1368,14 +1368,9 @@ impl IOop {
13681368
}
13691369
}
13701370

1371-
/*
1372-
* The various states an IO can be in when it is on the work hashmap.
1373-
* There is a state that is unique to each downstairs task we have and
1374-
* they operate independent of each other.
1375-
*/
13761371
#[allow(clippy::derive_partial_eq_without_eq)]
13771372
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
1378-
pub enum IOState {
1373+
pub enum ReconcileIOState {
13791374
// A new IO request.
13801375
New,
13811376
// The request has been sent to this tasks downstairs.
@@ -1385,17 +1380,31 @@ pub enum IOState {
13851380
// The IO request should be ignored. Ex: we could be doing recovery and
13861381
// we only want a specific downstairs to do that work.
13871382
Skipped,
1388-
// The IO returned an error.
1383+
}
1384+
1385+
/*
1386+
* The various states an IO can be in when it is on the work hashmap.
1387+
* There is a state that is unique to each downstairs task we have and
1388+
* they operate independent of each other.
1389+
*/
1390+
#[allow(clippy::derive_partial_eq_without_eq)]
1391+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
1392+
pub enum IOState {
1393+
/// The request has been sent to this tasks downstairs.
1394+
InProgress,
1395+
/// The successful response came back from downstairs.
1396+
Done,
1397+
/// The IO request should be ignored. Ex: we could be doing recovery and
1398+
/// we only want a specific downstairs to do that work.
1399+
Skipped,
1400+
/// The IO returned an error.
13891401
Error(CrucibleError),
13901402
}
13911403

13921404
impl fmt::Display for IOState {
13931405
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13941406
// Make sure to right-align output on 4 characters
13951407
match self {
1396-
IOState::New => {
1397-
write!(f, " New")
1398-
}
13991408
IOState::InProgress => {
14001409
write!(f, "Sent")
14011410
}
@@ -1442,7 +1451,6 @@ impl ClientIOStateCount {
14421451

14431452
fn get_mut(&mut self, state: &IOState) -> &mut u32 {
14441453
match state {
1445-
IOState::New => &mut self.new,
14461454
IOState::InProgress => &mut self.in_progress,
14471455
IOState::Done => &mut self.done,
14481456
IOState::Skipped => &mut self.skipped,
@@ -1463,7 +1471,6 @@ pub struct IOStateCount {
14631471
impl IOStateCount {
14641472
fn show_all(&self) {
14651473
println!(" STATES DS:0 DS:1 DS:2 TOTAL");
1466-
self.show(IOState::New);
14671474
self.show(IOState::InProgress);
14681475
self.show(IOState::Done);
14691476
self.show(IOState::Skipped);
@@ -1473,7 +1480,6 @@ impl IOStateCount {
14731480

14741481
fn get(&self, state: &IOState) -> &ClientData<u32> {
14751482
match state {
1476-
IOState::New => &self.new,
14771483
IOState::InProgress => &self.in_progress,
14781484
IOState::Done => &self.done,
14791485
IOState::Skipped => &self.skipped,
@@ -1484,9 +1490,6 @@ impl IOStateCount {
14841490
fn show(&self, state: IOState) {
14851491
let state_stat = self.get(&state);
14861492
match state {
1487-
IOState::New => {
1488-
print!(" New ");
1489-
}
14901493
IOState::InProgress => {
14911494
print!(" Sent ");
14921495
}

0 commit comments

Comments
 (0)