Hi there, I've implemented a file copier that attempts to:
-memory map the source file
-memory map the destination file
-FIRST VERSION SequentialBlockCopier() copy the blocks in sequential from source map to destination map. IT WORKS.
-SECOND VERSION ParallelBlockCopier() copy the blocks in parallel from source map to destination map.
Compilation error: *mut u8 cannot be sent between threads safely.
My poor head can't solve this. I'm sorry. Could anybody help with this?
Thank you in advance for any advice and suggestions. Cheers.
-copy the quotient remainder bytes from source map to destination map. IT WORKS.
Done.
I've attached the source below for the project called dtmfcopy. DTMF = dedicated to my family.
cat Cargo.toml
[package]
name = "dtmfcopy"
version = "0.1.0"
authors = ["David Marceau <uticdmarceau2007@yahoo.ca>"]
edition = "2018"
[dependencies]
libc = "0.2.77"
flume = "0.9.1"
threadpool = "1.8.1"
[profile.release]
lto = 'thin'
panic = 'abort'
codegen-units = 1
cat src/main.rs
//dtmfcopy
//dtmf stands for "dedicated to my family"
//Oct 2020
// This program is heavily inspired by b3sum for being so good at reading a huge file so quickly.
use std::env;
use libc;
use std::{
fs::File,
fs::OpenOptions,
io::{Seek, SeekFrom, Write},
os::unix::prelude::AsRawFd,
ptr,
};
use threadpool::ThreadPool;
#[derive(Debug,Clone)]
pub struct BlockCopyConf {
pub TakeCPUCores : i32,
pub Block_size : i64,
pub Blocks_per_chunk : i64,
pub Chunk_size : i64,
pub QuotientChunks : i64,
pub NumberOfBlocksToCopy : i64,
pub ModuloRemainderBytes : i64,
pub SourceFileMap : *mut libc::c_void,
pub DestinationFileMap : *mut libc::c_void,
pub Src_offset : *mut u8,
pub Dst_offset : *mut u8,
}
fn main() {
let mut srcFilePath : String = "".to_string();
let mut dstFilePath : String = "".to_string();
let mut arg_counter = 0;
for argument in env::args() {
match arg_counter {
1 => {
srcFilePath = argument.clone();
println!("srcFilePath:<<{}>>", srcFilePath);
},
2 => {
dstFilePath = argument.clone();
println!("dstFilePath:<<{}>>", dstFilePath);
},
_ => {
}
}
arg_counter = arg_counter + 1;
}
let mut myBlockCopyConf = BlockCopyConf {
TakeCPUCores : 4,
Block_size : 4096,
Blocks_per_chunk : 1024,
Chunk_size : 4096 * 1024,
QuotientChunks : 0,
NumberOfBlocksToCopy : 0,
ModuloRemainderBytes : 0,
SourceFileMap : 0 as *mut libc::c_void,
DestinationFileMap : 0 as *mut libc::c_void,
Src_offset : 0 as *mut u8,
Dst_offset : 0 as *mut u8,
};
let mut theModuloChunkCounter : i64 = 999;
let mut nChunkCounter : i64 = 0;
//let mut nDeterminedNumberOfChunks : i64 = 0;
let mut srcFileOpenOptions : &mut std::fs::OpenOptions;
let mut srcFile : File;
let mut srcMetadata : std::fs::Metadata;
let mut srcFile_size : u64;
let mut srcFileResult : std::result::Result<File, std::io::Error>;
let mut srcFileOpenOptions = OpenOptions::new();
srcFileOpenOptions.read(true).write(true);
srcFileResult = srcFileOpenOptions.open(srcFilePath);
if( !srcFileResult.is_ok() ) {
return;
} else {
srcFile = srcFileResult.unwrap();
srcMetadata = srcFile.metadata().unwrap();
if !srcMetadata.is_file() {
return;
}
srcFile_size = srcMetadata.len();
}
unsafe {
myBlockCopyConf.SourceFileMap = libc::mmap(
/* addr: */ ptr::null_mut(),
/* len: */ srcFile_size as usize,
/* prot: */ libc::PROT_READ | libc::PROT_WRITE,
// Then make the mapping *public* so it is written back to the file
/* flags: */ libc::MAP_SHARED,
/* fd: */ srcFile.as_raw_fd(),
/* offset: */ 0,
);
}
if myBlockCopyConf.SourceFileMap == libc::MAP_FAILED {
return;
}
let mut dstFileOpenOptions : &mut std::fs::OpenOptions;
let mut dstFile : File;
let mut dstMetadata : std::fs::Metadata;
let mut dstFile_size : u64;
let mut dstFileResult : std::result::Result<File, std::io::Error>;
let mut dstFileOpenOptions = OpenOptions::new();
dstFileOpenOptions.read(true).write(true).create(true);
dstFileResult = dstFileOpenOptions.open(dstFilePath);
if( !dstFileResult.is_ok() ) {
return;
} else {
dstFile = dstFileResult.unwrap();
}
// Reserve filesize capacity beforehand
let dstFile_size = srcFile_size;
dstFile.seek(SeekFrom::Start((dstFile_size - 1) as u64)).unwrap();
dstFile.write_all(&[0]).unwrap();
dstFile.seek(SeekFrom::Start(0)).unwrap();
unsafe {
myBlockCopyConf.DestinationFileMap = libc::mmap(
/* addr: */ ptr::null_mut(),
/* len: */ dstFile_size as usize,
/* prot: */ libc::PROT_READ | libc::PROT_WRITE,
// Then make the mapping *public* so it is written back to the file
/* flags: */ libc::MAP_SHARED,
/* fd: */ dstFile.as_raw_fd(),
/* offset: */ 0,
);
}
if myBlockCopyConf.DestinationFileMap == libc::MAP_FAILED {
return;
}
myBlockCopyConf.QuotientChunks = (srcFile_size as i64) / (myBlockCopyConf.Chunk_size as i64);
myBlockCopyConf.ModuloRemainderBytes = (srcFile_size as i64) % (myBlockCopyConf.Chunk_size as i64);
myBlockCopyConf.Src_offset = myBlockCopyConf.SourceFileMap as *mut u8; // as *mut u8 as usize;
myBlockCopyConf.Dst_offset = myBlockCopyConf.DestinationFileMap as *mut u8; // as *mut u8 as usize;
myBlockCopyConf.NumberOfBlocksToCopy = myBlockCopyConf.Blocks_per_chunk * myBlockCopyConf.QuotientChunks;
SequentialBlockCopier(&mut myBlockCopyConf);
//ParallelBlockCopier(&mut myBlockCopyConf);
if (myBlockCopyConf.ModuloRemainderBytes > 0) {
println!("ModuloRemainderBytes:<<{}>>",myBlockCopyConf.ModuloRemainderBytes);
let mut myBlock_Src_offset = myBlockCopyConf.SourceFileMap as *mut u8; // as *mut u8 as usize;
let mut myBlock_Dst_offset = myBlockCopyConf.DestinationFileMap as *mut u8; // as *mut u8 as usize;
myBlock_Src_offset = (myBlock_Src_offset as usize + (myBlockCopyConf.NumberOfBlocksToCopy * myBlockCopyConf.Block_size) as usize ) as *mut u8;
myBlock_Dst_offset = (myBlock_Dst_offset as usize + (myBlockCopyConf.NumberOfBlocksToCopy * myBlockCopyConf.Block_size) as usize ) as *mut u8;
unsafe {
ptr::copy_nonoverlapping(myBlock_Src_offset as *mut u8, myBlock_Dst_offset as *mut u8, myBlockCopyConf.ModuloRemainderBytes as usize);
}
} else {
//println!("No remainder bytes.");
}
println!("\nsrcFile_size:<<{}>>",srcFile_size);
println!("Done");
}
pub fn SequentialBlockCopier(theBlockCopyConf_ : &mut BlockCopyConf) {
for blockCounter in 0..theBlockCopyConf_.NumberOfBlocksToCopy {
unsafe {
ptr::copy_nonoverlapping(theBlockCopyConf_.Src_offset as *mut u8, theBlockCopyConf_.Dst_offset as *mut u8, theBlockCopyConf_.Block_size as usize);
}
theBlockCopyConf_.Src_offset = (theBlockCopyConf_.Src_offset as usize + theBlockCopyConf_.Block_size as usize) as *mut u8;
theBlockCopyConf_.Dst_offset = (theBlockCopyConf_.Dst_offset as usize + theBlockCopyConf_.Block_size as usize) as *mut u8;
if (blockCounter % theBlockCopyConf_.Blocks_per_chunk == 0) {
print!("."); // displays a . progress for a chunk
std::io::stdout().flush();
}
}
}
// pub fn ParallelBlockCopier(theBlockCopyConf_ : &mut BlockCopyConf) {
// let (tx, rx) = flume::unbounded();
// let mut mySourceMapStart = theBlockCopyConf_.SourceFileMap as *mut u8; // as *mut u8 as usize;
// let mut myDestMapStart = theBlockCopyConf_.DestinationFileMap as *mut u8; // as *mut u8 as usize;
// let mut myBlockSize = theBlockCopyConf_.Block_size;
// let mut pool = ThreadPool::new(theBlockCopyConf_.TakeCPUCores as usize); //pool count to cpu cores you want to take
// for nBlockCopyLaunchRequestCounter in 0..theBlockCopyConf_.NumberOfBlocksToCopy { //upper bound is exclusive
// let tx2 = tx.clone();
// unsafe {
// pool.execute(move || {
// //do the block copy here
// //println!("nBlockCopyLaunchRequestCounter:<<{}>>", nBlockCopyLaunchRequestCounter);
// let mut myBlock_Src_offset = mySourceMapStart;
// let mut myBlock_Dst_offset = myDestMapStart;
// myBlock_Src_offset = (myBlock_Src_offset as usize + (nBlockCopyLaunchRequestCounter * myBlockSize ) as usize ) as *mut u8;
// myBlock_Dst_offset = (myBlock_Dst_offset as usize + (nBlockCopyLaunchRequestCounter * myBlockSize ) as usize ) as *mut u8;
// unsafe {
// ptr::copy_nonoverlapping(myBlock_Src_offset as *mut u8, myBlock_Dst_offset as *mut u8, myBlockSize as usize);
// }
// tx2.send(nBlockCopyLaunchRequestCounter);
// });
// }
// }
// drop(tx); // We are done with our sending half so we can explicitly drop it here.
// for theReturnedBlockCopyIndex in rx {
// //println!("theReturnedBlockCopyIndex:<<{}>>",theReturnedBlockCopyIndex);
// }
// }
// error[E0277]: `*mut u8` cannot be sent between threads safely
// --> src/main.rs:207:22
// |
// 207 | pool.execute(move || {
// | ______________________^^^^^^^_-
// | | |
// | | `*mut u8` cannot be sent between threads safely
// 208 | | //do the block copy here
// 209 | | //println!("nBlockCopyLaunchRequestCounter:<<{}>>", nBlockCopyLaunchRequestCounter);
// 210 | |
// ... |
// 221 | | tx2.send(nBlockCopyLaunchRequestCounter);
// 222 | | });
// | |_________________- within this `[closure@src/main.rs:207:30: 222:18]`
// |
// = help: within `[closure@src/main.rs:207:30: 222:18]`, the trait `Send` is not implemented for `*mut u8`
// = note: required because it appears within the type `[closure@src/main.rs:207:30: 222:18]`
[david@eastwoodarch dtmfcopy]$