diff --git a/bigtools/src/utils/cli/bigwigtobedgraph.rs b/bigtools/src/utils/cli/bigwigtobedgraph.rs index a20228d..883020d 100644 --- a/bigtools/src/utils/cli/bigwigtobedgraph.rs +++ b/bigtools/src/utils/cli/bigwigtobedgraph.rs @@ -18,7 +18,7 @@ use ufmt::uwrite; #[command( name = "bigwigtobedgraph", about = "Converts an input bigWig to a bedGraph.", - long_about = "Converts an input bigWig to a bedGraph. Can be multi-threaded for substantial speedups. Note for roughly each core, one temporary file will be opened." + long_about = "Converts an input bigWig to a bedGraph. Can be multi-threaded for substantial speedups." )] pub struct BigWigToBedGraphArgs { /// the bigwig to get convert to bedgraph @@ -42,10 +42,16 @@ pub struct BigWigToBedGraphArgs { /// If set, restrict output to regions overlapping the bed file pub overlap_bed: Option, - /// Set the number of threads to use. This tool will nearly always benefit from more cores (<= # chroms). Note: for parts of the runtime, the actual usage may be nthreads+1 + /// Set the number of threads to use. This tool will nearly always benefit from more cores (<= # chroms). #[arg(short = 't', long)] #[arg(default_value_t = 6)] pub nthreads: usize, + + /// Do not create temporary files for intermediate data. (Only applicable when using multiple threads.) + /// By default, approximately one temporary file will be opened for each core. + #[arg(long)] + #[arg(default_value_t = false)] + pub inmemory: bool, } pub fn bigwigtobedgraph(args: BigWigToBedGraphArgs) -> Result<(), Box> { @@ -92,6 +98,7 @@ pub fn bigwigtobedgraph(args: BigWigToBedGraphArgs) -> Result<(), Box args.start, args.end, runtime.handle(), + args.inmemory, ))?; } } @@ -143,18 +150,19 @@ pub async fn write_bg( start: Option, end: Option, runtime: &runtime::Handle, + inmemory: bool, ) -> Result<(), BBIReadError> { let start = chrom.as_ref().and_then(|_| start); let end = chrom.as_ref().and_then(|_| end); let chroms: Vec = bigwig.chroms().to_vec(); - let chrom_files: Vec)>> = chroms + let chrom_files: Vec, String)>> = chroms .into_iter() .filter(|c| chrom.as_ref().map_or(true, |chrom| &c.name == chrom)) .map(|chrom| { let bigwig = bigwig.reopen()?; let (buf, file): (TempFileBuffer, TempFileBufferWriter) = - TempFileBuffer::new(true); + TempFileBuffer::new(inmemory); let writer = io::BufWriter::new(file); async fn file_future( mut bigwig: BigWigRead, @@ -183,17 +191,18 @@ pub async fn write_bg( } let start = start.unwrap_or(0); let end = end.unwrap_or(chrom.length); + let name = chrom.name.clone(); let handle = runtime .spawn(file_future(bigwig, chrom, writer, start, end)) .map(|f| f.unwrap()); - Ok((handle, buf)) + Ok((handle, buf, name)) }) .collect::>(); for res in chrom_files { - let (f, mut buf) = res.unwrap(); + let (f, mut buf, name) = res?; buf.switch(out_file); - f.await.unwrap(); + f.await?; while !buf.is_real_file_ready() { tokio::task::yield_now().await; } diff --git a/bigtools/src/utils/file/tempfilebuffer.rs b/bigtools/src/utils/file/tempfilebuffer.rs index 06d35c9..5d4f67d 100644 --- a/bigtools/src/utils/file/tempfilebuffer.rs +++ b/bigtools/src/utils/file/tempfilebuffer.rs @@ -78,7 +78,7 @@ impl TempFileBuffer { BufferState::Real(_) => panic!("Should not have switched already."), BufferState::InMemory(data) => Ok(data.len() as u64), BufferState::Temp(ref mut t) => t.seek(io::SeekFrom::Current(0)), - BufferState::NotStarted => panic!("No data was written."), + BufferState::NotStarted => Ok(0), } } @@ -113,11 +113,10 @@ impl TempFileBuffer { // Writer was dropped with no tempfile being created (or written to) real_file } - (None, BufferState::InMemory(_) | BufferState::Temp(_)) => { + (None, BufferState::Real(real_file)) => real_file, + (None, BufferState::InMemory(_) | BufferState::Temp(_) | BufferState::NotStarted) => { panic!("Should have switched already.") } - (None, BufferState::Real(real_file)) => real_file, - (None, BufferState::NotStarted) => panic!("No data was written."), } } @@ -144,8 +143,8 @@ impl TempFileBuffer { BufferState::InMemory(data) => { real.write_all(&data)?; } + BufferState::NotStarted => {} BufferState::Real(_) => panic!("Should only be writing to real file."), - BufferState::NotStarted => panic!("No data was written."), } Ok(()) } @@ -197,10 +196,7 @@ impl Drop for TempFileBufferWriter { let &(ref lock, ref cvar) = &*self.closed; let mut closed = lock.lock().unwrap(); let buffer_state = std::mem::replace(&mut self.buffer_state, BufferState::NotStarted); - match buffer_state { - BufferState::NotStarted => {} - state => *closed = Some(state), - } + *closed = Some(buffer_state); cvar.notify_one(); drop(closed); }