-
Notifications
You must be signed in to change notification settings - Fork 158
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
change: use snapshot-id to identify a snapshot stream
A snapshot stream should be identified by some id, since the server end should not assume messages are arrived in the correct order. Without an id, two `install_snapshot` request belonging to different snapshot data may corrupt the snapshot data, explicitly or even worse, silently. - Add SnapshotId to identify a snapshot stream. - Add SnapshotSegmentId to identify a segment in a snapshot stream. - Add field `snapshot_id` to snapshot related data structures. - Add error `RaftError::SnapshotMismatch`. - `Storage::create_snapshot()` does not need to return and id. Since the receiving end only keeps one snapshot stream session at most. Instead, `Storage::do_log_compaction()` should build a unique id everytime it is called. - When the raft node receives an `install_snapshot` request, the id must match to continue. A request with a different id should be rejected. A new id with offset=0 indicates the sender has started a new stream. In this case, the old unfinished stream is dropped and cleaned. - Add test for `install_snapshot` API.
- Loading branch information
1 parent
6409d10
commit 933e0b3
Showing
11 changed files
with
197 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
mod fixtures; | ||
|
||
use std::sync::Arc; | ||
|
||
use anyhow::Result; | ||
use async_raft::raft::InstallSnapshotRequest; | ||
use async_raft::Config; | ||
use async_raft::LogId; | ||
use async_raft::State; | ||
use fixtures::RaftRouter; | ||
use maplit::hashset; | ||
|
||
/// API test: install_snapshot with various condition. | ||
/// | ||
/// What does this test do? | ||
/// | ||
/// - build a stable single node cluster. | ||
/// - send install_snapshot request with matched/mismatched id and offset | ||
/// | ||
/// export RUST_LOG=async_raft,memstore,snapshot_ge_half_threshold=trace | ||
/// cargo test -p async-raft --test snapshot_ge_half_threshold | ||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)] | ||
async fn snapshot_ge_half_threshold() -> Result<()> { | ||
fixtures::init_tracing(); | ||
|
||
let config = Arc::new(Config::build("test".into()).validate().expect("failed to build Raft config")); | ||
let router = Arc::new(RaftRouter::new(config.clone())); | ||
|
||
let mut want = 0; | ||
|
||
tracing::info!("--- initializing cluster"); | ||
{ | ||
router.new_raft_node(0).await; | ||
|
||
router.wait_for_log(&hashset![0], want, None, "empty").await?; | ||
router.wait_for_state(&hashset![0], State::NonVoter, None, "empty").await?; | ||
|
||
router.initialize_from_single_node(0).await?; | ||
want += 1; | ||
|
||
router.wait_for_log(&hashset![0], want, None, "init leader").await?; | ||
router.assert_stable_cluster(Some(1), Some(want)).await; | ||
} | ||
|
||
let n = router.remove_node(0).await.ok_or_else(|| anyhow::anyhow!("node not found"))?; | ||
let req0 = InstallSnapshotRequest { | ||
term: 1, | ||
leader_id: 0, | ||
snapshot_id: "ss1".into(), | ||
last_included: LogId { term: 1, index: 0 }, | ||
offset: 0, | ||
data: vec![1, 2, 3], | ||
done: false, | ||
}; | ||
tracing::info!("--- install and write ss1:[0,3)"); | ||
{ | ||
let req = req0.clone(); | ||
n.0.install_snapshot(req).await?; | ||
} | ||
|
||
tracing::info!("-- continue write with different id"); | ||
{ | ||
let mut req = req0.clone(); | ||
req.offset = 3; | ||
req.snapshot_id = "ss2".into(); | ||
let res = n.0.install_snapshot(req).await; | ||
assert_eq!("expect: ss1+3, got: ss2+3", res.unwrap_err().to_string()); | ||
} | ||
|
||
tracing::info!("-- write from offset=0 with different id, create a new session"); | ||
{ | ||
let mut req = req0.clone(); | ||
req.offset = 0; | ||
req.snapshot_id = "ss2".into(); | ||
n.0.install_snapshot(req).await?; | ||
|
||
let mut req = req0.clone(); | ||
req.offset = 3; | ||
req.snapshot_id = "ss2".into(); | ||
n.0.install_snapshot(req).await?; | ||
} | ||
|
||
tracing::info!("-- continue write with mismatched offset is allowed"); | ||
{ | ||
let mut req = req0.clone(); | ||
req.offset = 8; | ||
req.snapshot_id = "ss2".into(); | ||
n.0.install_snapshot(req).await?; | ||
} | ||
Ok(()) | ||
} |
Oops, something went wrong.