Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_o3db_sync/src/base/constant.rs

13.1 KiB, 39 runs

created by r1870400018:721, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 base::cfg::OzoneConfig,
3 comm::response::Wait,
4};
5
6use oxedyne_fe2o3_core::{
7 prelude::*,
8 byte::Encoding,
9};
10use oxedyne_fe2o3_jdat::{
11 usr::UsrKindCode,
12 version::SemVer,
13};
14
15use std::time::Duration;
16
17impl OzoneConfig {
18 pub fn check_constants() -> Outcome<()> {
19 if CHECK_INTERVAL > USER_REQUEST_TIMEOUT {
20 return Err(err!(
21 "The prescribed constant check interval, {:?}, should not be larger than the \
22 constant maximum wait, {:?}.", CHECK_INTERVAL,
23 USER_REQUEST_TIMEOUT;
24 Invalid, Input));
25 }
26 // The three deadlines nest: a bot gives up on another bot first, a user request next,
27 // and a control operation last. Invert any pair and the outer waiter reports a failure
28 // the inner one has not yet had the chance to make.
29 if USER_REQUEST_TIMEOUT <= BOT_REQUEST_TIMEOUT {
30 return Err(err!(
31 "The user request timeout, {:?}, must exceed the internal bot request timeout, \
32 {:?}, or a user request can be abandoned while the bot serving it is still \
33 waiting on another bot.", USER_REQUEST_TIMEOUT, BOT_REQUEST_TIMEOUT;
34 Invalid, Input));
35 }
36 if CONTROL_REQUEST_TIMEOUT < USER_REQUEST_TIMEOUT {
37 return Err(err!(
38 "The control operation timeout, {:?}, must be at least the user request \
39 timeout, {:?}. A control operation is issued once, at startup, behind \
40 whatever initialisation work the zone bots are still doing, so it cannot be \
41 held to a deadline shorter than an ordinary request's.",
42 CONTROL_REQUEST_TIMEOUT, USER_REQUEST_TIMEOUT;
43 Invalid, Input));
44 }
45 if DURABILITY_TIMEOUT <= USER_REQUEST_TIMEOUT || DURABILITY_TIMEOUT > CONTROL_REQUEST_TIMEOUT {
46 return Err(err!(
47 "The durability timeout, {:?}, must exceed the user request timeout, {:?}, and \
48 not exceed the control operation timeout, {:?}. It waits on the disk, which \
49 answers more slowly than any bot, and it is a request's deadline, which a \
50 start-up control operation outlasts.",
51 DURABILITY_TIMEOUT, USER_REQUEST_TIMEOUT, CONTROL_REQUEST_TIMEOUT;
52 Invalid, Input));
53 }
54 Ok(())
55 }
56}
57
58pub const VERSION: SemVer = SemVer::new(0, 5, 0);
59pub const NAMEX_ID: &'static str = "QByizewdCnRH/E6ksx4rOnqv5lFuB6PX1EA4Z5kNQwA=";
60
61pub const CURRENT_FORMAT_VERSION: u8 = 2;
62
63// Files.
64pub const MAX_ZONES: u16 = 100;
65pub const LIVE_FILE_CLAIM_LIMIT: usize = 1024;
66pub const DEFAULT_MAX_ZONE_DIR_BYTES: u64 = 104_857_600; // 100 MiB
67pub const CONFIG_FILENAME: &'static str = "config.jdat";
68pub const DB_UID_CHAR_LEN: usize = 5;
69
70pub const DATA_FILE_EXT: &'static str = "dat";
71// Prefix of the temporary data file written into a zone directory while a data file's
72// garbage is collected. One left behind is an abandoned transcription.
73pub const GC_TEMP_FILE_PREFIX: &'static str = ".gc";
74pub const INDEX_FILE_EXT: &'static str = "ind";
75pub const DB_DIR_PREFIX: &'static str = "o3db";
76pub const HASH_BYTES: usize = 8; // u64
77pub const CACHE_HASH_BYTES: usize = 4; // u32
78
79// File size management.
80// When the total length of old values in a data file exceeds the following percentage of the
81// maximum data file length, garbage collection on the file is triggered.
82pub const OLD_DATA_PERCENT_GC_TRIGGER: f64 = 30.0;
83
84// File reading cache.
85pub const FILE_CACHE_EXPIRY_SECS: u64 = 15*60; // 15 mins
86pub const MAX_CACHED_FILES: usize = 200;
87
88// A read whose record is not the one its cache bot named -- a location a collection has moved, or
89// one read through the handle of the file's previous generation -- retries with a freshly fetched
90// location. This bounds those retries, for every read, so a file a supersession burst keeps
91// collecting cannot spin a reader for ever.
92pub const MAX_READ_ATTEMPTS: usize = 8;
93
94// Resource management.
95pub const CACHE_JETTISON_FRAC_OF_LIM: f64 = 0.20;
96
97// Bots.
98pub const BOT_ERR_COUNT_WARNING: usize = 10;
99pub const STACK_SIZE: usize = 2 * 1024 * 1024;
100
101// Shutdown.
102// How long a close waits for the bots to finish in order before the supervisor answers it; any
103// still running are finished afterwards, in the same order (`Supervisor::shutdown`).
104pub const SHUTDOWN_MAX_WAIT: Duration = Duration::from_secs(3);
105
106// Intervals.
107pub const HEALTH_CHECK_INTERVAL: Duration = Duration::from_secs(60);
108
109// Busy waiting intervals.
110pub const CHECK_INTERVAL: Duration = Duration::from_millis(100);
111pub const CONFIGWATCHER_CHECK_INTERVAL_SECS: u64 = 3;
112// The server bot blocks on its internal channel rather than polling, so no channel check
113// interval is needed. The external UDP socket, when enabled, reads with this timeout.
114pub const SERVER_EXT_SOCKET_CHECK_INTERVAL: Duration = Duration::from_nanos(999_000);
115
116// Timeouts.
117// User timeouts must last longer than internal bot timeouts to avoid lockups.
118pub const USER_REQUEST_TIMEOUT: Duration =
119 BOT_REQUEST_TIMEOUT.saturating_add(Duration::from_secs(1));
120pub const USER_REQUEST_WAIT: Wait = Wait {
121 max_wait: USER_REQUEST_TIMEOUT,
122 check_interval: CHECK_INTERVAL,
123};
124pub const BOT_REQUEST_TIMEOUT: Duration = Duration::from_secs(5);
125pub const BOT_REQUEST_WAIT: Wait = Wait {
126 max_wait: BOT_REQUEST_TIMEOUT,
127 check_interval: CHECK_INTERVAL,
128};
129// A write is answered twice. `OzoneMsg::Written` says its record is appended, which is the
130// writer's own work and is held to USER_REQUEST_TIMEOUT like any request. The final answer says
131// the record is durable under the store's sync policy and readable, and that waits on the disk:
132// an fsync queued behind everything else a busy machine is writing took over eleven seconds when
133// measured (2026-09-23), and a six-second deadline then reported as failed a write that went on
134// to land. So this deadline marks a disk that has stopped rather than one that is busy, and what
135// its expiry reports is a write not confirmed durable, never a write that failed.
136pub const DURABILITY_TIMEOUT: Duration = Duration::from_secs(120);
137// A control operation -- activating garbage collection, rolling every writer onto a fresh live
138// file -- is issued once, by whoever owns the database, and usually while it is still starting.
139// Its message queues behind whatever the zone bots are already doing, and the initial survey of
140// a large store's files runs for minutes, so this deadline marks not how long the answer should
141// take but the point at which a bot is better presumed dead than busy.
142//
143// It is deliberately larger than USER_REQUEST_TIMEOUT and the two must not be unified. A user
144// request is one of very many, on a path a client is blocked on, and its short deadline is what
145// turns a slow request path into a visible error instead of a hang; stretching it to cover
146// startup would hide the very thing it exists to expose. A control operation has no client
147// waiting on it and happens once, so waiting costs nothing and failing costs everything: six
148// seconds applied here stops a large database booting at all.
149//
150// Five minutes rather than no limit, because a bot that has said nothing for five minutes is a
151// fault to report, not a slow start to wait out.
152pub const CONTROL_REQUEST_TIMEOUT: Duration = Duration::from_secs(300);
153pub const CONTROL_REQUEST_WAIT: Wait = Wait {
154 max_wait: CONTROL_REQUEST_TIMEOUT,
155 check_interval: CHECK_INTERVAL,
156};
157pub const ZONE_STATE_UPDATER_LISTEN_TIMEOUT: Duration = Duration::from_millis(300);
158//pub const GET_DATA_WAIT: Wait = Wait::new_default();
159pub const PING_TIMEOUT: Duration = Duration::from_secs(5);
160
161// ConfigBot.
162pub const CONFIGWATCHER_REFRESH_FILE_AFTER_N_CHECKS: usize = 100;
163
164// ServerBot.
165pub const SERVER_ADDRESS: &'static str = "127.0.0.1";
166pub const UDP_BUFFER_SIZE: usize = 1_400;
167// Mostly completely arbitrary...
168pub const POW_CREATE_TIMEOUT: Duration = Duration::from_secs(30);
169pub const POW_CREATE_COUNT_LIM: usize = usize::MAX;
170pub const DEFAULT_UDP_PACKET_SIZE: usize = 700;
171pub const REQ_TIMER_LEN: usize = 100;
172pub const MAX_ALLOWED_AVG_REQ_PER_SEC: u64 = 30;
173pub const POW_MAX_ZERO_BITS: usize = 30;
174pub const POW_NONCE_LEN: usize = 8;
175pub const POW_CODE_LEN: usize = 8;
176pub const POW_ADDR_LEN: usize = 16;
177pub const POW_TIMESTAMP_LEN: usize = 8;
178pub const POW_PREFIX_LEN: usize =
179 POW_ADDR_LEN +
180 POW_CODE_LEN;
181pub const POW_PREIMAGE_LEN: usize =
182 POW_ADDR_LEN +
183 POW_CODE_LEN +
184 POW_TIMESTAMP_LEN;
185pub const POW_INPUT_LEN: usize =
186 POW_PREIMAGE_LEN +
187 POW_NONCE_LEN;
188pub const THROTTLED_INTERVAL_MIN: Duration = Duration::from_secs(1);
189pub const ADDR_THROTTLE_SUNSET_SECS_MIN: u64 = 1_800; // 30 min
190pub const ADDR_THROTTLE_SUNSET_SECS_MAX: u64 = 259_200; // 3 days
191pub const THROTTLE_COUNT_BEFORE_BLACKLIST: u16 = 10;
192pub const SESSION_REQUEST_EXPIRY: Duration = Duration::from_secs(600); // 10 min
193pub const PARTIAL_MESSAGE_SUNSET: Duration = Duration::from_secs(600); // 10 min
194pub const MSG_ASSEMBLY_SUNSET: Duration = Duration::from_secs(600);
195pub const MSG_ASSEMBLY_IDLE_MAX: Duration = Duration::from_secs(60);
196pub const MSG_ASSEMBLY_REP_TOTAL_LIM: u8 = 128;
197pub const MSG_ASSEMBLY_REP_PACKET_LIM: u8 = 32;
198pub const MSG_ASSEMBLY_GC_INTERVAL: Duration = Duration::from_secs(600);
199pub const DEFAULT_MSG_ENCODING: Encoding = Encoding::Binary;
200
201// Schemes =====================================================================
202// Chunking.
203// Min chunk size rationale:
204// (Dat::BU64 + AES_GCM) overhead, safety factor of 2
205pub const MIN_CHUNK_SIZE: usize = (9 + 12)*2;
206pub const DEFAULT_REST_CHUNK_BYTES: usize = 1_024_000; // 1 MiB
207pub const DEFAULT_WIRE_CHUNK_BYTES: usize = 1_024; // 1 KiB
208
209// Hashing.
210pub const KEY_HASH_SALT: [u8; 16] = SALT16;
211// Salt for the deterministic chunk set identifier, kept distinct from the
212// routing salt so the two hashes of a key never coincide.
213pub const CHUNK_SET_ID_SALT: [u8; 16] = [
214 0x7a, 0x1d, 0x3f, 0x9c, 0x42, 0xe8, 0x05, 0xb6,
215 0x11, 0x93, 0xaf, 0x6e, 0x28, 0xd4, 0x7c, 0x50,
216];
217pub const SALT8: [u8; 8] = [
218 0x15, 0x04, 0x84, 0x1e, 0xf2, 0x07, 0x19, 0xbc,
219];
220pub const SALT16: [u8; 16] = [
221 0xc9, 0x48, 0xcc, 0xbe, 0xd5, 0xd1, 0x16, 0x6c,
222 0xc2, 0x2a, 0x78, 0x85, 0xce, 0x3e, 0x25, 0xcd,
223];
224pub const SALT32: [u8; 32] = [
225 0xbd, 0xd5, 0x81, 0xba, 0x0c, 0xeb, 0x4f, 0xad,
226 0x23, 0x72, 0xd4, 0xac, 0x92, 0xeb, 0xa6, 0x6f,
227 0xf9, 0x65, 0x4f, 0x04, 0xca, 0xd5, 0x8b, 0x73,
228 0xb2, 0xfa, 0x72, 0x39, 0x21, 0x6b, 0x6c, 0x5f,
229];
230
231// Encryption.
232pub const DEFAULT_SYMMETRIC_KEY_BYTES: usize = 32;
233
234// Randomness.
235pub const DB_UID_CHARS: &'static str =
236 // 1 2 3 4 5
237 // 123456789012345678901234567890123456789012345678901234
238 "ABCDEFGHKMNPQRSTUVWXYZabcedefghkmnpqrstuvwxyz123456789";
239
240// Document Data Abstraction Layer.
241pub const USER_KIND_DIR_CODE: UsrKindCode = 5;
242pub const USER_KIND_DOC_CODE: UsrKindCode = 6;
243pub const DOC_PATH_LEN_LIMIT: usize = 1024;
244
245pub const USER_ID_BYTE_LEN: usize = 16;
246
247pub const MAX_FILE_BYTES: u64 = i64::MAX as u64;
248pub const MAX_FILE_TO_CHUNKING_THRESHOLD_RATIO: f64 = 0.8;
249pub const MAX_FILE_TO_CHUNK_SIZE_RATIO: f64 = 0.3;
250/// When restarting an ozone database, the live file in a zone is usually chosen to be one with
251/// the highest file number. This will remain the case if the ratio of the live data file size
252/// to the maximum data file size is below this fraction, otherwise a new live file will be
253/// created.
254pub const LIVE_FILE_INIT_SIZE_RATIO_THRESHOLD: f64 = 0.5;
255
256// Credits:
257// Image: https://ascii-generator.site/
258// Text: https://www.asciiart.eu/text-to-ascii-art Nancyj Improved with touch ups.
259pub const SPLASH: &'static str =
260r#"
261
262 .:::::::::::::::::::::.
263 .' '.
264 .: :.
265 .. .. .o88888o. dP dP
266 .. .. d8' `8b 88 88
267 .. .... .... .. 88 88 .d888b88 88d888b.
268 .. .....: :..... .. 88 88 d8888b. 88' `88 88' `88
269 .. '...... ......' .. Y8. .8P `88 88. .88 88. .88
270 .. ...:::... .. `888888P' aaad8' `88888P8 88Y8888'
271 .. ....... .. `88
272 .. '...' .. d88888P
273 .: :.
274 '-:::::::::::::::::::::-'
275 Ozone Database
276
277"#;
278
279