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

Return Value

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

  1. File Existence Check:
    If share_full_path already exists, the function skips any further operations and returns Ok(()). This prevents overwriting existing data.

  2. Temporary File Path Generation:
    Calls get_temp_file_path(tmp_dir_path) (imported from crate::helper) to obtain a unique temporary file path within the given temporary directory.

  3. Parent Directory Creation:
    Ensures that the parent directory of the temporary file path exists by creating it recursively if necessary.

  4. Data Writing:
    Opens the temporary file for writing and copies the entire content from the data reader into it.

  5. File Synchronization:
    Calls file.sync_all() to ensure all buffered writes are flushed to the underlying storage, providing durability before renaming.

  6. Atomic Rename:
    Renames the temporary file to the target share_full_path, ensuring an atomic operation that either fully writes the new file or leaves the old state untouched.

  7. Tracing:
    Throughout the process, tracing macros (tracing::trace!) provide detailed logging for debugging or audit purposes.

Interaction with Other Components

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.