Skip to content

Commit 07bb366

Browse files
committed
Merge branch 'main' into use-nw-service
2 parents 93897eb + f9fc36b commit 07bb366

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+4662
-3140
lines changed

Cargo.lock

+605-329
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+7-5
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ nix = { version = "0.26", features = [ "feature", "uio" ] }
6262
num_enum = "0.7"
6363
num-derive = "0.4"
6464
num-traits = "0.2"
65-
omicron-zone-package = "0.9.1"
65+
omicron-zone-package = "0.10.0"
6666
openapiv3 = "2.0.0"
6767
opentelemetry = "0.21.0"
68-
opentelemetry-jaeger = { version = "0.17.0" }
68+
opentelemetry-jaeger = { version = "0.20.0" }
6969
percent-encoding = "2.3"
7070
proptest = "1.4.0"
7171
rayon = "1.8.0"
@@ -85,10 +85,12 @@ signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"] }
8585
slog = { version = "2.7", features = ["max_level_trace", "release_max_level_debug"] }
8686
slog-async = { version = "2.8" }
8787
slog-bunyan = "2.4.0"
88-
slog-dtrace = "0.2"
88+
slog-dtrace = "0.3"
8989
slog-term = { version = "2.9" }
90+
static_assertions = "1.1.0"
9091
statistical = "1.0.0"
9192
subprocess = "0.2.9"
93+
strum_macros = "0.25.3"
9294
tempfile = "3"
9395
test-strategy = "0.3.1"
9496
thiserror = "1"
@@ -98,10 +100,10 @@ tokio-test = "*"
98100
tokio-util = { version = "0.7", features = ["codec"]}
99101
toml = "0.8"
100102
tracing = "0.1"
101-
tracing-opentelemetry = "0.18.0"
103+
tracing-opentelemetry = "0.22.0"
102104
tracing-subscriber = "0.3.18"
103105
twox-hash = "1.6.3"
104-
usdt = "0.3.5"
106+
usdt = "0.5.0"
105107
uuid = { version = "1", features = [ "serde", "v4" ] }
106108

107109
# git

common/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ pub enum CrucibleError {
155155

156156
#[error("context slot deserialization failed: {0}")]
157157
BadContextSlot(String),
158+
159+
#[error("missing block context for non-empty block")]
160+
MissingBlockContext,
158161
}
159162

160163
impl From<std::io::Error> for CrucibleError {
@@ -398,7 +401,8 @@ impl From<CrucibleError> for dropshot::HttpError {
398401
| CrucibleError::UuidMismatch
399402
| CrucibleError::MissingContextSlot(..)
400403
| CrucibleError::BadMetadata(..)
401-
| CrucibleError::BadContextSlot(..) => {
404+
| CrucibleError::BadContextSlot(..)
405+
| CrucibleError::MissingBlockContext => {
402406
dropshot::HttpError::for_internal_error(e.to_string())
403407
}
404408
}

crudd/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ tokio-util.workspace = true
2323
tokio.workspace = true
2424
toml.workspace = true
2525
crucible-workspace-hack.workspace = true
26+
itertools.workspace = true

crudd/src/main.rs

+68-64
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{cmp, io};
1111
use anyhow::{bail, Result};
1212
use clap::Parser;
1313
use futures::stream::StreamExt;
14+
use itertools::Itertools;
1415
use signal_hook::consts::signal::*;
1516
use signal_hook_tokio::Signals;
1617
use tokio::sync::oneshot;
@@ -102,7 +103,7 @@ pub fn opts() -> Result<Opt> {
102103
Ok(opt)
103104
}
104105

105-
async fn cmd_read<T: BlockIO>(
106+
async fn cmd_read<T: BlockIO + std::marker::Send + 'static>(
106107
opt: &Opt,
107108
crucible: Arc<T>,
108109
mut early_shutdown: oneshot::Receiver<()>,
@@ -154,7 +155,6 @@ async fn cmd_read<T: BlockIO>(
154155
//
155156
// TODO this is no longer true after the Upstairs is async, multiple
156157
// requests can be submitted and await'ed on at the same time.
157-
let mut buffers = VecDeque::with_capacity(opt.pipeline_length);
158158
let mut futures = VecDeque::with_capacity(opt.pipeline_length);
159159

160160
// First, align our offset to the underlying blocks with an initial read
@@ -171,16 +171,16 @@ async fn cmd_read<T: BlockIO>(
171171
cmp::min(num_bytes, native_block_size - offset_misalignment);
172172
if offset_misalignment != 0 {
173173
// Read the full block
174-
let buffer = Buffer::new(native_block_size as usize);
174+
let mut buffer = Buffer::new(1, native_block_size as usize);
175175
let block_idx = opt.byte_offset / native_block_size;
176176
let offset = Block::new(block_idx, native_block_size.trailing_zeros());
177-
crucible.read(offset, buffer.clone()).await?;
177+
crucible.read(offset, &mut buffer).await?;
178178

179179
// write only (block size - misalignment) bytes
180180
// So say we have an offset of 5. we're misaligned by 5 bytes, so we
181181
// read 5 bytes we don't need. we skip those 5 bytes then write
182182
// the rest to the output
183-
let bytes = buffer.into_vec().unwrap();
183+
let bytes = buffer.into_vec();
184184
output.write_all(
185185
&bytes[offset_misalignment as usize
186186
..(offset_misalignment + alignment_bytes) as usize],
@@ -207,47 +207,50 @@ async fn cmd_read<T: BlockIO>(
207207
let cmd_count = num_bytes / (opt.iocmd_block_count * native_block_size);
208208
let remainder = num_bytes % (opt.iocmd_block_count * native_block_size);
209209

210-
// Issue all of our read commands
211-
for i in 0..cmd_count {
212-
// which blocks in the underlying store are we accessing?
213-
let block_idx = block_offset + (i * opt.iocmd_block_count);
214-
let offset = Block::new(block_idx, native_block_size.trailing_zeros());
210+
let mut buffers: Vec<Buffer> = (0..opt.pipeline_length)
211+
.map(|_| {
212+
Buffer::new(
213+
opt.iocmd_block_count as usize,
214+
native_block_size as usize,
215+
)
216+
})
217+
.collect();
215218

216-
// Send the read command with whichever buffer is at the back of the
217-
// queue. We re-use the buffers to avoid lots of allocations
218-
let w_buf =
219-
Buffer::new((opt.iocmd_block_count * native_block_size) as usize);
220-
let w_future = crucible.read(offset, w_buf.clone());
221-
buffers.push_back(w_buf);
222-
futures.push_back(w_future);
223-
total_bytes_read +=
224-
(opt.iocmd_block_count * native_block_size) as usize;
219+
// Issue all of our read commands
220+
for cmd_range in &(0..cmd_count as usize).chunks(opt.pipeline_length) {
221+
for i in cmd_range {
222+
// which blocks in the underlying store are we accessing?
223+
let block_idx = block_offset + (i as u64 * opt.iocmd_block_count);
224+
let offset =
225+
Block::new(block_idx, native_block_size.trailing_zeros());
226+
227+
// Send the read command with whichever buffer is at the back of the
228+
// queue. We re-use the buffers to avoid lots of allocations
229+
let mut buffer = buffers.pop().unwrap();
230+
let crucible = crucible.clone();
231+
futures.push_back(tokio::spawn(async move {
232+
crucible.read(offset, &mut buffer).await?;
233+
Ok(buffer)
234+
}));
235+
236+
total_bytes_read +=
237+
(opt.iocmd_block_count * native_block_size) as usize;
238+
}
225239

226-
// If we have a queue of futures, drain the oldest one to output.
227-
if futures.len() == opt.pipeline_length {
228-
futures.pop_front().unwrap().await?;
229-
let r_buf = buffers.pop_front().unwrap();
230-
output.write_all(&r_buf.as_vec().await)?;
240+
for future in futures.drain(..) {
241+
let result: Result<Buffer, CrucibleError> = future.await?;
242+
let r_buf = result?;
243+
output.write_all(&r_buf)?;
244+
buffers.push(r_buf);
231245
}
232246

233247
if early_shutdown.try_recv().is_ok() {
234248
eprintln!("shutting down early in response to SIGUSR1");
235-
join_all(futures).await?;
236249
return Ok(total_bytes_read);
237250
}
238251
}
239252

240-
// Drain the outstanding commands
241-
if !futures.is_empty() {
242-
crucible::join_all(futures).await?;
243-
244-
// drain the buffer to the output file
245-
while !buffers.is_empty() {
246-
// unwrapping is safe because of the length check
247-
let r_buf = buffers.pop_front().unwrap();
248-
output.write_all(&r_buf.as_vec().await)?;
249-
}
250-
}
253+
assert!(futures.is_empty());
251254

252255
// Issue our final read command, if any. This could be interleaved with
253256
// draining the outstanding commands but it's more complicated and
@@ -256,12 +259,13 @@ async fn cmd_read<T: BlockIO>(
256259
// let block_remainder = remainder % native_block_size;
257260
// round up
258261
let blocks = (remainder + native_block_size - 1) / native_block_size;
259-
let buffer = Buffer::new((blocks * native_block_size) as usize);
262+
let mut buffer =
263+
Buffer::new(blocks as usize, native_block_size as usize);
260264
let block_idx = (cmd_count * opt.iocmd_block_count) + block_offset;
261265
let offset = Block::new(block_idx, native_block_size.trailing_zeros());
262-
crucible.read(offset, buffer.clone()).await?;
266+
crucible.read(offset, &mut buffer).await?;
263267
total_bytes_read += remainder as usize;
264-
output.write_all(&buffer.as_vec().await[0..remainder as usize])?;
268+
output.write_all(&buffer[0..remainder as usize])?;
265269
}
266270

267271
Ok(total_bytes_read)
@@ -280,7 +284,7 @@ async fn write_remainder_and_finalize<'a, T: BlockIO>(
280284
offset: Block,
281285
n_read: usize,
282286
native_block_size: u64,
283-
mut futures: VecDeque<crucible::CrucibleBlockIOFuture<'a>>,
287+
mut futures: VecDeque<CrucibleBlockIOFuture<'a>>,
284288
) -> Result<()> {
285289
// the input stream ended,
286290
// - read/mod/write for alignment
@@ -310,11 +314,11 @@ async fn write_remainder_and_finalize<'a, T: BlockIO>(
310314
offset.value + uflow_blocks,
311315
native_block_size.trailing_zeros(),
312316
);
313-
let uflow_r_buf = Buffer::new(native_block_size as usize);
314-
crucible.read(uflow_offset, uflow_r_buf.clone()).await?;
317+
let mut uflow_r_buf = Buffer::new(1, native_block_size as usize);
318+
crucible.read(uflow_offset, &mut uflow_r_buf).await?;
315319

316320
// Copy it into w_buf
317-
let r_bytes = uflow_r_buf.into_vec().unwrap();
321+
let r_bytes = uflow_r_buf.into_vec();
318322
w_buf[n_read..n_read + uflow_backfill]
319323
.copy_from_slice(&r_bytes[uflow_remainder as usize..]);
320324

@@ -323,12 +327,12 @@ async fn write_remainder_and_finalize<'a, T: BlockIO>(
323327
futures.push_back(w_future);
324328
}
325329

326-
// Flush
327-
let flush_future = crucible.flush(None);
328-
futures.push_back(flush_future);
330+
// Wait for all the writes first, then flush
331+
for future in futures {
332+
future.await?;
333+
}
329334

330-
// Wait for all the writes
331-
join_all(futures).await?;
335+
crucible.flush(None).await?;
332336

333337
Ok(())
334338
}
@@ -395,12 +399,12 @@ async fn cmd_write<T: BlockIO>(
395399
// We need to read-modify-write here.
396400

397401
// Read the full block
398-
let buffer = Buffer::new(native_block_size as usize);
402+
let mut buffer = Buffer::new(1, native_block_size as usize);
399403
let block_idx = opt.byte_offset / native_block_size;
400404
let offset = Block::new(block_idx, native_block_size.trailing_zeros());
401-
crucible.read(offset, buffer.clone()).await?;
405+
crucible.read(offset, &mut buffer).await?;
402406

403-
let mut w_vec = buffer.into_vec().unwrap();
407+
let mut w_vec = buffer.into_vec();
404408
// Write our data into the buffer
405409
let bytes_read = input.read(
406410
&mut w_vec[offset_misalignment as usize
@@ -485,7 +489,9 @@ async fn cmd_write<T: BlockIO>(
485489

486490
if early_shutdown.try_recv().is_ok() {
487491
eprintln!("shutting down early in response to SIGUSR1");
488-
join_all(futures).await?;
492+
for future in futures {
493+
future.await?;
494+
}
489495
crucible.flush(None).await?;
490496
return Ok(total_bytes_written);
491497
}
@@ -523,7 +529,9 @@ async fn cmd_write<T: BlockIO>(
523529
)
524530
.await?;
525531
} else {
526-
join_all(futures).await?;
532+
for future in futures {
533+
future.await?;
534+
}
527535
crucible.flush(None).await?;
528536
}
529537

@@ -536,14 +544,10 @@ async fn handle_signals(
536544
mut signals: Signals,
537545
early_shutdown: oneshot::Sender<()>,
538546
) {
539-
while let Some(signal) = signals.next().await {
540-
match signal {
541-
SIGUSR1 => {
542-
early_shutdown.send(()).unwrap();
543-
break;
544-
}
545-
_ => unreachable!(),
546-
}
547+
match signals.next().await {
548+
Some(SIGUSR1) => early_shutdown.send(()).unwrap(),
549+
Some(_) => unreachable!(),
550+
None => (), // signal sender is dropped
547551
}
548552
}
549553

@@ -563,10 +567,10 @@ async fn main() -> Result<()> {
563567
};
564568

565569
// TODO: volumes?
566-
let guest = Arc::new(Guest::new(None));
570+
let (guest, io) = Guest::new(None);
571+
let guest = Arc::new(guest);
567572

568-
let _join_handle =
569-
up_main(crucible_opts, opt.gen, None, guest.clone(), None)?;
573+
let _join_handle = up_main(crucible_opts, opt.gen, None, io, None)?;
570574
eprintln!("Crucible runtime is spawned");
571575

572576
// IO time

crutest/src/cli.rs

+20-25
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ pub enum DscCommand {
8888
#[derive(Debug, Parser, PartialEq)]
8989
#[clap(name = "", term_width = 80, no_binary_name = true)]
9090
enum CliCommand {
91-
/// Send an activation message to all the downstairs and block
92-
/// until all the downstairs answer
91+
/// Send an activation message and wait for an answer.
9392
Activate {
9493
/// Specify this generation number to use when requesting activation.
9594
#[clap(long, short, default_value = "1", action)]
@@ -225,14 +224,12 @@ async fn cli_read(
225224
* Convert offset to its byte value.
226225
*/
227226
let offset = Block::new(block_index as u64, ri.block_size.trailing_zeros());
228-
let length: usize = size * ri.block_size as usize;
229-
230-
let data = crucible::Buffer::from_vec(vec![255; length]);
227+
let mut data = crucible::Buffer::repeat(255, size, ri.block_size as usize);
231228

232229
println!("Read at block {:5}, len:{:7}", offset.value, data.len());
233-
guest.read(offset, data.clone()).await?;
230+
guest.read(offset, &mut data).await?;
234231

235-
let mut dl = data.into_vec().unwrap();
232+
let mut dl = data.into_vec();
236233
match validate_vec(
237234
dl.clone(),
238235
block_index,
@@ -661,24 +658,22 @@ pub async fn start_cli_client(attach: SocketAddr) -> Result<()> {
661658
let tcp = sock.connect(attach);
662659
tokio::pin!(tcp);
663660

664-
let mut tcp: TcpStream = loop {
665-
tokio::select! {
666-
_ = &mut deadline => {
667-
println!("connect timeout");
668-
continue 'outer;
669-
}
670-
tcp = &mut tcp => {
671-
match tcp {
672-
Ok(tcp) => {
673-
println!("connected to {}", attach);
674-
break tcp;
675-
}
676-
Err(e) => {
677-
println!("connect to {0} failure: {1:?}",
678-
attach, e);
679-
tokio::time::sleep_until(deadline_secs(10.0)).await;
680-
continue 'outer;
681-
}
661+
let mut tcp: TcpStream = tokio::select! {
662+
_ = &mut deadline => {
663+
println!("connect timeout");
664+
continue 'outer;
665+
}
666+
tcp = &mut tcp => {
667+
match tcp {
668+
Ok(tcp) => {
669+
println!("connected to {}", attach);
670+
tcp
671+
}
672+
Err(e) => {
673+
println!("connect to {0} failure: {1:?}",
674+
attach, e);
675+
tokio::time::sleep_until(deadline_secs(10.0)).await;
676+
continue 'outer;
682677
}
683678
}
684679
}

0 commit comments

Comments
 (0)