mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-08-17 14:56:04 +00:00
274 lines
7.7 KiB
Rust
274 lines
7.7 KiB
Rust
#![allow(dead_code)]
|
|
|
|
use std::collections::HashSet;
|
|
use std::sync::Arc;
|
|
|
|
use tranquil_store::blockstore::{
|
|
BlockStoreConfig, CidBytes, DEFAULT_MAX_FILE_SIZE, GroupCommitConfig, TranquilBlockStore,
|
|
};
|
|
use tranquil_store::eventlog::{EventLog, EventLogConfig};
|
|
use tranquil_store::metastore::{Metastore, MetastoreConfig};
|
|
use tranquil_store::{RealIO, SystemClock};
|
|
use tranquil_types::{CidLink, Did, Handle, Tid};
|
|
use uuid::Uuid;
|
|
|
|
pub const NAMES: &[&str] = &["olaren", "teq", "nel", "lyna", "bailey"];
|
|
|
|
pub fn test_cid(seed: u32) -> CidBytes {
|
|
let le = seed.to_le_bytes();
|
|
std::array::from_fn(|i| match i {
|
|
0 => 0x01,
|
|
1 => 0x71,
|
|
2 => 0x12,
|
|
3 => 0x20,
|
|
4..8 => le[i - 4],
|
|
_ => (seed as u8).wrapping_add(i as u8),
|
|
})
|
|
}
|
|
|
|
pub fn block_data(seed: u32) -> Vec<u8> {
|
|
let tag = seed.to_le_bytes();
|
|
std::iter::repeat(tag).flatten().take(80).collect()
|
|
}
|
|
|
|
pub fn test_did(seed: u64) -> Did {
|
|
let name = NAMES[(seed as usize) % NAMES.len()];
|
|
Did::new(format!("did:plc:{name}{seed}")).expect("generated DID is valid")
|
|
}
|
|
|
|
pub fn test_rev(sequence: u64, discriminator: u64) -> Tid {
|
|
const ALPHABET: &[u8] = b"234567abcdefghijklmnopqrstuvwxyz";
|
|
let value = (sequence << 40) | (discriminator & 0xFF_FFFF_FFFF);
|
|
let s: String = (0..13)
|
|
.rev()
|
|
.map(|i| ALPHABET[((value >> (i * 5)) & 0x1F) as usize] as char)
|
|
.collect();
|
|
Tid::new(s).expect("generated TID is valid")
|
|
}
|
|
|
|
pub fn test_handle(seed: u64) -> Handle {
|
|
let name = NAMES[(seed as usize) % NAMES.len()];
|
|
Handle::new(format!("{name}{seed}.test")).unwrap()
|
|
}
|
|
|
|
pub fn test_cid_link(seed: u8) -> CidLink {
|
|
let digest: [u8; 32] = std::array::from_fn(|i| seed.wrapping_add(i as u8));
|
|
let mh = multihash::Multihash::<64>::wrap(0x12, &digest).unwrap();
|
|
let c = cid::Cid::new_v1(0x71, mh);
|
|
CidLink::from_cid(&c)
|
|
}
|
|
|
|
pub fn test_uuid(seed: u64) -> Uuid {
|
|
Uuid::from_u128(seed as u128 | 0x4000_0000_0000_0000_8000_0000_0000_0000)
|
|
}
|
|
|
|
pub fn small_blockstore_config(dir: &std::path::Path) -> BlockStoreConfig {
|
|
BlockStoreConfig {
|
|
data_dir: dir.join("data"),
|
|
index_dir: dir.join("index"),
|
|
max_file_size: 1024,
|
|
group_commit: GroupCommitConfig::default(),
|
|
shard_count: 1,
|
|
}
|
|
}
|
|
|
|
pub fn default_blockstore_config(dir: &std::path::Path) -> BlockStoreConfig {
|
|
BlockStoreConfig {
|
|
data_dir: dir.join("data"),
|
|
index_dir: dir.join("index"),
|
|
max_file_size: DEFAULT_MAX_FILE_SIZE,
|
|
group_commit: GroupCommitConfig::default(),
|
|
shard_count: 1,
|
|
}
|
|
}
|
|
|
|
pub fn with_runtime<F: FnOnce()>(f: F) {
|
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
|
let _guard = rt.enter();
|
|
f();
|
|
}
|
|
|
|
pub fn advance_epoch(store: &TranquilBlockStore<RealIO, SystemClock>) {
|
|
store.apply_commit_blocking(vec![], vec![]).unwrap();
|
|
}
|
|
|
|
pub fn collect_all_dead(store: &TranquilBlockStore<RealIO, SystemClock>) -> HashSet<CidBytes> {
|
|
let result = store.collect_dead_blocks(0).unwrap();
|
|
result
|
|
.candidates
|
|
.values()
|
|
.flat_map(|v| v.iter().copied())
|
|
.collect()
|
|
}
|
|
|
|
pub fn compact_all_sealed(store: &TranquilBlockStore<RealIO, SystemClock>) {
|
|
let Ok(files) = store.list_data_files() else {
|
|
return;
|
|
};
|
|
files
|
|
.iter()
|
|
.copied()
|
|
.take(files.len().saturating_sub(1))
|
|
.for_each(|fid| {
|
|
let _ = store.compact_file(fid, 0);
|
|
});
|
|
}
|
|
|
|
pub fn tiny_blockstore_config(dir: &std::path::Path) -> BlockStoreConfig {
|
|
BlockStoreConfig {
|
|
data_dir: dir.join("data"),
|
|
index_dir: dir.join("index"),
|
|
max_file_size: 300,
|
|
group_commit: GroupCommitConfig {
|
|
checkpoint_interval_ms: 100,
|
|
checkpoint_write_threshold: 10,
|
|
..GroupCommitConfig::default()
|
|
},
|
|
shard_count: 1,
|
|
}
|
|
}
|
|
|
|
pub fn compact_by_liveness(store: &TranquilBlockStore<RealIO, SystemClock>) {
|
|
let liveness = store.compaction_liveness(0).unwrap();
|
|
liveness
|
|
.iter()
|
|
.filter(|(_, info)| info.total_blocks > 0 && info.ratio() < 0.99)
|
|
.map(|(&fid, _)| fid)
|
|
.collect::<Vec<_>>()
|
|
.into_iter()
|
|
.for_each(|fid| match store.compact_file(fid, 0) {
|
|
Ok(_) => {}
|
|
Err(tranquil_store::blockstore::CompactionError::ActiveFileCannotBeCompacted) => {}
|
|
Err(e) => eprintln!("compaction: {e}"),
|
|
});
|
|
}
|
|
|
|
pub fn compact_lowest_liveness(store: &TranquilBlockStore<RealIO, SystemClock>) {
|
|
let liveness = store.compaction_liveness(0).unwrap();
|
|
let candidate = liveness
|
|
.iter()
|
|
.filter(|(_, info)| info.total_blocks > 0 && info.ratio() < 0.99)
|
|
.min_by(|(_, a), (_, b)| {
|
|
a.ratio()
|
|
.partial_cmp(&b.ratio())
|
|
.unwrap_or(std::cmp::Ordering::Equal)
|
|
})
|
|
.map(|(&fid, _)| fid);
|
|
|
|
if let Some(fid) = candidate {
|
|
match store.compact_file(fid, 0) {
|
|
Ok(_) => {}
|
|
Err(tranquil_store::blockstore::CompactionError::ActiveFileCannotBeCompacted) => {}
|
|
Err(e) => eprintln!("compaction: {e}"),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn collect_refcounts(
|
|
store: &TranquilBlockStore<RealIO, SystemClock>,
|
|
cids: &[CidBytes],
|
|
) -> Vec<(u32, u32)> {
|
|
cids.iter()
|
|
.map(|cid| {
|
|
let seed = u32::from_le_bytes([cid[4], cid[5], cid[6], cid[7]]);
|
|
let rc = store
|
|
.block_index()
|
|
.get(cid)
|
|
.map(|e| e.refcount.raw())
|
|
.unwrap_or(0);
|
|
(seed, rc)
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
pub struct TestStores {
|
|
pub blockstore: TranquilBlockStore<RealIO, SystemClock>,
|
|
pub eventlog: Arc<EventLog<RealIO>>,
|
|
pub metastore: Metastore,
|
|
}
|
|
|
|
pub fn open_test_stores(
|
|
base: &std::path::Path,
|
|
max_file_size: u64,
|
|
cache_size_bytes: u64,
|
|
) -> TestStores {
|
|
let bs_data = base.join("blockstore/data");
|
|
let bs_index = base.join("blockstore/index");
|
|
let segments_dir = base.join("eventlog/segments");
|
|
let metastore_dir = base.join("metastore");
|
|
|
|
[&bs_data, &bs_index, &segments_dir, &metastore_dir]
|
|
.iter()
|
|
.for_each(|d| std::fs::create_dir_all(d).unwrap());
|
|
|
|
let blockstore = TranquilBlockStore::open(BlockStoreConfig {
|
|
data_dir: bs_data,
|
|
index_dir: bs_index,
|
|
max_file_size,
|
|
group_commit: GroupCommitConfig::default(),
|
|
shard_count: 1,
|
|
})
|
|
.unwrap();
|
|
|
|
let eventlog = Arc::new(
|
|
EventLog::open(
|
|
EventLogConfig {
|
|
segments_dir,
|
|
..EventLogConfig::default()
|
|
},
|
|
RealIO::new(),
|
|
)
|
|
.unwrap(),
|
|
);
|
|
|
|
let metastore = Metastore::open(&metastore_dir, MetastoreConfig { cache_size_bytes }).unwrap();
|
|
|
|
TestStores {
|
|
blockstore,
|
|
eventlog,
|
|
metastore,
|
|
}
|
|
}
|
|
|
|
pub fn assert_store_consistent(stores: &TestStores, context: &str) {
|
|
let options = tranquil_store::consistency::ConsistencyCheckOptions {
|
|
check_block_references: false,
|
|
..Default::default()
|
|
};
|
|
let report = tranquil_store::consistency::verify_store_consistency_with_options(
|
|
&stores.blockstore,
|
|
&stores.metastore,
|
|
&stores.eventlog,
|
|
options,
|
|
);
|
|
assert!(report.is_consistent(), "{context}: {report}",);
|
|
}
|
|
|
|
pub struct Rng {
|
|
state: u64,
|
|
}
|
|
|
|
impl Rng {
|
|
pub fn new(seed: u64) -> Self {
|
|
Self {
|
|
state: seed.wrapping_mul(6364136223846793005).wrapping_add(1),
|
|
}
|
|
}
|
|
|
|
pub fn next_u64(&mut self) -> u64 {
|
|
self.state = self
|
|
.state
|
|
.wrapping_mul(6364136223846793005)
|
|
.wrapping_add(1442695040888963407);
|
|
self.state
|
|
}
|
|
|
|
pub fn next_u32(&mut self) -> u32 {
|
|
(self.next_u64() >> 16) as u32
|
|
}
|
|
|
|
pub fn range_u32(&mut self, max: u32) -> u32 {
|
|
self.next_u32() % max
|
|
}
|
|
}
|