Skip to main content

noxu_db/
environment_config.rs

1//! Environment configuration.
2//!
3//! Mirrors `EnvironmentConfig` / `EnvironmentMutableConfig` from7.5.11.
4//! Every parameter from 's `EnvironmentConfig.java` is represented here.
5//! Java-specific parameters (NIO, JCA/RA) are included with documentation
6//! noting the accepted deviation for a native Rust implementation.
7//!
8//! Parameters are grouped by subsystem to match the layout.
9
10use crate::durability::Durability;
11use crate::error::ExceptionListener;
12use std::fmt;
13use std::path::PathBuf;
14use std::sync::Arc;
15
16/// Wrapper around an optional `ExceptionListener` that implements `Debug` and
17/// `Clone` so that `EnvironmentConfig` can keep those derives.
18///
19/// Mirrors `EnvironmentConfig.setExceptionListener(ExceptionListener)`.
20#[derive(Clone, Default)]
21pub struct ExceptionListenerHolder(pub Option<Arc<dyn ExceptionListener>>);
22
23impl fmt::Debug for ExceptionListenerHolder {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match &self.0 {
26            None => f.write_str("None"),
27            Some(_) => f.write_str("Some(<ExceptionListener>)"),
28        }
29    }
30}
31
32/// Configuration for opening a Noxu DB environment.
33///
34/// Configuration for a Noxu DB environment. Provides 150+ typed parameters for tuning all subsystems.
35/// Use the builder pattern (`set_*` / `with_*`) to configure individual
36/// parameters; all fields have -identical defaults unless noted.
37#[derive(Debug, Clone)]
38pub struct EnvironmentConfig {
39    // -----------------------------------------------------------------------
40    // Core / environment lifecycle
41    // -----------------------------------------------------------------------
42    /// Home directory for the environment.
43    pub home: PathBuf,
44
45    /// Allow creation of a new environment if it does not exist.
46    /// Mirrors `EnvironmentConfig.setAllowCreate()` / default false.
47    pub allow_create: bool,
48
49    /// Open the environment for transactional use.
50    /// Mirrors `ENV_IS_TRANSACTIONAL` / default false.
51    pub transactional: bool,
52
53    /// Open the environment in read-only mode.
54    /// Mirrors `ENV_READ_ONLY` / default false.
55    pub read_only: bool,
56
57    /// Enable locking.  When false the environment runs without a lock
58    /// manager (equivalent to-transactional, non-locking mode).
59    /// Mirrors `ENV_IS_LOCKING` / default true.
60    pub env_is_locking: bool,
61
62    /// Share the B-tree cache across multiple environments in the same JVM.
63    /// In Noxu, this is a configuration hint; shared-cache pooling is
64    /// accepted as a future work item.
65    /// Mirrors `SHARED_CACHE` / default false.
66    pub shared_cache: bool,
67
68    /// Force a checkpoint after recovery completes.
69    /// Mirrors `ENV_RECOVERY_FORCE_CHECKPOINT` / default false.
70    pub env_recovery_force_checkpoint: bool,
71
72    /// Force a new log file to be started after recovery.
73    /// Mirrors `ENV_RECOVERY_FORCE_NEW_FILE` / default false.
74    pub env_recovery_force_new_file: bool,
75
76    /// Halt the environment on commit after a `ChecksumException`.
77    /// Mirrors `HALT_ON_COMMIT_AFTER_CHECKSUMEXCEPTION` / default false.
78    pub halt_on_commit_after_checksum_exception: bool,
79
80    /// Logging level for this environment (uses Rust `log` crate levels:
81    /// `"ERROR"`, `"WARN"`, `"INFO"`, `"DEBUG"`, `"TRACE"`).
82    /// : maps to `java.util.logging.level` / default `"INFO"`.
83    pub logging_level: Option<String>,
84
85    // -----------------------------------------------------------------------
86    // Memory / cache
87    // -----------------------------------------------------------------------
88    /// Maximum bytes for the B-tree cache.
89    /// Mirrors `MAX_MEMORY` / `EnvironmentConfig.setCacheSize()` / default 0
90    /// ( auto-sizes to 60% of heap).  Noxu default: 64 MiB.
91    pub cache_size: u64,
92
93    /// Cache size as a percentage of system memory (0 = use `cache_size`).
94    /// Mirrors `MAX_MEMORY_PERCENT` / `EnvironmentConfig.setCachePercent()` /
95    /// default 60.  When non-zero, overrides `cache_size`.
96    pub cache_percent: u32,
97
98    /// Off-heap cache size in bytes.  0 = disabled.
99    /// Mirrors `MAX_OFF_HEAP_MEMORY` / default 0.
100    pub max_off_heap_memory: u64,
101
102    /// Maximum disk space the environment may use in bytes.  0 = unlimited.
103    /// Mirrors `MAX_DISK` / default 0.
104    pub max_disk: u64,
105
106    /// Minimum free disk space in bytes; triggers `DiskLimitExceeded` if the
107    /// available space on the file-system falls below this threshold.
108    /// Mirrors `FREE_DISK` / default 5 GiB.
109    pub free_disk: u64,
110
111    // -----------------------------------------------------------------------
112    // Background daemons — run flags
113    // -----------------------------------------------------------------------
114    /// Run the background INCompressor daemon.
115    /// Mirrors `ENV_RUN_IN_COMPRESSOR` / default true.
116    pub run_in_compressor: bool,
117
118    /// Run the background Checkpointer daemon.
119    /// Mirrors `ENV_RUN_CHECKPOINTER` / default true.
120    pub run_checkpointer: bool,
121
122    /// Run the background Cleaner daemon.
123    /// Mirrors `ENV_RUN_CLEANER` / default true.
124    pub run_cleaner: bool,
125
126    /// Run the background Evictor daemon.
127    /// Mirrors `ENV_RUN_EVICTOR` / default true.
128    pub run_evictor: bool,
129
130    /// Run the background off-heap Evictor daemon.
131    /// Mirrors `ENV_RUN_OFFHEAP_EVICTOR` / default true (when off-heap configured).
132    pub run_offheap_evictor: bool,
133
134    /// Run the background data-integrity Verifier daemon.
135    /// Mirrors `ENV_RUN_VERIFIER` / default false.
136    pub run_verifier: bool,
137
138    // -----------------------------------------------------------------------
139    // Background daemons — rate limits & sleep
140    // -----------------------------------------------------------------------
141    /// Maximum read throughput for background daemons in KB/s.  0 = unlimited.
142    /// Mirrors `ENV_BACKGROUND_READ_LIMIT` / default 0.
143    pub env_background_read_limit_kb: u32,
144
145    /// Maximum write throughput for background daemons in KB/s.  0 = unlimited.
146    /// Mirrors `ENV_BACKGROUND_WRITE_LIMIT` / default 0.
147    pub env_background_write_limit_kb: u32,
148
149    /// Sleep interval for background daemons between work units in
150    /// microseconds.  0 = no enforced sleep.
151    /// Mirrors `ENV_BACKGROUND_SLEEP_INTERVAL` / default 0.
152    pub env_background_sleep_interval_us: u64,
153
154    // -----------------------------------------------------------------------
155    // Environment behaviour flags
156    // -----------------------------------------------------------------------
157    /// Check for lock leaks when databases are closed.
158    ///
159    /// **Reserved / not yet implemented as of v3.1.** Setting a non-default
160    /// value (false) has no effect and emits a `WARN` log at
161    /// `Environment::open` time.
162    ///
163    /// Mirrors `ENV_CHECK_LEAKS` / default true.
164    pub env_check_leaks: bool,
165
166    /// Force thread yields in critical sections (useful for testing fairness).
167    ///
168    /// **Reserved / not yet implemented as of v3.1.** Setting a non-default
169    /// value (true) has no effect and emits a `WARN` log at
170    /// `Environment::open` time.
171    ///
172    /// Mirrors `ENV_FORCED_YIELD` / default false.
173    pub env_forced_yield: bool,
174
175    /// Use fair (FIFO-ordered) latches.  May reduce throughput under low
176    /// contention but prevents starvation.
177    ///
178    /// **Reserved / not yet implemented as of v3.1.** Setting a non-default
179    /// value (true) has no effect and emits a `WARN` log at
180    /// `Environment::open` time.
181    ///
182    /// Mirrors `ENV_FAIR_LATCHES` / default false.
183    pub env_fair_latches: bool,
184
185    /// Latch acquisition timeout in milliseconds.  0 = no timeout (block
186    /// indefinitely).  In JE, a timeout causes `EnvironmentFailure`.
187    ///
188    /// **Reserved / not yet implemented as of v3.1.** Setting a non-default
189    /// value (non-zero) has no effect and emits a `WARN` log at
190    /// `Environment::open` time.  The latch layer always blocks indefinitely.
191    ///
192    /// Mirrors `ENV_LATCH_TIMEOUT` / default 300_000 ms (5 min).
193    pub env_latch_timeout_ms: u64,
194
195    /// TTL clock tolerance — records within this many milliseconds of their
196    /// expiration time are treated as expired.
197    ///
198    /// **Reserved / not yet implemented as of v3.1.** Setting a non-default
199    /// value (non-zero) has no effect and emits a `WARN` log at
200    /// `Environment::open` time.
201    ///
202    /// Mirrors `ENV_TTL_CLOCK_TOLERANCE` / default 0.
203    pub env_ttl_clock_tolerance_ms: u64,
204
205    /// Enable TTL-based record expiration at the environment level.
206    ///
207    /// **Reserved / not yet implemented as of v3.1.** Setting a non-default
208    /// value (true) has no effect and emits a `WARN` log at
209    /// `Environment::open` time.
210    ///
211    /// Mirrors `ENV_EXPIRATION_ENABLED` / default false.
212    pub env_expiration_enabled: bool,
213
214    /// Enable per-database node eviction.
215    ///
216    /// **Reserved / not yet implemented as of v3.1.** Setting a non-default
217    /// value (true) has no effect and emits a `WARN` log at
218    /// `Environment::open` time.
219    ///
220    /// Mirrors `ENV_DB_EVICTION` / default false.
221    pub env_db_eviction: bool,
222
223    /// Preload all duplicate-tree data before converting dup databases.
224    /// Mirrors `ENV_DUP_CONVERT_PRELOAD_ALL` / default true.
225    pub env_dup_convert_preload_all: bool,
226
227    /// Chunk size (bytes) for Adler32 checksums.  0 = disabled (use CRC32).
228    /// Mirrors `ADLER32_CHUNK_SIZE` / default 0.
229    pub adler32_chunk_size: usize,
230
231    // -----------------------------------------------------------------------
232    // Log / I-O
233    // -----------------------------------------------------------------------
234    /// Maximum size of a single log file in bytes.
235    /// Mirrors `LOG_FILE_MAX` / default 10 MiB.
236    pub log_file_max_bytes: u64,
237
238    /// Number of cached open file handles (LRU-evicted when full).
239    /// Mirrors `LOG_FILE_CACHE_SIZE` / default 100.
240    pub log_file_cache_size: usize,
241
242    /// Validate entry checksums on every log read.
243    /// Mirrors `LOG_CHECKSUM_READ` / default true.
244    pub log_checksum_read: bool,
245
246    /// Verify all checksums during log scans (more thorough than
247    /// `log_checksum_read`; used by background verifier).
248    /// Mirrors `LOG_VERIFY_CHECKSUMS` / default false.
249    pub log_verify_checksums: bool,
250
251    /// Timeout for a single `fdatasync` call in milliseconds.
252    /// Mirrors `LOG_FSYNC_TIMEOUT` / default 500_000 ms.
253    pub log_fsync_timeout_ms: u64,
254
255    /// Soft limit on fsync duration in milliseconds; logs a warning when
256    /// exceeded.  0 = disabled.
257    /// Mirrors `LOG_FSYNC_TIME_LIMIT` / default 0.
258    pub log_fsync_time_limit_ms: u64,
259
260    /// Number of write buffers in the log buffer pool.
261    /// Mirrors `LOG_NUM_BUFFERS` / default 3.
262    pub log_num_buffers: usize,
263
264    /// Total bytes across all log write buffers.
265    /// Mirrors `LOG_TOTAL_BUFFER_BYTES` / default 7 MiB.
266    pub log_total_buffer_bytes: u64,
267
268    /// Per-buffer size override in bytes.  0 = derive from
269    /// `log_total_buffer_bytes / log_num_buffers`.
270    /// Mirrors `LOG_BUFFER_SIZE` / default 0.
271    pub log_buffer_size: usize,
272
273    /// Size of the fault-in read buffer for random BIN fetches.
274    /// Mirrors `LOG_FAULT_READ_SIZE` / default 2 KiB.
275    pub log_fault_read_size: usize,
276
277    /// Log iterator read buffer in bytes.
278    /// Mirrors `LOG_ITERATOR_READ_SIZE` / default 8 KiB.
279    pub log_iterator_read_size: usize,
280
281    /// Log iterator maximum buffer size in bytes (grows up to this limit).
282    /// Mirrors `LOG_ITERATOR_MAX_SIZE` / default 16 MiB.
283    pub log_iterator_max_size: usize,
284
285    /// Number of data directories for log file striping.  0 = single dir.
286    /// Mirrors `LOG_N_DATA_DIRECTORIES` / default 0.
287    pub log_n_data_directories: u32,
288
289    /// Run in in-memory-only mode (no log files written).
290    /// Mirrors `LOG_MEM_ONLY` / default false.
291    pub log_mem_only: bool,
292
293    /// Detect external deletion of log files and respond gracefully.
294    /// Mirrors `LOG_DETECT_FILE_DELETE` / default false.
295    pub log_detect_file_delete: bool,
296
297    /// Interval between log-file deletion detection polls in milliseconds.
298    /// Mirrors `LOG_DETECT_FILE_DELETE_INTERVAL` / default 3_000 ms.
299    pub log_detect_file_delete_interval_ms: u64,
300
301    /// Interval between periodic flush-and-sync operations in milliseconds.
302    /// 0 = disabled.  : `LOG_FLUSH_SYNC_INTERVAL` / default 0.
303    pub log_flush_sync_interval_ms: u64,
304
305    /// Interval between periodic flush-without-sync operations in
306    /// milliseconds.  0 = disabled.
307    /// Mirrors `LOG_FLUSH_NO_SYNC_INTERVAL` / default 0.
308    pub log_flush_no_sync_interval_ms: u64,
309
310    /// Use `O_DSYNC` when opening log files.  Accepted deviation: on Linux
311    /// Noxu passes `O_DSYNC` to `OpenOptions`; semantics are equivalent.
312    /// Mirrors `LOG_USE_ODSYNC` / default false.
313    pub log_use_odsync: bool,
314
315    /// Use an asynchronous write queue between the log manager and the OS.
316    /// Mirrors `LOG_USE_WRITE_QUEUE` / default false.
317    pub log_use_write_queue: bool,
318
319    /// Size of the asynchronous write queue in bytes.
320    /// Mirrors `LOG_WRITE_QUEUE_SIZE` / default 1 MiB.
321    pub log_write_queue_size: usize,
322
323    /// Group-commit waiter threshold.  0 = disabled.
324    /// Mirrors `LOG_GROUP_COMMIT_THRESHOLD` / default 0.
325    pub log_group_commit_threshold: usize,
326
327    /// Group-commit interval in milliseconds.  0 = disabled.
328    /// Mirrors `LOG_GROUP_COMMIT_INTERVAL` / default 0.
329    pub log_group_commit_interval_ms: u64,
330
331    // -----------------------------------------------------------------------
332    // B-tree
333    // -----------------------------------------------------------------------
334    /// Maximum number of entries per Internal Node (IN).
335    /// Mirrors `NODE_MAX_ENTRIES` / default 128.
336    pub node_max_entries: u32,
337
338    /// Maximum number of entries per duplicate-tree node.
339    /// Mirrors `NODE_DUP_TREE_MAX_ENTRIES` / default 128.
340    pub node_dup_tree_max_entries: u32,
341
342    /// Maximum value size in bytes for inline (embedded) LNs stored directly
343    /// in the BIN slot.  Records larger than this are stored as separate LNs.
344    /// Mirrors `TREE_MAX_EMBEDDED_LN` / default 16.
345    pub tree_max_embedded_ln: u32,
346
347    /// Maximum percentage of BIN entries that may be in a delta before a
348    /// full BIN is written (0–100).
349    /// Mirrors `TREE_MAX_DELTA` / default 25.
350    pub tree_max_delta: u8,
351
352    /// Write BIN-delta log entries (partial BIN updates).
353    /// Mirrors `TREE_BIN_DELTA` / default true.
354    pub tree_bin_delta: bool,
355
356    /// Minimum memory per B-tree node in bytes.  0 = no minimum.
357    /// Mirrors `TREE_MIN_MEMORY` / default 0.
358    pub tree_min_memory: u64,
359
360    /// Maximum key length for compact (prefix-compressed) key storage.
361    /// Mirrors `TREE_COMPACT_MAX_KEY_LENGTH` / default 16.
362    pub tree_compact_max_key_length: u32,
363
364    // -----------------------------------------------------------------------
365    // INCompressor
366    // -----------------------------------------------------------------------
367    /// INCompressor wakeup interval in milliseconds.
368    /// Mirrors `COMPRESSOR_WAKEUP_INTERVAL` / default 5_000 ms.
369    pub in_compressor_wakeup_interval_ms: u64,
370
371    /// Number of deadlock retries per INCompressor pass.
372    /// Mirrors `COMPRESSOR_DEADLOCK_RETRY` / default 3.
373    pub compressor_deadlock_retry: u32,
374
375    /// Lock timeout for INCompressor operations in milliseconds.
376    /// Mirrors `COMPRESSOR_LOCK_TIMEOUT` / default 500 ms.
377    pub compressor_lock_timeout_ms: u64,
378
379    /// Purge the root IN when it becomes empty after compression.
380    /// Mirrors `COMPRESSOR_PURGE_ROOT` / default false.
381    pub compressor_purge_root: bool,
382
383    // -----------------------------------------------------------------------
384    // Cleaner
385    // -----------------------------------------------------------------------
386    /// Minimum log utilization percentage; cleaning triggers when below this.
387    /// Mirrors `CLEANER_MIN_UTILIZATION` / default 50.
388    pub cleaner_min_utilization: u8,
389
390    /// Minimum per-file utilization; files below this are always candidates.
391    /// Mirrors `CLEANER_MIN_FILE_UTILIZATION` / default 5.
392    pub cleaner_min_file_utilization: u8,
393
394    /// Number of background cleaner threads.
395    /// Mirrors `CLEANER_THREADS` / default 1.
396    pub cleaner_threads: u32,
397
398    /// Minimum number of log files that must exist before cleaning begins.
399    /// Mirrors `CLEANER_MIN_FILES_TO_CLEAN` / default 2.
400    pub cleaner_min_file_count: u32,
401
402    /// Minimum age of a log file (in checkpoints) before it becomes a
403    /// candidate.  : `CLEANER_MIN_AGE` / default 2.
404    pub cleaner_min_age: u32,
405
406    /// Bytes written between cleaner wakeups (byte-based trigger).
407    /// 0 = disabled.  : `CLEANER_BYTES_INTERVAL` / default 0.
408    pub cleaner_bytes_interval: u64,
409
410    /// Time between cleaner wakeups in milliseconds (time-based trigger).
411    /// 0 = disabled.  : `CLEANER_WAKEUP_INTERVAL` / default 0.
412    pub cleaner_wakeup_interval_ms: u64,
413
414    /// Fetch the sizes of obsolete records when calculating utilization.
415    /// Mirrors `CLEANER_FETCH_OBSOLETE_SIZE` / default false.
416    pub cleaner_fetch_obsolete_size: bool,
417
418    /// Adjust utilization accounting for uncommitted transactions.
419    /// Mirrors `CLEANER_ADJUST_UTILIZATION` / default false.
420    pub cleaner_adjust_utilization: bool,
421
422    /// Number of deadlock retries per cleaner migration pass.
423    /// Mirrors `CLEANER_DEADLOCK_RETRY` / default 3.
424    pub cleaner_deadlock_retry: u32,
425
426    /// Lock timeout for cleaner migration operations in milliseconds.
427    /// Mirrors `CLEANER_LOCK_TIMEOUT` / default 500 ms.
428    pub cleaner_lock_timeout_ms: u64,
429
430    /// Expunge (delete) cleaned log files immediately rather than keeping them
431    /// in a `deleted/` sub-directory.
432    /// Mirrors `CLEANER_EXPUNGE` / default true.
433    pub cleaner_expunge: bool,
434
435    /// Move cleaned log files to a `deleted/` sub-directory instead of
436    /// deleting them in place.
437    /// Mirrors `CLEANER_USE_DELETED_DIR` / default false.
438    pub cleaner_use_deleted_dir: bool,
439
440    /// Maximum number of log files processed per cleaner batch.
441    /// 0 = unlimited.  : `CLEANER_MAX_BATCH_FILES` / default 0.
442    pub cleaner_max_batch_files: u32,
443
444    /// Bytes read per cleaner file scan pass.
445    /// Mirrors `CLEANER_READ_SIZE` / default 8 KiB.
446    pub cleaner_read_size: usize,
447
448    /// Maximum percentage of the cache to use for cleaner utilization detail.
449    /// Mirrors `CLEANER_DETAIL_MAX_MEMORY_PERCENTAGE` / default 2.
450    pub cleaner_detail_max_memory_percentage: u32,
451
452    /// Number of LN records to look ahead during file cleaning.
453    /// Mirrors `CLEANER_LOOK_AHEAD_CACHE_SIZE` / default 32.
454    pub cleaner_look_ahead_cache_size: usize,
455
456    /// Migrate live records proactively in the foreground (user threads).
457    /// Mirrors `CLEANER_FOREGROUND_PROACTIVE_MIGRATION` / default false.
458    pub cleaner_foreground_proactive_migration: bool,
459
460    /// Migrate live records proactively in the background cleaner thread.
461    /// Mirrors `CLEANER_BACKGROUND_PROACTIVE_MIGRATION` / default false.
462    pub cleaner_background_proactive_migration: bool,
463
464    /// Lazy migration: defer LN migration until the slot is next accessed.
465    /// Mirrors `CLEANER_LAZY_MIGRATION` / default false.
466    pub cleaner_lazy_migration: bool,
467
468    /// Enable TTL-based record expiration tracking in the cleaner.
469    /// Mirrors `CLEANER_EXPIRATION_ENABLED` / default false.
470    pub cleaner_expiration_enabled: bool,
471
472    // -----------------------------------------------------------------------
473    // Checkpointer
474    // -----------------------------------------------------------------------
475    /// Number of bytes written between automatic checkpoints.
476    /// Mirrors `CHECKPOINTER_BYTES_INTERVAL` / default 20 MiB.
477    pub checkpointer_bytes_interval: u64,
478
479    /// Time between automatic checkpoints in milliseconds.
480    /// 0 = disabled.  : `CHECKPOINTER_WAKEUP_INTERVAL` / default 30_000 ms.
481    pub checkpointer_wakeup_interval_ms: u64,
482
483    /// Minimum time between automatic checkpoints in seconds (0 = disabled).
484    /// : relates to `CHECKPOINTER_HIGH_PRIORITY`.
485    pub checkpointer_min_interval_secs: u64,
486
487    /// Number of deadlock retries per checkpoint.
488    /// Mirrors `CHECKPOINTER_DEADLOCK_RETRY` / default 3.
489    pub checkpointer_deadlock_retry: u32,
490
491    /// Run checkpoints at high priority (flush more aggressively).
492    /// Mirrors `CHECKPOINTER_HIGH_PRIORITY` / default false.
493    pub checkpointer_high_priority: bool,
494
495    // -----------------------------------------------------------------------
496    // Evictor
497    // -----------------------------------------------------------------------
498    /// Number of tree nodes examined per evictor pass.
499    /// Mirrors `EVICTOR_NODES_PER_SCAN` / default 10.
500    pub evictor_nodes_per_scan: usize,
501
502    /// Bytes to evict from the cache per evictor pass.
503    /// Mirrors `EVICTOR_EVICT_BYTES` / default 512 KiB.
504    pub evictor_evict_bytes: u64,
505
506    /// Percentage above the cache target at which critical eviction kicks in.
507    /// Mirrors `EVICTOR_CRITICAL_PERCENTAGE` / default 5.
508    pub evictor_critical_percentage: u32,
509
510    /// Use LRU-only eviction (no priority-1 / priority-2 split).
511    /// Mirrors `EVICTOR_LRU_ONLY` / default false.
512    pub evictor_lru_only: bool,
513
514    /// Number of LRU lists (increases parallelism under contention).
515    /// Mirrors `EVICTOR_N_LRU_LISTS` / default 4.
516    pub evictor_n_lru_lists: u32,
517
518    /// Number of deadlock retries per evictor pass.
519    /// Mirrors `EVICTOR_DEADLOCK_RETRY` / default 3.
520    pub evictor_deadlock_retry: u32,
521
522    /// Minimum number of background evictor threads always kept alive.
523    /// Mirrors `EVICTOR_CORE_THREADS` / default 1.
524    pub evictor_core_threads: usize,
525
526    /// Maximum number of background evictor threads.
527    /// Mirrors `EVICTOR_MAX_THREADS` / default 10.
528    pub evictor_max_threads: usize,
529
530    /// Keep-alive time for idle evictor threads in milliseconds.
531    /// Mirrors `EVICTOR_KEEP_ALIVE` / default 60_000 ms.
532    pub evictor_keep_alive_ms: u64,
533
534    /// Allow the evictor to write BIN-delta entries rather than full BINs.
535    /// Mirrors `EVICTOR_ALLOW_BIN_DELTAS` / default true.
536    pub evictor_allow_bin_deltas: bool,
537
538    // -----------------------------------------------------------------------
539    // Off-heap evictor
540    // -----------------------------------------------------------------------
541    /// Bytes to evict from the off-heap cache per pass.
542    /// Mirrors `OFFHEAP_EVICT_BYTES` / default 512 KiB.
543    pub offheap_evict_bytes: u64,
544
545    /// Number of LRU lists for the off-heap cache.
546    /// Mirrors `OFFHEAP_N_LRU_LISTS` / default 4.
547    pub offheap_n_lru_lists: u32,
548
549    /// Checksum off-heap cache entries on write and verify on read.
550    /// Mirrors `OFFHEAP_CHECKSUM` / default false.
551    pub offheap_checksum: bool,
552
553    /// Minimum number of off-heap evictor threads always kept alive.
554    /// Mirrors `OFFHEAP_CORE_THREADS` / default 1.
555    pub offheap_core_threads: usize,
556
557    /// Maximum number of off-heap evictor threads.
558    /// Mirrors `OFFHEAP_MAX_THREADS` / default 10.
559    pub offheap_max_threads: usize,
560
561    /// Keep-alive time for idle off-heap evictor threads in milliseconds.
562    /// Mirrors `OFFHEAP_KEEP_ALIVE` / default 60_000 ms.
563    pub offheap_keep_alive_ms: u64,
564
565    // -----------------------------------------------------------------------
566    // Locking
567    // -----------------------------------------------------------------------
568    /// Lock timeout in milliseconds.
569    /// Mirrors `LOCK_TIMEOUT` / default 500 ms.
570    pub lock_timeout_ms: u64,
571
572    /// Number of lock table shards.
573    /// Mirrors `LOCK_N_LOCK_TABLES` / default 1.  Noxu default: 16.
574    pub lock_n_lock_tables: u32,
575
576    /// Run the deadlock detector on lock waits.
577    /// Mirrors `LOCK_DEADLOCK_DETECT` / default true.
578    pub lock_deadlock_detect: bool,
579
580    /// Delay before deadlock detection runs (milliseconds).
581    /// 0 = detect immediately on every wait.
582    /// Mirrors `LOCK_DEADLOCK_DETECT_DELAY` / default 0.
583    pub lock_deadlock_detect_delay_ms: u64,
584
585    // -----------------------------------------------------------------------
586    // Transactions
587    // -----------------------------------------------------------------------
588    /// Transaction timeout in milliseconds.  0 = no timeout.
589    /// Mirrors `TXN_TIMEOUT` / default 0.
590    pub txn_timeout_ms: u64,
591
592    /// Default durability policy for transactions.
593    /// Mirrors `TXN_DURABILITY`.
594    pub durability: Durability,
595
596    /// Commits do not wait for the log to reach disk.
597    /// Mirrors `TXN_NO_SYNC` / default false.
598    ///
599    /// **Deprecated since 2.4.1** — use the [`durability`][Self::durability]
600    /// field with `Durability::commit_no_sync()` instead.
601    pub txn_no_sync: bool,
602
603    /// Commits write the log to the OS buffer but skip `fdatasync`.
604    /// Mirrors `TXN_WRITE_NO_SYNC` / default false.
605    ///
606    /// **Deprecated since 2.4.1** — use the [`durability`][Self::durability]
607    /// field with `Durability::commit_write_no_sync()` instead.
608    pub txn_write_no_sync: bool,
609
610    /// When `true`, all transactions default to **serializable**
611    /// (degree-3) isolation: read locks are retained through commit.
612    /// When `false` (the default), transactions use
613    /// **repeatable-read** isolation — read locks are still held for
614    /// the lifetime of the txn but predicate / phantom protection is
615    /// not provided.  Per-transaction overrides are available via
616    /// [`crate::transaction_config::TransactionConfig::set_serializable_isolation`]
617    /// and [`crate::transaction_config::TransactionConfig::set_read_committed`].
618    /// Mirrors `TXN_SERIALIZABLE_ISOLATION` / default false.
619    pub txn_serializable_isolation: bool,
620
621    /// Capture a stack trace at deadlock detection time (expensive).
622    /// Mirrors `TXN_DEADLOCK_STACK_TRACE` / default false.
623    pub txn_deadlock_stack_trace: bool,
624
625    /// Dump all lock state on deadlock detection (diagnostic, expensive).
626    /// Mirrors `TXN_DUMP_LOCKS` / default false.
627    pub txn_dump_locks: bool,
628
629    // -----------------------------------------------------------------------
630    // Verifier daemon
631    // -----------------------------------------------------------------------
632    /// Cron-style schedule string for the background verifier.
633    /// Empty string = run continuously when `run_verifier = true`.
634    /// Mirrors `VERIFY_SCHEDULE` / default `""`.
635    pub verify_schedule: String,
636
637    /// Verify log-file checksums in the background.
638    /// Mirrors `VERIFY_LOG` / default false.
639    pub verify_log: bool,
640
641    /// Delay between log verification read operations in milliseconds.
642    /// Mirrors `VERIFY_LOG_READ_DELAY` / default 0.
643    pub verify_log_read_delay_ms: u64,
644
645    /// Verify the B-tree structure in the background.
646    /// Mirrors `VERIFY_BTREE` / default false.
647    pub verify_btree: bool,
648
649    /// Verify secondary index consistency in the background.
650    /// Mirrors `VERIFY_SECONDARIES` / default true.
651    pub verify_secondaries: bool,
652
653    /// Verify data records (values) in the background.
654    /// Mirrors `VERIFY_DATA_RECORDS` / default false.
655    pub verify_data_records: bool,
656
657    /// Verify obsolete records have correct LSNs in the background.
658    /// Mirrors `VERIFY_OBSOLETE_RECORDS` / default false.
659    pub verify_obsolete_records: bool,
660
661    /// Number of B-tree nodes verified per verifier batch.
662    /// Mirrors `VERIFY_BTREE_BATCH_SIZE` / default 1_000.
663    pub verify_btree_batch_size: u32,
664
665    /// Delay between B-tree verification batches in milliseconds.
666    /// Mirrors `VERIFY_BTREE_BATCH_DELAY` / default 10 ms.
667    pub verify_btree_batch_delay_ms: u64,
668
669    // -----------------------------------------------------------------------
670    // Disk-ordered cursor
671    // -----------------------------------------------------------------------
672    /// Timeout for the disk-ordered cursor producer queue in milliseconds.
673    /// Mirrors `DOS_PRODUCER_QUEUE_TIMEOUT` / default 10_000 ms.
674    pub dos_producer_queue_timeout_ms: u64,
675
676    // -----------------------------------------------------------------------
677    // Recovery
678    // -----------------------------------------------------------------------
679    /// Force a checkpoint after recovery completes (alias; see
680    /// `env_recovery_force_checkpoint` above).
681    // (No duplicate field; already covered above.)
682
683    // -----------------------------------------------------------------------
684    // Background stats collection
685    // -----------------------------------------------------------------------
686
687    /// Collect environment statistics in the background.
688    /// Mirrors `STATS_COLLECT` / default false.
689    pub stats_collect: bool,
690
691    /// Interval between background stats collection passes in seconds.
692    /// Mirrors `STATS_COLLECT_INTERVAL` / default 300 s.
693    pub stats_collect_interval_secs: u64,
694
695    /// Maximum number of stats CSV files to retain.
696    /// Mirrors `STATS_MAX_FILES` / default 100.
697    pub stats_max_files: u32,
698
699    /// Rows per stats CSV file before rotation.
700    /// Mirrors `STATS_FILE_ROW_COUNT` / default 1_000.
701    pub stats_file_row_count: u32,
702
703    /// Directory for stats CSV files.  `None` = use the environment home.
704    /// Mirrors `STATS_FILE_DIRECTORY` / default `None`.
705    pub stats_file_directory: Option<PathBuf>,
706
707    // -----------------------------------------------------------------------
708    // Logging / tracing
709    // -----------------------------------------------------------------------
710    /// Enable log-file-based tracing (uses env home as destination).
711    /// Mirrors `TRACE_FILE` / default false.
712    pub trace_file: bool,
713
714    /// Enable console (stderr) tracing.
715    /// Mirrors `TRACE_CONSOLE` / default false.
716    pub trace_console: bool,
717
718    /// Enable database-record-based tracing (internal trace DB).
719    /// Mirrors `TRACE_DB` / default false.
720    pub trace_db: bool,
721
722    /// Maximum size of each trace log file in bytes.
723    /// Mirrors `TRACE_FILE_LIMIT` / default 10 MiB.
724    pub trace_file_limit_bytes: u64,
725
726    /// Number of rotating trace log files.
727    /// Mirrors `TRACE_FILE_COUNT` / default 10.
728    pub trace_file_count: u32,
729
730    /// Overall logging level (e.g. `"INFO"`, `"DEBUG"`).
731    /// Mirrors `TRACE_LEVEL` / default `"INFO"`.
732    pub trace_level: Option<String>,
733
734    /// Console-handler logging level.
735    /// Mirrors `CONSOLE_LOGGING_LEVEL` / default `"SEVERE"`.
736    pub console_logging_level: Option<String>,
737
738    /// File-handler logging level.
739    /// Mirrors `FILE_LOGGING_LEVEL` / default `"INFO"`.
740    pub file_logging_level: Option<String>,
741
742    /// Lock-manager subsystem trace level.
743    /// Mirrors `TRACE_LEVEL_LOCK_MANAGER` / default `"FINE"`.
744    pub trace_level_lock_manager: Option<String>,
745
746    /// Recovery subsystem trace level.
747    /// Mirrors `TRACE_LEVEL_RECOVERY` / default `"FINE"`.
748    pub trace_level_recovery: Option<String>,
749
750    /// Evictor subsystem trace level.
751    /// Mirrors `TRACE_LEVEL_EVICTOR` / default `"FINE"`.
752    pub trace_level_evictor: Option<String>,
753
754    /// Cleaner subsystem trace level.
755    /// Mirrors `TRACE_LEVEL_CLEANER` / default `"FINE"`.
756    pub trace_level_cleaner: Option<String>,
757
758    /// Startup statistics dump threshold in milliseconds.  Dump stats if
759    /// startup takes longer than this.  0 = disabled.
760    /// Mirrors `STARTUP_DUMP_THRESHOLD` / default 0.
761    pub startup_dump_threshold_ms: u64,
762
763    // -----------------------------------------------------------------------
764    // Callbacks
765    // -----------------------------------------------------------------------
766    /// Optional callback invoked when a background daemon thread encounters
767    /// an exception.  Set this to receive notifications from the Checkpointer,
768    /// Cleaner, Evictor, INCompressor, and Verifier daemons.
769    ///
770    /// Mirrors `EnvironmentConfig.setExceptionListener(ExceptionListener)`.
771    pub exception_listener: ExceptionListenerHolder,
772}
773
774impl EnvironmentConfig {
775    /// Creates a new `EnvironmentConfig` with the given home directory and
776    /// -identical defaults for all parameters.
777    pub fn new(home: PathBuf) -> Self {
778        Self {
779            home,
780            // Core
781            allow_create: false,
782            transactional: false,
783            read_only: false,
784            env_is_locking: true,
785            shared_cache: false,
786            env_recovery_force_checkpoint: false,
787            env_recovery_force_new_file: false,
788            halt_on_commit_after_checksum_exception: false,
789            logging_level: None,
790            // Memory
791            cache_size: 64 * 1024 * 1024, // Noxu default: 64 MiB
792            cache_percent: 0,
793            max_off_heap_memory: 0,
794            max_disk: 0,
795            free_disk: 5 * 1024 * 1024 * 1024, //: 5 GiB
796            // Daemon run flags
797            run_in_compressor: true,
798            run_checkpointer: true,
799            run_cleaner: true,
800            run_evictor: true,
801            run_offheap_evictor: false,
802            run_verifier: false,
803            // Background daemon rate limits
804            env_background_read_limit_kb: 0,
805            env_background_write_limit_kb: 0,
806            env_background_sleep_interval_us: 0,
807            // Environment behaviour
808            env_check_leaks: true,
809            env_forced_yield: false,
810            env_fair_latches: false,
811            env_latch_timeout_ms: 300_000,
812            env_ttl_clock_tolerance_ms: 0,
813            env_expiration_enabled: false,
814            env_db_eviction: false,
815            env_dup_convert_preload_all: true,
816            adler32_chunk_size: 0,
817            // Log
818            log_file_max_bytes: 10 * 1024 * 1024,
819            log_file_cache_size: 100,
820            log_checksum_read: true,
821            log_verify_checksums: false,
822            log_fsync_timeout_ms: 500_000,
823            log_fsync_time_limit_ms: 0,
824            log_num_buffers: 3,
825            log_total_buffer_bytes: 7 * 1024 * 1024,
826            log_buffer_size: 0,
827            log_fault_read_size: 2048,
828            log_iterator_read_size: 8192,
829            log_iterator_max_size: 16 * 1024 * 1024,
830            log_n_data_directories: 0,
831            log_mem_only: false,
832            log_detect_file_delete: false,
833            log_detect_file_delete_interval_ms: 3_000,
834            log_flush_sync_interval_ms: 0,
835            log_flush_no_sync_interval_ms: 0,
836            log_use_odsync: false,
837            log_use_write_queue: false,
838            log_write_queue_size: 1024 * 1024,
839            log_group_commit_threshold: 4,
840            log_group_commit_interval_ms: 1,
841            // B-tree
842            node_max_entries: 128,
843            node_dup_tree_max_entries: 128,
844            tree_max_embedded_ln: 16,
845            tree_max_delta: 25,
846            tree_bin_delta: true,
847            tree_min_memory: 0,
848            tree_compact_max_key_length: 16,
849            // INCompressor
850            in_compressor_wakeup_interval_ms: 5_000,
851            compressor_deadlock_retry: 3,
852            compressor_lock_timeout_ms: 500,
853            compressor_purge_root: false,
854            // Cleaner
855            cleaner_min_utilization: 50,
856            cleaner_min_file_utilization: 5,
857            cleaner_threads: 1,
858            cleaner_min_file_count: 2,
859            cleaner_min_age: 2,
860            cleaner_bytes_interval: 0,
861            cleaner_wakeup_interval_ms: 0,
862            cleaner_fetch_obsolete_size: false,
863            cleaner_adjust_utilization: false,
864            cleaner_deadlock_retry: 3,
865            cleaner_lock_timeout_ms: 500,
866            cleaner_expunge: true,
867            cleaner_use_deleted_dir: false,
868            cleaner_max_batch_files: 0,
869            cleaner_read_size: 8192,
870            cleaner_detail_max_memory_percentage: 2,
871            cleaner_look_ahead_cache_size: 32,
872            cleaner_foreground_proactive_migration: false,
873            cleaner_background_proactive_migration: false,
874            cleaner_lazy_migration: false,
875            cleaner_expiration_enabled: false,
876            // Checkpointer
877            checkpointer_bytes_interval: 20_000_000,
878            checkpointer_wakeup_interval_ms: 30_000,
879            checkpointer_min_interval_secs: 0,
880            checkpointer_deadlock_retry: 3,
881            checkpointer_high_priority: false,
882            // Evictor
883            evictor_nodes_per_scan: 10,
884            evictor_evict_bytes: 512 * 1024,
885            evictor_critical_percentage: 5,
886            evictor_lru_only: false,
887            evictor_n_lru_lists: 4,
888            evictor_deadlock_retry: 3,
889            evictor_core_threads: 1,
890            evictor_max_threads: 10,
891            evictor_keep_alive_ms: 60_000,
892            evictor_allow_bin_deltas: true,
893            // Off-heap evictor
894            offheap_evict_bytes: 512 * 1024,
895            offheap_n_lru_lists: 4,
896            offheap_checksum: false,
897            offheap_core_threads: 1,
898            offheap_max_threads: 10,
899            offheap_keep_alive_ms: 60_000,
900            // Locking
901            lock_timeout_ms: 500,
902            lock_n_lock_tables: 16, // Noxu default; is 1
903            lock_deadlock_detect: true,
904            lock_deadlock_detect_delay_ms: 0,
905            // Transactions
906            txn_timeout_ms: 0,
907            durability: Durability::default(),
908            txn_no_sync: false,
909            txn_write_no_sync: false,
910            txn_serializable_isolation: false,
911            txn_deadlock_stack_trace: false,
912            txn_dump_locks: false,
913            // Verifier
914            verify_schedule: String::new(),
915            verify_log: false,
916            verify_log_read_delay_ms: 0,
917            verify_btree: false,
918            verify_secondaries: true,
919            verify_data_records: false,
920            verify_obsolete_records: false,
921            verify_btree_batch_size: 1_000,
922            verify_btree_batch_delay_ms: 10,
923            // Disk-ordered cursor
924            dos_producer_queue_timeout_ms: 10_000,
925            // Stats
926            stats_collect: false,
927            stats_collect_interval_secs: 300,
928            stats_max_files: 100,
929            stats_file_row_count: 1_000,
930            stats_file_directory: None,
931            // Logging / tracing
932            trace_file: false,
933            trace_console: false,
934            trace_db: false,
935            trace_file_limit_bytes: 10 * 1024 * 1024,
936            trace_file_count: 10,
937            trace_level: None,
938            console_logging_level: None,
939            file_logging_level: None,
940            trace_level_lock_manager: None,
941            trace_level_recovery: None,
942            trace_level_evictor: None,
943            trace_level_cleaner: None,
944            startup_dump_threshold_ms: 0,
945            exception_listener: ExceptionListenerHolder(None),
946        }
947    }
948
949    // -----------------------------------------------------------------------
950    // Core setters
951    // -----------------------------------------------------------------------
952
953    pub fn set_allow_create(&mut self, v: bool) -> &mut Self {
954        self.allow_create = v;
955        self
956    }
957    pub fn with_allow_create(mut self, v: bool) -> Self {
958        self.allow_create = v;
959        self
960    }
961
962    pub fn set_transactional(&mut self, v: bool) -> &mut Self {
963        self.transactional = v;
964        self
965    }
966    pub fn with_transactional(mut self, v: bool) -> Self {
967        self.transactional = v;
968        self
969    }
970
971    pub fn set_read_only(&mut self, v: bool) -> &mut Self {
972        self.read_only = v;
973        self
974    }
975    pub fn with_read_only(mut self, v: bool) -> Self {
976        self.read_only = v;
977        self
978    }
979
980    pub fn set_env_is_locking(&mut self, v: bool) -> &mut Self {
981        self.env_is_locking = v;
982        self
983    }
984
985    pub fn set_shared_cache(&mut self, v: bool) -> &mut Self {
986        self.shared_cache = v;
987        self
988    }
989
990    pub fn set_env_recovery_force_checkpoint(&mut self, v: bool) -> &mut Self {
991        self.env_recovery_force_checkpoint = v;
992        self
993    }
994
995    pub fn set_env_recovery_force_new_file(&mut self, v: bool) -> &mut Self {
996        self.env_recovery_force_new_file = v;
997        self
998    }
999
1000    pub fn set_halt_on_commit_after_checksum_exception(
1001        &mut self,
1002        v: bool,
1003    ) -> &mut Self {
1004        self.halt_on_commit_after_checksum_exception = v;
1005        self
1006    }
1007
1008    pub fn set_logging_level(&mut self, level: String) -> &mut Self {
1009        self.logging_level = Some(level);
1010        self
1011    }
1012
1013    // -----------------------------------------------------------------------
1014    // Memory setters
1015    // -----------------------------------------------------------------------
1016
1017    pub fn set_cache_size(&mut self, bytes: u64) -> &mut Self {
1018        self.cache_size = bytes;
1019        self
1020    }
1021    pub fn with_cache_size(mut self, bytes: u64) -> Self {
1022        self.cache_size = bytes;
1023        self
1024    }
1025
1026    pub fn set_cache_percent(&mut self, pct: u32) -> &mut Self {
1027        self.cache_percent = pct;
1028        self
1029    }
1030
1031    pub fn set_max_off_heap_memory(&mut self, bytes: u64) -> &mut Self {
1032        self.max_off_heap_memory = bytes;
1033        self
1034    }
1035
1036    pub fn set_max_disk(&mut self, bytes: u64) -> &mut Self {
1037        self.max_disk = bytes;
1038        self
1039    }
1040
1041    pub fn set_free_disk(&mut self, bytes: u64) -> &mut Self {
1042        self.free_disk = bytes;
1043        self
1044    }
1045
1046    // -----------------------------------------------------------------------
1047    // Daemon run-flag setters
1048    // -----------------------------------------------------------------------
1049
1050    pub fn set_run_in_compressor(&mut self, v: bool) -> &mut Self {
1051        self.run_in_compressor = v;
1052        self
1053    }
1054    pub fn set_run_checkpointer(&mut self, v: bool) -> &mut Self {
1055        self.run_checkpointer = v;
1056        self
1057    }
1058    pub fn set_run_cleaner(&mut self, v: bool) -> &mut Self {
1059        self.run_cleaner = v;
1060        self
1061    }
1062    pub fn set_run_evictor(&mut self, v: bool) -> &mut Self {
1063        self.run_evictor = v;
1064        self
1065    }
1066    pub fn set_run_offheap_evictor(&mut self, v: bool) -> &mut Self {
1067        self.run_offheap_evictor = v;
1068        self
1069    }
1070    pub fn set_run_verifier(&mut self, v: bool) -> &mut Self {
1071        self.run_verifier = v;
1072        self
1073    }
1074
1075    // -----------------------------------------------------------------------
1076    // Background daemon rate / sleep
1077    // -----------------------------------------------------------------------
1078
1079    pub fn set_env_background_read_limit_kb(&mut self, kb: u32) -> &mut Self {
1080        self.env_background_read_limit_kb = kb;
1081        self
1082    }
1083    pub fn set_env_background_write_limit_kb(&mut self, kb: u32) -> &mut Self {
1084        self.env_background_write_limit_kb = kb;
1085        self
1086    }
1087    pub fn set_env_background_sleep_interval_us(
1088        &mut self,
1089        us: u64,
1090    ) -> &mut Self {
1091        self.env_background_sleep_interval_us = us;
1092        self
1093    }
1094
1095    // -----------------------------------------------------------------------
1096    // Environment behaviour setters
1097    // -----------------------------------------------------------------------
1098
1099    pub fn set_env_check_leaks(&mut self, v: bool) -> &mut Self {
1100        self.env_check_leaks = v;
1101        self
1102    }
1103    pub fn set_env_forced_yield(&mut self, v: bool) -> &mut Self {
1104        self.env_forced_yield = v;
1105        self
1106    }
1107    pub fn set_env_fair_latches(&mut self, v: bool) -> &mut Self {
1108        self.env_fair_latches = v;
1109        self
1110    }
1111    pub fn set_env_latch_timeout_ms(&mut self, ms: u64) -> &mut Self {
1112        self.env_latch_timeout_ms = ms;
1113        self
1114    }
1115    pub fn set_env_ttl_clock_tolerance_ms(&mut self, ms: u64) -> &mut Self {
1116        self.env_ttl_clock_tolerance_ms = ms;
1117        self
1118    }
1119    pub fn set_env_expiration_enabled(&mut self, v: bool) -> &mut Self {
1120        self.env_expiration_enabled = v;
1121        self
1122    }
1123    pub fn set_env_db_eviction(&mut self, v: bool) -> &mut Self {
1124        self.env_db_eviction = v;
1125        self
1126    }
1127    pub fn set_adler32_chunk_size(&mut self, bytes: usize) -> &mut Self {
1128        self.adler32_chunk_size = bytes;
1129        self
1130    }
1131
1132    // -----------------------------------------------------------------------
1133    // Log setters
1134    // -----------------------------------------------------------------------
1135
1136    pub fn set_log_file_max_bytes(&mut self, bytes: u64) -> &mut Self {
1137        self.log_file_max_bytes = bytes;
1138        self
1139    }
1140    pub fn with_log_file_max_bytes(mut self, bytes: u64) -> Self {
1141        self.log_file_max_bytes = bytes;
1142        self
1143    }
1144    pub fn set_log_file_cache_size(&mut self, n: usize) -> &mut Self {
1145        self.log_file_cache_size = n;
1146        self
1147    }
1148    pub fn set_log_checksum_read(&mut self, v: bool) -> &mut Self {
1149        self.log_checksum_read = v;
1150        self
1151    }
1152    pub fn set_log_verify_checksums(&mut self, v: bool) -> &mut Self {
1153        self.log_verify_checksums = v;
1154        self
1155    }
1156    pub fn set_log_fsync_timeout_ms(&mut self, ms: u64) -> &mut Self {
1157        self.log_fsync_timeout_ms = ms;
1158        self
1159    }
1160    pub fn set_log_fsync_time_limit_ms(&mut self, ms: u64) -> &mut Self {
1161        self.log_fsync_time_limit_ms = ms;
1162        self
1163    }
1164    pub fn set_log_num_buffers(&mut self, n: usize) -> &mut Self {
1165        self.log_num_buffers = n;
1166        self
1167    }
1168    pub fn set_log_total_buffer_bytes(&mut self, bytes: u64) -> &mut Self {
1169        self.log_total_buffer_bytes = bytes;
1170        self
1171    }
1172    pub fn set_log_buffer_size(&mut self, bytes: usize) -> &mut Self {
1173        self.log_buffer_size = bytes;
1174        self
1175    }
1176    pub fn set_log_fault_read_size(&mut self, bytes: usize) -> &mut Self {
1177        self.log_fault_read_size = bytes;
1178        self
1179    }
1180    pub fn set_log_iterator_read_size(&mut self, bytes: usize) -> &mut Self {
1181        self.log_iterator_read_size = bytes;
1182        self
1183    }
1184    pub fn set_log_iterator_max_size(&mut self, bytes: usize) -> &mut Self {
1185        self.log_iterator_max_size = bytes;
1186        self
1187    }
1188    pub fn set_log_n_data_directories(&mut self, n: u32) -> &mut Self {
1189        self.log_n_data_directories = n;
1190        self
1191    }
1192    pub fn set_log_mem_only(&mut self, v: bool) -> &mut Self {
1193        self.log_mem_only = v;
1194        self
1195    }
1196    pub fn set_log_detect_file_delete(&mut self, v: bool) -> &mut Self {
1197        self.log_detect_file_delete = v;
1198        self
1199    }
1200    pub fn set_log_detect_file_delete_interval_ms(
1201        &mut self,
1202        ms: u64,
1203    ) -> &mut Self {
1204        self.log_detect_file_delete_interval_ms = ms;
1205        self
1206    }
1207    pub fn set_log_flush_sync_interval_ms(&mut self, ms: u64) -> &mut Self {
1208        self.log_flush_sync_interval_ms = ms;
1209        self
1210    }
1211    pub fn set_log_flush_no_sync_interval_ms(&mut self, ms: u64) -> &mut Self {
1212        self.log_flush_no_sync_interval_ms = ms;
1213        self
1214    }
1215    pub fn set_log_use_odsync(&mut self, v: bool) -> &mut Self {
1216        self.log_use_odsync = v;
1217        self
1218    }
1219    pub fn set_log_use_write_queue(&mut self, v: bool) -> &mut Self {
1220        self.log_use_write_queue = v;
1221        self
1222    }
1223    pub fn set_log_write_queue_size(&mut self, bytes: usize) -> &mut Self {
1224        self.log_write_queue_size = bytes;
1225        self
1226    }
1227    pub fn set_log_group_commit_threshold(&mut self, n: usize) -> &mut Self {
1228        self.log_group_commit_threshold = n;
1229        self
1230    }
1231    pub fn set_log_group_commit_interval_ms(&mut self, ms: u64) -> &mut Self {
1232        self.log_group_commit_interval_ms = ms;
1233        self
1234    }
1235    pub fn with_log_group_commit(
1236        mut self,
1237        threshold: usize,
1238        interval_ms: u64,
1239    ) -> Self {
1240        self.log_group_commit_threshold = threshold;
1241        self.log_group_commit_interval_ms = interval_ms;
1242        self
1243    }
1244
1245    // -----------------------------------------------------------------------
1246    // B-tree setters
1247    // -----------------------------------------------------------------------
1248
1249    pub fn set_node_max_entries(&mut self, n: u32) -> &mut Self {
1250        self.node_max_entries = n;
1251        self
1252    }
1253    pub fn set_node_dup_tree_max_entries(&mut self, n: u32) -> &mut Self {
1254        self.node_dup_tree_max_entries = n;
1255        self
1256    }
1257    pub fn set_tree_max_embedded_ln(&mut self, bytes: u32) -> &mut Self {
1258        self.tree_max_embedded_ln = bytes;
1259        self
1260    }
1261    pub fn set_tree_max_delta(&mut self, pct: u8) -> &mut Self {
1262        self.tree_max_delta = pct;
1263        self
1264    }
1265    pub fn set_tree_bin_delta(&mut self, v: bool) -> &mut Self {
1266        self.tree_bin_delta = v;
1267        self
1268    }
1269    pub fn set_tree_min_memory(&mut self, bytes: u64) -> &mut Self {
1270        self.tree_min_memory = bytes;
1271        self
1272    }
1273    pub fn set_tree_compact_max_key_length(&mut self, bytes: u32) -> &mut Self {
1274        self.tree_compact_max_key_length = bytes;
1275        self
1276    }
1277
1278    // -----------------------------------------------------------------------
1279    // INCompressor setters
1280    // -----------------------------------------------------------------------
1281
1282    pub fn set_in_compressor_wakeup_interval_ms(
1283        &mut self,
1284        ms: u64,
1285    ) -> &mut Self {
1286        self.in_compressor_wakeup_interval_ms = ms;
1287        self
1288    }
1289    pub fn set_compressor_deadlock_retry(&mut self, n: u32) -> &mut Self {
1290        self.compressor_deadlock_retry = n;
1291        self
1292    }
1293    pub fn set_compressor_lock_timeout_ms(&mut self, ms: u64) -> &mut Self {
1294        self.compressor_lock_timeout_ms = ms;
1295        self
1296    }
1297    pub fn set_compressor_purge_root(&mut self, v: bool) -> &mut Self {
1298        self.compressor_purge_root = v;
1299        self
1300    }
1301
1302    // -----------------------------------------------------------------------
1303    // Cleaner setters
1304    // -----------------------------------------------------------------------
1305
1306    pub fn set_cleaner_min_utilization(&mut self, pct: u8) -> &mut Self {
1307        self.cleaner_min_utilization = pct;
1308        self
1309    }
1310    pub fn with_cleaner_min_utilization(mut self, pct: u8) -> Self {
1311        self.cleaner_min_utilization = pct;
1312        self
1313    }
1314    pub fn set_cleaner_min_file_utilization(&mut self, pct: u8) -> &mut Self {
1315        self.cleaner_min_file_utilization = pct;
1316        self
1317    }
1318    pub fn set_cleaner_threads(&mut self, n: u32) -> &mut Self {
1319        self.cleaner_threads = n;
1320        self
1321    }
1322    pub fn set_cleaner_min_file_count(&mut self, n: u32) -> &mut Self {
1323        self.cleaner_min_file_count = n;
1324        self
1325    }
1326    pub fn set_cleaner_min_age(&mut self, checkpoints: u32) -> &mut Self {
1327        self.cleaner_min_age = checkpoints;
1328        self
1329    }
1330    pub fn set_cleaner_bytes_interval(&mut self, bytes: u64) -> &mut Self {
1331        self.cleaner_bytes_interval = bytes;
1332        self
1333    }
1334    pub fn set_cleaner_wakeup_interval_ms(&mut self, ms: u64) -> &mut Self {
1335        self.cleaner_wakeup_interval_ms = ms;
1336        self
1337    }
1338    pub fn set_cleaner_fetch_obsolete_size(&mut self, v: bool) -> &mut Self {
1339        self.cleaner_fetch_obsolete_size = v;
1340        self
1341    }
1342    pub fn set_cleaner_adjust_utilization(&mut self, v: bool) -> &mut Self {
1343        self.cleaner_adjust_utilization = v;
1344        self
1345    }
1346    pub fn set_cleaner_deadlock_retry(&mut self, n: u32) -> &mut Self {
1347        self.cleaner_deadlock_retry = n;
1348        self
1349    }
1350    pub fn set_cleaner_lock_timeout_ms(&mut self, ms: u64) -> &mut Self {
1351        self.cleaner_lock_timeout_ms = ms;
1352        self
1353    }
1354    pub fn set_cleaner_expunge(&mut self, v: bool) -> &mut Self {
1355        self.cleaner_expunge = v;
1356        self
1357    }
1358    pub fn set_cleaner_use_deleted_dir(&mut self, v: bool) -> &mut Self {
1359        self.cleaner_use_deleted_dir = v;
1360        self
1361    }
1362    pub fn set_cleaner_max_batch_files(&mut self, n: u32) -> &mut Self {
1363        self.cleaner_max_batch_files = n;
1364        self
1365    }
1366    pub fn set_cleaner_read_size(&mut self, bytes: usize) -> &mut Self {
1367        self.cleaner_read_size = bytes;
1368        self
1369    }
1370    pub fn set_cleaner_detail_max_memory_percentage(
1371        &mut self,
1372        pct: u32,
1373    ) -> &mut Self {
1374        self.cleaner_detail_max_memory_percentage = pct;
1375        self
1376    }
1377    pub fn set_cleaner_look_ahead_cache_size(&mut self, n: usize) -> &mut Self {
1378        self.cleaner_look_ahead_cache_size = n;
1379        self
1380    }
1381    pub fn set_cleaner_foreground_proactive_migration(
1382        &mut self,
1383        v: bool,
1384    ) -> &mut Self {
1385        self.cleaner_foreground_proactive_migration = v;
1386        self
1387    }
1388    pub fn set_cleaner_background_proactive_migration(
1389        &mut self,
1390        v: bool,
1391    ) -> &mut Self {
1392        self.cleaner_background_proactive_migration = v;
1393        self
1394    }
1395    pub fn set_cleaner_lazy_migration(&mut self, v: bool) -> &mut Self {
1396        self.cleaner_lazy_migration = v;
1397        self
1398    }
1399    pub fn set_cleaner_expiration_enabled(&mut self, v: bool) -> &mut Self {
1400        self.cleaner_expiration_enabled = v;
1401        self
1402    }
1403
1404    // -----------------------------------------------------------------------
1405    // Checkpointer setters
1406    // -----------------------------------------------------------------------
1407
1408    pub fn set_checkpointer_bytes_interval(&mut self, bytes: u64) -> &mut Self {
1409        self.checkpointer_bytes_interval = bytes;
1410        self
1411    }
1412    pub fn with_checkpointer_bytes_interval(mut self, bytes: u64) -> Self {
1413        self.checkpointer_bytes_interval = bytes;
1414        self
1415    }
1416    pub fn set_checkpointer_wakeup_interval_ms(
1417        &mut self,
1418        ms: u64,
1419    ) -> &mut Self {
1420        self.checkpointer_wakeup_interval_ms = ms;
1421        self
1422    }
1423    pub fn set_checkpointer_min_interval_secs(
1424        &mut self,
1425        secs: u64,
1426    ) -> &mut Self {
1427        self.checkpointer_min_interval_secs = secs;
1428        self
1429    }
1430    pub fn set_checkpointer_deadlock_retry(&mut self, n: u32) -> &mut Self {
1431        self.checkpointer_deadlock_retry = n;
1432        self
1433    }
1434    pub fn set_checkpointer_high_priority(&mut self, v: bool) -> &mut Self {
1435        self.checkpointer_high_priority = v;
1436        self
1437    }
1438
1439    // -----------------------------------------------------------------------
1440    // Evictor setters
1441    // -----------------------------------------------------------------------
1442
1443    pub fn set_evictor_nodes_per_scan(&mut self, n: usize) -> &mut Self {
1444        self.evictor_nodes_per_scan = n;
1445        self
1446    }
1447    pub fn with_evictor_nodes_per_scan(mut self, n: usize) -> Self {
1448        self.evictor_nodes_per_scan = n;
1449        self
1450    }
1451    pub fn set_evictor_evict_bytes(&mut self, bytes: u64) -> &mut Self {
1452        self.evictor_evict_bytes = bytes;
1453        self
1454    }
1455    pub fn set_evictor_critical_percentage(&mut self, pct: u32) -> &mut Self {
1456        self.evictor_critical_percentage = pct;
1457        self
1458    }
1459    pub fn set_evictor_lru_only(&mut self, v: bool) -> &mut Self {
1460        self.evictor_lru_only = v;
1461        self
1462    }
1463    pub fn set_evictor_n_lru_lists(&mut self, n: u32) -> &mut Self {
1464        self.evictor_n_lru_lists = n;
1465        self
1466    }
1467    pub fn set_evictor_deadlock_retry(&mut self, n: u32) -> &mut Self {
1468        self.evictor_deadlock_retry = n;
1469        self
1470    }
1471    pub fn set_evictor_core_threads(&mut self, n: usize) -> &mut Self {
1472        self.evictor_core_threads = n;
1473        self
1474    }
1475    pub fn set_evictor_max_threads(&mut self, n: usize) -> &mut Self {
1476        self.evictor_max_threads = n;
1477        self
1478    }
1479    pub fn set_evictor_keep_alive_ms(&mut self, ms: u64) -> &mut Self {
1480        self.evictor_keep_alive_ms = ms;
1481        self
1482    }
1483    pub fn set_evictor_allow_bin_deltas(&mut self, v: bool) -> &mut Self {
1484        self.evictor_allow_bin_deltas = v;
1485        self
1486    }
1487
1488    // -----------------------------------------------------------------------
1489    // Off-heap evictor setters
1490    // -----------------------------------------------------------------------
1491
1492    pub fn set_offheap_evict_bytes(&mut self, bytes: u64) -> &mut Self {
1493        self.offheap_evict_bytes = bytes;
1494        self
1495    }
1496    pub fn set_offheap_n_lru_lists(&mut self, n: u32) -> &mut Self {
1497        self.offheap_n_lru_lists = n;
1498        self
1499    }
1500    pub fn set_offheap_checksum(&mut self, v: bool) -> &mut Self {
1501        self.offheap_checksum = v;
1502        self
1503    }
1504    pub fn set_offheap_core_threads(&mut self, n: usize) -> &mut Self {
1505        self.offheap_core_threads = n;
1506        self
1507    }
1508    pub fn set_offheap_max_threads(&mut self, n: usize) -> &mut Self {
1509        self.offheap_max_threads = n;
1510        self
1511    }
1512    pub fn set_offheap_keep_alive_ms(&mut self, ms: u64) -> &mut Self {
1513        self.offheap_keep_alive_ms = ms;
1514        self
1515    }
1516
1517    // -----------------------------------------------------------------------
1518    // Locking setters
1519    // -----------------------------------------------------------------------
1520
1521    pub fn set_lock_timeout(&mut self, ms: u64) -> &mut Self {
1522        self.lock_timeout_ms = ms;
1523        self
1524    }
1525    pub fn set_lock_n_lock_tables(&mut self, n: u32) -> &mut Self {
1526        self.lock_n_lock_tables = n;
1527        self
1528    }
1529    pub fn set_lock_deadlock_detect(&mut self, v: bool) -> &mut Self {
1530        self.lock_deadlock_detect = v;
1531        self
1532    }
1533    pub fn set_lock_deadlock_detect_delay_ms(&mut self, ms: u64) -> &mut Self {
1534        self.lock_deadlock_detect_delay_ms = ms;
1535        self
1536    }
1537
1538    // -----------------------------------------------------------------------
1539    // Transaction setters
1540    // -----------------------------------------------------------------------
1541
1542    pub fn set_txn_timeout(&mut self, ms: u64) -> &mut Self {
1543        self.txn_timeout_ms = ms;
1544        self
1545    }
1546    pub fn set_durability(&mut self, d: Durability) -> &mut Self {
1547        self.durability = d;
1548        self
1549    }
1550    pub fn with_durability(mut self, d: Durability) -> Self {
1551        self.durability = d;
1552        self
1553    }
1554    /// Sets `txn_no_sync`.
1555    ///
1556    /// **Deprecated** — use [`set_durability`][Self::set_durability] /
1557    /// [`with_durability`][Self::with_durability] instead.
1558    #[deprecated(
1559        since = "2.4.1",
1560        note = "use set_durability(Durability::commit_no_sync()) instead"
1561    )]
1562    pub fn set_txn_no_sync(&mut self, v: bool) -> &mut Self {
1563        self.txn_no_sync = v;
1564        self
1565    }
1566    /// Builder-style `txn_no_sync`.
1567    ///
1568    /// **Deprecated** — use [`with_durability`][Self::with_durability] instead.
1569    #[deprecated(
1570        since = "2.4.1",
1571        note = "use with_durability(Durability::commit_no_sync()) instead"
1572    )]
1573    pub fn with_txn_no_sync(mut self, v: bool) -> Self {
1574        self.txn_no_sync = v;
1575        self
1576    }
1577    /// Sets `txn_write_no_sync`.
1578    ///
1579    /// **Deprecated** — use [`set_durability`][Self::set_durability] instead.
1580    #[deprecated(
1581        since = "2.4.1",
1582        note = "use set_durability(Durability::commit_write_no_sync()) instead"
1583    )]
1584    pub fn set_txn_write_no_sync(&mut self, v: bool) -> &mut Self {
1585        self.txn_write_no_sync = v;
1586        self
1587    }
1588    pub fn set_txn_serializable_isolation(&mut self, v: bool) -> &mut Self {
1589        self.txn_serializable_isolation = v;
1590        self
1591    }
1592    pub fn set_txn_deadlock_stack_trace(&mut self, v: bool) -> &mut Self {
1593        self.txn_deadlock_stack_trace = v;
1594        self
1595    }
1596    pub fn set_txn_dump_locks(&mut self, v: bool) -> &mut Self {
1597        self.txn_dump_locks = v;
1598        self
1599    }
1600
1601    // -----------------------------------------------------------------------
1602    // Verifier setters
1603    // -----------------------------------------------------------------------
1604
1605    pub fn set_verify_schedule(&mut self, s: String) -> &mut Self {
1606        self.verify_schedule = s;
1607        self
1608    }
1609    pub fn set_verify_log(&mut self, v: bool) -> &mut Self {
1610        self.verify_log = v;
1611        self
1612    }
1613    pub fn set_verify_log_read_delay_ms(&mut self, ms: u64) -> &mut Self {
1614        self.verify_log_read_delay_ms = ms;
1615        self
1616    }
1617    pub fn set_verify_btree(&mut self, v: bool) -> &mut Self {
1618        self.verify_btree = v;
1619        self
1620    }
1621    pub fn set_verify_secondaries(&mut self, v: bool) -> &mut Self {
1622        self.verify_secondaries = v;
1623        self
1624    }
1625    pub fn set_verify_data_records(&mut self, v: bool) -> &mut Self {
1626        self.verify_data_records = v;
1627        self
1628    }
1629    pub fn set_verify_obsolete_records(&mut self, v: bool) -> &mut Self {
1630        self.verify_obsolete_records = v;
1631        self
1632    }
1633    pub fn set_verify_btree_batch_size(&mut self, n: u32) -> &mut Self {
1634        self.verify_btree_batch_size = n;
1635        self
1636    }
1637    pub fn set_verify_btree_batch_delay_ms(&mut self, ms: u64) -> &mut Self {
1638        self.verify_btree_batch_delay_ms = ms;
1639        self
1640    }
1641
1642    // -----------------------------------------------------------------------
1643    // Disk-ordered cursor setters
1644    // -----------------------------------------------------------------------
1645
1646    pub fn set_dos_producer_queue_timeout_ms(&mut self, ms: u64) -> &mut Self {
1647        self.dos_producer_queue_timeout_ms = ms;
1648        self
1649    }
1650
1651    // -----------------------------------------------------------------------
1652    // Stats setters
1653    // -----------------------------------------------------------------------
1654
1655    pub fn set_stats_collect(&mut self, v: bool) -> &mut Self {
1656        self.stats_collect = v;
1657        self
1658    }
1659    pub fn set_stats_collect_interval_secs(&mut self, secs: u64) -> &mut Self {
1660        self.stats_collect_interval_secs = secs;
1661        self
1662    }
1663    pub fn set_stats_max_files(&mut self, n: u32) -> &mut Self {
1664        self.stats_max_files = n;
1665        self
1666    }
1667    pub fn set_stats_file_row_count(&mut self, n: u32) -> &mut Self {
1668        self.stats_file_row_count = n;
1669        self
1670    }
1671    pub fn set_stats_file_directory(&mut self, dir: PathBuf) -> &mut Self {
1672        self.stats_file_directory = Some(dir);
1673        self
1674    }
1675
1676    // -----------------------------------------------------------------------
1677    // Logging / tracing setters
1678    // -----------------------------------------------------------------------
1679
1680    pub fn set_trace_file(&mut self, v: bool) -> &mut Self {
1681        self.trace_file = v;
1682        self
1683    }
1684    pub fn set_trace_console(&mut self, v: bool) -> &mut Self {
1685        self.trace_console = v;
1686        self
1687    }
1688    pub fn set_trace_db(&mut self, v: bool) -> &mut Self {
1689        self.trace_db = v;
1690        self
1691    }
1692    pub fn set_trace_file_limit_bytes(&mut self, bytes: u64) -> &mut Self {
1693        self.trace_file_limit_bytes = bytes;
1694        self
1695    }
1696    pub fn set_trace_file_count(&mut self, n: u32) -> &mut Self {
1697        self.trace_file_count = n;
1698        self
1699    }
1700    pub fn set_trace_level(&mut self, level: String) -> &mut Self {
1701        self.trace_level = Some(level);
1702        self
1703    }
1704    pub fn set_console_logging_level(&mut self, level: String) -> &mut Self {
1705        self.console_logging_level = Some(level);
1706        self
1707    }
1708    pub fn set_file_logging_level(&mut self, level: String) -> &mut Self {
1709        self.file_logging_level = Some(level);
1710        self
1711    }
1712    pub fn set_trace_level_lock_manager(&mut self, level: String) -> &mut Self {
1713        self.trace_level_lock_manager = Some(level);
1714        self
1715    }
1716    pub fn set_trace_level_recovery(&mut self, level: String) -> &mut Self {
1717        self.trace_level_recovery = Some(level);
1718        self
1719    }
1720    pub fn set_trace_level_evictor(&mut self, level: String) -> &mut Self {
1721        self.trace_level_evictor = Some(level);
1722        self
1723    }
1724    pub fn set_trace_level_cleaner(&mut self, level: String) -> &mut Self {
1725        self.trace_level_cleaner = Some(level);
1726        self
1727    }
1728    pub fn set_startup_dump_threshold_ms(&mut self, ms: u64) -> &mut Self {
1729        self.startup_dump_threshold_ms = ms;
1730        self
1731    }
1732
1733    // -----------------------------------------------------------------------
1734    // Callback setters
1735    // -----------------------------------------------------------------------
1736
1737    /// Registers a callback to be invoked when a background daemon thread
1738    /// encounters an unhandled exception.
1739    ///
1740    /// Mirrors `EnvironmentConfig.setExceptionListener(ExceptionListener)`.
1741    pub fn set_exception_listener(
1742        &mut self,
1743        listener: Arc<dyn ExceptionListener>,
1744    ) -> &mut Self {
1745        self.exception_listener = ExceptionListenerHolder(Some(listener));
1746        self
1747    }
1748
1749    /// Returns the registered `ExceptionListener`, if any.
1750    pub fn get_exception_listener(&self) -> Option<Arc<dyn ExceptionListener>> {
1751        self.exception_listener.0.clone()
1752    }
1753}
1754
1755impl Default for EnvironmentConfig {
1756    fn default() -> Self {
1757        Self::new(PathBuf::from("."))
1758    }
1759}
1760
1761#[cfg(test)]
1762mod tests {
1763    use super::*;
1764
1765    #[test]
1766    fn test_defaults_core() {
1767        let c = EnvironmentConfig::default();
1768        assert_eq!(c.home, PathBuf::from("."));
1769        assert!(!c.allow_create);
1770        assert!(!c.transactional);
1771        assert!(!c.read_only);
1772        assert!(c.env_is_locking);
1773        assert!(!c.shared_cache);
1774        assert!(!c.env_recovery_force_checkpoint);
1775        assert!(!c.env_recovery_force_new_file);
1776        assert!(!c.halt_on_commit_after_checksum_exception);
1777    }
1778
1779    #[test]
1780    fn test_defaults_memory() {
1781        let c = EnvironmentConfig::default();
1782        assert_eq!(c.cache_size, 64 * 1024 * 1024);
1783        assert_eq!(c.cache_percent, 0);
1784        assert_eq!(c.max_off_heap_memory, 0);
1785        assert_eq!(c.max_disk, 0);
1786        assert_eq!(c.free_disk, 5 * 1024 * 1024 * 1024);
1787    }
1788
1789    #[test]
1790    fn test_defaults_daemons() {
1791        let c = EnvironmentConfig::default();
1792        assert!(c.run_in_compressor);
1793        assert!(c.run_checkpointer);
1794        assert!(c.run_cleaner);
1795        assert!(c.run_evictor);
1796        assert!(!c.run_offheap_evictor);
1797        assert!(!c.run_verifier);
1798    }
1799
1800    #[test]
1801    fn test_defaults_log() {
1802        let c = EnvironmentConfig::default();
1803        assert_eq!(c.log_file_max_bytes, 10 * 1024 * 1024);
1804        assert_eq!(c.log_file_cache_size, 100);
1805        assert!(c.log_checksum_read);
1806        assert!(!c.log_verify_checksums);
1807        assert_eq!(c.log_fsync_timeout_ms, 500_000);
1808        assert_eq!(c.log_fsync_time_limit_ms, 0);
1809        assert_eq!(c.log_num_buffers, 3);
1810        assert_eq!(c.log_total_buffer_bytes, 7 * 1024 * 1024);
1811        assert_eq!(c.log_buffer_size, 0);
1812        assert_eq!(c.log_fault_read_size, 2048);
1813        assert_eq!(c.log_iterator_read_size, 8192);
1814        assert_eq!(c.log_iterator_max_size, 16 * 1024 * 1024);
1815        assert_eq!(c.log_n_data_directories, 0);
1816        assert!(!c.log_mem_only);
1817        assert!(!c.log_detect_file_delete);
1818        assert_eq!(c.log_detect_file_delete_interval_ms, 3_000);
1819        assert_eq!(c.log_flush_sync_interval_ms, 0);
1820        assert_eq!(c.log_flush_no_sync_interval_ms, 0);
1821        assert!(!c.log_use_odsync);
1822        assert!(!c.log_use_write_queue);
1823        assert_eq!(c.log_write_queue_size, 1024 * 1024);
1824        assert_eq!(c.log_group_commit_threshold, 4);
1825        assert_eq!(c.log_group_commit_interval_ms, 1);
1826    }
1827
1828    #[test]
1829    fn test_defaults_btree() {
1830        let c = EnvironmentConfig::default();
1831        assert_eq!(c.node_max_entries, 128);
1832        assert_eq!(c.node_dup_tree_max_entries, 128);
1833        assert_eq!(c.tree_max_embedded_ln, 16);
1834        assert_eq!(c.tree_max_delta, 25);
1835        assert!(c.tree_bin_delta);
1836        assert_eq!(c.tree_min_memory, 0);
1837        assert_eq!(c.tree_compact_max_key_length, 16);
1838    }
1839
1840    #[test]
1841    fn test_defaults_cleaner() {
1842        let c = EnvironmentConfig::default();
1843        assert_eq!(c.cleaner_min_utilization, 50);
1844        assert_eq!(c.cleaner_min_file_utilization, 5);
1845        assert_eq!(c.cleaner_threads, 1);
1846        assert_eq!(c.cleaner_min_file_count, 2);
1847        assert_eq!(c.cleaner_min_age, 2);
1848        assert_eq!(c.cleaner_bytes_interval, 0);
1849        assert_eq!(c.cleaner_wakeup_interval_ms, 0);
1850        assert!(!c.cleaner_fetch_obsolete_size);
1851        assert!(!c.cleaner_adjust_utilization);
1852        assert_eq!(c.cleaner_deadlock_retry, 3);
1853        assert_eq!(c.cleaner_lock_timeout_ms, 500);
1854        assert!(c.cleaner_expunge);
1855        assert!(!c.cleaner_use_deleted_dir);
1856        assert_eq!(c.cleaner_max_batch_files, 0);
1857        assert_eq!(c.cleaner_read_size, 8192);
1858        assert_eq!(c.cleaner_detail_max_memory_percentage, 2);
1859        assert_eq!(c.cleaner_look_ahead_cache_size, 32);
1860        assert!(!c.cleaner_foreground_proactive_migration);
1861        assert!(!c.cleaner_background_proactive_migration);
1862        assert!(!c.cleaner_lazy_migration);
1863        assert!(!c.cleaner_expiration_enabled);
1864    }
1865
1866    #[test]
1867    fn test_defaults_checkpointer() {
1868        let c = EnvironmentConfig::default();
1869        assert_eq!(c.checkpointer_bytes_interval, 20_000_000);
1870        assert_eq!(c.checkpointer_wakeup_interval_ms, 30_000);
1871        assert_eq!(c.checkpointer_min_interval_secs, 0);
1872        assert_eq!(c.checkpointer_deadlock_retry, 3);
1873        assert!(!c.checkpointer_high_priority);
1874    }
1875
1876    #[test]
1877    fn test_defaults_evictor() {
1878        let c = EnvironmentConfig::default();
1879        assert_eq!(c.evictor_nodes_per_scan, 10);
1880        assert_eq!(c.evictor_evict_bytes, 512 * 1024);
1881        assert_eq!(c.evictor_critical_percentage, 5);
1882        assert!(!c.evictor_lru_only);
1883        assert_eq!(c.evictor_n_lru_lists, 4);
1884        assert_eq!(c.evictor_deadlock_retry, 3);
1885        assert_eq!(c.evictor_core_threads, 1);
1886        assert_eq!(c.evictor_max_threads, 10);
1887        assert_eq!(c.evictor_keep_alive_ms, 60_000);
1888        assert!(c.evictor_allow_bin_deltas);
1889    }
1890
1891    #[test]
1892    fn test_defaults_offheap() {
1893        let c = EnvironmentConfig::default();
1894        assert_eq!(c.offheap_evict_bytes, 512 * 1024);
1895        assert_eq!(c.offheap_n_lru_lists, 4);
1896        assert!(!c.offheap_checksum);
1897        assert_eq!(c.offheap_core_threads, 1);
1898        assert_eq!(c.offheap_max_threads, 10);
1899        assert_eq!(c.offheap_keep_alive_ms, 60_000);
1900    }
1901
1902    #[test]
1903    fn test_defaults_locking() {
1904        let c = EnvironmentConfig::default();
1905        assert_eq!(c.lock_timeout_ms, 500);
1906        assert_eq!(c.lock_n_lock_tables, 16);
1907        assert!(c.lock_deadlock_detect);
1908        assert_eq!(c.lock_deadlock_detect_delay_ms, 0);
1909    }
1910
1911    #[test]
1912    fn test_defaults_txn() {
1913        let c = EnvironmentConfig::default();
1914        assert_eq!(c.txn_timeout_ms, 0);
1915        assert!(!c.txn_no_sync);
1916        assert!(!c.txn_write_no_sync);
1917        assert!(!c.txn_serializable_isolation);
1918        assert!(!c.txn_deadlock_stack_trace);
1919        assert!(!c.txn_dump_locks);
1920    }
1921
1922    #[test]
1923    fn test_defaults_verifier() {
1924        let c = EnvironmentConfig::default();
1925        assert_eq!(c.verify_schedule, "");
1926        assert!(!c.verify_log);
1927        assert_eq!(c.verify_log_read_delay_ms, 0);
1928        assert!(!c.verify_btree);
1929        assert!(c.verify_secondaries);
1930        assert!(!c.verify_data_records);
1931        assert!(!c.verify_obsolete_records);
1932        assert_eq!(c.verify_btree_batch_size, 1_000);
1933        assert_eq!(c.verify_btree_batch_delay_ms, 10);
1934    }
1935
1936    #[test]
1937    fn test_defaults_stats() {
1938        let c = EnvironmentConfig::default();
1939        assert!(!c.stats_collect);
1940        assert_eq!(c.stats_collect_interval_secs, 300);
1941        assert_eq!(c.stats_max_files, 100);
1942        assert_eq!(c.stats_file_row_count, 1_000);
1943        assert!(c.stats_file_directory.is_none());
1944    }
1945
1946    #[test]
1947    fn test_set_allow_create() {
1948        let mut c = EnvironmentConfig::default();
1949        c.set_allow_create(true);
1950        assert!(c.allow_create);
1951    }
1952
1953    #[test]
1954    fn test_set_cache_size() {
1955        let mut c = EnvironmentConfig::default();
1956        c.set_cache_size(128 * 1024 * 1024);
1957        assert_eq!(c.cache_size, 128 * 1024 * 1024);
1958    }
1959
1960    #[test]
1961    fn test_set_free_disk() {
1962        let mut c = EnvironmentConfig::default();
1963        c.set_free_disk(1024 * 1024 * 1024);
1964        assert_eq!(c.free_disk, 1024 * 1024 * 1024);
1965    }
1966
1967    #[test]
1968    fn test_set_log_params() {
1969        let mut c = EnvironmentConfig::default();
1970        c.set_log_file_max_bytes(20 * 1024 * 1024);
1971        c.set_log_num_buffers(5);
1972        c.set_log_total_buffer_bytes(5 * 1024 * 1024);
1973        c.set_log_iterator_read_size(16384);
1974        c.set_log_iterator_max_size(32 * 1024 * 1024);
1975        c.set_log_n_data_directories(2);
1976        c.set_log_mem_only(true);
1977        c.set_log_use_odsync(true);
1978        c.set_log_detect_file_delete(true);
1979        c.set_log_detect_file_delete_interval_ms(5000);
1980        c.set_log_flush_sync_interval_ms(1000);
1981        c.set_log_flush_no_sync_interval_ms(500);
1982        c.set_log_fsync_time_limit_ms(200);
1983        c.set_log_use_write_queue(true);
1984        c.set_log_write_queue_size(2 * 1024 * 1024);
1985        c.set_log_verify_checksums(true);
1986        assert_eq!(c.log_file_max_bytes, 20 * 1024 * 1024);
1987        assert_eq!(c.log_num_buffers, 5);
1988        assert_eq!(c.log_total_buffer_bytes, 5 * 1024 * 1024);
1989        assert_eq!(c.log_iterator_read_size, 16384);
1990        assert_eq!(c.log_iterator_max_size, 32 * 1024 * 1024);
1991        assert_eq!(c.log_n_data_directories, 2);
1992        assert!(c.log_mem_only);
1993        assert!(c.log_use_odsync);
1994        assert!(c.log_detect_file_delete);
1995        assert_eq!(c.log_detect_file_delete_interval_ms, 5000);
1996        assert_eq!(c.log_flush_sync_interval_ms, 1000);
1997        assert_eq!(c.log_flush_no_sync_interval_ms, 500);
1998        assert_eq!(c.log_fsync_time_limit_ms, 200);
1999        assert!(c.log_use_write_queue);
2000        assert_eq!(c.log_write_queue_size, 2 * 1024 * 1024);
2001        assert!(c.log_verify_checksums);
2002    }
2003
2004    #[test]
2005    fn test_set_btree_params() {
2006        let mut c = EnvironmentConfig::default();
2007        c.set_node_max_entries(256);
2008        c.set_node_dup_tree_max_entries(64);
2009        c.set_tree_max_embedded_ln(32);
2010        c.set_tree_max_delta(30);
2011        c.set_tree_bin_delta(false);
2012        c.set_tree_min_memory(1024);
2013        c.set_tree_compact_max_key_length(32);
2014        assert_eq!(c.node_max_entries, 256);
2015        assert_eq!(c.node_dup_tree_max_entries, 64);
2016        assert_eq!(c.tree_max_embedded_ln, 32);
2017        assert_eq!(c.tree_max_delta, 30);
2018        assert!(!c.tree_bin_delta);
2019        assert_eq!(c.tree_min_memory, 1024);
2020        assert_eq!(c.tree_compact_max_key_length, 32);
2021    }
2022
2023    #[test]
2024    fn test_set_cleaner_params() {
2025        let mut c = EnvironmentConfig::default();
2026        c.set_cleaner_threads(4);
2027        c.set_cleaner_min_file_count(5);
2028        c.set_cleaner_min_age(3);
2029        c.set_cleaner_expiration_enabled(true);
2030        c.set_cleaner_bytes_interval(5_000_000);
2031        c.set_cleaner_wakeup_interval_ms(10_000);
2032        c.set_cleaner_fetch_obsolete_size(true);
2033        c.set_cleaner_adjust_utilization(true);
2034        c.set_cleaner_deadlock_retry(5);
2035        c.set_cleaner_lock_timeout_ms(1000);
2036        c.set_cleaner_expunge(false);
2037        c.set_cleaner_use_deleted_dir(true);
2038        c.set_cleaner_max_batch_files(10);
2039        c.set_cleaner_detail_max_memory_percentage(5);
2040        c.set_cleaner_foreground_proactive_migration(true);
2041        c.set_cleaner_background_proactive_migration(true);
2042        c.set_cleaner_lazy_migration(true);
2043        assert_eq!(c.cleaner_threads, 4);
2044        assert_eq!(c.cleaner_min_file_count, 5);
2045        assert_eq!(c.cleaner_min_age, 3);
2046        assert!(c.cleaner_expiration_enabled);
2047        assert_eq!(c.cleaner_bytes_interval, 5_000_000);
2048        assert_eq!(c.cleaner_wakeup_interval_ms, 10_000);
2049        assert!(c.cleaner_fetch_obsolete_size);
2050        assert!(c.cleaner_adjust_utilization);
2051        assert_eq!(c.cleaner_deadlock_retry, 5);
2052        assert_eq!(c.cleaner_lock_timeout_ms, 1000);
2053        assert!(!c.cleaner_expunge);
2054        assert!(c.cleaner_use_deleted_dir);
2055        assert_eq!(c.cleaner_max_batch_files, 10);
2056        assert_eq!(c.cleaner_detail_max_memory_percentage, 5);
2057        assert!(c.cleaner_foreground_proactive_migration);
2058        assert!(c.cleaner_background_proactive_migration);
2059        assert!(c.cleaner_lazy_migration);
2060    }
2061
2062    #[test]
2063    fn test_set_checkpointer_params() {
2064        let mut c = EnvironmentConfig::default();
2065        c.set_checkpointer_wakeup_interval_ms(60_000);
2066        c.set_checkpointer_deadlock_retry(5);
2067        c.set_checkpointer_high_priority(true);
2068        assert_eq!(c.checkpointer_wakeup_interval_ms, 60_000);
2069        assert_eq!(c.checkpointer_deadlock_retry, 5);
2070        assert!(c.checkpointer_high_priority);
2071    }
2072
2073    #[test]
2074    fn test_set_evictor_params() {
2075        let mut c = EnvironmentConfig::default();
2076        c.set_evictor_evict_bytes(1024 * 1024);
2077        c.set_evictor_critical_percentage(10);
2078        c.set_evictor_n_lru_lists(8);
2079        c.set_evictor_deadlock_retry(5);
2080        c.set_evictor_keep_alive_ms(30_000);
2081        c.set_evictor_allow_bin_deltas(false);
2082        assert_eq!(c.evictor_evict_bytes, 1024 * 1024);
2083        assert_eq!(c.evictor_critical_percentage, 10);
2084        assert_eq!(c.evictor_n_lru_lists, 8);
2085        assert_eq!(c.evictor_deadlock_retry, 5);
2086        assert_eq!(c.evictor_keep_alive_ms, 30_000);
2087        assert!(!c.evictor_allow_bin_deltas);
2088    }
2089
2090    #[test]
2091    fn test_set_offheap_params() {
2092        let mut c = EnvironmentConfig::default();
2093        c.set_offheap_evict_bytes(1024 * 1024);
2094        c.set_offheap_n_lru_lists(8);
2095        c.set_offheap_checksum(true);
2096        c.set_offheap_core_threads(2);
2097        c.set_offheap_max_threads(4);
2098        c.set_offheap_keep_alive_ms(30_000);
2099        assert_eq!(c.offheap_evict_bytes, 1024 * 1024);
2100        assert_eq!(c.offheap_n_lru_lists, 8);
2101        assert!(c.offheap_checksum);
2102        assert_eq!(c.offheap_core_threads, 2);
2103        assert_eq!(c.offheap_max_threads, 4);
2104        assert_eq!(c.offheap_keep_alive_ms, 30_000);
2105    }
2106
2107    #[test]
2108    fn test_set_locking_params() {
2109        let mut c = EnvironmentConfig::default();
2110        c.set_lock_timeout(1000);
2111        c.set_lock_n_lock_tables(32);
2112        c.set_lock_deadlock_detect(false);
2113        c.set_lock_deadlock_detect_delay_ms(100);
2114        assert_eq!(c.lock_timeout_ms, 1000);
2115        assert_eq!(c.lock_n_lock_tables, 32);
2116        assert!(!c.lock_deadlock_detect);
2117        assert_eq!(c.lock_deadlock_detect_delay_ms, 100);
2118    }
2119
2120    #[test]
2121    #[allow(deprecated)] // exercises the deprecated txn_no_sync / txn_write_no_sync setters
2122    fn test_set_txn_params() {
2123        let mut c = EnvironmentConfig::default();
2124        c.set_txn_timeout(5000);
2125        c.set_txn_no_sync(true);
2126        c.set_txn_write_no_sync(true);
2127        c.set_txn_serializable_isolation(true);
2128        c.set_txn_deadlock_stack_trace(true);
2129        c.set_txn_dump_locks(true);
2130        assert_eq!(c.txn_timeout_ms, 5000);
2131        assert!(c.txn_no_sync);
2132        assert!(c.txn_write_no_sync);
2133        assert!(c.txn_serializable_isolation);
2134        assert!(c.txn_deadlock_stack_trace);
2135        assert!(c.txn_dump_locks);
2136    }
2137
2138    #[test]
2139    fn test_set_verifier_params() {
2140        let mut c = EnvironmentConfig::default();
2141        c.set_run_verifier(true);
2142        c.set_verify_schedule("0 2 * * *".to_string());
2143        c.set_verify_log(true);
2144        c.set_verify_log_read_delay_ms(50);
2145        c.set_verify_btree(true);
2146        c.set_verify_secondaries(false);
2147        c.set_verify_data_records(true);
2148        c.set_verify_obsolete_records(true);
2149        c.set_verify_btree_batch_size(500);
2150        c.set_verify_btree_batch_delay_ms(20);
2151        assert!(c.run_verifier);
2152        assert_eq!(c.verify_schedule, "0 2 * * *");
2153        assert!(c.verify_log);
2154        assert_eq!(c.verify_log_read_delay_ms, 50);
2155        assert!(c.verify_btree);
2156        assert!(!c.verify_secondaries);
2157        assert!(c.verify_data_records);
2158        assert!(c.verify_obsolete_records);
2159        assert_eq!(c.verify_btree_batch_size, 500);
2160        assert_eq!(c.verify_btree_batch_delay_ms, 20);
2161    }
2162
2163    #[test]
2164    fn test_set_stats_params() {
2165        let mut c = EnvironmentConfig::default();
2166        c.set_stats_collect(true);
2167        c.set_stats_collect_interval_secs(60);
2168        c.set_stats_max_files(50);
2169        c.set_stats_file_row_count(2000);
2170        c.set_stats_file_directory(PathBuf::from("/var/log/noxu"));
2171        assert!(c.stats_collect);
2172        assert_eq!(c.stats_collect_interval_secs, 60);
2173        assert_eq!(c.stats_max_files, 50);
2174        assert_eq!(c.stats_file_row_count, 2000);
2175        assert_eq!(
2176            c.stats_file_directory,
2177            Some(PathBuf::from("/var/log/noxu"))
2178        );
2179    }
2180
2181    #[test]
2182    fn test_set_trace_params() {
2183        let mut c = EnvironmentConfig::default();
2184        c.set_trace_file(true);
2185        c.set_trace_console(true);
2186        c.set_trace_file_limit_bytes(20 * 1024 * 1024);
2187        c.set_trace_file_count(5);
2188        c.set_trace_level("DEBUG".to_string());
2189        c.set_console_logging_level("WARN".to_string());
2190        c.set_file_logging_level("DEBUG".to_string());
2191        c.set_trace_level_lock_manager("TRACE".to_string());
2192        c.set_trace_level_recovery("TRACE".to_string());
2193        c.set_trace_level_evictor("DEBUG".to_string());
2194        c.set_trace_level_cleaner("DEBUG".to_string());
2195        c.set_startup_dump_threshold_ms(5000);
2196        assert!(c.trace_file);
2197        assert!(c.trace_console);
2198        assert_eq!(c.trace_file_limit_bytes, 20 * 1024 * 1024);
2199        assert_eq!(c.trace_file_count, 5);
2200        assert_eq!(c.trace_level, Some("DEBUG".to_string()));
2201        assert_eq!(c.console_logging_level, Some("WARN".to_string()));
2202        assert_eq!(c.file_logging_level, Some("DEBUG".to_string()));
2203        assert_eq!(c.trace_level_lock_manager, Some("TRACE".to_string()));
2204        assert_eq!(c.startup_dump_threshold_ms, 5000);
2205    }
2206
2207    #[test]
2208    #[allow(deprecated)] // exercises deprecated with_txn_no_sync in builder chain
2209    fn test_builder_chain() {
2210        let c = EnvironmentConfig::new(PathBuf::from("/data"))
2211            .with_allow_create(true)
2212            .with_transactional(true)
2213            .with_cache_size(512 * 1024 * 1024)
2214            .with_log_file_max_bytes(5 * 1024 * 1024)
2215            .with_cleaner_min_utilization(40)
2216            .with_checkpointer_bytes_interval(10_000_000)
2217            .with_evictor_nodes_per_scan(20)
2218            .with_log_group_commit(5, 10)
2219            .with_txn_no_sync(false)
2220            .with_durability(Durability::COMMIT_SYNC);
2221        assert_eq!(c.home, PathBuf::from("/data"));
2222        assert!(c.allow_create);
2223        assert!(c.transactional);
2224        assert_eq!(c.cache_size, 512 * 1024 * 1024);
2225        assert_eq!(c.log_file_max_bytes, 5 * 1024 * 1024);
2226        assert_eq!(c.cleaner_min_utilization, 40);
2227        assert_eq!(c.checkpointer_bytes_interval, 10_000_000);
2228        assert_eq!(c.evictor_nodes_per_scan, 20);
2229        assert_eq!(c.log_group_commit_threshold, 5);
2230        assert_eq!(c.log_group_commit_interval_ms, 10);
2231        assert!(!c.txn_no_sync);
2232        assert_eq!(c.durability, Durability::COMMIT_SYNC);
2233    }
2234
2235    #[test]
2236    fn test_env_behaviour_params() {
2237        let mut c = EnvironmentConfig::default();
2238        c.set_env_check_leaks(false);
2239        c.set_env_forced_yield(true);
2240        c.set_env_fair_latches(true);
2241        c.set_env_latch_timeout_ms(60_000);
2242        c.set_env_ttl_clock_tolerance_ms(100);
2243        c.set_env_expiration_enabled(true);
2244        c.set_env_db_eviction(true);
2245        c.set_adler32_chunk_size(4096);
2246        c.set_env_background_read_limit_kb(10_000);
2247        c.set_env_background_write_limit_kb(5_000);
2248        c.set_env_background_sleep_interval_us(100);
2249        assert!(!c.env_check_leaks);
2250        assert!(c.env_forced_yield);
2251        assert!(c.env_fair_latches);
2252        assert_eq!(c.env_latch_timeout_ms, 60_000);
2253        assert_eq!(c.env_ttl_clock_tolerance_ms, 100);
2254        assert!(c.env_expiration_enabled);
2255        assert!(c.env_db_eviction);
2256        assert_eq!(c.adler32_chunk_size, 4096);
2257        assert_eq!(c.env_background_read_limit_kb, 10_000);
2258        assert_eq!(c.env_background_write_limit_kb, 5_000);
2259        assert_eq!(c.env_background_sleep_interval_us, 100);
2260    }
2261
2262    #[test]
2263    fn test_compressor_params() {
2264        let mut c = EnvironmentConfig::default();
2265        c.set_in_compressor_wakeup_interval_ms(1000);
2266        c.set_compressor_deadlock_retry(5);
2267        c.set_compressor_lock_timeout_ms(1000);
2268        c.set_compressor_purge_root(true);
2269        assert_eq!(c.in_compressor_wakeup_interval_ms, 1000);
2270        assert_eq!(c.compressor_deadlock_retry, 5);
2271        assert_eq!(c.compressor_lock_timeout_ms, 1000);
2272        assert!(c.compressor_purge_root);
2273    }
2274
2275    #[test]
2276    fn test_dos_cursor_params() {
2277        let mut c = EnvironmentConfig::default();
2278        c.set_dos_producer_queue_timeout_ms(5000);
2279        assert_eq!(c.dos_producer_queue_timeout_ms, 5000);
2280    }
2281
2282    #[test]
2283    fn test_clone() {
2284        let c1 = EnvironmentConfig::default()
2285            .with_allow_create(true)
2286            .with_cache_size(256 * 1024 * 1024);
2287        let c2 = c1.clone();
2288        assert_eq!(c1.allow_create, c2.allow_create);
2289        assert_eq!(c1.cache_size, c2.cache_size);
2290        assert_eq!(c1.free_disk, c2.free_disk);
2291    }
2292}