内存优化

This commit is contained in:
xiuting.xu
2026-05-12 16:45:56 +08:00
parent 4c6b441753
commit ff711a2fe1
15 changed files with 152 additions and 96 deletions

28
src/rtr/cache/core.rs vendored
View File

@@ -578,33 +578,7 @@ fn merge_deltas_minimally(current_serial: u32, deltas: &[Arc<Delta>]) -> Delta {
}
fn project_snapshot_for_version(snapshot: &Snapshot, version: u8) -> Snapshot {
let mut payloads = Vec::new();
for payload in snapshot.payloads() {
if let Some(projected) = project_payload_for_version(&payload, version) {
payloads.push(projected);
}
}
Snapshot::from_payloads(payloads)
}
fn project_payload_for_version(payload: &Payload, version: u8) -> Option<Payload> {
match payload {
Payload::RouteOrigin(origin) => Some(Payload::RouteOrigin(origin.clone())),
Payload::RouterKey(key) => {
if version >= 1 {
Some(Payload::RouterKey(key.clone()))
} else {
None
}
}
Payload::Aspa(aspa) => {
if version >= 2 {
Some(Payload::Aspa(aspa.clone()))
} else {
None
}
}
}
snapshot.project_for_version(version)
}
fn estimate_snapshot_payload_wire_size(snapshot: &Snapshot) -> usize {

157
src/rtr/cache/model.rs vendored
View File

@@ -1,4 +1,4 @@
use std::collections::{BTreeMap, BTreeSet};
use std::collections::BTreeMap;
use std::sync::{Arc, OnceLock};
use std::time::{Duration, Instant};
@@ -69,9 +69,9 @@ impl<'de> Deserialize<'de> for DualTime {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Snapshot {
origins: BTreeSet<RouteOrigin>,
router_keys: BTreeSet<RouterKey>,
aspas: BTreeSet<Aspa>,
origins: Arc<Vec<RouteOrigin>>,
router_keys: Arc<Vec<RouterKey>>,
aspas: Arc<Vec<Aspa>>,
created_at: DualTime,
origins_hash: [u8; 32],
router_keys_hash: [u8; 32],
@@ -83,14 +83,26 @@ pub struct Snapshot {
impl Snapshot {
pub fn new(
origins: BTreeSet<RouteOrigin>,
router_keys: BTreeSet<RouterKey>,
aspas: BTreeSet<Aspa>,
origins: Vec<RouteOrigin>,
router_keys: Vec<RouterKey>,
aspas: Vec<Aspa>,
) -> Self {
Self::from_shared_parts(
Arc::new(sorted_dedup(origins)),
Arc::new(sorted_dedup(router_keys)),
Arc::new(normalize_aspas(aspas)),
)
}
fn from_shared_parts(
origins: Arc<Vec<RouteOrigin>>,
router_keys: Arc<Vec<RouterKey>>,
aspas: Arc<Vec<Aspa>>,
) -> Self {
let mut snapshot = Snapshot {
origins,
router_keys,
aspas: normalize_aspas(aspas),
aspas,
created_at: DualTime::now(),
origins_hash: [0u8; 32],
router_keys_hash: [0u8; 32],
@@ -105,21 +117,21 @@ impl Snapshot {
}
pub fn empty() -> Self {
Self::new(BTreeSet::new(), BTreeSet::new(), BTreeSet::new())
Self::new(Vec::new(), Vec::new(), Vec::new())
}
pub fn from_payloads(payloads: Vec<Payload>) -> Self {
let mut origins = BTreeSet::new();
let mut router_keys = BTreeSet::new();
let mut origins = Vec::new();
let mut router_keys = Vec::new();
let mut aspas = Vec::new();
for p in payloads {
match p {
Payload::RouteOrigin(o) => {
origins.insert(o);
origins.push(o);
}
Payload::RouterKey(k) => {
router_keys.insert(k);
router_keys.push(k);
}
Payload::Aspa(a) => {
aspas.push(a);
@@ -130,6 +142,21 @@ impl Snapshot {
Snapshot::new(origins, router_keys, normalize_aspas(aspas))
}
pub fn project_for_version(&self, version: u8) -> Self {
let router_keys = if version >= 1 {
self.router_keys.clone()
} else {
Arc::new(Vec::new())
};
let aspas = if version >= 2 {
self.aspas.clone()
} else {
Arc::new(Vec::new())
};
Self::from_shared_parts(self.origins.clone(), router_keys, aspas)
}
pub fn recompute_hashes(&mut self) {
self.origins_hash = self.compute_origins_hash();
self.router_keys_hash = self.compute_router_keys_hash();
@@ -182,21 +209,23 @@ impl Snapshot {
let mut withdrawn = Vec::new();
if !self.same_origins(new_snapshot) {
for origin in new_snapshot.origins.difference(&self.origins) {
announced.push(Payload::RouteOrigin(origin.clone()));
}
for origin in self.origins.difference(&new_snapshot.origins) {
withdrawn.push(Payload::RouteOrigin(origin.clone()));
}
diff_sorted(
self.origins.as_slice(),
new_snapshot.origins.as_slice(),
&mut announced,
&mut withdrawn,
Payload::RouteOrigin,
);
}
if !self.same_router_keys(new_snapshot) {
for key in new_snapshot.router_keys.difference(&self.router_keys) {
announced.push(Payload::RouterKey(key.clone()));
}
for key in self.router_keys.difference(&new_snapshot.router_keys) {
withdrawn.push(Payload::RouterKey(key.clone()));
}
diff_sorted(
self.router_keys.as_slice(),
new_snapshot.router_keys.as_slice(),
&mut announced,
&mut withdrawn,
Payload::RouterKey,
);
}
if !self.same_aspas(new_snapshot) {
@@ -268,16 +297,16 @@ impl Snapshot {
self.snapshot_hash == other.snapshot_hash
}
pub fn origins(&self) -> &BTreeSet<RouteOrigin> {
&self.origins
pub fn origins(&self) -> &[RouteOrigin] {
self.origins.as_ref()
}
pub fn router_keys(&self) -> &BTreeSet<RouterKey> {
&self.router_keys
pub fn router_keys(&self) -> &[RouterKey] {
self.router_keys.as_ref()
}
pub fn aspas(&self) -> &BTreeSet<Aspa> {
&self.aspas
pub fn aspas(&self) -> &[Aspa] {
self.aspas.as_ref()
}
pub fn is_empty(&self) -> bool {
@@ -369,15 +398,15 @@ fn build_snapshot_payloads_for_rtr(snapshot: &Snapshot) -> Vec<Payload> {
}
fn dedup_payloads(payloads: &mut Vec<Payload>) {
let mut seen = BTreeSet::new();
payloads.retain(|p| seen.insert(p.clone()));
payloads.sort();
payloads.dedup();
}
fn normalize_aspas<I>(aspas: I) -> BTreeSet<Aspa>
fn normalize_aspas<I>(aspas: I) -> Vec<Aspa>
where
I: IntoIterator<Item = Aspa>,
{
let mut by_customer = BTreeMap::<u32, BTreeSet<_>>::new();
let mut by_customer = BTreeMap::<u32, Vec<_>>::new();
for aspa in aspas {
let providers = by_customer
@@ -386,17 +415,19 @@ where
providers.extend(aspa.provider_asns().iter().copied());
}
by_customer
let mut normalized = by_customer
.into_iter()
.map(|(customer_asn, providers)| {
Aspa::new(customer_asn.into(), providers.into_iter().collect())
Aspa::new(customer_asn.into(), providers)
})
.collect()
.collect::<Vec<_>>();
normalized.sort();
normalized
}
fn diff_aspas(
current: &BTreeSet<Aspa>,
next: &BTreeSet<Aspa>,
current: &[Aspa],
next: &[Aspa],
announced: &mut Vec<Payload>,
withdrawn: &mut Vec<Payload>,
) {
@@ -413,7 +444,7 @@ fn diff_aspas(
.keys()
.chain(next.keys())
.copied()
.collect::<BTreeSet<_>>();
.collect::<std::collections::BTreeSet<_>>();
for customer in customers {
match (current.get(&customer), next.get(&customer)) {
@@ -426,3 +457,47 @@ fn diff_aspas(
}
}
}
fn sorted_dedup<T: Ord>(mut items: Vec<T>) -> Vec<T> {
items.sort();
items.dedup();
items
}
fn diff_sorted<T, F>(
current: &[T],
next: &[T],
announced: &mut Vec<Payload>,
withdrawn: &mut Vec<Payload>,
wrap: F,
) where
T: Ord + Clone,
F: Fn(T) -> Payload,
{
let mut i = 0usize;
let mut j = 0usize;
while i < current.len() && j < next.len() {
match current[i].cmp(&next[j]) {
std::cmp::Ordering::Less => {
withdrawn.push(wrap(current[i].clone()));
i += 1;
}
std::cmp::Ordering::Greater => {
announced.push(wrap(next[j].clone()));
j += 1;
}
std::cmp::Ordering::Equal => {
i += 1;
j += 1;
}
}
}
while i < current.len() {
withdrawn.push(wrap(current[i].clone()));
i += 1;
}
while j < next.len() {
announced.push(wrap(next[j].clone()));
j += 1;
}
}

View File

@@ -213,14 +213,5 @@ fn persist_update_job(job: StoreSyncJob) {
}
fn project_snapshot_for_version(snapshot: &Snapshot, version: u8) -> Snapshot {
let mut payloads = Vec::new();
for payload in snapshot.payloads() {
match payload {
Payload::RouteOrigin(_) => payloads.push(payload),
Payload::RouterKey(_) if version >= 1 => payloads.push(payload),
Payload::Aspa(_) if version >= 2 => payloads.push(payload),
_ => {}
}
}
Snapshot::from_payloads(payloads)
snapshot.project_for_version(version)
}