20260626 优化PP缓存索引与证书缓存长尾

This commit is contained in:
2026-06-26 07:19:11 +08:00
parent af25316d68
commit 9e339e63e7
24 changed files with 3158 additions and 329 deletions

View File

@@ -14,6 +14,37 @@ fn sha256_32(input: &[u8]) -> [u8; 32] {
compute_sha256_32(input)
}
fn sample_child_certificate_cache_projection(
cache_key_sha256_hex: String,
child_cert_uri: &str,
child_cert_sha256_hex: &str,
) -> ChildCertificateCacheProjection {
ChildCertificateCacheProjection {
schema_version: CHILD_CERTIFICATE_CACHE_SCHEMA_VERSION,
algorithm_version: CHILD_CERTIFICATE_CACHE_ALGORITHM_VERSION,
cache_key_sha256_hex,
child_cert_uri: child_cert_uri.to_string(),
child_cert_sha256_hex: child_cert_sha256_hex.to_string(),
child_cert_serial: vec![1],
issuer_ca_sha256_hex: sha256_hex(b"issuer-ca"),
issuer_crl_uri: "rsync://example.test/repo/issuer.crl".to_string(),
issuer_crl_sha256_hex: sha256_hex(b"issuer-crl"),
parent_context_digest: sha256_32(b"parent-context"),
validation_policy_fingerprint: sha256_32(b"policy"),
effective_not_before: pack_time(0),
effective_until: pack_time(24),
payload: ChildCertificateCachePayload::ChildCa {
child_manifest_rsync_uri: format!("{child_cert_uri}.mft"),
child_ski: "11".repeat(20),
child_rsync_base_uri: "rsync://example.test/repo/child/".to_string(),
child_publication_point_rsync_uri: "rsync://example.test/repo/child/".to_string(),
child_rrdp_notification_uri: Some("https://example.test/notify.xml".to_string()),
child_effective_ip_resources: None,
child_effective_as_resources: None,
},
}
}
#[test]
fn parse_work_db_blob_mode_accepts_supported_values() {
assert_eq!(default_work_db_blob_mode(), WorkDbBlobMode::Disabled);
@@ -565,6 +596,128 @@ fn publication_point_cache_mmap_index_dirty_overlay_wins_and_refreshes_segment()
assert_eq!(got.manifest_sha256, sha256_32(b"manifest-new"));
}
#[test]
fn publication_point_cache_mmap_index_write_before_read_refreshes_segment() {
let td = tempfile::tempdir().expect("tempdir");
let db_path = td.path().join("work-db");
let vcir = sample_vcir("rsync://example.test/repo/current.mft");
let mut projection = PublicationPointCacheProjection::from_vcir_with_context(
&vcir,
"rsync://example.test/repo/".to_string(),
Some("rsync://example.test/repo/ca.cer".to_string()),
sha256_32(b"ca-cert"),
sha256_32(b"manifest-old"),
sha256_32(b"ta-context"),
sha256_32(b"parent-context"),
sha256_32(b"policy"),
)
.expect("build publication point projection");
{
let store = RocksStore::open(&db_path).expect("open rocksdb");
store
.put_vcir_with_publication_point_cache_projection(&vcir, Some(&projection))
.expect("put old projection");
let stats = store
.refresh_publication_point_cache_mmap_index()
.expect("refresh base mmap index")
.expect("refresh stats");
assert_eq!(stats.state, "written");
}
{
let store = RocksStore::open(&db_path).expect("reopen rocksdb");
projection.manifest_sha256 = sha256_32(b"manifest-new");
store
.put_vcir_with_publication_point_cache_projection(&vcir, Some(&projection))
.expect("put new projection before any cached read");
let stats = store
.refresh_publication_point_cache_mmap_index()
.expect("refresh dirty mmap segment")
.expect("refresh stats");
assert_eq!(stats.state, "segment_written");
assert_eq!(stats.dirty_entries, 1);
assert_eq!(stats.new_entries, 1);
}
let store = RocksStore::open(&db_path).expect("reopen rocksdb after segment");
let got = store
.get_publication_point_cache_projection_cached(&vcir.manifest_rsync_uri)
.expect("get refreshed projection")
.expect("projection exists");
assert_eq!(got.manifest_sha256, sha256_32(b"manifest-new"));
}
#[test]
fn publication_point_cache_mmap_index_delete_before_read_refreshes_tombstone_segment() {
let td = tempfile::tempdir().expect("tempdir");
let db_path = td.path().join("work-db");
let vcir = sample_vcir("rsync://example.test/repo/current.mft");
let projection = PublicationPointCacheProjection::from_vcir_with_context(
&vcir,
"rsync://example.test/repo/".to_string(),
Some("rsync://example.test/repo/ca.cer".to_string()),
sha256_32(b"ca-cert"),
sha256_32(b"manifest"),
sha256_32(b"ta-context"),
sha256_32(b"parent-context"),
sha256_32(b"policy"),
)
.expect("build publication point projection");
{
let store = RocksStore::open(&db_path).expect("open rocksdb");
store
.put_vcir_with_publication_point_cache_projection(&vcir, Some(&projection))
.expect("put projection");
let stats = store
.refresh_publication_point_cache_mmap_index()
.expect("refresh base mmap index")
.expect("refresh stats");
assert_eq!(stats.state, "written");
}
{
let store = RocksStore::open(&db_path).expect("reopen rocksdb");
store
.replace_vcir_manifest_replay_meta_and_projection_action(
&vcir,
None,
PublicationPointCacheProjectionWriteAction::Delete {
manifest_rsync_uri: &vcir.manifest_rsync_uri,
},
)
.expect("delete projection before any cached read");
assert!(
store
.get_publication_point_cache_projection_cached(&vcir.manifest_rsync_uri)
.expect("dirty tombstone lookup")
.is_none()
);
let stats = store
.refresh_publication_point_cache_mmap_index()
.expect("refresh tombstone mmap segment")
.expect("refresh stats");
assert_eq!(stats.state, "segment_written");
assert_eq!(stats.dirty_entries, 1);
assert_eq!(stats.new_entries, 1);
}
let store = RocksStore::open(&db_path).expect("reopen rocksdb after tombstone segment");
assert!(
store
.get_publication_point_cache_projection_cached(&vcir.manifest_rsync_uri)
.expect("tombstone shadows old current index")
.is_none()
);
assert!(
store
.get_publication_point_cache_projection(&vcir.manifest_rsync_uri)
.expect("direct db lookup")
.is_none()
);
}
#[test]
fn publication_point_cache_projection_rejects_version_mismatch() {
let vcir = sample_vcir("rsync://example.test/repo/current.mft");
@@ -1364,6 +1517,196 @@ fn replace_vcir_and_manifest_replay_meta_replaces_current_entry() {
);
}
#[test]
fn get_child_certificate_cache_projections_batch_preserves_order_and_misses() {
let td = tempfile::tempdir().expect("tempdir");
let store = RocksStore::open(td.path()).expect("open rocksdb");
let first_key = sha256_hex(b"child-cache-key-first");
let missing_key = sha256_hex(b"child-cache-key-missing");
let second_key = sha256_hex(b"child-cache-key-second");
let first_hash = sha256_hex(b"first-child-cert");
let second_hash = sha256_hex(b"second-child-cert");
let first = sample_child_certificate_cache_projection(
first_key.clone(),
"rsync://example.test/repo/first.cer",
&first_hash,
);
let second = sample_child_certificate_cache_projection(
second_key.clone(),
"rsync://example.test/repo/second.cer",
&second_hash,
);
store
.put_child_certificate_cache_projection(&first)
.expect("put first projection");
store
.put_child_certificate_cache_projection(&second)
.expect("put second projection");
let got = store
.get_child_certificate_cache_projections_batch(&[
second_key.clone(),
missing_key,
first_key.clone(),
])
.expect("batch get child projections");
assert_eq!(got.len(), 3);
assert_eq!(
got[0]
.as_ref()
.expect("second projection")
.child_cert_sha256_hex,
second_hash
);
assert!(got[1].is_none());
assert_eq!(
got[2]
.as_ref()
.expect("first projection")
.child_cert_sha256_hex,
first_hash
);
}
#[test]
fn child_certificate_cache_mmap_segment_preserves_order_and_misses() {
let td = tempfile::tempdir().expect("tempdir");
let store = RocksStore::open(td.path()).expect("open rocksdb");
let manifest_uri = "rsync://example.test/repo/parent.mft";
let first_key = sha256_hex(b"child-cache-mmap-key-first");
let missing_key = sha256_hex(b"child-cache-mmap-key-missing");
let second_key = sha256_hex(b"child-cache-mmap-key-second");
let first_hash = sha256_hex(b"first-child-cert-mmap");
let second_hash = sha256_hex(b"second-child-cert-mmap");
let first = sample_child_certificate_cache_projection(
first_key.clone(),
"rsync://example.test/repo/first.cer",
&first_hash,
);
let second = sample_child_certificate_cache_projection(
second_key.clone(),
"rsync://example.test/repo/second.cer",
&second_hash,
);
assert!(
store
.get_child_certificate_cache_projections_mmap_segment(
manifest_uri,
&[first_key.clone()]
)
.expect("missing segment lookup")
.is_none()
);
let write_stats = store
.write_child_certificate_cache_mmap_segment(manifest_uri, &[first.clone(), second.clone()])
.expect("write child projection segment");
assert_eq!(write_stats.new_entries, 2);
assert!(write_stats.file_bytes > 0);
let got = store
.get_child_certificate_cache_projections_mmap_segment(
manifest_uri,
&[second_key.clone(), missing_key, first_key.clone()],
)
.expect("lookup child projection segment")
.expect("segment exists");
assert_eq!(got.hits, 2);
assert_eq!(got.misses, 1);
assert!(got.file_bytes > 0);
assert_eq!(got.projections.len(), 3);
assert_eq!(
got.projections[0]
.as_ref()
.expect("second projection")
.child_cert_sha256_hex,
second_hash
);
assert!(got.projections[1].is_none());
assert_eq!(
got.projections[2]
.as_ref()
.expect("first projection")
.child_cert_sha256_hex,
first_hash
);
}
#[test]
fn child_certificate_cache_mmap_segment_overlay_preserves_existing_values() {
let td = tempfile::tempdir().expect("tempdir");
let store = RocksStore::open(td.path()).expect("open rocksdb");
let manifest_uri = "rsync://example.test/repo/parent-overlay.mft";
let first_key = sha256_hex(b"child-cache-overlay-key-first");
let second_key = sha256_hex(b"child-cache-overlay-key-second");
let missing_key = sha256_hex(b"child-cache-overlay-key-missing");
let first_hash = sha256_hex(b"first-child-cert-overlay");
let old_second_hash = sha256_hex(b"old-second-child-cert-overlay");
let new_second_hash = sha256_hex(b"new-second-child-cert-overlay");
let first = sample_child_certificate_cache_projection(
first_key.clone(),
"rsync://example.test/repo/first-overlay.cer",
&first_hash,
);
let old_second = sample_child_certificate_cache_projection(
second_key.clone(),
"rsync://example.test/repo/second-overlay.cer",
&old_second_hash,
);
let new_second = sample_child_certificate_cache_projection(
second_key.clone(),
"rsync://example.test/repo/second-overlay.cer",
&new_second_hash,
);
store
.write_child_certificate_cache_mmap_segment(
manifest_uri,
&[first.clone(), old_second.clone()],
)
.expect("write initial segment");
let stats = store
.write_child_certificate_cache_mmap_segment_overlay(
manifest_uri,
&[first_key.clone(), second_key.clone(), missing_key.clone()],
std::slice::from_ref(&new_second),
)
.expect("write segment overlay");
assert_eq!(stats.new_entries, 2);
let got = store
.get_child_certificate_cache_projections_mmap_segment(
manifest_uri,
&[first_key.clone(), second_key.clone(), missing_key],
)
.expect("lookup segment")
.expect("segment exists");
assert_eq!(got.hits, 2);
assert_eq!(got.misses, 1);
assert_eq!(
got.projections[0]
.as_ref()
.expect("first projection")
.child_cert_sha256_hex,
first_hash
);
assert_eq!(
got.projections[1]
.as_ref()
.expect("updated second projection")
.child_cert_sha256_hex,
new_second_hash
);
assert!(got.projections[2].is_none());
}
#[test]
fn storage_helpers_cover_optional_validation_paths() {
let withdrawn = RepositoryViewEntry {