Skip to main content

feoxdb/core/store/
init.rs

1use ahash::RandomState;
2use crossbeam_skiplist::SkipMap;
3use parking_lot::RwLock;
4use scc::HashMap;
5use std::fs::File;
6use std::sync::Arc;
7
8use crate::constants::*;
9use crate::error::{FeoxError, Result};
10use crate::stats::Statistics;
11use crate::storage::free_space::FreeSpaceManager;
12use crate::storage::metadata::Metadata;
13use crate::storage::write_buffer::WriteBuffer;
14
15use super::{FeoxStore, StoreConfig, VersionClock};
16
17enum OpenMode {
18    ReadWrite,
19    ReadOnly(File),
20    Fresh(File),
21}
22
23impl FeoxStore {
24    /// Create a new FeoxStore with default configuration
25    pub fn new(device_path: Option<String>) -> Result<Self> {
26        let memory_only = device_path.is_none();
27        let config = StoreConfig {
28            hash_bits: DEFAULT_HASH_BITS,
29            memory_only,
30            enable_caching: !memory_only, // Disable caching for memory-only mode
31            device_path,
32            file_size: None,
33            max_memory: Some(DEFAULT_MAX_MEMORY),
34            enable_ttl: false,
35            ttl_config: None,
36        };
37        Self::with_config_and_legacy_recovery(config, false)
38    }
39
40    /// Create a new FeoxStore with custom configuration
41    pub fn with_config(config: StoreConfig) -> Result<Self> {
42        Self::with_config_and_legacy_recovery(config, false)
43    }
44
45    pub(super) fn with_config_and_legacy_recovery(
46        config: StoreConfig,
47        allow_ambiguous_legacy_recovery: bool,
48    ) -> Result<Self> {
49        Self::with_config_and_open_mode(
50            config,
51            allow_ambiguous_legacy_recovery,
52            OpenMode::ReadWrite,
53        )
54    }
55
56    pub(super) fn with_config_for_migration_source(
57        config: StoreConfig,
58        allow_ambiguous_legacy_recovery: bool,
59        file: File,
60    ) -> Result<Self> {
61        Self::with_config_and_open_mode(
62            config,
63            allow_ambiguous_legacy_recovery,
64            OpenMode::ReadOnly(file),
65        )
66    }
67
68    pub(super) fn with_config_for_migration_destination(
69        config: StoreConfig,
70        file: File,
71    ) -> Result<Self> {
72        Self::with_config_and_open_mode(config, false, OpenMode::Fresh(file))
73    }
74
75    fn with_config_and_open_mode(
76        config: StoreConfig,
77        allow_ambiguous_legacy_recovery: bool,
78        open_mode: OpenMode,
79    ) -> Result<Self> {
80        let read_only = matches!(&open_mode, OpenMode::ReadOnly(_));
81        // Initialize hash table with configured capacity
82        let hasher = RandomState::new();
83        let hash_table = HashMap::with_capacity_and_hasher(1 << config.hash_bits, hasher.clone());
84
85        let free_space = Arc::new(RwLock::new(FreeSpaceManager::new()));
86        let metadata = Metadata::new();
87        let format_version = metadata.version;
88        let metadata = Arc::new(RwLock::new(metadata));
89        let stats = Arc::new(Statistics::new());
90
91        let cache = if config.enable_caching {
92            Some(Arc::new(crate::core::cache::ClockCache::new(stats.clone())))
93        } else {
94            None
95        };
96
97        let mut store = Self {
98            hash_table,
99            tree: Arc::new(SkipMap::new()),
100            stats: stats.clone(),
101            version_clock: VersionClock::new(hasher),
102            write_buffer: None,
103            free_space: free_space.clone(),
104            _metadata: metadata,
105            format_version,
106            fresh_device: false,
107            allow_ambiguous_legacy_recovery,
108            ambiguous_legacy_markers: 0,
109            read_only,
110            initialized: config.memory_only,
111            memory_only: config.memory_only,
112            enable_caching: config.enable_caching,
113            max_memory: config.max_memory,
114            cache,
115            #[cfg(unix)]
116            device_fd: None,
117            device_size: 0,
118            device_file: None,
119            disk_io: None,
120            ttl_sweeper: Arc::new(RwLock::new(None)),
121            enable_ttl: config.enable_ttl,
122        };
123
124        if !config.memory_only {
125            match open_mode {
126                OpenMode::ReadWrite => {
127                    store.open_device(&config.device_path, config.file_size)?;
128                }
129                OpenMode::ReadOnly(file) => {
130                    store.open_device_read_only(file)?;
131                }
132                OpenMode::Fresh(file) => {
133                    store.open_fresh_device(file, config.file_size)?;
134                }
135            }
136            store.load_indexes()?;
137
138            // Initialize write buffer for persistent mode
139            if !read_only {
140                let disk_io = store.disk_io.as_ref().ok_or(FeoxError::NoDevice)?;
141                let mut write_buffer = WriteBuffer::new(
142                    disk_io.clone(),
143                    free_space,
144                    stats.clone(),
145                    store.format_version,
146                );
147                let num_workers = (num_cpus::get() / 2).max(1);
148                write_buffer.start_workers(num_workers);
149                store.write_buffer = Some(Arc::new(write_buffer));
150            }
151            store.initialized = true;
152        }
153
154        Ok(store)
155    }
156}