Skip to content

Commit

Permalink
Doc: add algorithm AppendEntries uses to local last matching log id
Browse files Browse the repository at this point in the history
- Fix: #124
  • Loading branch information
drmingdrmer committed Jul 20, 2024
1 parent 0117ce5 commit c323974
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
51 changes: 51 additions & 0 deletions openraft/src/docs/protocol/log_replication.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,54 @@ R2 | 1-1 1-2 3-3
applies `2-3`.


## Algorithm to find the last matching log id on a Follower

When a Leader is established, it does not know which log entries are present on
Followers and Learners. Therefore, it must determine the last matching log ID on
each Follower before sending append-entries.

This process utilizes a binary search:

The Leader uses a span `[matching_log_id, first_conflict_index]` to search:
- The left bound is the last known matching log ID.
- The right bound is the index of the first known log that the Follower does not have.

This span is defined in `ProgressEntry`, which the Leader uses to track
replication progress for each Follower/Learner.

```rust,ignore
pub(crate) struct ProgressEntry<C> {
// Left bound
pub(crate) matching: Option<LogId<C::NodeId>>,
// Right bound
pub(crate) searching_end: u64,
}
```

### Algorithm steps:

- The Leader initializes the span as `[None, leader_last_log_index + 1]`.
Because the Leader is assumed to have all committed logs. Any logs after
`leader_last_log_index` are uncommitted and can be safely deleted.

- The Leader sends the log entry at the midpoint of `[ProgressEntry.matching.next_index(), ProgressEntry.searching_end]` to the Follower.

- If the log entry is accepted, update `ProgressEntry.matching` to the current log ID.

- If the log entry is rejected, update `ProgressEntry.searching_end` to the current log index.

- Repeat the process until `matching.next_index() == searching_end`.

By following these steps, the Leader can efficiently find the last matching log
ID on a Follower using binary search.

Notes:

- `ProgressEntry.matching.next_index()` refers to the index right after the last
known matching log ID.


[`ProgressEntry`]: crate::progress::entry::ProgressEntry


[binary search]: https://en.wikipedia.org/wiki/Binary_search_algorithm
7 changes: 5 additions & 2 deletions openraft/src/progress/entry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,11 @@ where C: RaftTypeConfig
/// Initialize a replication action: sending log entries or sending snapshot.
///
/// If there is an action in progress, i.e., `inflight` is not None, it returns an `Err`
/// containing the current `inflight` data
#[allow(dead_code)]
/// containing the current `inflight` data.
///
/// See: [Algorithm to find the last matching log id on a Follower][algo].
///
/// [algo]: crate::docs::protocol::replication::log_replication#algorithm-to-find-the-last-matching-log-id-on-a-follower
pub(crate) fn next_send(
&mut self,
log_state: &impl LogStateReader<C>,
Expand Down

0 comments on commit c323974

Please sign in to comment.