changeset 292:fac1ed1b3f7d

db_impl: Move some code around and add some comments.
author Lewin Bormann <lbo@spheniscida.de>
date Tue, 26 Sep 2017 19:09:12 +0200
parents d2a96aac4edf
children 20a4c98ca0d5
files src/db_impl.rs
diffstat 1 files changed, 101 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/src/db_impl.rs	Tue Sep 26 19:01:29 2017 +0200
+++ b/src/db_impl.rs	Tue Sep 26 19:09:12 2017 +0200
@@ -52,6 +52,8 @@
 }
 
 impl DB {
+    // RECOVERY AND INITIALIZATION //
+
     /// new initializes a new DB object, but doesn't touch disk.
     fn new(name: &str, mut opt: Options) -> DB {
         if opt.log.is_none() {
@@ -112,6 +114,24 @@
         Ok(db)
     }
 
+    /// initialize_db initializes a new database.
+    fn initialize_db(&mut self) -> Result<()> {
+        let mut ve = VersionEdit::new();
+        ve.set_comparator_name(self.opt.cmp.id());
+        ve.set_log_num(0);
+        ve.set_next_file(2);
+        ve.set_last_seq(0);
+
+        {
+            let manifest = manifest_file_name(&self.name, 1);
+            let manifest_file = self.opt.env.open_writable_file(Path::new(&manifest))?;
+            let mut lw = LogWriter::new(manifest_file);
+            lw.add_record(&ve.encode())?;
+            lw.flush()?;
+        }
+        set_current_file(&self.opt.env, &self.name, 1)
+    }
+
     /// recover recovers from the existing state on disk. If the wrapped result is `true`, then
     /// log_and_apply() should be called after recovery has finished.
     fn recover(&mut self, ve: &mut VersionEdit) -> Result<bool> {
@@ -174,25 +194,9 @@
         Ok(save_manifest)
     }
 
-    /// initialize_db initializes a new database.
-    fn initialize_db(&mut self) -> Result<()> {
-        let mut ve = VersionEdit::new();
-        ve.set_comparator_name(self.opt.cmp.id());
-        ve.set_log_num(0);
-        ve.set_next_file(2);
-        ve.set_last_seq(0);
-
-        {
-            let manifest = manifest_file_name(&self.name, 1);
-            let manifest_file = self.opt.env.open_writable_file(Path::new(&manifest))?;
-            let mut lw = LogWriter::new(manifest_file);
-            lw.add_record(&ve.encode())?;
-            lw.flush()?;
-        }
-        set_current_file(&self.opt.env, &self.name, 1)
-    }
-
-
+    /// recover_log_file reads a single log file into a memtable, writing new L0 tables if
+    /// necessary. If is_last is true, it checks whether the log file can be reused, and sets up
+    /// the database's logging handles appropriately if that's the case.
     fn recover_log_file(&mut self,
                         log_num: FileNum,
                         is_last: bool,
@@ -259,6 +263,57 @@
         Ok((save_manifest, max_seq))
     }
 
+    /// delete_obsolete_files removes files that are no longer needed from the file system.
+    fn delete_obsolete_files(&mut self) -> Result<()> {
+        let files = self.vset.live_files();
+        let filenames = self.opt.env.children(Path::new(&self.name))?;
+        for name in filenames {
+            if let Ok((num, typ)) = parse_file_name(&name) {
+                log!(self.opt.log, "{} {:?}", num, typ);
+                match typ {
+                    FileType::Log => {
+                        if num >= self.vset.log_num {
+                            continue;
+                        }
+                    }
+                    FileType::Descriptor => {
+                        if num >= self.vset.manifest_num {
+                            continue;
+                        }
+                    }
+                    FileType::Table => {
+                        if files.contains(&num) {
+                            continue;
+                        }
+                    }
+                    // NOTE: In this non-concurrent implementation, we likely never find temp
+                    // files.
+                    FileType::Temp => {
+                        if files.contains(&num) {
+                            continue;
+                        }
+                    }
+                    FileType::Current | FileType::DBLock | FileType::InfoLog => continue,
+                }
+
+                // If we're here, delete this file.
+                if typ == FileType::Table {
+                    self.cache.borrow_mut().evict(num).is_ok();
+                }
+                log!(self.opt.log, "Deleting file type={:?} num={}", typ, num);
+                if let Err(e) = self.opt
+                    .env
+                    .delete(Path::new(&format!("{}/{}", &self.name, &name))) {
+                    log!(self.opt.log, "Deleting file num={} failed: {}", num, e);
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+impl DB {
+    // STATISTICS //
     fn add_stats(&mut self, level: usize, cs: CompactionStats) {
         assert!(level < NUM_LEVELS);
         self.cstats[level].add(cs);
@@ -271,7 +326,10 @@
             self.maybe_do_compaction();
         }
     }
+}
 
+impl DB {
+    // SNAPSHOTS //
     pub fn get_snapshot(&mut self) -> Snapshot {
         self.snaps.new_snapshot(self.vset.last_seq)
     }
@@ -279,7 +337,10 @@
     pub fn release_snapshot(&mut self, snapshot: Snapshot) {
         self.snaps.delete(snapshot)
     }
+}
 
+impl DB {
+    // COMPACTIONS //
     /// make_room_for_write checks if the memtable has become too large, and triggers a compaction
     /// if it's the case.
     fn make_room_for_write(&mut self) -> Result<()> {
@@ -575,53 +636,6 @@
         }
         self.vset.log_and_apply(cs.compaction.into_edit())
     }
-
-    fn delete_obsolete_files(&mut self) -> Result<()> {
-        let files = self.vset.live_files();
-        let filenames = self.opt.env.children(Path::new(&self.name))?;
-        for name in filenames {
-            if let Ok((num, typ)) = parse_file_name(&name) {
-                log!(self.opt.log, "{} {:?}", num, typ);
-                match typ {
-                    FileType::Log => {
-                        if num >= self.vset.log_num {
-                            continue;
-                        }
-                    }
-                    FileType::Descriptor => {
-                        if num >= self.vset.manifest_num {
-                            continue;
-                        }
-                    }
-                    FileType::Table => {
-                        if files.contains(&num) {
-                            continue;
-                        }
-                    }
-                    // NOTE: In this non-concurrent implementation, we likely never find temp
-                    // files.
-                    FileType::Temp => {
-                        if files.contains(&num) {
-                            continue;
-                        }
-                    }
-                    FileType::Current | FileType::DBLock | FileType::InfoLog => continue,
-                }
-
-                // If we're here, delete this file.
-                if typ == FileType::Table {
-                    self.cache.borrow_mut().evict(num).is_ok();
-                }
-                log!(self.opt.log, "Deleting file type={:?} num={}", typ, num);
-                if let Err(e) = self.opt
-                    .env
-                    .delete(Path::new(&format!("{}/{}", &self.name, &name))) {
-                    log!(self.opt.log, "Deleting file num={} failed: {}", num, e);
-                }
-            }
-        }
-        Ok(())
-    }
 }
 
 impl Drop for DB {
@@ -797,13 +811,32 @@
         let opt = options::for_test();
         let env = opt.env.clone();
 
+        // Several test cases with different options follow. The printlns can eventually be
+        // removed.
+
         {
+            let mut opt = opt.clone();
+            opt.reuse_manifest = false;
+            let db = DB::open("otherdb", opt.clone()).unwrap();
+
+            println!("children after: {:?}",
+                     env.children(Path::new("otherdb/")).unwrap());
+            assert!(env.exists(Path::new("otherdb/CURRENT")).unwrap());
+            // Database is initialized and initial manifest reused.
+            assert!(!env.exists(Path::new("otherdb/MANIFEST-000001")).unwrap());
+            assert!(env.exists(Path::new("otherdb/MANIFEST-000002")).unwrap());
+            assert!(env.exists(Path::new("otherdb/000003.log")).unwrap());
+        }
+
+        {
+            let mut opt = opt.clone();
+            opt.reuse_manifest = true;
             let db = DB::open("db", opt.clone()).unwrap();
 
             println!("children after: {:?}",
                      env.children(Path::new("db/")).unwrap());
             assert!(env.exists(Path::new("db/CURRENT")).unwrap());
-            // Database is initialized.
+            // Database is initialized and initial manifest reused.
             assert!(env.exists(Path::new("db/MANIFEST-000001")).unwrap());
             assert!(env.exists(Path::new("db/LOCK")).unwrap());
             assert!(env.exists(Path::new("db/000003.log")).unwrap());
@@ -840,6 +873,7 @@
                      env.children(Path::new("db/")).unwrap());
             assert!(!env.exists(Path::new("db/MANIFEST-000001")).unwrap());
             assert!(env.exists(Path::new("db/MANIFEST-000002")).unwrap());
+            assert!(!env.exists(Path::new("db/MANIFEST-000005")).unwrap());
             assert!(env.exists(Path::new("db/000004.log")).unwrap());
             // 000004 should be reused, no new log file should be created.
             assert!(!env.exists(Path::new("db/000006.log")).unwrap());