openraft 0.10.0-alpha.22

Advanced Raft consensus
Documentation
### What are the differences between Openraft and standard Raft?

These are protocol-level departures from the Raft paper. API conveniences
(extensible type config, split storage, manual triggers, lifecycle callbacks,
etc.) are covered elsewhere.


#### Election and `Vote`

- **`Vote` unifies `term` and `voted_for`.** Standard Raft tracks `currentTerm`
  and `votedFor` separately. Openraft combines them into a single
  partially-ordered [`Vote`][] value that drives every election and replication
  decision: a node grants a request iff the incoming `Vote` is greater than or
  equal to the last `Vote` it has seen. See [`Vote`][`Vote doc`].

- **Advanced-mode leader-id (default): multiple leaders per term.** Standard
  Raft elects at most one leader per term. Openraft's default leader-id is
  `(term, node_id)` and totally ordered, so multiple candidates may be granted
  in the same term — the last one wins. This minimizes election conflicts at
  the cost of embedding `node_id` in every [`LogId`][]. A standard-mode
  leader-id is available if the extra bytes matter. See [`leader_id`][].


#### Leader is not tied to voter role

Standard Raft requires the leader to be a voter in the current configuration.
In Openraft, leadership is determined solely by a committed [`Vote`][] —
Paxos-style — so a leader may be a learner or even a node outside the
membership. Voter/learner status only affects quorum counting, never the right
to lead.

This generalization rolls out in phases:

- **Phase A — supported.** A committed membership change demotes the leader to
  a learner or removes it from the membership entirely. The leader keeps
  replicating and committing until it steps down, and does not count itself in
  any quorum while non-voting. It also replicates the `membership-is-committed`
  message before stepping down, so the new configuration can operate without
  re-committing the membership log. See `RaftCore::current_leader` in
  `openraft/src/core/raft_core.rs`.

- **Phase B — not yet implemented.** A node that was never in the membership
  becomes a leader. This completes the generalization and is tracked on the
  roadmap.


#### Membership change

- **Extended joint consensus.** Standard Raft alternates uniform and two-config
  joint memberships (`c1 → c1c2 → c2`). Openraft's extended algorithm accepts
  arbitrary joint configs and reversion (`c1 → c1c2c3 → c3c4 → c4`, or
  `c1c2c3 → c1`), as long as the **old-new-intersect** constraint holds between
  adjacent memberships. See [`extended membership`][].

- **No single-step change.** Single-step membership change is a restricted
  subset of joint consensus; Openraft only exposes the joint variant, which can
  express any single-step transition and more.

- **`change_membership` is concurrency-safe.** Parallel calls may interleave
  and leave the cluster in a valid joint state. This is by design — it
  simplifies leader-crash recovery and lets the leader pivot if a target node
  becomes unreliable mid-transition.

  A membership log entry also takes effect the moment it appears in the log,
  not when it commits (the **use-at-once** constraint in
  [`extended membership`][]). This is what lets a leader keep serving after it
  has been demoted or removed by an uncommitted membership change.


#### Log and state

- **Committed log id is persisted.** Openraft lets the log storage persist the
  committed log id via [`RaftLogStorage::save_committed()`][]. On startup,
  previously-committed entries can be re-applied to the state machine without
  a fresh commit round. Standard Raft does not persist commit progress.

- **Restarted leader stays leader when possible.** After a restart, a node
  whose saved `Vote` still names itself as leader resumes the Leader role
  immediately, subject to lease checks. Standard Raft always restarts as a
  follower.


#### Read

- **`ReadIndex` without the blank-log round-trip.** Standard Raft requires the
  leader to commit a blank log entry at the start of its term before serving
  linearizable reads. Openraft uses the term's initial blank log id as
  `read_log_id` directly, skipping the extra round-trip. See
  [`Linearizable Read`][].

- **Lease-based linearizable read.** In addition to `ReadIndex`, Openraft
  offers [`ReadPolicy::LeaseRead`][], which confirms leadership via lease
  instead of a quorum heartbeat. See [`leader lease`][].

- **Linearizable follower read.** A follower may obtain `read_log_id` from the
  leader via application RPC, wait for its local state machine to catch up,
  then read locally — distributing read load without losing linearizability.
  See [`Linearizable Read`][].


[`Vote`]: `crate::vote::Vote`
[`Vote doc`]: `crate::docs::data::vote`
[`LogId`]: `crate::LogId`
[`leader_id`]: `crate::docs::data::leader_id`
[`extended membership`]: `crate::docs::data::extended_membership`
[`leader lease`]: `crate::docs::protocol::replication::leader_lease`
[`Linearizable Read`]: `crate::docs::protocol::read`
[`RaftLogStorage::save_committed()`]: `crate::storage::RaftLogStorage::save_committed`
[`ReadPolicy::LeaseRead`]: `crate::raft::ReadPolicy::LeaseRead`