diff --git a/USAGE_GUIDE.md b/USAGE_GUIDE.md new file mode 100644 index 0000000..ecfc199 --- /dev/null +++ b/USAGE_GUIDE.md @@ -0,0 +1,306 @@ +# rio Usage Guide + +## Introduction + +rio is a pure Rust io_uring library built on libc, thread & async friendly, and misuse resistant. + +## Quick Start + +### Basic File Read + +```rust +use rio::{Rio, Uring}; + +fn main() -> std::io::Result<()> { + let uring = Uring::new(32)?; + let rio = Rio::new(uring)?; + + let file = rio.open_at( + rio.cwd()?, + "example.txt", + rio::OpenOptions::new().read(true), + )?; + + let buf = vec![0u8; 4096]; + let (file, result) = file.read_at(buf, 0).wait()?; + + println!("Read {} bytes", result?); + Ok(()) +} +``` + +### Async File Write + +```rust +use rio::{Rio, Uring}; +use std::io::Write; + +#[tokio::main] +async fn main() -> std::io::Result<()> { + let uring = Uring::new(32)?; + let rio = Rio::new(uring)?; + + let file = rio.open_at( + rio.cwd()?, + "output.txt", + rio::OpenOptions::new() + .write(true) + .create(true) + .truncate(true), + )?; + + let data = b"Hello, io_uring!"; + let buf = data.to_vec(); + let (_file, result) = file.write_at(buf, 0).await?; + + println!("Wrote {} bytes", result?); + Ok(()) +} +``` + +## Advanced Usage + +### Parallel Operations + +```rust +use rio::{Rio, Uring}; +use std::sync::Arc; + +fn parallel_reads() -> std::io::Result<()> { + let uring = Uring::new(64)?; + let rio = Arc::new(Rio::new(uring)?); + + let mut handles = vec![]; + + for i in 0..4 { + let rio = Arc::clone(&rio); + handles.push(std::thread::spawn(move || { + let file = rio.open_at( + rio.cwd().unwrap(), + format!("file_{}.txt", i), + rio::OpenOptions::new().read(true), + ).unwrap(); + + let buf = vec![0u8; 1024]; + let (_file, result) = file.read_at(buf, 0).wait().unwrap(); + result.unwrap() + })); + } + + for handle in handles { + let bytes = handle.join().unwrap(); + println!("Thread read {} bytes", bytes); + } + + Ok(()) +} +``` + +### Network Operations + +```rust +use rio::{Rio, Uring, TcpListener}; +use std::net::SocketAddr; + +fn tcp_server() -> std::io::Result<()> { + let uring = Uring::new(32)?; + let rio = Rio::new(uring)?; + + let addr: SocketAddr = "127.0.0.1:8080".parse()?; + let listener = TcpListener::bind(&rio, addr)?; + + println!("Listening on {}", addr); + + loop { + let (stream, addr) = listener.accept().wait()?; + println!("Connection from {}", addr); + + // Handle connection in new thread + std::thread::spawn(move || { + // Handle stream... + }); + } +} +``` + +### Buffer Management + +```rust +use rio::{Rio, Uring}; + +// rio automatically manages buffer lifetimes +fn safe_buffer_usage() -> std::io::Result<()> { + let uring = Uring::new(32)?; + let rio = Rio::new(uring)?; + + let file = rio.open_at( + rio.cwd()?, + "data.bin", + rio::OpenOptions::new().read(true), + )?; + + // Buffer is automatically managed + // No manual memory management needed + let buf = vec![0u8; 8192]; + let (_file, bytes_read) = file.read_at(buf, 0).wait()?; + + println!("Read {} bytes safely", bytes_read?); + Ok(()) +} +``` + +## Performance Tips + +### Queue Depth Tuning + +```rust +// Larger queue depth for more parallelism +let uring = Uring::new(256)?; // Default: 32 + +// Smaller for lower latency +let uring = Uring::new(16)?; +``` + +### Batch Operations + +```rust +use rio::{Rio, Uring}; + +fn batch_writes() -> std::io::Result<()> { + let uring = Uring::new(64)?; + let rio = Rio::new(uring)?; + + let file = rio.open_at( + rio.cwd()?, + "batch.txt", + rio::OpenOptions::new().write(true).create(true), + )?; + + // Submit multiple writes + let mut completions = vec![]; + for i in 0..10 { + let data = format!("Line {}\n", i).into_bytes(); + let offset = (i * 10) as u64; + completions.push(file.write_at(data, offset)); + } + + // Wait for all completions + for completion in completions { + let (_file, result) = completion.wait()?; + println!("Wrote: {} bytes", result?); + } + + Ok(()) +} +``` + +## Troubleshooting + +### Permission Denied + +```bash +# io_uring requires kernel 5.1+ +uname -r + +# Check io_uring support +cat /proc/sys/kernel/io_uring_disabled +# Should be 0 (enabled) +``` + +### Resource Limits + +```rust +// Increase max entries if needed +let uring = Uring::new(512)?; + +// Check system limits +cat /proc/sys/fs/aio-max-nr +``` + +### Debug Mode + +```rust +// Enable debug logging +std::env::set_var("RIO_DEBUG", "1"); + +// Use Rio with debug output +let uring = Uring::new(32)?; +let rio = Rio::new(uring)?; +``` + +## Common Patterns + +### Read-Modify-Write + +```rust +use rio::{Rio, Uring}; + +fn read_modify_write() -> std::io::Result<()> { + let uring = Uring::new(32)?; + let rio = Rio::new(uring)?; + + let file = rio.open_at( + rio.cwd()?, + "data.txt", + rio::OpenOptions::new().read(true).write(true), + )?; + + // Read + let buf = vec![0u8; 1024]; + let (file, bytes_read) = file.read_at(buf, 0).wait()?; + + // Modify + let mut data = String::from_utf8_lossy(&bytes_read).to_string(); + data.push_str("\nNew content"); + + // Write back + let (_file, _bytes_written) = file.write_at(data.into_bytes(), 0).wait()?; + + Ok(()) +} +``` + +### Streaming Large Files + +```rust +use rio::{Rio, Uring}; + +fn stream_large_file() -> std::io::Result<()> { + let uring = Uring::new(32)?; + let rio = Rio::new(uring)?; + + let file = rio.open_at( + rio.cwd()?, + "large_file.bin", + rio::OpenOptions::new().read(true), + )?; + + let mut offset = 0u64; + let chunk_size = 4096u64; + + loop { + let buf = vec![0u8; chunk_size as usize]; + let (f, bytes_read) = file.read_at(buf, offset).wait()?; + + if bytes_read? == 0 { + break; // EOF + } + + // Process chunk... + offset += chunk_size; + } + + Ok(()) +} +``` + +## Community + +- **Repository**: https://github.com/spacejam/rio +- **Documentation**: https://docs.rs/rio +- **Chat**: https://discord.gg/Z6VsXds +- **Sponsor**: https://github.com/sponsors/spacejam + +--- + +*Community contribution - unofficial usage guide*