Find the divergence point between our cached view and the remote's actual state using binary search on Merkle states. Returns the sequence number at which divergence begins. All entries before this point are identical between cache and remote. # Algorithm 1. Check if the last cached state matches the remote's current state. If yes, we're already in sync — return `last + 1`. 2. Otherwise, binar
(&mut self, view: &str)
| 489 | /// Each round-trip is a single `GET ?view={s}&state=` request that |
| 490 | /// returns three values: `(position, merkle, tag_merkle)`. |
| 491 | async fn dichotomy_changelist(&mut self, view: &str) -> RemoteResult<u64> { |
| 492 | // If cache is empty, divergence is at the beginning |
| 493 | let last_seq = match self.cache.last_sequence() { |
| 494 | Some(seq) => seq, |
| 495 | None => { |
| 496 | debug!("dichotomy: cache is empty, starting from 0"); |
| 497 | return Ok(0); |
| 498 | } |
| 499 | }; |
| 500 | |
| 501 | let last_state = match self.cache.last_merkle_state() { |
| 502 | Some(s) => s.to_string(), |
| 503 | None => return Ok(0), |
| 504 | }; |
| 505 | |
| 506 | debug!( |
| 507 | "dichotomy: cache has {} entries, last_seq={}, last_state={}", |
| 508 | self.cache.len(), |
| 509 | last_seq, |
| 510 | &last_state[..8.min(last_state.len())] |
| 511 | ); |
| 512 | |
| 513 | // Check if we're already in sync by comparing the last state |
| 514 | let remote_state = self.remote.get_state(view).await?; |
| 515 | self.stats.dichotomy_comparisons += 1; |
| 516 | |
| 517 | match &remote_state { |
| 518 | StateResponse::State { merkle, .. } if *merkle == last_state => { |
| 519 | debug!("dichotomy: already in sync at seq {}", last_seq); |
| 520 | return Ok(last_seq + 1); |
| 521 | } |
| 522 | StateResponse::Empty => { |
| 523 | debug!("dichotomy: remote view is empty"); |
| 524 | return Ok(0); |
| 525 | } |
| 526 | _ => { |
| 527 | debug!("dichotomy: states differ, starting binary search"); |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | // Binary search for the divergence point |
| 532 | let mut lo: u64 = 0; |
| 533 | let mut hi: u64 = last_seq; |
| 534 | |
| 535 | while lo < hi { |
| 536 | let mid = (lo + hi) / 2; |
| 537 | |
| 538 | // Get the Merkle state at the midpoint from our cache |
| 539 | let cached_state = match self.cache.get_state(mid) { |
| 540 | Some(s) => s.to_string(), |
| 541 | None => { |
| 542 | // Gap in cache — we can't compare, assume divergence is here or earlier |
| 543 | debug!( |
| 544 | "dichotomy: gap in cache at {}, narrowing to [{}, {}]", |
| 545 | mid, lo, mid |
| 546 | ); |
| 547 | hi = mid; |
| 548 | continue; |
no test coverage detected