use std::sync::atomic::{AtomicU8, Ordering};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::segment::types::Memory;
use crate::segment::vector_storage::common::get_async_scorer;
#[derive(Debug, Deserialize, Serialize, JsonSchema, Copy, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum IoUringMode {
Disabled,
Auto,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum IoUringFallback {
AsyncScorer,
Mmap,
}
static IO_URING_MODE: AtomicU8 = AtomicU8::new(MODE_UNSET);
const MODE_UNSET: u8 = 0;
const MODE_DISABLED: u8 = 1;
const MODE_AUTO: u8 = 2;
fn encode_mode(mode: Option<IoUringMode>) -> u8 {
match mode {
None => MODE_UNSET,
Some(IoUringMode::Disabled) => MODE_DISABLED,
Some(IoUringMode::Auto) => MODE_AUTO,
}
}
fn decode_mode(encoded: u8) -> Option<IoUringMode> {
match encoded {
MODE_UNSET => None,
MODE_DISABLED => Some(IoUringMode::Disabled),
MODE_AUTO => Some(IoUringMode::Auto),
_ => {
debug_assert!(false, "unknown encoded io_uring mode: {encoded}");
None
}
}
}
pub fn set_io_uring_mode(mode: Option<IoUringMode>) {
IO_URING_MODE.store(encode_mode(mode), Ordering::Relaxed);
}
pub fn io_uring_mode() -> Option<IoUringMode> {
decode_mode(IO_URING_MODE.load(Ordering::Relaxed))
}
pub fn use_io_uring(fallback: IoUringFallback, memory: Memory, feature_flag: bool) -> bool {
if !feature_flag {
return false;
}
match io_uring_mode() {
None => match fallback {
IoUringFallback::AsyncScorer => get_async_scorer() && is_io_uring_supported(),
IoUringFallback::Mmap => false,
},
Some(IoUringMode::Disabled) => false,
Some(IoUringMode::Auto) => memory.is_cold() && is_io_uring_supported(),
}
}
#[cfg(target_os = "linux")]
fn is_io_uring_supported() -> bool {
crate::common::universal_io::is_io_uring_supported()
}
#[cfg(not(target_os = "linux"))]
fn is_io_uring_supported() -> bool {
false
}
#[cfg(test)]
mod tests {
use super::*;
use crate::segment::vector_storage::common::set_async_scorer;
#[test]
fn test_use_io_uring() {
use IoUringFallback::{AsyncScorer, Mmap};
let supported = is_io_uring_supported();
set_io_uring_mode(None);
set_async_scorer(true);
assert_eq!(use_io_uring(AsyncScorer, Memory::Cold, true), supported);
assert_eq!(use_io_uring(AsyncScorer, Memory::Cached, true), supported);
assert!(!use_io_uring(Mmap, Memory::Cold, true));
set_async_scorer(false);
assert!(!use_io_uring(AsyncScorer, Memory::Cold, true));
set_io_uring_mode(Some(IoUringMode::Disabled));
set_async_scorer(true);
assert!(!use_io_uring(AsyncScorer, Memory::Cold, true));
assert!(!use_io_uring(Mmap, Memory::Cold, true));
set_io_uring_mode(Some(IoUringMode::Auto));
set_async_scorer(false);
assert_eq!(use_io_uring(Mmap, Memory::Cold, true), supported);
assert_eq!(use_io_uring(AsyncScorer, Memory::Cold, true), supported);
assert!(!use_io_uring(Mmap, Memory::Cached, true));
assert!(!use_io_uring(Mmap, Memory::Pinned, true));
assert!(!use_io_uring(Mmap, Memory::Cold, false));
set_io_uring_mode(None);
set_async_scorer(false);
}
}