-
Notifications
You must be signed in to change notification settings - Fork 6
suffixの明示的な削除コードを追加(issue18対策) #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
b806512
suffixの明示的な削除コードを追加(issue18対策)
yuezato e60ba99
Merge branch 'master' into delete_io
yuezato a6e89c2
Followerでのhandle_timeoutでDelete中のタイムアウトは禁止する。禁止しない場合に問題と なる検証コードも付記
yuezato 9aea0b1
historyとlogにズレがある状態での状態遷移を防ぐ
yuezato ba7659a
テストケースの説明文を修正
yuezato 159c6a6
assertionの成立に関するコメントの更新
yuezato File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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,203 @@ | ||
use futures::{Async, Future}; | ||
|
||
use super::super::{Common, NextState, RoleState}; | ||
use super::{Follower, FollowerIdle}; | ||
use crate::log::LogPosition; | ||
use crate::message::{AppendEntriesCall, Message}; | ||
use crate::{Io, Result}; | ||
|
||
/// ローカルログの削除を行うサブ状態 | ||
pub struct FollowerDelete<IO: Io> { | ||
future: IO::DeleteLog, | ||
from: LogPosition, | ||
message: AppendEntriesCall, | ||
|
||
// 削除処理中にtimeoutしたかどうかを記録するフラグ。 | ||
// trueの場合は、削除処理後にcandidateに遷移する。 | ||
// falseの場合は、FollowerIdleに遷移する。 | ||
timeouted: bool, | ||
} | ||
|
||
impl<IO: Io> FollowerDelete<IO> { | ||
pub fn new(common: &mut Common<IO>, from: LogPosition, message: AppendEntriesCall) -> Self { | ||
let future = common.delete_suffix_from(from.index); | ||
FollowerDelete { | ||
future, | ||
from, | ||
message, | ||
timeouted: false, | ||
} | ||
} | ||
pub fn handle_message( | ||
&mut self, | ||
common: &mut Common<IO>, | ||
message: Message, | ||
) -> Result<NextState<IO>> { | ||
if let Message::AppendEntriesCall(m) = message { | ||
common.rpc_callee(&m.header).reply_busy(); | ||
} | ||
Ok(None) | ||
} | ||
pub fn run_once(&mut self, common: &mut Common<IO>) -> Result<NextState<IO>> { | ||
// logに対する削除が進行中であることを | ||
// commonに通知(フラグをセット)する。 | ||
common.set_if_log_is_being_deleted(true); | ||
|
||
if let Async::Ready(_) = track!(self.future.poll())? { | ||
track!(common.handle_log_rollbacked(self.from))?; | ||
|
||
// logに対する削除が完了し | ||
// common.historyとlogが一致したので | ||
// commonに通知する。 | ||
common.set_if_log_is_being_deleted(false); | ||
|
||
common | ||
.rpc_callee(&self.message.header) | ||
.reply_append_entries(self.from); | ||
|
||
if self.timeouted { | ||
Ok(Some(common.transit_to_candidate())) | ||
} else { | ||
let next = Follower::Idle(FollowerIdle::new()); | ||
Ok(Some(RoleState::Follower(next))) | ||
} | ||
} else { | ||
Ok(None) | ||
} | ||
} | ||
/// 削除処理中にtimeoutが発生した場合にそれを記録するためのメソッド | ||
pub fn set_timeout(&mut self) { | ||
self.timeouted = true; | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::test_dsl::dsl::*; | ||
|
||
#[test] | ||
#[rustfmt::skip] | ||
fn delete_test_scenario1() { | ||
use Command::*; | ||
use LogEntry::*; | ||
|
||
let a = NodeName(0); | ||
let b = NodeName(1); | ||
let c = NodeName(2); | ||
let (mut service, _cluster) = build_complete_graph(&[a, b, c]); | ||
|
||
interpret( | ||
&vec![ | ||
RunAllUntilStabilize, | ||
Timeout(a), | ||
RunAllUntilStabilize, | ||
// ここまでで a がリーダーになっている | ||
|
||
// 実際にリーダーになっていることを確認する | ||
Check(a, Pred::IsLeader), | ||
Check(b, Pred::IsFollower), | ||
Check(c, Pred::IsFollower), | ||
|
||
RecvBan(a, b), RecvBan(a, c), // aはbからもcからも受け取らない | ||
RecvBan(b, a), // bはaからは受け取らない | ||
RecvBan(c, a), // cはaからは受け取らない | ||
|
||
// aが孤立している状況で | ||
// データをproposeすることで | ||
// aにデータをためる | ||
Propose(a), Propose(a), Propose(a), | ||
|
||
// bとcは新しいTermへ移る準備(aのfollowを外す) | ||
Timeout(b), Timeout(c), RunAllUntilStabilize, | ||
|
||
// bを新しいリーダーにする | ||
Timeout(b), | ||
|
||
// bとcだけ適当な回数計算を進める | ||
Step(b), Step(c), | ||
Step(b), Step(c), | ||
Step(b), Step(c), | ||
Step(b), Step(c), | ||
Step(b), Step(c), | ||
Step(b), Step(c), | ||
|
||
// cを独立させる | ||
RecvBan(c, b), | ||
RecvBan(c, a), | ||
brly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
RunAllUntilStabilize, | ||
|
||
// 想定している状況になっていることを確認する | ||
Check(a, Pred::IsLeader), | ||
Check(b, Pred::IsLeader), | ||
Check(c, Pred::IsFollower), | ||
Check(a, Pred::RawLogIs(0, 0, vec![Noop(2), Com(2), Com(2), Com(2)])), | ||
Check(b, Pred::RawLogIs(0, 0, vec![Noop(2), Noop(4)])), | ||
Check(c, Pred::RawLogIs(0, 0, vec![Noop(2)])), // Noop(4)がないことに注意 | ||
|
||
// a<->b は通信可能にする | ||
RecvAllow(b, a), | ||
RecvAllow(a, b), | ||
|
||
// bからハートビートを送る | ||
Heartbeat(b), | ||
// メモリ上のlogとdisk上のlogにgapが生じるところまで進める | ||
Step(b), Step(a), | ||
Step(b), Step(a), | ||
Step(b), Step(a), | ||
Step(b), Step(a), | ||
|
||
// これは a のメモリ上のlogの終端位置が | ||
// 4にあって、その直前のtermが2であることを意味している | ||
Check(a, Pred::HistoryTail(2, 4)), | ||
|
||
// 一方で、既にDiskからは削除済みである | ||
Check(a, Pred::RawLogIs(0, 0, vec![Noop(2)])), | ||
|
||
// この状態のまま、aがタイムアウトしてしまうと | ||
// 上の食い違った状態でleaderになろうとする。 | ||
// | ||
// follower/mod.rs において handle_timeout で | ||
// Delete中のタイムアウトは禁止している場合は | ||
// このような場合を防ぐためであり、 | ||
// 以下のコードで問題は起きない。 | ||
// | ||
// 一方で、タイムアウトを許す場合は | ||
// 以下のコード(最後のStepAll)で問題が起こる。 | ||
|
||
// まず a<->c 間だけ通信を可能にする | ||
RecvAllow(a, c), | ||
RecvAllow(c, a), | ||
RecvBan(b, a), | ||
RecvBan(b, c), | ||
RecvBan(c, b), | ||
RecvBan(a, b), | ||
|
||
// aとcをタイムアウトさせて十分に実行させることで | ||
// 両者をcandidateにする | ||
Timeout(a), Timeout(c), StepAll(100), | ||
|
||
// そのあと、aがLeaderになれるようにTermを増やす手助け | ||
Timeout(a), | ||
|
||
// Delete中のタイムアウトを許していない場合 => aはfollowerのまま, cはcandidate | ||
// Delete中のタイムアウトを許している場合 => a も c も candidate になる | ||
// | ||
// Delete中の「タイムアウトを許可している場合」は、 | ||
// aがleaderとなった後で、 | ||
// メモリ上のlogと実体との差に起因するエラーが生じる。 | ||
// | ||
// 発生するエラーについて: | ||
// 今回は `impl_io::over_write` で | ||
// Disk上で「連続しないlog」を作成しようとしてエラーとなる。 | ||
// | ||
// RaftlogではDisk上のlogは | ||
// 論理上連続していることが仮定されているが | ||
// (IO traitのload_log methodの引数を参照せよ) | ||
// 仮にエラーとなる部分のassertionを外したとしても、 | ||
// 存在しない領域へのloadが発生し、どのみちエラーになる。 | ||
StepAll(100), | ||
], | ||
&mut service | ||
); | ||
} | ||
} |
This file contains hidden or 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 hidden or 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.