@@ -4,6 +4,7 @@ use crate::storage::MemTable;
44use serde_json:: Value ;
55use std:: fs;
66use uuid:: Uuid ;
7+ use std:: iter:: Peekable ;
78
89const MEMTABLE_THRESHOLD : usize = 10 ;
910const JSTABLE_THRESHOLD : u64 = 5 ;
@@ -15,6 +16,63 @@ pub struct DB {
1516 logger : Logger ,
1617}
1718
19+ struct MergedIterator < ' a > {
20+ sources : Vec < Peekable < Box < dyn Iterator < Item = ( String , Value ) > + ' a > > > ,
21+ }
22+
23+ impl < ' a > Iterator for MergedIterator < ' a > {
24+ type Item = ( String , Value ) ;
25+
26+ fn next ( & mut self ) -> Option < Self :: Item > {
27+ loop {
28+ // Find min_id
29+ let mut min_id: Option < String > = None ;
30+
31+ for source in & mut self . sources {
32+ if let Some ( ( id, _) ) = source. peek ( ) {
33+ match & min_id {
34+ None => min_id = Some ( id. clone ( ) ) ,
35+ Some ( current_min) => {
36+ if id < current_min {
37+ min_id = Some ( id. clone ( ) ) ;
38+ }
39+ }
40+ }
41+ }
42+ }
43+
44+ let min_id = min_id?; // If None, all exhausted
45+
46+ // Consume from sources
47+ let mut result: Option < Value > = None ;
48+
49+ for source in & mut self . sources {
50+ let is_match = if let Some ( ( id, _) ) = source. peek ( ) {
51+ id == & min_id
52+ } else {
53+ false
54+ } ;
55+
56+ if is_match {
57+ let ( _, doc) = source. next ( ) . unwrap ( ) ;
58+ if result. is_none ( ) {
59+ // First match (highest priority)
60+ result = Some ( doc) ;
61+ }
62+ // Else: ignored (shadowed)
63+ }
64+ }
65+
66+ if let Some ( doc) = result {
67+ if !doc. is_null ( ) {
68+ return Some ( ( min_id, doc) ) ;
69+ }
70+ // If null (tombstone), loop again
71+ }
72+ }
73+ }
74+ }
75+
1876impl DB {
1977 pub fn new ( jstable_dir : & str ) -> Self {
2078 fs:: create_dir_all ( jstable_dir) . unwrap ( ) ;
@@ -49,6 +107,26 @@ impl DB {
49107 }
50108 }
51109
110+ pub fn scan ( & self ) -> impl Iterator < Item = ( String , Value ) > + ' _ {
111+ let mut sources: Vec < Peekable < Box < dyn Iterator < Item = ( String , Value ) > > > > = Vec :: new ( ) ;
112+
113+ // 1. MemTable Iterator (Priority 0 - Highest)
114+ let mem_iter = self . memtable . documents . iter ( ) . map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) ) ;
115+ sources. push ( ( Box :: new ( mem_iter) as Box < dyn Iterator < Item = ( String , Value ) > > ) . peekable ( ) ) ;
116+
117+ // 2. JSTable Iterators (Newer to Older)
118+ for i in ( 0 ..self . jstable_count ) . rev ( ) {
119+ let path = format ! ( "{}/jstable-{}" , self . jstable_dir, i) ;
120+ if let Ok ( iter) = jstable:: JSTableIterator :: new ( & path) {
121+ // Map Result to Value, unwrapping errors for now
122+ let iter = iter. map ( |r| r. unwrap ( ) ) ;
123+ sources. push ( ( Box :: new ( iter) as Box < dyn Iterator < Item = ( String , Value ) > > ) . peekable ( ) ) ;
124+ }
125+ }
126+
127+ MergedIterator { sources }
128+ }
129+
52130 pub fn insert ( & mut self , doc : Value ) -> String {
53131 if self . memtable . len ( ) >= MEMTABLE_THRESHOLD {
54132 self . flush ( ) ;
@@ -281,4 +359,48 @@ mod tests {
281359 // Verify other documents exist (e.g. from flush 1)
282360 assert ! ( table. documents. len( ) > 40 ) ;
283361 }
362+
363+ #[ test]
364+ fn test_db_scan ( ) {
365+ let dir = tempdir ( ) . unwrap ( ) ;
366+ let mut db = DB :: new ( dir. path ( ) . to_str ( ) . unwrap ( ) ) ;
367+
368+ // 1. Insert into JSTable (flush)
369+ // 0..9
370+ let mut ids = Vec :: new ( ) ;
371+ for i in 0 ..MEMTABLE_THRESHOLD {
372+ ids. push ( db. insert ( json ! ( { "val" : i} ) ) ) ;
373+ }
374+ // This filled memtable (10 items). Next insert triggers flush.
375+
376+ // 2. Insert into MemTable (triggers flush of 0..9 to jstable-0)
377+ let id_val_10 = db. insert ( json ! ( { "val" : 10 } ) ) ;
378+ // Memtable has 1 item (val 10). jstable-0 has 10 items.
379+
380+ // 3. Shadowing: Update an item from jstable-0
381+ let id_to_shadow = ids[ 0 ] . clone ( ) ; // val: 0
382+ db. update ( & id_to_shadow, json ! ( { "val" : 999 } ) ) ;
383+ // Memtable has: val: 10, val: 999 (id_to_shadow).
384+
385+ // 4. Deletion: Delete an item from jstable-0
386+ let id_to_delete = ids[ 1 ] . clone ( ) ; // val: 1
387+ db. delete ( & id_to_delete) ;
388+ // Memtable has: val: 10, val: 999, tombstone(id_to_delete).
389+
390+ // Scan
391+ let results: std:: collections:: HashMap < String , Value > = db. scan ( ) . collect ( ) ;
392+
393+ // Check shadowing
394+ assert_eq ! ( results. get( & id_to_shadow) . unwrap( ) , & json!( { "val" : 999 } ) ) ;
395+
396+ // Check deletion
397+ assert ! ( !results. contains_key( & id_to_delete) ) ;
398+
399+ // Check preservation of older jstable item
400+ let id_preserved = ids[ 2 ] . clone ( ) ; // val: 2
401+ assert_eq ! ( results. get( & id_preserved) . unwrap( ) , & json!( { "val" : 2 } ) ) ;
402+
403+ // Check memtable item
404+ assert_eq ! ( results. get( & id_val_10) . unwrap( ) , & json!( { "val" : 10 } ) ) ;
405+ }
284406}
0 commit comments