pub(crate) use super::v7::{Commit, RepoStatus};
use crate::db::types::DbTid;
use serde::{Deserialize, Serialize};
/// rows are msgpack arrays, so new fields go last and old rows decode with them defaulted
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct RepoMetadata {
pub tracked: bool,
pub index_id: u64,
/// failed backfills in a row. not on the resync entry, because requeueing deletes that
#[serde(default)]
pub retry_count: u32,
/// last status a relay listing asked the pds about, so the same status isn't asked again
#[serde(default)]
pub relay_inactive: Option<RepoStatus>,
/// a commit at or below this is already in the car, even if the shard gets it after
#[serde(default)]
pub backfilled_rev: Option<DbTid>,
/// a good backfill doesn't reset this, or a peer that keeps sending #sync never runs out
#[serde(default)]
pub refetch: Option<Allowance>,
/// live commits are dropped while this is set, because the refetch replaces what they change
#[serde(default)]
pub refetch_deferred: bool,
}
/// a fixed window that starts at the first use, not a rolling one
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct Allowance {
pub since: i64,
pub used: u32,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn v16_repo_metadata_golden_fixtures() {
let metadata = RepoMetadata {
tracked: true,
index_id: 7,
retry_count: 3,
relay_inactive: Some(RepoStatus::Takendown),
backfilled_rev: Some(DbTid::new_from_bytes(0x0102030405060708_u64.to_be_bytes())),
refetch: Some(Allowance {
since: 1000,
used: 2,
}),
refetch_deferred: true,
};
let encoded = rmp_serde::to_vec(&metadata).unwrap();
assert_eq!(
crate::util::hex::encode(&encoded),
"97c30703a954616b656e646f776ec408010203040506070892cd03e802c3"
);
let decoded: RepoMetadata = rmp_serde::from_slice(&encoded).unwrap();
assert!(decoded.tracked);
assert_eq!(decoded.index_id, 7);
assert_eq!(decoded.retry_count, 3);
assert_eq!(decoded.relay_inactive, Some(RepoStatus::Takendown));
assert_eq!(decoded.backfilled_rev, metadata.backfilled_rev);
assert_eq!(decoded.refetch, metadata.refetch);
assert!(decoded.refetch_deferred);
let healthy = rmp_serde::to_vec(&RepoMetadata {
relay_inactive: None,
retry_count: 0,
backfilled_rev: None,
refetch: None,
refetch_deferred: false,
..metadata
})
.unwrap();
assert_eq!(crate::util::hex::encode(&healthy), "97c30700c0c0c0c2");
}
#[test]
fn v4_and_v14_repo_metadata_rows_decode_with_no_refetches() {
let v4 = super::super::v4::RepoMetadata {
tracked: false,
index_id: 7,
};
let encoded = rmp_serde::to_vec(&v4).unwrap();
assert_eq!(crate::util::hex::encode(&encoded), "92c207");
let decoded: RepoMetadata = rmp_serde::from_slice(&encoded).unwrap();
assert!(!decoded.tracked);
assert_eq!(decoded.index_id, 7);
assert_eq!(decoded.retry_count, 0);
assert_eq!(decoded.relay_inactive, None);
assert_eq!(decoded.backfilled_rev, None);
assert_eq!(decoded.refetch, None);
assert!(!decoded.refetch_deferred);
let v14 = super::super::v14::RepoMetadata {
tracked: true,
index_id: 7,
retry_count: 3,
relay_inactive: Some(RepoStatus::Takendown),
backfilled_rev: Some(DbTid::new_from_bytes(0x0102030405060708_u64.to_be_bytes())),
};
let decoded: RepoMetadata =
rmp_serde::from_slice(&rmp_serde::to_vec(&v14).unwrap()).unwrap();
assert_eq!(decoded.retry_count, 3);
assert_eq!(decoded.backfilled_rev, v14.backfilled_rev);
assert_eq!(decoded.refetch, None);
assert!(!decoded.refetch_deferred);
}
#[test]
fn a_v14_reader_rejects_a_v16_row() {
let encoded = crate::util::hex::decode("97c30700c0c0c0c2").unwrap();
assert!(rmp_serde::from_slice::<RepoMetadata>(&encoded).is_ok());
assert!(rmp_serde::from_slice::<super::super::v14::RepoMetadata>(&encoded).is_err());
}
}