share_blob.rs
Overview
This file defines a single function, share_blob, responsible for safely writing binary data to a shared file path. It ensures that the target file is created atomically by first writing data to a temporary file within a specified temporary directory, then renaming that temporary file to the intended final path. This approach minimizes risks of partial writes or corrupted files in concurrent or failure-prone environments.
Function Details
share_blob
pub fn share_blob(
share_full_path: PathBuf,
tmp_dir_path: &Path,
data: &mut dyn std::io::Read,
) -> anyhow::Result<()>
Purpose
Writes the data from a readable stream to a file at share_full_path. If the target file already exists, the function returns early without overwriting. Otherwise, it writes to a temporary file within tmp_dir_path and then atomically renames the temporary file to the final destination.
Parameters
share_full_path: PathBuf
The full path where the blob data should be stored permanently. This is the target file path.tmp_dir_path: &Path
The directory path in which a temporary file will be created during the writing process.data: &mut dyn std::io::Read
A mutable reference to a trait object implementingReadfrom which the binary data is read.
Return Value
anyhow::Result<()>
ReturnsOk(())if the operation completes successfully. Returns an error if file creation, writing, syncing, or renaming fails.
Usage Example
use std::fs::File;
use std::path::PathBuf;
let tmp_dir = std::path::Path::new("/tmp");
let target_path = PathBuf::from("/shared/data_blob.bin");
let mut file = File::open("source_blob.bin")?;
share_blob(target_path, tmp_dir, &mut file)?;
Implementation Details
File Existence Check:
Ifshare_full_pathalready exists, the function skips any further operations and returnsOk(()). This prevents overwriting existing data.Temporary File Path Generation:
Callsget_temp_file_path(tmp_dir_path)(imported fromcrate::helper) to obtain a unique temporary file path within the given temporary directory.Parent Directory Creation:
Ensures that the parent directory of the temporary file path exists by creating it recursively if necessary.Data Writing:
Opens the temporary file for writing and copies the entire content from thedatareader into it.File Synchronization:
Callsfile.sync_all()to ensure all buffered writes are flushed to the underlying storage, providing durability before renaming.Atomic Rename:
Renames the temporary file to the targetshare_full_path, ensuring an atomic operation that either fully writes the new file or leaves the old state untouched.Tracing:
Throughout the process, tracing macros (tracing::trace!) provide detailed logging for debugging or audit purposes.
Interaction with Other Components
crate::helper::get_temp_file_path:
This helper function is used to generate a safe and unique temporary file path inside the provided temporary directory. The exact algorithm or naming schema is encapsulated in this function.Filesystem Operations:
Utilizes Rust's standard library filesystem APIs (std::fs) for file creation, directory creation, and renaming.Logging/Tracing:
Uses thetracingcrate for diagnostic logging, which integrates with the system's logging infrastructure.
Algorithmic Considerations
The function avoids direct writes to the target file path to reduce risks of partial writes and data corruption. By writing to a temporary file and atomically renaming it, it guarantees that at no point a partially written file is exposed at the target location. This pattern is common in scenarios requiring data integrity and safe file updates.
Diagram: Function Workflow
flowchart TD
Start --> CheckExistence
CheckExistence{"share_full_path exists?"}
CheckExistence -- Yes --> EndSuccess
CheckExistence -- No --> GetTempPath
GetTempPath --> CheckParentDir
CheckParentDir{"Parent dir exists?"}
CheckParentDir -- No --> CreateParentDir
CreateParentDir --> CreateTempFile
CheckParentDir -- Yes --> CreateTempFile
CreateTempFile --> CopyData
CopyData --> SyncFile
SyncFile --> RenameFile
RenameFile --> EndSuccess
EndSuccess["Return Ok(())"]
This flowchart outlines the key steps of the share_blob function, emphasizing decision points and sequential operations to ensure safe file writing.
For deeper understanding of file handling, atomic renames, and error management, refer to the topics on File I/O and Atomic Operations. For logging and tracing, see Tracing and Logging.