From 71154e4100775f6932ee517da4350c433ba14ec7 Mon Sep 17 00:00:00 2001 From: William Casarin Date: Thu, 28 Nov 2024 16:22:23 -0800 Subject: [PATCH] mapsize: try to shrink mapsize until init works On some systems like windows and iOS, the mapsize can be an issue. This continually decreases the mapsize until we find one that works. Will-Fix: https://github.com/damus-io/notedeck/issues/491 --- src/config.rs | 1 + src/ndb.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index ddb5344..6721f57 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ use crate::bindings; +#[derive(Copy, Clone)] pub struct Config { pub config: bindings::ndb_config, } diff --git a/src/ndb.rs b/src/ndb.rs index 8294af8..0e6e8fe 100644 --- a/src/ndb.rs +++ b/src/ndb.rs @@ -10,6 +10,7 @@ use std::os::raw::c_int; use std::path::Path; use std::sync::Arc; use tokio::task; // Make sure to import the task module +use tracing::debug; #[derive(Debug)] struct NdbRef { @@ -51,7 +52,28 @@ impl Ndb { let _ = fs::create_dir_all(path); } - let result = unsafe { bindings::ndb_init(&mut ndb, db_dir_cstr.as_ptr(), config.as_ptr()) }; + let min_mapsize = 1024 * 1024 * 512; + let mut mapsize = config.config.mapsize; + let mut config = *config; + + let result = loop { + let result = + unsafe { bindings::ndb_init(&mut ndb, db_dir_cstr.as_ptr(), config.as_ptr()) }; + + if result == 0 { + mapsize /= 2; + config = config.set_mapsize(mapsize); + debug!("ndb init failed, reducing mapsize to {}", mapsize); + + if mapsize > min_mapsize { + continue; + } else { + break 0; + } + } else { + break result; + } + }; if result == 0 { return Err(Error::DbOpenFailed); @@ -448,4 +470,43 @@ mod tests { assert_eq!(note.kind(), 1); } } + + #[test] + #[cfg(target_os = "windows")] + fn test_windows_large_mapsize() { + use std::{fs, path::Path}; + + let db = "target/testdbs/windows_large_mapsize"; + test_util::cleanup_db(&db); + + { + // 32 TiB should be way too big for CI + let config = + Config::new().set_mapsize(1024usize * 1024usize * 1024usize * 1024usize * 32usize); + + // in this case, nostrdb should try to keep resizing to + // smaller mapsizes until success + + let ndb = Ndb::new(db, &config); + + assert!(ndb.is_ok()); + } + + let file_len = fs::metadata(Path::new(db).join("data.mdb")) + .expect("metadata") + .len(); + + assert!(file_len > 0); + + if cfg!(target_os = "windows") { + // on windows the default mapsize will be 1MB when we fail + // to open it + assert_ne!(file_len, 1048576); + } else { + assert!(file_len < 1024u64 * 1024u64); + } + + // we should definitely clean this up... especially on windows + test_util::cleanup_db(&db); + } }