2-状态机
boost::statechart
Ceph在处理PG的状态转换时,使用了boost库提供的statechart状态机。因此,这里先简单介绍一下statechart状态机的基本概念和涉及的相关知识,以便更好地理解Peering过程PG的状态转换流程。
3.1 状态
在statechart里,状态的定义有两种方式:
没有子状态情况下的状态定义:
struct Reset : boost::statechart::state< Reset, RecoveryMachine >, NamedState { };
定义一个状态需要继承boost::statechart::simple_state或者boost::statechart::state类。上面Reset状态继承了boost::statechart::state类。该类的模板参数中,第一个参数为状态机自己的名字Reset,第二个参数为所属状态机的名字,表明Reset是状态机RecoveryMachine的一个状态。
有子状态情况下的状态定义:
struct Start; struct Started : boost::statechart::state<Started, RecoveryMachine, Start>, NamedState { };
状态Started
也是状态机RecoveryMachine的一个状态,模板参数中多了一个参数Start
,它是状态Started
的默认初始子状态,其定义如下:
struct Start : boost::statechart::state<Start, Started>, NamedState { };
上面定义的状态Start
是状态Started的子状态。第一个模板参数是自己的名字,第二个模板参数是该子状态所属父状态的名字。
综上所述,一个状态,要么属于一个状态机,要么属于一个状态,成为该状态的子状态。其定义的模板参数是自己,第二个模板参数是拥有者,第三个模板参数是它的起始子状态。
1.2 事件
状态能够接收并处理事件。事件可以改变状态,促使状态发生转移。在boost库的statechart状态机中定义事件的方式如下所示:
struct QueryState : boost::statechart::event<QueryState> { };
QueryState为一个事件,需要继承boost::statechart::event类,模板参数为自己的名字。
1.2.1状态响应事件
在一个状态内部,需要定义状态机处于当前状态时,可以接受的事件以及如何处理这些事件的方法:
#define TrivialEvent(T) struct T : boost::statechart::event< T > { \ T() : boost::statechart::event< T >() {} \ void print(std::ostream *out) const { \ *out << #T; \ } \ }; TrivialEvent(Initialize) TrivialEvent(Load) TrivialEvent(NullEvt) struct Initial : boost::statechart::state< Initial, RecoveryMachine >, NamedState { explicit Initial(my_context ctx); void exit(); typedef boost::mpl::list < boost::statechart::transition< Initialize, Reset >, boost::statechart::custom_reaction< Load >, boost::statechart::custom_reaction< NullEvt >, boost::statechart::transition< boost::statechart::event_base, Crashed > > reactions; boost::statechart::result react(const Load&); boost::statechart::result react(const MNotifyRec&); boost::statechart::result react(const MInfoRec&); boost::statechart::result react(const MLogRec&); boost::statechart::result react(const boost::statechart::event_base&) { return discard_event(); } };
1.2.2 可处理的事件及处理对应事件的方法
上述代码列出了状态RecoveryMachine/Initial可以处理的事件列表和处理对应事件的方法:
1) 通过boost::mpl::list定义该状态可以处理多个事件类型。在本例中可以处理Initialize
、Load
、NullEvt
和event_base
事件。
2)简单事件处理
boost::statechart::transition<Initialize, Reset>
定义了状态Initial接收到事件Initialize后,无条件直接跳转到Reset状态;
3) 用户自定义事件处理: 当接收到事件后,需要根据一些条件来决定状态如何转移,这个逻辑需要用户自己定义实现
boost::statechart::custom_reaction<Load>
custom_reaction定义了一个用户自定义的事件处理方法,必须有一个react()的处理函数处理对应该事件。状态转移的逻辑需要用户自己在react函数里实现:
boost::statechart::result react(const Load&);
1.3 statechart示例
1. boost::statechart示例代码:
// Example program
#include <iostream>
#include <string>
#include <boost/statechart/custom_reaction.hpp>
#include <boost/statechart/event.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/event_base.hpp>
#define TrivialEvent(T) struct T : boost::statechart::event< T > { \
T() : boost::statechart::event< T >() {} \
void print(std::ostream *out) const { \
*out << #T; \
} \
};
TrivialEvent(Initialize)
TrivialEvent(Load)
TrivialEvent(NullEvt)
TrivialEvent(GoClean)
struct MInfoRec : boost::statechart::event< MInfoRec>
{
std::string name;
MInfoRec(std::string name): name(name){
}
void print() {
std::cout<<"MInfoRec: "<<name<<"\n";
}
};
struct MLogRec : boost::statechart::event<MLogRec>
{
std::string name;
MLogRec(std::string name): name(name) {
}
void print() {
std::cout<<"MLogRec: "<<name<<"\n";
}
};
struct MNotifyRec : boost::statechart::event<MNotifyRec>
{
std::string name;
MNotifyRec(std::string name): name(name){
}
void print() {
std::cout<<"MNotifyRec: "<<name<<"\n";
}
};
struct Initial;
struct RecoveryMachine : boost::statechart::state_machine< RecoveryMachine, Initial> {};
struct Reset;
struct Crashed : boost::statechart::state<Crashed, RecoveryMachine>
{
explicit Crashed(my_context ctx) : my_base(ctx) {
std::cout << "Hello, Crashed!\n";
}
};
struct Initial : boost::statechart::state< Initial, RecoveryMachine>
{
typedef boost::mpl::list<
boost::statechart::transition<Initialize, Reset>,
boost::statechart::custom_reaction<Load>,
boost::statechart::custom_reaction<NullEvt>,
boost::statechart::transition<boost::statechart::event_base, Crashed>> reactions;
explicit Initial(my_context ctx) : my_base(ctx) {
std::cout << "Hello, Initial!\n";
}
boost::statechart::result react(const Load& l) {
return transit<Reset>();
}
boost::statechart::result react(const MNotifyRec& notify) {
std::cout<<"Initial::react::MLogRec!\n";
return discard_event();
}
boost::statechart::result react(const MInfoRec& i) {
std::cout<<"Initial::react::MNotifiyRec!\n";
return discard_event();
}
boost::statechart::result react(const MLogRec& log) {
std::cout<<"Initial::react::MLogRec!\n";
return discard_event();
}
boost::statechart::result react(const boost::statechart::event_base&) {
std::cout << "Initial event_base processed!\n";
return discard_event();
}
void exit() {
std::cout << "Bye, Initial!\n";
}
};
struct Reset : boost::statechart::state<Reset, RecoveryMachine>
{
explicit Reset(my_context ctx) : my_base(ctx) {
std::cout << "Hello, Reset!\n";
}
void exit() {
std::cout << "Bye, Reset!\n";
}
};
int main(int argc, char *argv[])
{
RecoveryMachine machine;
machine.initiate();
// machine.process_event(NullEvt()); //语句1
//machine.process_event(GoClean()); //语句2
//machine.process_event(MNotifyRec("notify record")); //语句3
return 0;
}
1 // Example program 2 #include <iostream> 3 #include <string> 4 #include <boost/statechart/custom_reaction.hpp> 5 #include <boost/statechart/event.hpp> 6 #include <boost/statechart/simple_state.hpp> 7 #include <boost/statechart/state.hpp> 8 #include <boost/statechart/state_machine.hpp> 9 #include <boost/statechart/transition.hpp> 10 #include <boost/statechart/event_base.hpp> 11 12 #define TrivialEvent(T) struct T : boost::statechart::event< T > { \ 13 T() : boost::statechart::event< T >() {} \ 14 void print(std::ostream *out) const { \ 15 *out << #T; \ 16 } \ 17 }; 18 19 TrivialEvent(Initialize) 20 TrivialEvent(Load) 21 TrivialEvent(NullEvt) 22 TrivialEvent(GoClean) 23 24 struct MInfoRec : boost::statechart::event< MInfoRec> 25 { 26 std::string name; 27 MInfoRec(std::string name): name(name){ 28 } 29 30 void print() { 31 std::cout<<"MInfoRec: "<<name<<"\n"; 32 } 33 }; 34 35 struct MLogRec : boost::statechart::event<MLogRec> 36 { 37 std::string name; 38 MLogRec(std::string name): name(name) { 39 } 40 41 void print() { 42 std::cout<<"MLogRec: "<<name<<"\n"; 43 } 44 }; 45 46 struct MNotifyRec : boost::statechart::event<MNotifyRec> 47 { 48 std::string name; 49 MNotifyRec(std::string name): name(name){ 50 } 51 52 void print() { 53 std::cout<<"MNotifyRec: "<<name<<"\n"; 54 } 55 }; 56 57 struct Initial; 58 struct RecoveryMachine : boost::statechart::state_machine< RecoveryMachine, Initial> {}; 59 60 struct Reset; 61 62 struct Crashed : boost::statechart::state<Crashed, RecoveryMachine> 63 { 64 explicit Crashed(my_context ctx) : my_base(ctx) { 65 std::cout << "Hello, Crashed!\n"; 66 } 67 }; 68 69 struct Initial : boost::statechart::state< Initial, RecoveryMachine> 70 { 71 typedef boost::mpl::list< 72 boost::statechart::transition<Initialize, Reset>, 73 boost::statechart::custom_reaction<Load>, 74 boost::statechart::custom_reaction<NullEvt>, 75 boost::statechart::transition<boost::statechart::event_base, Crashed>> reactions; 76 77 explicit Initial(my_context ctx) : my_base(ctx) { 78 std::cout << "Hello, Initial!\n"; 79 } 80 81 boost::statechart::result react(const Load& l) { 82 return transit<Reset>(); 83 } 84 85 boost::statechart::result react(const MNotifyRec& notify) { 86 std::cout<<"Initial::react::MLogRec!\n"; 87 return discard_event(); 88 } 89 90 boost::statechart::result react(const MInfoRec& i) { 91 std::cout<<"Initial::react::MNotifiyRec!\n"; 92 93 return discard_event(); 94 } 95 96 boost::statechart::result react(const MLogRec& log) { 97 std::cout<<"Initial::react::MLogRec!\n"; 98 99 return discard_event(); 100 } 101 102 boost::statechart::result react(const boost::statechart::event_base&) { 103 std::cout << "Initial event_base processed!\n"; 104 return discard_event(); 105 } 106 107 void exit() { 108 std::cout << "Bye, Initial!\n"; 109 } 110 }; 111 112 struct Reset : boost::statechart::state<Reset, RecoveryMachine> 113 { 114 explicit Reset(my_context ctx) : my_base(ctx) { 115 std::cout << "Hello, Reset!\n"; 116 } 117 118 void exit() { 119 std::cout << "Bye, Reset!\n"; 120 } 121 }; 122 123 int main(int argc, char *argv[]) 124 { 125 RecoveryMachine machine; 126 127 machine.initiate(); 128 129 // machine.process_event(NullEvt()); //语句1 130 131 //machine.process_event(GoClean()); //语句2 132 133 //machine.process_event(MNotifyRec("notify record")); //语句3 134 135 return 0; 136 }
上面的示例与PG中对于Initial状态的处理类似,下面我们来看一下分别执行上述语句时的打印情况:
单独执行语句1:
单独执行语句2:
单独执行语句3: