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

swiftfuse architecture

Pure-Rust FUSE client for OpenStack Swift. Native Swift v1 API — no S3 translation layer.

                 ┌───────────────────────────────┐
                 │  swiftfuse (Rust, tokio)      │
   POSIX         │                               │
  syscalls       │  PathFilesystem (fuse3)       │
      │          │   │                           │
      ▼          │   ├─ attr cache (TTL)         │
 /dev/fuse ─────►│   ├─ dir cache (TTL)          │
                 │   ├─ open-file handles        │
                 │   │   └─ temp-file write-back │
                 │   └─ prefetch read window     │
                 │          │                    │
                 │          ▼                    │
                 │   SwiftClient (retry, auth)   │
                 └──────────┬────────────────────┘
                            │ native Swift v1 HTTP
                            ▼
                    Swift proxy (LB) → object nodes

Phase 1: thin native adapter (this codebase)

Layout: / = Swift account, /container = container, /container/name = object. Sub-directories are synthesized from name prefixes (/ separator); mkdir materializes a zero-byte marker object <dir>/ so empty directories persist across remounts. Raw objects remain fully visible to native Swift clients.

Consistency model (close-to-open, GeeseFS/JuiceFS-style)

OperationImplementation
readrange GETs straight from Swift; per-handle prefetch
writebuffered into a local temp file per open handle
flush/closeONE atomic object PUT (≤ 5 GiB) or segment manifest
metadataTTL caches; invalidated on local mutation
renameserver-side COPY + DELETE (file); recursive dir copy

Readers never observe a partially written object: a replace is either the old object or the new one. This is the “objects are immutable, mutation happens in metadata” principle applied at the object granularity.

Large objects

Files above single_put_max are written as immutable segments (<cont>_segments/<name>.segments/<hash>/<seq>) and published atomically as a manifest:

  • DLO (default): empty object + X-Object-Manifest header. Works on every Swift deployment.
  • SLO: JSON manifest PUT. Requires the cluster’s slo middleware; the lab cluster’s SLO middleware is not functional (missing [filter:slo] config was added, still inert), hence DLO default.

Segment names are deterministic (content hash of the object name), so rewrites coalesce and orphaned segments can be garbage-collected by prefix.

Authentication

  • TempAuthV1: GET /auth/v1.0, X-Auth-User / X-Auth-Key. Storage URL overridable (node-local endpoint instead of VIP).
  • KeystoneV3: password → scoped token; object-store endpoint resolved from the catalog, overridable.
  • Token cached, proactively refreshed, force-refreshed on 401.
  • Idempotent requests retry with exponential backoff; streaming PUTs recreate their body per attempt.

Known limitations (phase 1)

  • Partial overwrite of a large existing file materializes the whole object to the temp file first (write amplification, like every object adapter).
  • No multi-client locking; last-flush-wins (close-to-open consistency).
  • No hard links; symlinks unsupported (ENOSYS).
  • xattrs not supported (ENOSYS).
  • Orphaned segments from overwritten large objects need GC.

Phase 2 roadmap: chunk/slice/block data plane

The 宗旨 architecture (metadata/data separation, immutable objects, mutation only in metadata) maps onto this codebase as follows:

inode (metadata: size, times, mode)      ← SQLite/etcd/TiKV (control plane)
  └── chunk 0..N  (logical 32–256 MiB)   ← fixed-size, like JuiceFS
        └── slice (one write op)          ← immutable
              └── block ≤ 4–16 MiB        ← the physical Swift object
  • Random 4 KiB write = one new immutable block + atomic metadata commit (never rewrite the object).
  • Background compaction merges slices per chunk.
  • FUSE layer already routes through Handle + SloWriter; the chunk plane replaces the temp-file full-buffer path behind the same flush/close hook.
  • Metadata engine choice for a 4-node lab: SQLite (single mount) or etcd (multi-client leases, ProxyFS-style).

Testing

  • crates/swift-client/tests/client_test.rs: auth flows, pagination, range GETs, retry/401-refresh (wiremock).
  • Integration on the cluster: scripts/smoke_test.sh (POSIX ops + md5 verification + SLO/DLO large files).