美文网首页
ceph state machine

ceph state machine

作者: jerry_xr | 来源:发表于2017-01-20 22:49 被阅读0次

    该系列文章主要记录阅读理解ceph代码时可能遇到的一些难点,可能跳跃比较大。如果有描述错误或任何疑问欢迎交流讨论。

    状态机本身机制是比较好理解的,看状态机代码时只要理解几个特殊的地方就很容易。

    默认子状态

    状态机的部分状态有默认子状态,从该状态到其默认子状态是不需要事件触发的。比如:

    struct Primary : boost::statechart::state< Primary, Started, Peering >, NamedState
     {
         Primary(my_context ctx);
         void exit();
    
        typedef boost::mpl::list <
           boost::statechart::custom_reaction< ActMap >,
               boost::statechart::custom_reaction< MNotifyRec >,
               boost::statechart::transition< NeedActingChange, WaitActingChange >
         > reactions;
         boost::statechart::result react(const ActMap&);
         boost::statechart::result react(const MNotifyRec&);      
    };               
    

    这里定义了Primary状态,其父状态是Started,默认子状态是Peering。因而从Primary进入Peering状态不需要任何事件触发。

    状态跳转

    状态机是由事件驱动的,定义事件的响应方法有2种方式。

    • 注册事件处理函数,比如上面Primary在处理ActMap事件就注册了boost::statechart::result react(const ActMap&)函数。
    • 跳转到另一个状态。比如上面Primary处理NeedActingChange事件。

    在事件处理中直接跳转状态是一种方式。
    还有一种状态跳转方式,就是显式的调用transit。比如:

    boost::statechart::result PG::RecoveryState::Reset::react(const ActMap&)
    {
        PG *pg = context< RecoveryMachine >().pg;
        ...
    
        ...
        pg->update_heartbeat_peers();
        pg->take_waiters();
    
        return transit< Started >();
    }
    

    事件处理

    注意事件不一定都是在当前状态下处理,如果当前状态处理不了,可以在其父状态处理,相当于子状态继承了父状态的事件处理方法。

    这里还有一个小疑问,我们看到有些地方执行post_event, 这些event是什么时候由谁执行的呢? 可以想象应该是状态机在处理完当前事件之后就开始执行了。查看boost源码也确实如此。
    post_event的实现:

    void post_event_impl( const event_base_ptr_type & pEvent )
    {
       BOOST_ASSERT( get_pointer( pEvent ) != 0 );
       eventQueue_.push_back( pEvent );
    }
    

    eventQueue_是在process_event中循环处理的。

    void process_event( const event_base_type & evt )
    {
      if ( send_event( evt ) == detail::do_defer_event )
      {
        deferredEventQueue_.push_back( evt.intrusive_from_this() );
      }
    
      process_queued_events();
    }
    
    void process_queued_events()
    {
      while ( !eventQueue_.empty() )
      {
        event_base_ptr_type pEvent = eventQueue_.front();
        eventQueue_.pop_front();
    
        if ( send_event( *pEvent ) == detail::do_defer_event )
        {
          deferredEventQueue_.push_back( pEvent );
        }
      }
    }
    

    有了上面的基础之后,再去找各种状态是怎么变化的就非常简单了。

    状态机的事务

    还有一点对于理解ceph状态机也比较重要,我们经常看到状态内部执行事务,但是没看到事务在哪里提交。答案在这里:

    if (!advance_pg(curmap->get_epoch(), pg, handle, &rctx, &split_pgs))
    {
        // we need to requeue the PG explicitly since we didn't actually
        // handle an event
        peering_wq.queue(pg);
    }
    else
    {
        assert(!pg->peering_queue.empty());
        PG::CephPeeringEvtRef evt = pg->peering_queue.front();
        pg->peering_queue.pop_front();
        pg->handle_peering_event(evt, &rctx);
    }
    need_up_thru = pg->need_up_thru || need_up_thru;
    same_interval_since = MAX(pg->info.history.same_interval_since,
                              same_interval_since);
    pg->write_if_dirty(*rctx.transaction);
    if (!split_pgs.empty())
    {
        rctx.on_applied->add(new C_CompleteSplits(this, split_pgs));
        split_pgs.clear();
    }
    dispatch_context_transaction(rctx, pg, &handle);
    

    就在最后一行。

    然后,好像没了,自己对着状态机那个图研究吧 : )

    相关文章

      网友评论

          本文标题:ceph state machine

          本文链接:https://www.haomeiwen.com/subject/shgwbttx.html