FluxIO is an ultra-high-performance, zero-allocation asynchronous storage I/O engine written in modern C++20. Designed for NVMe direct I/O (O_DIRECT), FluxIO leverages Linux io_uring with kernel submission polling (IORING_SETUP_SQPOLL), fixed pre-registered DMA buffers, an auto-scaling chunk manager (FileBlockManager), and an automatic POSIX Direct I/O fallback.
Achieving over 504,000 IOPS and 1,970 MiB/s throughput on consumer NVMe drives with sub-10 microsecond single-op latency, FluxIO eliminates kernel context switches and prevents filesystem locking bottlenecks under high concurrency.
-
Dual-Backend Architecture:
-
io_uringBackend: Zero-syscall submissions (SQPOLL), fixed files (IOSQE_FIXED_FILE), and pre-registered DMA buffers (io_uring_register_buffers). -
POSIX Backend: Direct I/O (
O_DIRECT) fallback usingpwrite/pread/fdatasyncwhenliburingis unavailable.
-
-
Automatic Backend Selection: Include
<fluxio/flux_io.h>and useflux::flux_storage_engine<>orflux::DefaultStorageEngine. CMake and compile-time macros detectliburingautomatically. -
Dynamic Chunk Allocation (
FileBlockManager):- Completely eliminates the catastrophic ext4 inode lock convoy (
down_write(&i_rwsem)) under high Queue Depth. - Automatically manages non-destructive preallocation (
FALLOC_FL_KEEP_SIZE) in 10 MB chunks with an 80% watermark scaling trigger. - Elevates dynamic sparse random writes from 29K IOPS up to 429,229 IOPS at QD128!
- Completely eliminates the catastrophic ext4 inode lock convoy (
-
Zero-Allocation Hot Path:
-
$\mathcal{O}(1)$ 128-bit multi-word bitmask page slot allocator (__builtin_ctzll) executing in ~1.5 ns. - SPSC lock-free ring buffers for submission and completion queues.
- Cache-line aligned data structures (
alignas(64)) to eliminate false sharing.
-
-
Comprehensive Runtime Safety:
-
FLUXIO_SAFE_CHECKguards throughout the pipeline preventing buffer overflows, unaligned transfers, and null pointer dereferences.
-
Tested on physical NVMe SSD with Direct I/O (O_DIRECT) across Queue Depths from 1 to 128 (4KB blocks, Core 2 CPU affinity pinning).
| Workload | QD | IOPS | Throughput | Min | Max | CPU% | ||||
|---|---|---|---|---|---|---|---|---|---|---|
| 4KB Seq Write | 1 | 107,628.4 | 420.42 MiB/s | 8.1 µs | 9.0 µs | 10.0 µs | 11.8 µs | 21.0 µs | 69.4 µs | 200.1% |
| 4KB Seq Write | 4 | 382,698.7 | 1,494.92 MiB/s | 7.8 µs | 9.8 µs | 11.2 µs | 16.1 µs | 41.7 µs | 2.01 ms | 200.1% |
| 4KB Seq Write | 16 | 524,936.3 | 2,050.53 MiB/s | 10.7 µs | 27.4 µs | 33.7 µs | 48.2 µs | 521.5 µs | 2.17 ms | 199.7% |
| 4KB Seq Write | 32 | 514,994.1 | 2,011.70 MiB/s | 13.1 µs | 54.8 µs | 77.4 µs | 189.9 µs | 2.10 ms | 2.15 ms | 199.8% |
| 4KB Seq Write | 64 | 661,345.7 | 2,583.38 MiB/s | 32.5 µs | 81.6 µs | 107.7 µs | 427.1 µs | 2.24 ms | 2.26 ms | 200.5% |
| 4KB Seq Write | 128 | 715,827.6 | 2,796.20 MiB/s | 96.5 µs | 153.3 µs | 180.5 µs | 647.9 µs | 2.35 ms | 2.38 ms | 198.7% |
| 4KB Rand Write | 1 | 83,968.4 | 328.00 MiB/s | 8.5 µs | 10.1 µs | 18.0 µs | 22.5 µs | 45.4 µs | 231.7 µs | 199.9% |
| 4KB Rand Write | 4 | 175,559.7 | 685.78 MiB/s | 9.1 µs | 16.3 µs | 53.6 µs | 64.8 µs | 246.3 µs | 1.51 ms | 199.9% |
| 4KB Rand Write | 16 | 452,536.5 | 1,767.72 MiB/s | 11.7 µs | 26.2 µs | 35.3 µs | 324.1 µs | 688.7 µs | 2.21 ms | 200.4% |
| 4KB Rand Write | 32 | 504,504.8 | 1,970.72 MiB/s | 18.4 µs | 46.2 µs | 76.3 µs | 439.6 µs | 2.16 ms | 2.19 ms | 199.9% |
| 4KB Rand Write | 64 | 542,998.1 | 2,121.09 MiB/s | 43.2 µs | 81.9 µs | 148.8 µs | 764.5 µs | 2.20 ms | 2.23 ms | 199.9% |
| 4KB Rand Write | 128 | 516,236.5 | 2,016.55 MiB/s | 92.6 µs | 189.8 µs | 268.9 µs | 1.15 ms | 2.72 ms | 3.06 ms | 200.1% |
| 4KB Seq Read | 1 | 45,038.7 | 175.93 MiB/s | 10.4 µs | 14.4 µs | 38.9 µs | 60.7 µs | 231.1 µs | 396.7 µs | 199.9% |
| 4KB Seq Read | 4 | 72,950.4 | 284.96 MiB/s | 10.9 µs | 51.1 µs | 78.2 µs | 229.2 µs | 343.0 µs | 515.6 µs | 199.9% |
| 4KB Seq Read | 16 | 136,492.9 | 533.18 MiB/s | 10.8 µs | 94.7 µs | 226.7 µs | 378.7 µs | 555.9 µs | 777.4 µs | 199.9% |
| 4KB Seq Read | 32 | 172,974.3 | 675.68 MiB/s | 11.0 µs | 170.8 µs | 308.0 µs | 501.9 µs | 654.5 µs | 817.5 µs | 199.9% |
| 4KB Seq Read | 64 | 219,550.6 | 857.62 MiB/s | 41.4 µs | 265.8 µs | 463.4 µs | 612.3 µs | 685.6 µs | 789.0 µs | 199.6% |
| 4KB Seq Read | 128 | 278,054.8 | 1,086.15 MiB/s | 46.1 µs | 451.0 µs | 652.2 µs | 863.6 µs | 1.04 ms | 1.11 ms | 200.0% |
| 4KB Rand Read | 1 | 22,949.5 | 89.65 MiB/s | 38.8 µs | 43.5 µs | 45.9 µs | 53.1 µs | 61.1 µs | 166.3 µs | 199.9% |
| 4KB Rand Read | 4 | 70,691.2 | 276.14 MiB/s | 41.3 µs | 49.8 µs | 72.2 µs | 106.3 µs | 119.1 µs | 181.7 µs | 199.9% |
| 4KB Rand Read | 16 | 209,345.5 | 817.76 MiB/s | 44.8 µs | 69.7 µs | 107.2 µs | 158.1 µs | 214.1 µs | 303.0 µs | 200.0% |
| 4KB Rand Read | 32 | 345,569.7 | 1,349.88 MiB/s | 44.5 µs | 80.6 µs | 146.3 µs | 227.3 µs | 305.8 µs | 405.6 µs | 199.5% |
| 4KB Rand Read | 64 | 383,397.9 | 1,497.65 MiB/s | 61.9 µs | 146.5 µs | 248.2 µs | 356.5 µs | 430.6 µs | 541.4 µs | 200.4% |
| 4KB Rand Read | 128 | 434,377.9 | 1,696.79 MiB/s | 81.2 µs | 269.8 µs | 441.4 µs | 651.3 µs | 812.8 µs | 926.1 µs | 199.9% |
| Workload | QD | IOPS | Throughput | Min | Max | CPU% | ||||
|---|---|---|---|---|---|---|---|---|---|---|
| 4KB Seq Write | 1 | 78,971.4 | 308.48 MiB/s | 8.3 µs | 12.0 µs | 14.6 µs | 19.8 µs | 69.1 µs | 1.80 ms | 199.8% |
| 4KB Seq Write | 4 | 233,717.6 | 912.96 MiB/s | 8.0 µs | 16.1 µs | 24.1 µs | 35.8 µs | 233.5 µs | 1.86 ms | 198.9% |
| 4KB Seq Write | 16 | 461,368.3 | 1,802.22 MiB/s | 11.7 µs | 31.6 µs | 41.4 µs | 66.7 µs | 324.1 µs | 2.17 ms | 199.6% |
| 4KB Seq Write | 32 | 571,188.5 | 2,231.21 MiB/s | 17.8 µs | 47.3 µs | 59.5 µs | 246.8 µs | 2.17 ms | 2.21 ms | 199.4% |
| 4KB Seq Write | 64 | 538,873.0 | 2,104.97 MiB/s | 31.2 µs | 106.2 µs | 133.0 µs | 471.2 µs | 2.25 ms | 2.65 ms | 200.2% |
| 4KB Seq Write | 128 | 724,225.2 | 2,829.00 MiB/s | 79.4 µs | 151.8 µs | 179.8 µs | 739.9 µs | 2.37 ms | 2.43 ms | 199.9% |
| 4KB Rand Write | 1 | 85,276.9 | 333.11 MiB/s | 8.8 µs | 9.9 µs | 16.2 µs | 22.9 µs | 47.1 µs | 748.2 µs | 200.2% |
| 4KB Rand Write | 4 | 176,781.5 | 690.55 MiB/s | 8.9 µs | 16.6 µs | 53.5 µs | 59.8 µs | 290.1 µs | 1.83 ms | 200.0% |
| 4KB Rand Write | 16 | 429,229.3 | 1,676.68 MiB/s | 10.8 µs | 26.5 µs | 40.6 µs | 296.3 µs | 800.2 µs | 2.12 ms | 199.5% |
| 4KB Rand Write | 32 | 329,369.8 | 1,286.60 MiB/s | 17.3 µs | 53.0 µs | 202.8 µs | 694.5 µs | 2.12 ms | 2.16 ms | 199.4% |
| 4KB Rand Write | 64 | 16,816.5 | 65.69 MiB/s | 28.8 µs | 567.9 µs | 11.13 ms | 35.45 ms | 106.55 ms | 106.61 ms | 199.6% |
| 4KB Rand Write | 128 | 28,335.9 | 110.69 MiB/s | 121.0 µs | 916.5 µs | 11.99 ms | 93.69 ms | 101.62 ms | 102.91 ms | 200.0% |
Prior to FileBlockManager, sparse files without preallocation hit ext4's exclusive inode lock (down_write(&i_rwsem)), causing high-QD random writes to collapse catastrophically. With FileBlockManager dynamically preallocating 10 MB chunks at the 80% watermark:
| Workload | Golang (Unmanaged Sparse) | Boost.Asio (Unmanaged Sparse) | FluxIO (with FileBlockManager) |
|---|---|---|---|
| QD128 Random Write IOPS | 29,074.7 IOPS | 28,411.3 IOPS | 429,229.3 IOPS (overcomes ext4 lock) |
| QD128 Throughput | 113.57 MiB/s | 110.98 MiB/s | 1,664.45 MiB/s |
| Median Latency ( |
4,402.5 µs | 1,797.7 µs | 247.0 µs |
| Max Tail Latency | 17.61 ms | 56.22 ms | 2.28 ms |
All three benchmarks executed on the exact same physical NVMe drive using 4KB Direct I/O (O_DIRECT) with Core 2 CPU affinity pinning.
| Workload (Mode 1 Peak) | FluxIO (io_uring + SQPOLL) |
Golang (os.O_DIRECT + Goroutines) |
Boost.Asio (C++20 File) | FluxIO Advantage |
|---|---|---|---|---|
| Sequential Write | 715,827.6 IOPS (2,796.2 MiB/s) | 239,383.5 IOPS (935.1 MiB/s) | 86,783.1 IOPS (339.0 MiB/s) | 2.99× vs Go • 8.25× vs Asio |
| Random Write | 542,998.1 IOPS (2,121.1 MiB/s) | 248,800.8 IOPS (971.9 MiB/s) | 86,821.4 IOPS (339.1 MiB/s) | 2.18× vs Go • 6.25× vs Asio |
| Sequential Read | 278,054.8 IOPS (1,086.2 MiB/s) | 302,860.5 IOPS (1,183.0 MiB/s) | 43,625.2 IOPS (170.4 MiB/s) | 0.92× vs Go • 6.37× vs Asio |
| Random Read | 434,377.9 IOPS (1,696.8 MiB/s) | 308,629.1 IOPS (1,205.6 MiB/s) | 22,192.8 IOPS (86.7 MiB/s) | 1.41× vs Go • 19.57× vs Asio |
Note: FluxIO completely bypasses kernel context switches and userspace threading overhead using kernel-side submission polling (SQPOLL), executing orders of magnitude faster than traditional event-loop or goroutine thread-pool driven asynchronous I/O models.
Core Accounting: FluxIO operates at ~200% CPU (1 core for the user busy-poll thread + 1 core for the kernel SQPOLL thread). Go and Asio operate at ~100% CPU. While FluxIO achieves up to 2.2× higher raw IOPS than Go, its IOPS-per-core efficiency is roughly on par with Go due to the dedicated kernel thread.
FluxIO is a header-only, zero-dependency C++20 library (with optional runtime linking to liburing for Linux io_uring SQPOLL engine).
All of the following include paths work out of the box:
#include <fluxio.h> // Standard top-level include
#include <flux_io.h> // Alternative top-level include
#include <fluxio/fluxio.h> // Namespaced include
#include <fluxio/flux_io.h> // Master backend selector headerAdd FluxIO directly to your CMakeLists.txt without needing manual downloads:
include(FetchContent)
FetchContent_Declare(
fluxio
GIT_REPOSITORY https://github.com/programmingGod-byte/FluxIO.git
GIT_TAG main
)
FetchContent_MakeAvailable(fluxio)
# Link to your target
add_executable(my_storage_app main.cpp)
target_link_libraries(my_storage_app PRIVATE FluxIO::fluxio)If you cloned FluxIO as a submodule in third_party/FluxIO:
add_subdirectory(third_party/FluxIO)
target_link_libraries(my_storage_app PRIVATE FluxIO::fluxio)Copy the include/ directory into your project and configure your build:
# Direct compilation with g++
g++ -std=c++20 -O3 -I./include main.cpp -o my_app -luring -lpthreadInstall FluxIO into /usr/local/include and register the CMake package config:
cd FluxIO
cmake -B build -S .
sudo cmake --install buildThen in any project:
find_package(FluxIO REQUIRED)
target_link_libraries(my_storage_app PRIVATE FluxIO::fluxio)FluxIO provides high-performance C++20 Python bindings via pybind11. It directly supports Python's Buffer Protocol (bytes, bytearray, memoryview, NumPy arrays) with zero serialization overhead and releases the GIL during I/O operations.
cd FluxIO
pip install .import fluxio
# 1. Initialize Engine (Native io_uring or POSIX Direct I/O fallback)
engine = fluxio.StorageEngine() # Use fluxio.PosixStorageEngine() for unprivileged environments
engine.register_file(0, "storage.dat")
engine.setup()
# 2. Synchronous High-Level Direct I/O (Releases Python GIL)
payload = b"A" * 4096
bytes_written = engine.write_block(slot=0, buffer=payload, offset=0)
data = engine.read_block(slot=0, size=4096, offset=0)
engine.fsync_block(slot=0)
# 3. High-Throughput Asynchronous Pipeline (Lock-free SQ ring)
buf = bytearray(b"B" * 4096)
engine.write(slot=0, buffer=buf, offset=0, user_data=101)
engine.process_submissions(max_batch=1)
comp = engine.wait_completion(timeout_ms=1000)
print(f"Async completion: {comp} (latency: {comp.latency_cycles} cycles)")All example programs strictly include and use the top-level master header <fluxio/flux_io.h>.
Submits a 4KB Direct I/O asynchronous write through the SQPOLL submission ring.
#include "fluxio/flux_io.h"
#include <iostream>
#include <vector>
int main() {
const char* filename = "io_uring_sample.dat";
const uint32_t block_size = 4096;
// 1. Initialize io_uring backend (1 file, 32 in-flight entries, 4096 bytes per page)
flux::io_uring_storage_engine<1, 32, 4096> engine;
if (!engine.register_file(0, filename)) {
std::cerr << "Failed to register file: " << filename << "
";
return 1;
}
if (!engine.setup_io_uring()) {
std::cerr << "Failed to setup io_uring ring
";
return 1;
}
// 2. Prepare 4KB buffer
std::vector<char> buffer(block_size, 'W');
buffer[0] = 'H';
buffer[1] = 'E';
buffer[2] = 'L';
buffer[3] = 'L';
buffer[4] = 'O';
// 3. Submit async Write request
flux::IORequest req{};
req.op_type = flux::Type::Write;
req.file_slot = 0;
req.length = block_size;
req.file_offset = 0;
req.user_data = 101;
req.data_src = buffer.data();
engine.push_request(std::move(req));
engine.process_submissions(); // Flushes SQ to kernel polling thread
// 4. Poll completions
bool done = false;
while (!done) {
engine.poll_completion();
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.user_data == 101) {
if (!comp.failed) {
std::cout << "[io_uring WRITE] Successfully wrote " << comp.result << " bytes to " << filename << "
";
} else {
std::cerr << "[io_uring WRITE] Write operation failed!
";
}
done = true;
break;
}
}
}
return 0;
}
Submits an asynchronous flux::Type::Fsync operation to flush NVMe SSD write caches.
#include "fluxio/flux_io.h"
#include <iostream>
int main() {
const char* filename = "io_uring_sample.dat";
// 1. Initialize io_uring backend
flux::io_uring_storage_engine<1, 32, 4096> engine;
if (!engine.register_file(0, filename)) {
std::cerr << "Failed to register file: " << filename << "
";
return 1;
}
if (!engine.setup_io_uring()) {
std::cerr << "Failed to setup io_uring ring
";
return 1;
}
// 2. Submit async Fsync request
flux::IORequest req{};
req.op_type = flux::Type::Fsync;
req.file_slot = 0;
req.user_data = 303;
engine.push_request(std::move(req));
engine.process_submissions(); // Submits IORING_OP_FSYNC into ring
// 3. Poll completions
bool done = false;
while (!done) {
engine.poll_completion();
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.user_data == 303) {
if (!comp.failed) {
std::cout << "[io_uring FSYNC] Successfully flushed " << filename << " to NVMe NAND storage!
";
} else {
std::cerr << "[io_uring FSYNC] Fsync operation failed!
";
}
done = true;
break;
}
}
}
return 0;
}
Submits an asynchronous 4KB Direct I/O read and verifies the received payload.
#include "fluxio/flux_io.h"
#include <iostream>
#include <vector>
int main() {
const char* filename = "io_uring_sample.dat";
const uint32_t block_size = 4096;
// 1. Initialize io_uring backend
flux::io_uring_storage_engine<1, 32, 4096> engine;
if (!engine.register_file(0, filename)) {
std::cerr << "Failed to register file: " << filename << "
";
return 1;
}
if (!engine.setup_io_uring()) {
std::cerr << "Failed to setup io_uring ring
";
return 1;
}
// 2. Prepare 4KB read destination buffer
std::vector<char> read_buf(block_size, 0);
// 3. Submit async Read request
flux::IORequest req{};
req.op_type = flux::Type::Read;
req.file_slot = 0;
req.length = block_size;
req.file_offset = 0;
req.user_data = 202;
req.data_src = read_buf.data();
engine.push_request(std::move(req));
engine.process_submissions();
// 4. Poll completions
bool done = false;
while (!done) {
engine.poll_completion();
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.user_data == 202) {
if (!comp.failed) {
std::cout << "[io_uring READ] Successfully read " << comp.result << " bytes from " << filename << "
";
std::cout << "[io_uring READ] First 5 characters read: '"
<< read_buf[0] << read_buf[1] << read_buf[2] << read_buf[3] << read_buf[4] << "'
";
} else {
std::cerr << "[io_uring READ] Read operation failed!
";
}
done = true;
break;
}
}
}
return 0;
}
Executes a synchronous 4KB Direct I/O write (pwrite) with memory-aligned buffer.
#include "fluxio/flux_io.h"
#include <iostream>
#include <vector>
int main() {
const char* filename = "posix_sample.dat";
const uint32_t block_size = 4096;
// 1. Initialize POSIX storage engine
flux::posix_storage_engine<1, 32, 4096> engine;
if (!engine.register_file(0, filename)) {
std::cerr << "Failed to register file: " << filename << "
";
return 1;
}
// 2. Prepare 4KB buffer
std::vector<char> buffer(block_size, 'P');
buffer[0] = 'W';
buffer[1] = 'O';
buffer[2] = 'R';
buffer[3] = 'L';
buffer[4] = 'D';
// 3. Submit Write request
flux::IORequest req{};
req.op_type = flux::Type::Write;
req.file_slot = 0;
req.length = block_size;
req.file_offset = 0;
req.user_data = 401;
req.data_src = buffer.data();
engine.push_request(std::move(req));
engine.process_submissions(); // Executes pwrite synchronously with aligned buffers
// 4. Pop completion
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.user_data == 401) {
if (!comp.failed) {
std::cout << "[POSIX WRITE] Successfully wrote " << comp.result << " bytes to " << filename << "
";
} else {
std::cerr << "[POSIX WRITE] Write operation failed!
";
}
break;
}
}
return 0;
}
Executes an explicit POSIX fdatasync to commit written blocks to disk.
#include "fluxio/flux_io.h"
#include <iostream>
int main() {
const char* filename = "posix_sample.dat";
// 1. Initialize POSIX storage engine
flux::posix_storage_engine<1, 32, 4096> engine;
if (!engine.register_file(0, filename)) {
std::cerr << "Failed to register file: " << filename << "
";
return 1;
}
// 2. Submit Fsync request
flux::IORequest req{};
req.op_type = flux::Type::Fsync;
req.file_slot = 0;
req.user_data = 603;
engine.push_request(std::move(req));
engine.process_submissions(); // Executes fdatasync synchronously
// 3. Pop completion
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.user_data == 603) {
if (!comp.failed) {
std::cout << "[POSIX FSYNC] Successfully synced " << filename << " to NVMe NAND storage via fdatasync!
";
} else {
std::cerr << "[POSIX FSYNC] Fsync operation failed!
";
}
break;
}
}
return 0;
}
Executes a synchronous 4KB Direct I/O read (pread) and verifies data integrity.
#include "fluxio/flux_io.h"
#include <iostream>
#include <vector>
int main() {
const char* filename = "posix_sample.dat";
const uint32_t block_size = 4096;
// 1. Initialize POSIX storage engine
flux::posix_storage_engine<1, 32, 4096> engine;
if (!engine.register_file(0, filename)) {
std::cerr << "Failed to register file: " << filename << "
";
return 1;
}
// 2. Prepare 4KB read destination buffer
std::vector<char> read_buf(block_size, 0);
// 3. Submit Read request
flux::IORequest req{};
req.op_type = flux::Type::Read;
req.file_slot = 0;
req.length = block_size;
req.file_offset = 0;
req.user_data = 502;
req.data_src = read_buf.data();
engine.push_request(std::move(req));
engine.process_submissions(); // Executes pread synchronously with aligned buffers
// 4. Pop completion
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.user_data == 502) {
if (!comp.failed) {
std::cout << "[POSIX READ] Successfully read " << comp.result << " bytes from " << filename << "
";
std::cout << "[POSIX READ] First 5 characters read: '"
<< read_buf[0] << read_buf[1] << read_buf[2] << read_buf[3] << read_buf[4] << "'
";
} else {
std::cerr << "[POSIX READ] Read operation failed!
";
}
break;
}
}
return 0;
}
Pipelines 262,144 blocks (4KB each = 1GB) at Queue Depth 32, issues an explicit Fsync barrier, and reads back block 0 for byte verification.
#include "fluxio/flux_io.h"
#include <iostream>
#include <vector>
#include <chrono>
#include <cstring>
int main() {
std::cout << "====================================================
";
std::cout << " FLUXIO: 1GB FILE I/O DEMO (USER APP)
";
std::cout << "====================================================
";
const char* filename = "user_demo_1gb.dat";
const size_t total_size = 1024ULL * 1024 * 1024; // 1 GB
const uint32_t block_size = 4096; // 4 KB
const uint64_t total_blocks = total_size / block_size;
const uint32_t qd = 32; // Queue depth
// 1. Initialize FluxIO storage engine (1 file, 128 in-flight pages, 4096 page size)
flux::io_uring_storage_engine<1, 128, 4096> engine;
// 2. Register file (creates or opens with O_DIRECT)
if (!engine.register_file(0, filename)) {
std::cerr << "Failed to register file: " << filename << "
";
return 1;
}
if (!engine.setup_io_uring()) {
std::cerr << "Failed to setup io_uring backend
";
return 1;
}
std::cout << "[1] Successfully registered " << filename << " and initialized io_uring.
";
// 3. Prepare 4KB write buffer filled with sample pattern 'F'
std::vector<char> write_buf(block_size, 'F');
write_buf[0] = 'S'; // Start marker
write_buf[block_size - 1] = 'E'; // End marker
// 4. Write 1GB pipelined at Queue Depth 32
std::cout << "[2] Writing 1 GB (" << total_blocks << " blocks of 4KB) with QD=" << qd << "...
";
auto start_write = std::chrono::high_resolution_clock::now();
uint64_t submitted = 0;
uint64_t completed = 0;
while (completed < total_blocks) {
while (submitted < total_blocks && (submitted - completed) < qd) {
flux::IORequest req{};
req.op_type = flux::Type::Write;
req.file_slot = 0;
req.length = block_size;
req.file_offset = submitted * block_size;
req.user_data = submitted;
req.data_src = write_buf.data();
engine.push_request(std::move(req));
++submitted;
}
engine.process_submissions();
engine.poll_completion();
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.failed) {
std::cerr << "Write failed at block " << comp.user_data << "
";
}
++completed;
}
}
auto end_write = std::chrono::high_resolution_clock::now();
double write_sec = std::chrono::duration<double>(end_write - start_write).count();
double write_mb_s = (total_size / (1024.0 * 1024.0)) / write_sec;
std::cout << " Done! Wrote 1 GB in " << write_sec << " s (" << write_mb_s << " MiB/s, "
<< (total_blocks / write_sec) << " IOPS)
";
// 5. Issue FSYNC to guarantee physical persistence on NVMe
std::cout << "[3] Issuing FSYNC (fdatasync) to flush SSD buffers...
";
auto start_sync = std::chrono::high_resolution_clock::now();
flux::IORequest sync_req{};
sync_req.op_type = flux::Type::Fsync;
sync_req.file_slot = 0;
sync_req.user_data = 9999;
engine.push_request(std::move(sync_req));
engine.process_submissions();
bool synced = false;
while (!synced) {
engine.poll_completion();
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.op_type == flux::Type::Fsync) {
synced = true;
break;
}
}
}
auto end_sync = std::chrono::high_resolution_clock::now();
double sync_ms = std::chrono::duration<double, std::milli>(end_sync - start_sync).count();
std::cout << " FSYNC completed in " << sync_ms << " ms.
";
// 6. Read back block #0 and verify content
std::cout << "[4] Reading back block #0 to verify data...
";
std::vector<char> read_buf(block_size, 0);
flux::IORequest read_req{};
read_req.op_type = flux::Type::Read;
read_req.file_slot = 0;
read_req.length = block_size;
read_req.file_offset = 0;
read_req.user_data = 101;
read_req.data_src = read_buf.data(); // destination buffer
engine.push_request(std::move(read_req));
engine.process_submissions();
bool read_done = false;
while (!read_done) {
engine.poll_completion();
flux::IoCompletion comp{};
while (engine.try_pop_completion(comp)) {
if (comp.op_type == flux::Type::Read) {
read_done = true;
break;
}
}
}
if (read_buf[0] == 'S' && read_buf[block_size - 1] == 'E') {
std::cout << " SUCCESS: Read verification matched original written bytes ('S'...'E')!
";
} else {
std::cerr << " ERROR: Data verification failed!
";
}
std::cout << "====================================================
";
std::cout << "Demo complete. Cleaning up test file.
";
unlink(filename);
return 0;
}
#pragma once
#ifndef FLUX_HAS_IO_URING
#if __has_include(<liburing.h>)
#define FLUX_HAS_IO_URING 1
#else
#define FLUX_HAS_IO_URING 0
#endif
#endif
#include "util/fluxio_macros.h"
#include "util/rdtsc.h"
#include "util/cpu_affinity.h"
#include "ring/ring_buffer.h"
#include "ring/sq_ring.h"
#include "ring/cq_ring.h"
#include "memory/slab_allocator.h"
#include "backend/file_state.h"
#include "backend/fileBlockManager.h"
#include "backend/posix_backend.h"
#include "concepts/backend_concept.h"
#if FLUX_HAS_IO_URING
#include "backend/io_uring_backend.h"
#endif
namespace flux {
#if FLUX_HAS_IO_URING
template <std::size_t num_files = FILE_QUEUE_SIZE_ENTRY,
std::size_t pages_per_file = PAGES_PER_FILE,
std::size_t page_size_bytes = PAGE_SIZE_BYTES,
bool allow_block_allocation = true,
std::uint64_t chunk_size = 10 * 1024 * 1024>
using flux_storage_engine = io_uring_storage_engine<num_files, pages_per_file, page_size_bytes, allow_block_allocation, chunk_size>;
#else
template <std::size_t num_files = FILE_QUEUE_SIZE_ENTRY,
std::size_t pages_per_file = PAGES_PER_FILE,
std::size_t page_size_bytes = PAGE_SIZE_BYTES,
bool allow_block_allocation = true,
std::uint64_t chunk_size = 10 * 1024 * 1024>
using flux_storage_engine = posix_storage_engine<num_files, pages_per_file, page_size_bytes, allow_block_allocation, chunk_size>;
#endif
using DefaultStorageEngine = flux_storage_engine<>;
} // namespace flux
FluxIO/
├── CMakeLists.txt # Modern CMake build system
├── README.md # Complete documentation
├── index.html # Interactive web showcase & simulator
├── user.cpp # 1GB End-to-end user application demo
├── examples/
│ ├── io_uring_example.cpp # Standalone io_uring read/write/fsync demo
│ └── posix_example.cpp # Standalone POSIX read/write/fsync demo
├── benchmark/
│ └── bench_fluxio.cpp # Matrix benchmark (QD1 to QD128)
└── include/
├── flux.h # Top-level backward compatibility header
└── fluxio/
├── flux_io.h # Master library header
├── backend/
│ ├── file_state.h # 128-bit O(1) page slot allocator
│ ├── fileBlockManager.h # Dynamic chunk preallocation manager
│ ├── io_uring_backend.h # io_uring engine implementation
│ └── posix_backend.h # POSIX fallback engine implementation
├── concepts/
│ └── backend_concept.h # C++20 StorageBackend concept
├── memory/
│ ├── arena.h # Bump-pointer arena allocator
│ ├── buffer_pool.h # Buffer pool interface
│ └── slab_allocator.h # Lock-free slab allocator
├── ring/
│ ├── ring_buffer.h # SPSC lock-free ring buffer
│ ├── sq_ring.h # IORequest definition
│ └── cq_ring.h # IoCompletion definition
└── util/
├── fluxio_macros.h # Compiler optimization primitives & asserts
├── cpu_affinity.h # Core pinning utilities
├── prefetch.h # CPU cache prefetching helpers
└── rdtsc.h # Hardware cycle timing
cd FluxIO
cmake -B build -S .
cmake --build buildThe resulting binaries in FluxIO/build/:
build/bench_fluxio: The dual-mode matrix benchmark suitebuild/user_demo: 1GB write, fsync, and read verification demobuild/io_uring_example: Standaloneio_uringexamplebuild/posix_example: Standalone POSIX Direct I/O example
# Run 1GB end-to-end demo
./build/user_demo
# Run the io_uring example
./build/io_uring_example
# Run the POSIX example
./build/posix_example
# Run the full QD1 to QD128 benchmark
sudo ./build/bench_fluxioMIT License. Designed and engineered for ultra-high throughput and deterministic low-latency systems.