feoxdb/core/store/
init.rs1use 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 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, 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 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 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 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}