[Interest] serialization of QStateMachine for recovery mode

K. Frank kfrank29.c at gmail.com
Sat Oct 12 00:47:35 CEST 2013


Hi Ingmar!

On Fri, Oct 11, 2013 at 3:51 PM, Wegner <> wrote:
> Hi Mandeep and K.Frank!
> ...
>>> Let's take a over-simplified SM.
>>>
>>> A->B->C->D
>>>
>>> now if the app crashed while it was state C, on restarting the app, I
>>> don't
>>> see a legal way of directly taking the SM to C, other than replaying the
>>> events that caused transitions to it.
>>> ...
>> ...
>> It's reasonable to imagine that your state-machine framework
>> can do something (or can be modified to do something) like
>> this:
>>
>>     myStateMachine.state = stateC;
>
> In general such a call would be against any finite state machine structure,
> right? For safety I would set this method as a very rare used friend method
> in order to prevent misuse.

Yes, this approach steps outside of the formal state-machine
paradigm.  But my advice would be not to be overly doctrinaire
about things, and consider this as a possibility.

After all, the notion would be to use this for recovery, where you
have already stepped outside the normal operation of your program.

>> ...
>> If your state-machine framework won't let you do this, or if you
>> prefer to live within the formal approach of events and transitions,
>> then you could add some helper events and transitions to your
>> state machine.  Let's say that your state machine gets initialized
>> to startState.  Then you could add:
>>
>>        event      transition
>>
>>        goToA:   startState --> stateA
>>        goToB:   startState --> stateB
>>        goToC:   startState --> stateC
>>        goToD:   startState --> stateD
>>
>> Then at startup, if you're in recovery mode, you would do
>> something like;
>>
>>     myStateMachine.postEvent (goToC);
>> ...
>
> Well, in general I would consider working with this approach

I think this approach is sound, so I wouldn't advise against it.

> and
> automatically adding those transitions between the start state and all other
> states. QTransition could be derived to QRecoveryTransition that throws only
> if a QRecoveryEvent is posted.
> But then we would need to keep some kind of a reference to the current state
> within the state machine. And I saw no opportunity to address the current
> state in QSM. Automatically adding a unique ID might help here...

Yes.  If your recovery strategy is to persist state to recoverable
storage, then you need to know what your state is.  Again, not
in the specific context of the Qt state-machine framework:

One way to implement a state machine is to store the state as a value,
say an enum or other integral value.  If your framework works this way,
then you "know" your state, and can persist it by simply writing that
value to recoverable storage.

But another approach (used in the classic object-oriented state pattern)
is to record your state as a type -- the state is stored in a polymorphic
variable, and the specific state is determined by the specific subtype of
this polymorphic variable's current value.  In this case you don't "know"
directly what state you're in -- you have to rely on the polymorphic
behavior of the state variable and ask it to tell you what state it is.

That is, more concretely, your state object would have a member function,

   char getStateCode()

and state C's version of this member function would return, for example,
the code 'C'.  (Or, if your language or framework supports reflection, you
could ask the reflection system to tell you the current dynamic type of
the state variable.)

(My personal preference is to store the state of a state machine as a value.
I find the polymorphic-type approach to be a bit overly complicated for my
taste.  But both approaches work just fine.)

> But as my intention is to use this approach in a work flow driven
> application that takes care of building up a set of data I also will have to
> take care of keeping data and state machine consistent.
> If some data would be lost but the state machine is recovered to a later
> state then we would end up in an inconsistent state! So recovering any state
> without check of data is critical.

I would make the following comment:  This doesn't really mean that you
would do anything differently than what you are proposing -- it's just a
slightly different way of looking at things.

Consider the formal state of your state machine to be composed of two
pieces:  the conventional state (be it the dynamic type of a polymorphic
variable or an integral value), and what I've been calling "extended state
data."  (Note that the whole state ("conventional" plus "extended") is, in
general, needed to determine which transitions occur in response to
various events.  This happens if you use transition guards that depend
on the extended state data.)

If you look at your total state this way, then when you persist your
state, you persist both the "conventional" state and the extend state
data at the same time, and (unless you have a bug) they remain
consistent throughout the persistence-recovery process.

Again, this isn't any different than what you propose -- it's just a slightly
different way of looking at it.

> So my current approach is to recover the data and set up a special
> QRecoveryState/-Transition connection with guards on data elements that once
> an QRecoveryEvent is posted automatically goes all the way to the right
> state.
>
> Would that be a considerable approach?

Yes, very much so.  Again, I might use differently language to describe the
same thing:  I  would call your data "extended state data" and then say that
you recover the entire state ("conventional" state plus extended state data).
You then issue a QRecoveryEvent that triggers a transition to the specific
"conventional" state that you recovered from persistent storage.

Obviously, for any real system, the implementation will requires some
significant work, but I think the basic approach is sound.

> ...
> Best Regards,
> Ingmar


Good luck.


K. Frank



More information about the Interest mailing list