Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ rustflags = ["--cfg", "tokio_unstable"]

[alias]
x = "run --package xtask --"

[env]
MIRIFLAGS = "-Zmiri-disable-isolation"
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Build artifacts
target/
!target/CACHEDIR.TAG

# IDE
.vscode/
.idea/

# Git
.git/
.gitignore

# Logs
*.log

# Documentation build
website/node_modules/
website/build/

# Miri clone (if present)
miri/

# macOS
.DS_Store
67 changes: 67 additions & 0 deletions .github/workflows/miri.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: "Miri"

on:
push:
branches:
- "main"
- "forks/*"
- release-*.*
pull_request:
branches:
- "main"
- "v*.*.*-rc"
- release-*.*
schedule:
# Run weekly on Monday at 00:00 UTC
- cron: '0 0 * * 1'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
RUST_TOOLCHAIN_NIGHTLY: nightly-2025-02-20
CARGO_TERM_COLOR: always
CACHE_KEY_SUFFIX: 20251109

jobs:
miri-test:
name: miri test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Install rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_TOOLCHAIN_NIGHTLY }}
components: miri

- name: Cache Cargo home
uses: actions/cache@v4
id: cache
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('**/Cargo.toml') }}-${{ env.CACHE_KEY_SUFFIX }}-miri-isolated

- name: Setup miri
env:
RUST_TOOLCHAIN_NIGHTLY: ${{ env.RUST_TOOLCHAIN_NIGHTLY }}
run: |
cargo +$RUST_TOOLCHAIN_NIGHTLY miri setup

# Run with stricter miri flags (isolation enabled, more checking)
- name: Run isolated miri tests (strict mode)
env:
RUST_BACKTRACE: 1
RUST_TOOLCHAIN_NIGHTLY: ${{ env.RUST_TOOLCHAIN_NIGHTLY }}
timeout-minutes: 10
run: |
cargo +$RUST_TOOLCHAIN_NIGHTLY miri test --features test_utils --workspace --exclude foyer-bench
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fastrace-opentelemetry = "0.14"
foyer = { version = "0.22.0-dev", path = "foyer" }
foyer-common = { version = "0.22.0-dev", path = "foyer-common" }
foyer-memory = { version = "0.22.0-dev", path = "foyer-memory" }
foyer-storage = { version = "0.22.0-dev", path = "foyer-storage" }
foyer-storage = { version = "0.22.0-dev", path = "foyer-storage", default-features = false }
fs4 = { version = "0.13", default-features = false }
futures-core = { version = "0.3" }
futures-util = { version = "0.3", default-features = false, features = ["std"] }
Expand Down
21 changes: 21 additions & 0 deletions Dockerfile.miri
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Dockerfile for running miri tests on Linux
# Miri's tokio support requires Linux (epoll shims only, not macOS kqueue)

FROM rust:latest

# Nightly toolchain version for miri
ARG NIGHTLY_VERSION=nightly-2025-02-20

# Install specific nightly toolchain and miri components
RUN rustup toolchain install ${NIGHTLY_VERSION} && \
rustup component add --toolchain ${NIGHTLY_VERSION} miri rust-src && \
cargo +${NIGHTLY_VERSION} miri setup

# Set miri flags for testing
ENV MIRIFLAGS="-Zmiri-disable-isolation"

# Set working directory
WORKDIR /workspace

# Default command: run all miri tests
CMD ["sh", "-c", "cargo +${NIGHTLY_VERSION} miri test --features test_utils --workspace --exclude foyer-bench"]
17 changes: 17 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
services:
# Miri testing service for Linux (tokio support via epoll shims)
# Note: macOS tokio is not supported by miri - use Linux container for testing
miri:
build:
context: .
dockerfile: Dockerfile.miri
volumes:
- .:/workspace
environment:
# Optional: Add miri flags for stricter checking
# MIRIFLAGS: "-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check"
- RUST_BACKTRACE=1
command: cargo +nightly miri test --features test_utils --workspace --exclude foyer-bench

# Monitoring stack services (for performance profiling and metrics)
# node-exporter collects system-level metrics (CPU, memory, disk, network)
# Used by Prometheus for monitoring foyer-bench and other performance tests
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
Expand Down
2 changes: 1 addition & 1 deletion foyer-bench/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ fn setup() {
console_subscriber::init();
}

#[cfg(feature = "tracing")]
#[cfg(all(feature = "tracing", not(feature = "tokio-console")))]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is unrelated; it allows running cargo test --all-features

fn setup() {
use fastrace::collector::Config;
let reporter = fastrace_jaeger::JaegerReporter::new("127.0.0.1:6831".parse().unwrap(), "foyer-bench").unwrap();
Expand Down
8 changes: 4 additions & 4 deletions foyer-common/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl SingletonHandle {
///
/// # Examples
///
/// ```
/// ```ignore (miri)
/// use tokio::runtime::Runtime;
///
/// # fn dox() {
Expand Down Expand Up @@ -122,7 +122,7 @@ impl SingletonHandle {
///
/// # Examples
///
/// ```
/// ```ignore (miri)
/// use tokio::runtime::Runtime;
///
/// # fn dox() {
Expand Down Expand Up @@ -173,7 +173,7 @@ impl SingletonHandle {
///
/// # Examples
///
/// ```
/// ```ignore (miri)
/// use tokio::runtime::Runtime;
///
/// // Create the runtime
Expand All @@ -190,7 +190,7 @@ impl SingletonHandle {
///
/// Or using `Handle::current`:
///
/// ```
/// ```ignore (miri)
/// use tokio::runtime::Handle;
///
/// #[tokio::main]
Expand Down
5 changes: 5 additions & 0 deletions foyer-memory/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1257,26 +1257,31 @@ mod tests {
}

#[tokio::test]
#[cfg_attr(miri, ignore = "hangs under miri - needs investigation")]
async fn test_fifo_cache() {
case(fifo()).await
}

#[tokio::test]
#[cfg_attr(miri, ignore = "hangs under miri - needs investigation")]
async fn test_lru_cache() {
case(lru()).await
}

#[tokio::test]
#[cfg_attr(miri, ignore = "hangs under miri - needs investigation")]
async fn test_lfu_cache() {
case(lfu()).await
}

#[tokio::test]
#[cfg_attr(miri, ignore = "hangs under miri - needs investigation")]
async fn test_s3fifo_cache() {
case(s3fifo()).await
}

#[tokio::test]
#[cfg_attr(miri, ignore = "hangs under miri - needs investigation")]
async fn test_sieve_cache() {
case(sieve()).await
}
Expand Down
1 change: 1 addition & 0 deletions foyer-memory/src/eviction/lru.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ where
(false, false) => unsafe { self.list.remove_from_ptr(Arc::as_ptr(record)) },
};

#[cfg(not(miri))]
strict_assert!(!state.link.is_linked());

record.set_in_eviction(false);
Expand Down
5 changes: 5 additions & 0 deletions foyer-memory/src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1807,6 +1807,7 @@ mod tests {
}

#[test_log::test]
#[cfg_attr(miri, ignore = "takes longer than 30 minutes")]
fn test_fifo_cache_fuzzy() {
let cache: RawCache<Fifo<u64, u64, TestProperties>, ModHasher, HashTableIndexer<_>> =
RawCache::new(RawCacheConfig {
Expand All @@ -1824,6 +1825,7 @@ mod tests {
}

#[test_log::test]
#[cfg_attr(miri, ignore = "takes longer than 30 minutes")]
fn test_s3fifo_cache_fuzzy() {
let cache: RawCache<S3Fifo<u64, u64, TestProperties>, ModHasher, HashTableIndexer<_>> =
RawCache::new(RawCacheConfig {
Expand All @@ -1841,6 +1843,7 @@ mod tests {
}

#[test_log::test]
#[cfg_attr(miri, ignore = "takes longer than 30 minutes")]
fn test_lru_cache_fuzzy() {
let cache: RawCache<Lru<u64, u64, TestProperties>, ModHasher, HashTableIndexer<_>> =
RawCache::new(RawCacheConfig {
Expand All @@ -1858,6 +1861,7 @@ mod tests {
}

#[test_log::test]
#[cfg_attr(miri, ignore = "takes longer than 30 minutes")]
fn test_lfu_cache_fuzzy() {
let cache: RawCache<Lfu<u64, u64, TestProperties>, ModHasher, HashTableIndexer<_>> =
RawCache::new(RawCacheConfig {
Expand All @@ -1875,6 +1879,7 @@ mod tests {
}

#[test_log::test]
#[cfg_attr(miri, ignore = "takes longer than 30 minutes")]
fn test_sieve_cache_fuzzy() {
let cache: RawCache<Sieve<u64, u64, TestProperties>, ModHasher, HashTableIndexer<_>> =
RawCache::new(RawCacheConfig {
Expand Down
6 changes: 4 additions & 2 deletions foyer-storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ exclude.workspace = true

[features]
default = []
serde = ["dep:serde"]
serde = ["dep:serde", "foyer-common/serde"]
clap = ["dep:clap"]
tracing = ["dep:fastrace", "foyer-common/tracing", "foyer-memory/tracing"]
nightly = ["allocator-api2/nightly", "hashbrown/nightly"]
Expand All @@ -31,7 +31,6 @@ anyhow = { workspace = true }
bytes = { workspace = true }
clap = { workspace = true, optional = true }
equivalent = { workspace = true }
fastant = { workspace = true, features = ["atomic"] }
fastrace = { workspace = true, optional = true }
foyer-common = { workspace = true }
foyer-memory = { workspace = true }
Expand Down Expand Up @@ -73,6 +72,9 @@ tokio = { workspace = true, features = [
"fs",
] }

[target.'cfg(not(miri))'.dependencies]
fastant = { workspace = true, features = ["atomic"] }

[target.'cfg(target_os = "linux")'.dependencies]
core_affinity = { workspace = true }
io-uring = { workspace = true }
Expand Down
16 changes: 15 additions & 1 deletion foyer-storage/src/engine/block/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ mod tests {
const KB: usize = 1024;

#[test_log::test]
#[cfg_attr(all(miri, not(target_os = "linux")), ignore = "requires Linux for tokio+miri")]
#[cfg_attr(all(miri, target_os = "linux"), ignore = "issue 1223")]
fn test_blob_index_serde() {
let mut bi = BlobIndex::new(IoSliceMut::new(PAGE * 2));
let indices = (0..bi.capacity() / 2)
Expand All @@ -519,6 +521,8 @@ mod tests {
}

#[test_log::test]
#[cfg_attr(all(miri, not(target_os = "linux")), ignore = "requires Linux for tokio+miri")]
#[cfg_attr(all(miri, target_os = "linux"), ignore = "issue 1223")]
fn test_buffer() {
const BLOCK_SIZE: usize = 16 * KB;
const BLOB_INDEX_SIZE: usize = 4 * KB;
Expand Down Expand Up @@ -678,6 +682,8 @@ mod tests {
}

#[test_log::test]
#[cfg_attr(all(miri, not(target_os = "linux")), ignore = "requires Linux for tokio+miri")]
#[cfg_attr(all(miri, target_os = "linux"), ignore = "issue 1223")]
fn test_split_block_last_entry() {
const KB: usize = 1 << 10;

Expand All @@ -689,7 +695,15 @@ mod tests {
let mut ctx = SplitCtx::new(BLOCK_SIZE, BLOB_INDEX_SIZE);
ctx.current_blob_block_offset = 40 * KB;
ctx.current_part_blob_offset = 16 * KB;
ctx.current_blob_index.count = ctx.current_blob_index.capacity() - 1;
// Fill the index with dummy entries to match the count we're setting
for _ in 0..ctx.current_blob_index.capacity() - 1 {
ctx.current_blob_index.write(&BlobEntryIndex {
hash: u64::MAX,
sequence: u64::MAX,
offset: 0,
len: 0,
});
}

let shared_io_slice = IoSliceMut::new(BATCH_SIZE).into_io_slice();
let batch = Splitter::split(
Expand Down
Loading
Loading