diff --git a/core/io/mod.rs b/core/io/mod.rs index 3a08940b5..e209561d3 100644 --- a/core/io/mod.rs +++ b/core/io/mod.rs @@ -52,6 +52,43 @@ pub trait File: Send + Sync { } fn size(&self) -> Result; fn truncate(&self, len: usize, c: Completion) -> Result; + fn copy_to(&self, io: &dyn IO, path: &str) -> Result<()> { + // Open or create the destination file + let dest_file = io.open_file(path, OpenFlags::Create, false)?; + // Get the size of the source file + let file_size = self.size()? as usize; + if file_size == 0 { + return Ok(()); + } + + // use 1MB chunk size + const BUFFER_SIZE: usize = 1024 * 1024; + let mut pos = 0; + + while pos < file_size { + let chunk_size = (file_size - pos).min(BUFFER_SIZE); + // Read from source + let read_buffer = Arc::new(RefCell::new(Buffer::allocate(chunk_size, Rc::new(|_| {})))); + let read_completion = self.pread( + pos, + Completion::new_read(read_buffer.clone(), move |_, _| {}), + )?; + + // Wait for read to complete + io.wait_for_completion(read_completion)?; + + // Write to destination + let write_completion = + dest_file.pwrite(pos, read_buffer, Completion::new_write(|_| {}))?; + io.wait_for_completion(write_completion)?; + + pos += chunk_size; + } + let sync_completion = dest_file.sync(Completion::new_sync(|_| {}))?; + io.wait_for_completion(sync_completion)?; + + Ok(()) + } } #[derive(Debug, Copy, Clone, PartialEq)] diff --git a/core/lib.rs b/core/lib.rs index 903e1b552..bd0eb257c 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -1737,6 +1737,17 @@ impl Connection { pub fn get_pager(&self) -> Rc { self.pager.borrow().clone() } + + /// Copy the current Database and write out to a new file + pub fn copy_db(&self, file: &str) -> Result<()> { + let io = self._db.io.clone(); + let disabled = false; + // checkpoint so everything is in the DB file before copying + self.pager + .borrow_mut() + .wal_checkpoint(disabled, CheckpointMode::Truncate)?; + self.pager.borrow_mut().db_file.copy_to(&*io, file) + } } pub struct Statement { diff --git a/core/storage/database.rs b/core/storage/database.rs index 3687cacb8..1e82b1028 100644 --- a/core/storage/database.rs +++ b/core/storage/database.rs @@ -22,6 +22,7 @@ pub trait DatabaseStorage: Send + Sync { fn sync(&self, c: Completion) -> Result; fn size(&self) -> Result; fn truncate(&self, len: usize, c: Completion) -> Result; + fn copy_to(&self, io: &dyn crate::IO, path: &str) -> Result<()>; } #[cfg(feature = "fs")] @@ -95,6 +96,11 @@ impl DatabaseStorage for DatabaseFile { let c = self.file.truncate(len, c)?; Ok(c) } + + #[instrument(skip_all, level = Level::INFO)] + fn copy_to(&self, io: &dyn crate::IO, path: &str) -> Result<()> { + self.file.copy_to(io, path) + } } #[cfg(feature = "fs")]