Expand description
This crate provides a simple file caching mechanism with a straightforward interface for creating, retrieving, and managing cached files efficiently.
§Features
- Temporary and Persistent Caches: Create caches in temporary directories or specified paths.
- Lazy File Creation: Files are created only when accessed, reducing unnecessary disk operations.
- Automatic Refresh: Files can be automatically refreshed based on a specified interval.
- Callback Functions: Custom logic can be executed when files are created or accessed.
§Setup
To use this crate, add the following entry to your Cargo.toml file in the dependencies section:
[dependencies]
fcache = "0.2.0"Alternatively, you can use the cargo add subcommand:
cargo add fcache§Usage
Use the new function to create a new cache instance in a temporary directory.
use fcache::prelude::*;
// Create a new cache instance
let cache = fcache::new()?;
// Get or create a cached file
let cache_file = cache.get("hello.txt", |mut file| {
// Write data to the file
file.write_all(b"Hello, world!")?;
Ok(())
})?;
// File is created and can be used...
// Open the cached file
let mut file = cache_file.open()?;
// Read the content of the file
let mut content = String::new();
file.read_to_string(&mut content)?;
// Assert the content matches what was written
assert_eq!(content, "Hello, world!");Use the with_dir function to create a cache in a specified directory.
use fcache::prelude::*;
// Create a new cache instance in a specified directory
let cache = fcache::with_dir("/path/to/cache")?;
// Get or create a cached file
let cache_file = cache.get("hello.txt", |mut file| {
// Write data to the file
file.write_all(b"Hello, world!")?;
Ok(())
})?;
// File is created and can be used...
// Open the cached file
let mut file = cache_file.open()?;
// Read the content of the file
let mut content = String::new();
file.read_to_string(&mut content)?;
// Assert the content matches what was written
assert_eq!(content, "Hello, world!");§Lazy files
Lazy files are a special type of file that is not created until it is accessed. This can be useful for reducing unnecessary disk operations, especially when the file may not be needed immediately.
See Cache::get_lazy, and CacheLazyFile for more details on how to use lazy files.
use fcache::prelude::*;
// Create a new cache instance in a specified directory
let cache = fcache::new()?;
// Get or create a lazy cached file
let cache_file = cache.get_lazy("hello.txt", |mut file| {
// Write data to the file
file.write_all(b"Hello, world!")?;
Ok(())
})?;
// File isn't created until opened...
// Open the cached file
let mut file = cache_file.open()?; // File is created here
// Read the content of the file
let mut content = String::new();
file.read_to_string(&mut content)?;
// Assert the content matches what was written
assert_eq!(content, "Hello, world!");§Force Refresh
Files in the cache can be forcefully refreshed to regenerate their content, even if they are still within their refresh interval. This is useful when you need to ensure the file content is updated immediately.
See CacheFile::force_refresh, and CacheLazyFile::force_refresh for more details.
use fcache::prelude::*;
// Create a new cache instance
let cache = fcache::new()?;
// Create a file with initial content
let cache_file = cache.get("data.txt", |mut file| {
file.write_all(b"Initial content")?;
Ok(())
})?;
// Force refresh the file with new content
let cache_file = cache.get("data.txt", |mut file| {
file.write_all(b"Updated content")?;
Ok(())
})?;
cache_file.force_refresh()?;
// The file now contains the updated content
let mut file = cache_file.open()?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert_eq!(content, "Updated content");§Locking and unlocking
Files can be locked and unlocked to prevent refreshing or modifying them while they are in use. This is useful for ensuring that the file remains consistent during operations.
See CacheFile::lock/CacheFile::unlock, and CacheLazyFile::lock/CacheLazyFile::unlock for more details.
This is not a thread-safe operation.
use fcache::prelude::*;
// Create a new cache instance in a specified directory
let cache = fcache::new()?;
// Get or create a cached file
let mut cache_file = cache.get("hello.txt", |mut file| {
// Write data to the file
file.write_all(b"Hello, world!")?;
Ok(())
})?;
// File is created and can be used...
// Lock the file to prevent refreshing
cache_file.lock()?; // Lock the file to prevent refreshing
// Perform operations on the file
// Unlock the file to allow refreshing
cache_file.unlock()?; // Unlock the file to allow refreshing
// ...§Thread Safety
The cache system is designed to be thread-safe for most operations. Cache instances can be safely shared across multiple threads using Arc or similar synchronization primitives.
use std::sync::Arc;
use std::thread;
use fcache::prelude::*;
// Create a cache instance that can be shared across threads
let cache = Arc::new(fcache::new()?);
// Spawn multiple threads that use the same cache
let handles: Vec<_> = (0..4)
.map(|i| {
let cache = Arc::clone(&cache);
thread::spawn(move || {
// Each thread can safely create files in the cache
let cache_file = cache.get(&format!("thread_{}.txt", i), move |mut file| {
file.write_all(format!("Content from thread {}", i).as_bytes())?;
Ok(())
})?;
// And read from them
let mut content = String::new();
cache_file.open()?.read_to_string(&mut content)?;
println!("Thread {}: {}", i, content);
Ok::<(), fcache::Error>(())
})
})
.collect();
// Wait for all threads to complete
for handle in handles {
handle
.join()
.expect("Thread should complete successfully")?;
}§Thread Safety Guarantees
- Cache instances: Safe to share across threads using
Arc. - File creation: Multiple threads can safely create different files simultaneously.
- File operations: Reading and writing operations are thread-safe at the filesystem level.
§Thread Safety Limitations
- File locking: The built-in locking mechanism is not thread-safe and should not be relied upon for inter-thread synchronization (see Locking and unlocking for more details).
- Concurrent access: Users must implement their own synchronization using external mechanisms like
MutexorRwLockwhen multiple threads access the same file path, as the cache does not provide automatic protection against race conditions.
§Tips and tricks
§Always refresh
Use Duration::ZERO to ensure the cache is always refreshed.
use std::time::Duration;
use fcache::prelude::*;
// Create a new cache instance
let cache = fcache::new()?.with_refresh_interval(Duration::ZERO);
// Get or create a cached file
let mut cache_file = cache.get("hello.txt", |mut file| {
// Write data to the file
file.write_all(b"Hello, world!")?;
// Inform about the refresh
println!("Refreshing file");
Ok(())
})?;
// File refreshes on every access
let file = cache_file.open()?;
let file = cache_file.open()?;
let file = cache_file.open()?;
// ...§Never refresh
Use Duration::MAX to disable automatic refresh. Use force_refresh for manual control.
use std::time::Duration;
use fcache::prelude::*;
// Create a new cache instance
let cache = fcache::new()?.with_refresh_interval(Duration::MAX);
// Get or create a cached file
let mut cache_file = cache.get("hello.txt", |mut file| {
// Write data to the file
file.write_all(b"Hello, world!")?;
// Inform about the refresh
println!("Refreshing file");
Ok(())
})?;
// File never refreshes automatically
let file = cache_file.open()?;
let file = cache_file.open()?;
let file = cache_file.open()?;
// ...
// Manual refresh when needed
cache_file.force_refresh()?;§License
This crate is licensed under the MIT License.
Modules§
- prelude
- Convenience module that re-exports commonly used types and traits.
Structs§
- Cache
- Represents a cache instance.
- Cache
File - A file in the cache.
- Cache
Lazy File - A file in the cache that is lazily created when accessed.
Enums§
- Error
- Custom error types for the cache operations.
Constants§
- DEFAULT_
REFRESH_ INTERVAL - Default refresh interval for the cache.
Traits§
- Callback
Fn - Trait alias for callback functions used in cache operations.
Functions§
- new
- Creates a new cache instance within a temporary directory.
- with_
dir - Creates a new cache instance within a specified directory.
- with_
prefix - Creates a new cache instance within a temporary directory with a specified prefix.