1use std::env;
20use std::io;
21use std::path::PathBuf;
22
23use subms_lsm_tree::LsmTree;
24
25fn main() -> io::Result<()> {
26 base_order_journal()?;
27
28 #[cfg(feature = "wal")]
29 wal_durable_log()?;
30
31 #[cfg(feature = "tiered-compaction")]
32 tiered_ingest_tier();
33
34 #[cfg(feature = "leveled-compaction")]
35 leveled_serving_tier();
36
37 #[cfg(feature = "snapshot")]
38 snapshot_end_of_day_report();
39
40 #[cfg(feature = "lz4")]
41 lz4_hot_tier();
42
43 #[cfg(feature = "zstd")]
44 zstd_cold_tier();
45
46 #[cfg(feature = "block-cache-integration")]
47 block_cache_read_path();
48
49 Ok(())
50}
51
52fn scratch_dir(label: &str) -> PathBuf {
55 let dir = env::temp_dir().join(format!("lsm-sample-{}-{}", label, std::process::id()));
56 let _ = std::fs::remove_dir_all(&dir);
57 dir
58}
59
60fn base_order_journal() -> io::Result<()> {
66 println!("== base: embedded order journal ==");
67 let dir = scratch_dir("base");
68 let mut journal = LsmTree::open(&dir, 256)?;
70
71 journal.put("ORD-0001", b"AAPL,100@150.10")?;
72 journal.put("ORD-0002", b"MSFT,50@320.55")?;
73 journal.put("ORD-0003", b"GOOG,25@140.20")?;
74 journal.flush()?; journal.put("ORD-0001", b"AAPL,100@150.42")?; journal.put("ORD-0004", b"NVDA,10@900.00")?;
78 journal.delete("ORD-0002")?; journal.flush()?; let filled = journal.get("ORD-0001")?.expect("ORD-0001 is live");
82 println!(" ORD-0001 -> {}", String::from_utf8_lossy(&filled));
83 assert_eq!(filled, b"AAPL,100@150.42", "newest write wins");
84
85 assert!(
87 journal.get("ORD-0002")?.is_none(),
88 "cancelled order is absent"
89 );
90
91 assert!(
94 journal.get("ORD-9999")?.is_none(),
95 "unknown id: bloom-accelerated miss"
96 );
97
98 let book = journal.range(Some("ORD-0001"), Some("ORD-0005"))?;
99 let live_ids: Vec<&str> = book.iter().map(|(k, _)| k.as_str()).collect();
100 println!(
101 " live book {live_ids:?} across {} sstables",
102 journal.sstable_count()
103 );
104 assert_eq!(
105 live_ids,
106 ["ORD-0001", "ORD-0003", "ORD-0004"],
107 "sorted, tombstone dropped"
108 );
109
110 let _ = std::fs::remove_dir_all(&dir);
111 Ok(())
112}
113
114#[cfg(feature = "wal")]
119fn wal_durable_log() -> io::Result<()> {
120 use subms_lsm_tree::WriteAheadLog;
121 println!("\n== wal: durable append-before-ack ==");
122 let dir = scratch_dir("wal");
123 std::fs::create_dir_all(&dir)?;
124 let path = dir.join("journal.wal");
125
126 {
127 let mut wal = WriteAheadLog::open(&path)?;
128 wal.log_put("ORD-0100", b"AAPL,100@150.10")?;
129 wal.log_put("ORD-0101", b"MSFT,50@320.55")?;
130 wal.log_delete("ORD-0100")?; wal.sync()?; }
133
134 let recovered = WriteAheadLog::replay(&path)?;
135 println!(" replayed {} records after crash", recovered.len());
136 assert_eq!(recovered.len(), 3, "every acked write survives");
137 assert!(
138 recovered[2].value.is_none(),
139 "the cancel replays as a tombstone"
140 );
141
142 let _ = std::fs::remove_dir_all(&dir);
143 Ok(())
144}
145
146#[cfg(feature = "tiered-compaction")]
152fn tiered_ingest_tier() {
153 use subms_lsm_tree::{TieredCompactionPlanner, TieredManifest, TieredRun};
154 println!("\n== tiered-compaction: write-heavy ingest tier ==");
155 let mut manifest = TieredManifest::new();
156 for i in 0..4 {
157 let entries = vec![(format!("ORD-{i:04}"), Some(b"fill".to_vec()))];
158 manifest.push(0, TieredRun::new(i, entries)); }
160
161 let planner = TieredCompactionPlanner::new(4);
162 let level = planner
163 .pick_level(&manifest)
164 .expect("level 0 is full at 4 runs");
165 planner.merge(&mut manifest, level, 100);
166 println!(
167 " merged 4 L0 runs -> {} run at L1",
168 manifest.level_run_count(1)
169 );
170 assert_eq!(manifest.level_run_count(0), 0, "L0 drained");
171 assert_eq!(manifest.level_run_count(1), 1, "one merged run promoted");
172 assert!(
173 planner.pick_level(&manifest).is_none(),
174 "a single run does not re-trigger"
175 );
176}
177
178#[cfg(feature = "leveled-compaction")]
183fn leveled_serving_tier() {
184 use subms_lsm_tree::features::leveled_compaction::level_is_non_overlapping;
185 use subms_lsm_tree::{LeveledCompactionPlanner, LeveledManifest, LeveledRun};
186 println!("\n== leveled-compaction: read-latency-SLA serving tier ==");
187 let mut manifest = LeveledManifest::new();
188 manifest.push(
190 0,
191 LeveledRun::new(
192 1,
193 vec![
194 ("AAPL".to_string(), Some(b"150.10".to_vec())),
195 ("MSFT".to_string(), Some(b"320.55".to_vec())),
196 ],
197 ),
198 );
199 manifest.push(
200 0,
201 LeveledRun::new(2, vec![("GOOG".to_string(), Some(b"140.20".to_vec()))]),
202 );
203 manifest.push(
204 1,
205 LeveledRun::new(
206 3,
207 vec![
208 ("AAPL".to_string(), Some(b"149.00".to_vec())), ("NVDA".to_string(), Some(b"900.00".to_vec())),
210 ],
211 ),
212 );
213
214 let planner = LeveledCompactionPlanner::new(1_000_000, 10, 2);
215 let from = planner
216 .pick_level(&manifest)
217 .expect("L0 over its 2-run limit");
218 planner.compact(&mut manifest, from, 100);
219 println!(
220 " compacted L0 -> L1: {} run(s) at L1",
221 manifest.level_run_count(1)
222 );
223 assert_eq!(manifest.level_run_count(0), 0, "L0 drained into L1");
224 assert!(
225 level_is_non_overlapping(&manifest, 1),
226 "L1 is key-disjoint after compaction"
227 );
228}
229
230#[cfg(feature = "snapshot")]
234fn snapshot_end_of_day_report() {
235 use subms_lsm_tree::{SnapshotManager, SnapshotManifest};
236 println!("\n== snapshot: point-in-time end-of-day report ==");
237 let manager = SnapshotManager::new();
238 manager.publish(SnapshotManifest::new(vec![1, 2, 3]));
239
240 let report_view = manager.snapshot(); manager.publish(SnapshotManifest::new(vec![1, 2, 3, 4, 5])); println!(
244 " report sees {:?}, live set is now {:?}",
245 report_view.sstable_ids(),
246 manager.current_ids()
247 );
248 assert_eq!(
249 report_view.sstable_ids(),
250 &[1, 2, 3],
251 "held view is isolated from later flushes"
252 );
253 assert_eq!(
254 manager.current_ids(),
255 vec![1, 2, 3, 4, 5],
256 "the live manifest moved on"
257 );
258}
259
260#[cfg(feature = "lz4")]
264fn lz4_hot_tier() {
265 use subms_lsm_tree::Lz4BlockCompressor;
266 println!("\n== lz4: fast compression for the hot tier ==");
267 let codec = Lz4BlockCompressor::new();
268 let block = "AAPL,100@150.10;".repeat(256).into_bytes();
270 let encoded = codec.compress(&block);
271 println!(" {} bytes -> {} compressed", block.len(), encoded.len());
272 assert!(encoded.len() < block.len(), "repetitive block shrinks");
273 assert_eq!(
274 codec.decompress(&encoded).unwrap(),
275 block,
276 "lossless round trip"
277 );
278}
279
280#[cfg(feature = "zstd")]
284fn zstd_cold_tier() {
285 use subms_lsm_tree::ZstdBlockCompressor;
286 println!("\n== zstd: higher-ratio compression for the cold tier ==");
287 let codec = ZstdBlockCompressor::new();
288 let block = "MSFT,50@320.55;".repeat(256).into_bytes();
289 let encoded = codec.compress(&block).unwrap();
290 println!(
291 " {} bytes -> {} compressed (level {})",
292 block.len(),
293 encoded.len(),
294 codec.level()
295 );
296 assert!(encoded.len() < block.len(), "cold block shrinks");
297 assert_eq!(
298 codec.decompress(&encoded).unwrap(),
299 block,
300 "lossless round trip"
301 );
302}
303
304#[cfg(feature = "block-cache-integration")]
309fn block_cache_read_path() {
310 use subms_lsm_tree::{Block, BlockCache, BlockKey, LruBlockCache};
311 println!("\n== block-cache-integration: read-side block cache ==");
312 let cache = LruBlockCache::new(2);
313 let hot = BlockKey::new(1, 0);
314
315 assert!(cache.get(&hot).is_none(), "cold: a miss");
316 cache.put(hot, Block::from(b"AAPL block".as_slice()));
317 let served = cache.get(&hot).expect("warm: a hit");
318 println!(
319 " {} hit / {} miss after one warm read",
320 cache.hits(),
321 cache.misses()
322 );
323 assert_eq!(&*served, b"AAPL block", "the cached payload is served");
324
325 cache.put(BlockKey::new(2, 0), Block::from(b"MSFT block".as_slice()));
327 cache.put(BlockKey::new(3, 0), Block::from(b"GOOG block".as_slice()));
328 assert!(
329 cache.get(&hot).is_none(),
330 "coldest block evicted at capacity"
331 );
332}