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 HashMap
s to BTreeMap
s 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 Message
s 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 retainHashMap
as long as it's wrapped it in a type that implementsHash
to facilitate model checking. The implementation ofHash
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 Protocol
s and Executor
s 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.