Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lessons from Similar Projects

Analysis of issues from vfs and agentfs to inform AnyFS design.

This chapter documents problems encountered by similar projects and how AnyFS addresses them. These lessons are incorporated into our Implementation Plan and Backend Guide.


Summary

PriorityIssueAnyFS Response
1Panics instead of errorsNo-panic policy, always return Result
2Thread safety problemsConcurrent stress tests required
3Inconsistent path handlingNormalize in one place, test edge cases
4Poor error ergonomicsFsError with context fields
5Missing documentationPerformance & thread safety docs required
6Platform issuesCross-platform CI pipeline

1. Thread Safety Issues

What Happened

ProjectIssueProblem
vfs#72RwLock panic in production
vfs#47create_dir_all races with itself

Root cause: Insufficient synchronization in concurrent access patterns.

AnyFS Response

  • Test concurrent operations explicitly - stress test with multiple threads
  • Document thread safety guarantees per backend
  • Fs: Send bound is intentional
  • MemoryBackend uses Arc<RwLock<...>> for interior mutability

Required tests:

#![allow(unused)]
fn main() {
#[test]
fn test_concurrent_create_dir_all() {
    let backend = Arc::new(RwLock::new(create_backend()));
    let handles: Vec<_> = (0..10).map(|_| {
        let backend = backend.clone();
        std::thread::spawn(move || {
            let mut backend = backend.write().unwrap();
            let _ = backend.create_dir_all(std::path::Path::new("/a/b/c/d"));
        })
    }).collect();
    for handle in handles {
        handle.join().unwrap();
    }
}
}

2. Panics Instead of Errors

What Happened

ProjectIssueProblem
vfs#8AltrootFS panics when file doesn’t exist
vfs#23Unhandled edge cases cause panics
vfs#68MemoryFS panics in WebAssembly

Root cause: Using .unwrap() or .expect() on fallible operations.

AnyFS Response

No-panic policy: Never use .unwrap() or .expect() in library code.

#![allow(unused)]
fn main() {
// BAD - will panic
let entry = self.entries.get(&path).unwrap();

// GOOD - returns error
let entry = self.entries.get(&path)
    .ok_or_else(|| FsError::NotFound { path: path.to_path_buf() })?;
}

Edge cases that must return errors (not panic):

  • File doesn’t exist
  • Directory doesn’t exist
  • Path is empty string
  • Invalid UTF-8 in path
  • Parent directory missing
  • Type mismatch (file vs directory)
  • Concurrent access conflicts

3. Path Handling Inconsistencies

What Happened

ProjectIssueProblem
vfs#24Inconsistent path definition across backends
vfs#42Path join doesn’t behave Unix-like
vfs#22Non-UTF-8 path support questions

Root cause: Each backend implemented path handling differently.

AnyFS Response

  • Normalize paths in ONE place (FileStorage resolver for virtual backends; SelfResolving backends delegate to the OS)
  • Consistent semantics: always absolute, always / separator
  • Use &Path in core traits for object safety; provide impl AsRef<Path> at the ergonomic layer (FileStorage/FsExt)

Required conformance tests:

InputExpected Output
/foo/../bar/bar
/foo/./bar/foo/bar
//double//slash/double/slash
//
`` (empty)Error
/foo/bar//foo/bar

4. Static Lifetime Requirements

What Happened

ProjectIssueProblem
vfs#66Why does filesystem require 'static?

Root cause: Design decision that confused users and limited flexibility.

AnyFS Response

  • Avoid 'static bounds unless necessary
  • Our design: Fs: Send (not 'static)
  • Document why bounds exist when needed

What Happened

ProjectIssueProblem
vfs#81Symlink support missing entirely

Root cause: Symlinks are complex and were deferred indefinitely.

AnyFS Response

  • Symlinks supported via FsLink trait - backends that implement FsLink support symlinks
  • Compile-time capability - no FsLink impl = no symlinks (won’t compile)
  • Bound resolution depth (default: 40 hops)
  • strict-path prevents symlink escapes in VRootFsBackend

6. Error Type Ergonomics

What Happened

ProjectIssueProblem
vfs#33Error type hard to match programmatically

Root cause: Error enum wasn’t designed for pattern matching.

AnyFS Response

FsError includes context and is easy to match:

#![allow(unused)]
fn main() {
#[derive(Debug, thiserror::Error)]
pub enum FsError {
    #[error("not found: {path}")]
    NotFound { path: PathBuf },

    #[error("{operation}: already exists: {path}")]
    AlreadyExists { path: PathBuf, operation: &'static str },

    #[error("quota exceeded: limit {limit}, requested {requested}, usage {usage}")]
    QuotaExceeded { limit: u64, requested: u64, usage: u64 },

    #[error("feature not enabled: {feature} ({operation})")]
    FeatureNotEnabled { feature: &'static str, operation: &'static str },

    #[error("permission denied: {path} ({operation})")]
    PermissionDenied { path: PathBuf, operation: &'static str },

    // ...
}
}

7. Seek + Write Operations

What Happened

ProjectIssueProblem
vfs#35Missing file positioning features

Root cause: Initial API was too simple.

AnyFS Response

  • Streaming I/O: open_read/open_write return Box<dyn Read/Write + Send>
  • Seek support varies by backend - document which support it
  • Consider future: open_read_seek variant or capability query

8. Read-Only Filesystem Request

What Happened

ProjectIssueProblem
vfs#58Request for immutable filesystem

Root cause: No built-in way to enforce read-only access.

AnyFS Response

Already solved: ReadOnly<B> middleware blocks all writes.

#![allow(unused)]
fn main() {
use anyfs::{ReadOnly, FileStorage};
use anyfs_sqlite::SqliteBackend;  // Ecosystem crate

let readonly_fs = FileStorage::new(
    ReadOnly::new(SqliteBackend::open("archive.db")?)
);
// All write operations return FsError::ReadOnly
}

This validates our middleware approach.


9. Performance Issues

What Happened

ProjectIssueProblem
agentfs#130File deletion is slow
agentfs#135Benchmark hangs

Root cause: SQLite operations not optimized, FUSE overhead.

AnyFS Response

  • Batch operations where possible in SqliteBackend
  • Use transactions for multi-file operations
  • Document performance characteristics per backend
  • Keep mounting optional - core AnyFS stays a library; mount concerns are behind feature flags (fuse, winfsp)

Documentation requirement:

#![allow(unused)]
fn main() {
/// # Performance Characteristics
///
/// | Operation | Complexity | Notes |
/// |-----------|------------|-------|
/// | `read` | O(1) | Single DB query |
/// | `write` | O(n) | n = data size |
/// | `remove_dir_all` | O(n) | n = descendants |
pub struct SqliteBackend { ... }
}

10. Signal Handling / Shutdown

What Happened

ProjectIssueProblem
agentfs#129Doesn’t shutdown on SIGTERM

Root cause: FUSE mount cleanup issues.

AnyFS Response

  • Core stays a library - daemon/mount shutdown concerns are behind feature flags
  • Ensure Drop implementations clean up properly
  • SqliteBackend flushes on drop
#![allow(unused)]
fn main() {
impl Drop for SqliteBackend {
    fn drop(&mut self) {
        if let Err(e) = self.sync() {
            eprintln!("Warning: failed to sync on drop: {}", e);
        }
    }
}
}

11. Platform Compatibility

What Happened

ProjectIssueProblem
agentfs#132FUSE-T support (macOS)
agentfs#138virtio-fs support

Root cause: Platform-specific FUSE variants.

AnyFS Response

  • We isolate this - core traits stay pure; FUSE lives behind feature flags (fuse, winfsp) in the anyfs crate
  • Cross-platform by design - Memory and SQLite work everywhere
  • VRootFsBackend uses strict-path which handles Windows/Unix

CI requirement:

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]

12. Multiple Sessions / Concurrent Access

What Happened

ProjectIssueProblem
agentfs#126Can’t have multiple sessions on same filesystem

Root cause: Locking/concurrency design.

AnyFS Response

  • SqliteBackend uses WAL mode for concurrent readers
  • Document concurrency model per backend
  • MemoryBackend uses Arc<RwLock<...>> for sharing

Issues We Already Avoid

Our design decisions already prevent these problems:

Problem in OthersAnyFS Solution
No middleware patternTower-style composable middleware
No quota enforcementQuota<B> middleware
No read-only modeReadOnly<B> middleware
Symlink complexityFsLink trait (compile-time)
Path escape via symlinksstrict-path canonicalization
FUSE complexityIsolated behind feature flags
SQLite-onlyMultiple backends
Monolithic featuresComposable middleware

References