stateright / stateright

A model checker for implementing distributed systems.

Home Page:https://docs.rs/stateright

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Relax trait bounds for messages and actor state

vitorenesduarte opened this issue · comments

Hi. I was upgrading to the latest version and noticed that new trait bounds were introduced (e.g. Ord for Actor::Message). If I understand correctly, this prevents the use of e.g. HashMap's in such messages. Would it be possible to relax these trait bounds?

(I tried to perform such change, but it turned out more complex than what I was expecting (probably because I'm not familiar with the codebase). If you have ideas on how to go about this, I can give it a try. Thanks.)

Hi @vitorenesduarte. Thanks for your interest in this library!

I'll look into removing the trait bound this weekend at the latest. In the meantime, the workaround would be to use a BTreeMap.

Now I remember why this was done.

States are converted to a fingerprint via Hash, and HashMap doesn't implement Hash. That means states must leverage hashable data structures such as BTreeMap/etc.

actor::system::Network in turn leverages BTreeSet, which forces messages to implement Ord. I lifted that constraint into Actor::Msg to highlight this earlier in the development process.

Please let me know if you see any holes in my reasoning, as I'd certainly like to minimize the number of constraints.

Thanks for taking a look at this. What you're saying matches exactly what I saw when I tried to remove both bounds. I leave two ideas below (although they might make little sense).

In order to maintain the current Network API (adding, removing, iterating Envelope's), I think that Network could become its own struct that internally stores a HashMap<(Id, Id), Vec<Msg>> (at least, that's what I was trying to do).

Regarding state fingerprints, if such concept is needed internally in stateright, maybe introduce a Fingerprint trait that is implemented for states that are Hash, but needs to be provided by the user in case states are not Hash? (Although, I'm not sure how I would implement this trait for the actor state I have).

A Fingerprint trait would be analogous to Hash, so we still need to decide how to hash a HashMap (even if we wrap it in another type). Presumably HashMap's current implementation is not amenable to this (at least not efficiently).

I'll be looking into alternative map-like data structures for use by models that minimize allocations during model checking, but it's not clear whether those will still require Ord.

I recommend adopting BTreeMap for now to unblock yourself. Will that work for your use case?

Converting all the HashMaps to BTreeMaps won't work for me. But no worries, I'm not blocked (working on other tasks). Thanks.
If you have ideas on how to proceed, even if you don't have the time, please let me know and I can try to do it.

Okay. Can you elaborate more on your constraints? That will help w/ deciding on viable solutions.

For example, if your concern is with BTreeMap performance at run time (real world run time, not model checking time), then you can retain HashMap as long as it's wrapped it in a type that implements Hash to facilitate model checking. The implementation of Hash wouldn't necessarily be efficient, but that wouldn't impact run time performance, only model checking performance (and the map size is usually small so it might be a non-issue for model checking as well).

Can you elaborate more on your constraints? That will help w/ deciding on viable solutions.

I'm building a framework for evaluating state-machine replication protocols (either through simulation or by actually running them on a real setting) and I thought it would be useful to also provide out-of-box model checking using stateright. Protocols implement the Protocol trait that has two associated types of interest: Message and Executor. Protocol instances exchange Messages in order to commit client commands. Once commands are committed, the Protocol instance outputs ordering constraints that are then used by the Executor to make sure that commands are executed in a consistent manner. I've started the work of mapping this trait to stateright's Actor trait here: https://github.com/vitorenesduarte/fantoch/blob/master/fantoch_mc/src/lib.rs. I couldn't finish it at the time because I also needed periodic local events (which I believe are already possible now).

I have no hard constraints, but requiring Protocol and Executor (which would be stored in the Actor state) to be Hash, and Message to be Ord is not ideal.

For example, if your concern is with BTreeMap performance at run time (real world run time, not model checking time), then you can retain HashMap as long as it's wrapped it in a type that implements Hash to facilitate model checking. The implementation of Hash wouldn't necessarily be efficient, but that wouldn't impact run time performance, only model checking performance (and the map size is usually small so it might be a non-issue for model checking as well).

Providing an inefficient Hash implementation looks like a good idea. The only downside is that it would have to be implemented for all Protocols and Executors even if not interested in model checking.

(BTW, you may have interest in this: https://github.com/spacejam/paxos/)

Thanks for the link @vitorenesduarte. Regarding the wrapper type approach to avoid an Ord constraint: I started coding this up, and it looks like a viable solution. Aiming to complete a proof of concept during the upcoming weekend.

@vitorenesduarte, thank you again for reaching out about this issue. It should be resolved with 2c38902

@jonnadal Thanks for looking into this

@vitorenesduarte My pleasure. I added https://github.com/vitorenesduarte/fantoch to my "watch" list and look forward to seeing how the project progresses!

@jonnadal Awesome, great to hear that! If you have any suggestions, I would love to know.