···44use jacquard_common::types::string::Did;
5566use lightrail::storage::{self, resync_queue::ResyncItem};
77-use lightrail::util::unix_now_ms;
77+use std::time::SystemTime;
8899#[derive(Parser, Debug)]
1010#[command(
···2828fn main() -> Result<(), Box<dyn std::error::Error>> {
2929 let args = Args::parse();
3030 let db = storage::open(&args.db_path, 64)?;
3131- let now = unix_now_ms();
3131+ let now = SystemTime::now();
32323333 for raw in &args.dids {
3434 let did = Did::new_owned(raw.clone())?;
+8-2
src/storage/meta.rs
···161161}
162162163163fn write_sketch(ks: &fjall::Keyspace, suffix: &[u8], sketch: &Mutex<Sk>) -> StorageResult<()> {
164164- let bytes = postcard::to_stdvec(&*sketch.lock().unwrap()).unwrap_or_default();
164164+ let bytes = match postcard::to_stdvec(&*sketch.lock().unwrap()) {
165165+ Ok(b) => b,
166166+ Err(e) => {
167167+ tracing::error!(key = ?suffix, error = %e, "failed to serialize sketch; skipping write");
168168+ return Ok(());
169169+ }
170170+ };
165171 ks.insert(full_key(suffix), bytes)?;
166172 Ok(())
167173}
···196202197203 // Set first_startup_ms if this is the very first startup.
198204 if stats.first_startup_ms.load(Ordering::Relaxed) == 0 {
199199- let now = crate::util::unix_now_ms();
205205+ let now = crate::util::to_millis(std::time::SystemTime::now());
200206 stats.first_startup_ms.store(now, Ordering::Relaxed);
201207 write_u64(ks, K_FIRST_STARTUP, now)?;
202208 }
···3131 backfill_progress::{BackfillProgress, get, set},
3232 resync_queue::ResyncItem,
3333 },
3434- util::{TokenExt, unix_now_ms},
3434+ util::TokenExt,
3535};
3636use std::sync::atomic::Ordering;
3737+use std::time::SystemTime;
37383839const PAGE_LIMIT: i64 = 500;
3940/// Delay between retry attempts after a transient page failure.
···4344/// Typical number of requests required to complete one repo resync
4445const REQUESTS_PER_RESYNC: u64 = 2;
45464646-/// Walk the full `listRepos` feed for `host`, enqueuing newly discovered repos.
4747-///
4848-/// Resumes from the last persisted cursor on restart. 4xx errors are treated
4949-/// as fatal and abort the walk immediately. Transient errors are retried up to
5050-/// `MAX_PAGE_FAILURES` times before giving up. Returns `Ok(true)` when the
5151-/// full walk completes, `Ok(false)` if cancelled or the host gives up.
5252-///
5347/// Walk `listRepos` on `host` and enqueue new repos for resync.
5448///
5549/// When `validate` is true (deep crawl / untrusted PDS), DIDs are verified to
···8882 // same host are spread across time at 1/crawl_qps intervals.
8983 // This prevents the timestamp-ordered queue from bunching all items for
9084 // a popular host together.
9191- let host_interval_ms = 1000 / crawl_qps.get() as u64;
9292- let mut host_schedule: HashMap<Arc<Url>, u64> = HashMap::new(); // host → last scheduled ts (seconds)
8585+ let host_interval = Duration::from_secs(1) / crawl_qps.get();
8686+ let mut host_schedule: HashMap<Arc<Url>, SystemTime> = HashMap::new();
93879488 loop {
9589 if token.is_cancelled() {
···10397 };
1049810599 let page_len = dids.len();
106106- let now = unix_now_ms();
100100+ let now = SystemTime::now();
107101108102 // For untrusted hosts (deep crawl), filter DIDs to those whose
109103 // resolved PDS actually matches this host.
···146140 dids_with_hosts,
147141 progress_cursor,
148142 now,
149149- host_interval_ms,
143143+ host_interval,
150144 schedule,
151145 )
152146 })
···184178 &host_owned,
185179 &BackfillProgress {
186180 cursor: "".to_string(),
187187- completed_at: Some(now.to_string()),
181181+ completed_at: Some(crate::util::to_millis(now).to_string()),
188182 },
189183 )
190184 })
···323317 host: &Host,
324318 items: Vec<(Did<'static>, Arc<Url>)>,
325319 progress_cursor: String,
326326- now: u64,
327327- interval_ms: u64,
328328- mut host_schedule: HashMap<Arc<Url>, u64>,
329329-) -> Result<(u64, HashMap<Arc<Url>, u64>)> {
320320+ now: SystemTime,
321321+ interval: Duration,
322322+ mut host_schedule: HashMap<Arc<Url>, SystemTime>,
323323+) -> Result<(u64, HashMap<Arc<Url>, SystemTime>)> {
330324 let mut count: u64 = 0;
331331- let meta_interval = interval_ms * REQUESTS_PER_RESYNC;
325325+ let meta_interval = interval * REQUESTS_PER_RESYNC as u32;
332326 for (did, pds) in items {
333327 let newly_inserted = storage::repo::ensure_repo(db, &did)?;
334328 if newly_inserted {
335329 let last = host_schedule.get(&pds).copied().unwrap_or(now);
336336- let ts = if last >= now {
330330+ let when = if last >= now {
337331 last + meta_interval
338332 } else {
339333 now
340334 };
341341- host_schedule.insert(pds, ts);
335335+ host_schedule.insert(pds, when);
342336 let item = ResyncItem {
343337 did,
344338 retry_count: 0,
345339 retry_reason: "backfill".to_string(),
346340 commit_cbor: vec![],
347341 };
348348- storage::resync_queue::enqueue(db, ts, &item)?;
342342+ storage::resync_queue::enqueue(db, when, &item)?;
349343 db.stats.repos_queued_total.fetch_add(1, Ordering::Relaxed);
350344 count += 1;
351345 }