blob: ae503f2a717f24519120b3cd3bffbbbe1f95682b [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Implementation of verifier thread.
//!
//! Generator makes verifiers job easy to check completion status. At the least
//! verifier checks if the IO commands returned successfully or not. In addition
//! to that it can perform IO content verification if requested/applicable.
//! IO packet has all the information whether
//! - we need verify a packet or not
//! - it needs extra IO
//! - how to verify
use {
crate::generator::ActiveCommands,
crate::io_packet::{InternalCommand, IoPacketType},
crate::log::Stats,
crate::operations::PipelineStages,
anyhow::Error,
log::{debug, error, warn},
std::{
collections::HashMap,
process,
sync::{
mpsc::{Receiver, Sender},
Arc, Mutex,
},
},
};
pub struct VerifierArgs {
/// Human friendly name for this thread.
name: String,
/// Unique identifier for each verifier.
verifier_unique_id: u64,
// Verifier's stage in lifetime of an IO.
stage: PipelineStages,
// Channel used to receive commands from issuer
from_issuer: Receiver<IoPacketType>,
// Channel used to send verify commands to generator
to_issuer: Sender<IoPacketType>,
// True if verify should do anything more than checking completion status.
verify: bool,
// Hashmap shared between verifier and generator. We remove io packet entries
// from the map once we are done with the packet.
io_map: Arc<Mutex<HashMap<u64, IoPacketType>>>,
// Stats to store data about time spent actively working on a packet.
stats: Arc<Mutex<Stats>>,
// Way to notify issuer that there is at least one verify packet on the other
// end of to_issuer channel.
active_commands: ActiveCommands,
}
// Current implementation of verifier checks only IO command return value.
impl VerifierArgs {
pub fn new(
base_name: String,
verifier_unique_id: u64,
from_issuer: Receiver<IoPacketType>,
to_issuer: Sender<IoPacketType>,
verify: bool,
io_map: Arc<Mutex<HashMap<u64, IoPacketType>>>,
stats: Arc<Mutex<Stats>>,
active_commands: ActiveCommands,
) -> VerifierArgs {
VerifierArgs {
name: format!("{}-{}", base_name, verifier_unique_id),
verifier_unique_id,
from_issuer,
to_issuer,
stage: PipelineStages::Verify,
verify,
io_map,
stats,
active_commands,
}
}
}
pub fn run_verifier(mut args: VerifierArgs) -> Result<(), Error> {
for mut cmd in args.from_issuer {
debug!(
"from verifier: {} id: {} io_seq: {} op: {:?}",
args.name,
args.verifier_unique_id,
cmd.sequence_number(),
cmd.operation_type(),
);
for stage in PipelineStages::iterator() {
let r = cmd.io_offset_range();
let (start, end) = cmd.interval_to_u64(*stage);
debug!(
" completed cmd {:?}->({}, {}) {} {}..{}",
stage,
start,
end,
cmd.stage_timestamps()[stage.stage_number()].duration(),
r.start,
r.end
);
}
cmd.timestamp_stage_start(args.stage);
cmd.get_error().unwrap();
if cmd.verify_needs_io() {
error!("VerifyIo not implemented");
process::abort();
}
// This is not implemented but it shows how ActiveCommands will be used
// when implemented.
if args.verify {
if args.to_issuer.send(cmd).is_err() {
error!("error sending command from issuer");
}
args.active_commands.increment();
error!("VerifyIo not implemented");
process::abort();
}
cmd.timestamp_stage_end(args.stage);
// Remove cmd from the hash map since we are done with verification
{
let mut map = args.io_map.lock().unwrap();
map.remove(&cmd.sequence_number());
debug!("removed cmd {}", cmd.sequence_number());
}
// Update stats
{
let mut stats = args.stats.lock().unwrap();
stats.log(cmd.operation_type(), cmd.io_size(), cmd.stage_timestamps());
}
// For graceful exit or abort
match cmd.abort_or_exit() {
InternalCommand::Exit => {
args.to_issuer.send(cmd).unwrap();
args.active_commands.increment();
debug!("{} - clean exit", args.name);
break;
}
InternalCommand::Abort => {
warn!("{} - aborted", args.name);
break;
}
InternalCommand::None => {}
}
}
Ok(())
}