use pagedb::options::OpenOptions;
use pagedb::vfs::memory::MemVfs;
use pagedb::{Db, ExtentRef, PagedbError, RealmId, SegmentKind, SegmentPageKind};
const PAGE: usize = 4096;
#[allow(dead_code)]
async fn open() -> Db<MemVfs> {
Db::open(
MemVfs::new(),
[7u8; 32],
PAGE,
RealmId::new([2; 16]),
OpenOptions::default(),
)
.await
.unwrap()
}
async fn open_with_budget(budget: usize) -> Db<MemVfs> {
let opts = OpenOptions::default().with_mmap_view_scratch_bytes(budget);
Db::open(MemVfs::new(), [7u8; 32], PAGE, RealmId::new([2; 16]), opts)
.await
.unwrap()
}
async fn setup_segment(db: &Db<MemVfs>, name: &str, payload: &[u8]) -> pagedb::Result<()> {
let realm = RealmId::new([2; 16]);
let mut w = db.create_segment(realm, SegmentKind::Unspecified).await?;
w.append_page(SegmentPageKind::Data, payload).await?;
let meta = w.seal().await?;
let mut t = db.begin_write().await?;
t.link_segment(name, &meta).await?;
t.commit().await?;
Ok(())
}
#[cfg(not(target_arch = "wasm32"))]
#[tokio::test(flavor = "current_thread")]
async fn mmap_view_reads_data() {
let budget = 1024 * 1024; let db = open_with_budget(budget).await;
let known = b"hello from mmap_view test";
setup_segment(&db, "mmap.seg", known).await.unwrap();
let realm = RealmId::new([2; 16]);
let reader = db.open_segment(realm, "mmap.seg").await.unwrap();
let view = reader.mmap_view(ExtentRef::new(1, 1)).await.unwrap();
assert!(
view.as_slice().starts_with(known),
"view does not start with expected payload"
);
}
#[cfg(target_arch = "wasm32")]
#[test]
fn mmap_view_unsupported_on_wasm() {
}
#[cfg(not(target_arch = "wasm32"))]
#[tokio::test(flavor = "current_thread")]
async fn mmap_view_budget_exceeded() {
let tiny_budget = 4096usize;
let db = open_with_budget(tiny_budget).await;
let realm = RealmId::new([2; 16]);
let mut w = db
.create_segment(realm, SegmentKind::Unspecified)
.await
.unwrap();
for _ in 0..5 {
w.append_page(SegmentPageKind::Data, &[0xABu8; 100])
.await
.unwrap();
}
let meta = w.seal().await.unwrap();
{
let mut t = db.begin_write().await.unwrap();
t.link_segment("budget.seg", &meta).await.unwrap();
t.commit().await.unwrap();
}
let reader = db.open_segment(realm, "budget.seg").await.unwrap();
let err = reader.mmap_view(ExtentRef::new(1, 5)).await.err().unwrap();
assert!(
matches!(err, PagedbError::MmapViewQuotaExceeded { .. }),
"expected MmapViewQuotaExceeded, got: {err:?}"
);
}
#[cfg(not(target_arch = "wasm32"))]
#[tokio::test(flavor = "current_thread")]
async fn mmap_view_drop_releases_budget() {
let budget = 32 * 1024usize;
let db = open_with_budget(budget).await;
let realm = RealmId::new([2; 16]);
let mut w = db
.create_segment(realm, SegmentKind::Unspecified)
.await
.unwrap();
w.append_page(SegmentPageKind::Data, b"drop-test-payload")
.await
.unwrap();
let meta = w.seal().await.unwrap();
{
let mut t = db.begin_write().await.unwrap();
t.link_segment("drop.seg", &meta).await.unwrap();
t.commit().await.unwrap();
}
let reader = db.open_segment(realm, "drop.seg").await.unwrap();
let extent = ExtentRef::new(1, 1);
let view1 = reader.mmap_view(extent).await.unwrap();
assert!(view1.as_slice().starts_with(b"drop-test-payload"));
drop(view1);
let view2 = reader.mmap_view(extent).await.unwrap();
assert!(view2.as_slice().starts_with(b"drop-test-payload"));
}