#![forbid(unsafe_code)]
use crate::store::transaction::CrashHooks;
use crate::store::{NewEntry, Store, StoreConfig};
use tempfile::TempDir;
fn create_store(dir: &TempDir) -> Store {
let cfg = StoreConfig {
segment_size: 1024 * 1024,
..Default::default()
};
Store::create(dir.path(), &cfg, [0x61; 16]).unwrap()
}
fn noise(n: usize, seed: u64) -> Vec<u8> {
let mut state = seed;
let mut out = Vec::with_capacity(n);
while out.len() < n {
state = state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^= z >> 31;
let b = z.to_le_bytes();
let take = (n - out.len()).min(8);
out.extend_from_slice(&b[..take]);
}
out
}
#[test]
fn inserted_region_roundtrips_and_uses_base_sequence() {
let dir = TempDir::new().unwrap();
let store = create_store(&dir);
let ino = store
.create_entry(
1,
b"f",
NewEntry::file(0o644, 1000, 1000),
&CrashHooks::none(),
)
.unwrap();
let v0 = noise(60 * 1024, 0x1111_2222_3333_4444);
store.write_region(ino, 0, &v0).unwrap();
let insert = noise(6 * 1024, 0xaaaa_bbbb_cccc_dddd);
let mut v1 = Vec::with_capacity(66 * 1024);
v1.extend_from_slice(&v0[..30 * 1024]);
v1.extend_from_slice(&insert);
v1.extend_from_slice(&v0[30 * 1024..]);
store.write_region(ino, 0, &v1).unwrap();
let back = store.read_file(ino, 0, v1.len() as u64).unwrap();
assert_eq!(back, v1, "shifted write must round-trip");
let limits = store.limits();
let inode = store.get_inode(ino).unwrap().unwrap();
let root = match inode.data {
crate::store::inode::InodeData::File { extent_root } => extent_root,
_ => panic!("not a file"),
};
let (_, bytes) = crate::store::extent_tree::covering(
root,
0,
crate::store::BTREE_ORDER,
limits.max_fanout,
&store,
)
.unwrap()
.unwrap();
let desc = crate::format::descriptor::decode(
&bytes,
limits.max_descriptor_bytes,
limits.max_inline_bytes,
limits.max_palette,
limits.max_period,
limits.max_chunk_size,
)
.unwrap();
match &desc {
crate::core::representation::Representation::BaseResidual { residual, .. } => {
assert!(
matches!(
residual,
crate::core::representation::Residual::BaseSequence { .. }
),
"shifted write must choose BASE_SEQUENCE, got {:?}",
residual
);
}
other => panic!("expected BASE_RESIDUAL, got {:?}", other.family()),
}
let bytes_m = crate::core::materialize::materialize_to_vec(&desc, &store, limits).unwrap();
assert_eq!(bytes_m, &v1[..65536]);
assert!(
desc.encoded_size() < 256,
"descriptor {}",
desc.encoded_size()
);
}