use ic_memory::ic_stable_structures::Memory;
use ic_memory::{
GenericAllocationPolicy, MemoryManagerConfig, RuntimeBootstrapError, RuntimeConstructionError,
RuntimeDiagnosticError, RuntimeOpenError, RuntimeStateError, bootstrap_default_memory_manager,
bootstrap_default_memory_manager_with_config, committed_allocations,
default_memory_manager_commit_recovery_diagnostic, default_memory_manager_diagnostic_export,
default_memory_manager_doctor_report, default_memory_manager_doctor_report_with_policy,
default_memory_manager_memory_allocation_summary, default_memory_manager_memory_allocations,
default_memory_manager_memory_id, is_default_memory_manager_bootstrapped,
open_default_memory_manager_memory, verify_default_memory_manager_authority,
};
const AUTHORITY: &str = "default_config";
const KEY: &str = "default_config.rows.v1";
const MEMORY_ID: u8 = 10;
ic_memory::ic_memory_declaration!(authority = AUTHORITY, key = "default_config.rows.v1");
fn assert_unbootstrapped_observations() {
assert!(!is_default_memory_manager_bootstrapped().unwrap());
assert_eq!(
committed_allocations(),
Err(RuntimeOpenError::NotBootstrapped)
);
assert!(matches!(
open_default_memory_manager_memory(KEY),
Err(RuntimeOpenError::NotBootstrapped)
));
assert!(matches!(
default_memory_manager_memory_allocations(),
Err(ic_memory::RuntimeDiagnosticError::NotBootstrapped)
));
assert_eq!(
default_memory_manager_memory_id(KEY),
Err(RuntimeOpenError::NotBootstrapped)
);
for result in diagnostic_observations() {
assert!(matches!(
result,
Err(RuntimeDiagnosticError::NotBootstrapped)
));
}
}
fn diagnostic_observations() -> [Result<(), RuntimeDiagnosticError>; 4] {
[
default_memory_manager_diagnostic_export().map(|_| ()),
default_memory_manager_commit_recovery_diagnostic().map(|_| ()),
default_memory_manager_doctor_report(&pool()).map(|_| ()),
default_memory_manager_doctor_report_with_policy(&pool(), &GenericAllocationPolicy)
.map(|_| ()),
]
}
#[test]
fn observations_allow_configured_generic_bootstrap_and_repeated_adoption() {
for pages in [4, 16, 128] {
std::thread::spawn(move || {
assert_unbootstrapped_observations();
let declarations = ic_memory::sealed_declaration_snapshot().unwrap();
assert_eq!(
verify_default_memory_manager_authority(&declarations, AUTHORITY),
Err(ic_memory::RuntimeAdoptionError::Open(
RuntimeOpenError::NotBootstrapped
))
);
assert!(matches!(
default_memory_manager_memory_allocation_summary(),
Err(ic_memory::RuntimeDiagnosticError::NotBootstrapped)
));
let config = MemoryManagerConfig::new(pages).unwrap();
let committed =
bootstrap_default_memory_manager_with_config(config, &pool(), &GenericAllocationPolicy).unwrap();
assert!(is_default_memory_manager_bootstrapped().unwrap());
assert_eq!(committed_allocations().unwrap(), committed);
assert_eq!(default_memory_manager_memory_id(KEY), Ok(MEMORY_ID));
verify_default_memory_manager_authority(&declarations, AUTHORITY).unwrap();
let memory = open_default_memory_manager_memory(KEY).unwrap();
assert_eq!(memory.grow(1), Ok(0));
memory.write(0, &[7, 8, 9]);
let before = default_memory_manager_memory_allocations().unwrap();
assert_eq!(before.bucket_size_pages, pages);
for result in diagnostic_observations() {
result.unwrap();
}
assert_eq!(default_memory_manager_memory_allocations().unwrap(), before);
let summary = default_memory_manager_memory_allocation_summary().unwrap();
assert_eq!(summary.physical_extent, before.physical_extent);
assert_eq!(summary.current_generation, Some(committed.generation()));
assert_eq!(
bootstrap_default_memory_manager_with_config(config, &pool(), &GenericAllocationPolicy).unwrap(),
committed
);
assert_eq!(bootstrap_default_memory_manager(&pool()).unwrap(), committed);
let different = MemoryManagerConfig::new(pages + 1).unwrap();
assert!(matches!(
bootstrap_default_memory_manager_with_config(different, &pool(), &GenericAllocationPolicy),
Err(RuntimeBootstrapError::State(RuntimeStateError::Construction(
RuntimeConstructionError::BucketSizeMismatch { persisted, requested }
))) if persisted == pages && requested == pages + 1
));
assert_eq!(committed_allocations().unwrap(), committed);
assert_eq!(default_memory_manager_memory_allocations().unwrap(), before);
let mut bytes = [0; 3];
memory.read(0, &mut bytes);
assert_eq!(bytes, [7, 8, 9]);
})
.join()
.unwrap();
}
}
fn pool() -> ic_memory::MemoryAllocationPool {
ic_memory::MemoryAllocationPool::new(
vec![ic_memory::MemoryAuthority::new("default_config", "default_config.").unwrap()],
vec![],
)
.unwrap()
}