From 005d60fe29f52815c04cb56e1e525af2c75f08f7 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 | 67 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-) 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..733ae37 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, error}; #[derive(Debug)] struct NdbRef { @@ -50,8 +51,31 @@ impl Ndb { if !path.exists() { let _ = fs::create_dir_all(path); } - - let result = unsafe { bindings::ndb_init(&mut ndb, db_dir_cstr.as_ptr(), config.as_ptr()) }; + let data_fname = path.join("data.mdb"); + + let min_mapsize = 1024 * 1024 * 512; + let default_mapsize = 1024 * 1024; + 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 +472,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); + } }