Closed HCanber closed 10 years ago
The Stash implementation I put together initially is very quick and dirty - needed it for a bunch of the system actors responsible for remoting (namely the protocol state actors), since they have to stash incoming messages while they wait for the handshake process to finish.
The biggest issue that needs to be fixed, as you point out, is being able to prepend messages to the front of the mailbox so we can try to preserve the order of the messages. Not possible to do at the moment without changing the mailbox implementation itself.
As for the canonical Akka implementation, I originally tried implementing this structure in Hyperion before I joined forces with Roger to work on Akka.NET. The original Akka implementation is very complicated. I don't know why they implemented it the way they did - maybe some of it was for performance optimization or backwards compatibility with older versions. Or maybe the person who wrote it had a strong passion for traits of traits of interfaces.
I broke it down like this when I was thinking about your discussion area this morning:
I don't have a strong opinion on question 1 just yet, but I'm leaning towards "yes" for question 2.
I feel like it's less expensive to just make mailboxes that always support stashing versus implementing (1) mailboxes that optionally do or don't support stashing, (2) configuration overhead for specifying what type of underlying data structure to use for the mailbox, (3) validation work to ensure that actors who require stashing don't get configured to use a mailbox or queue that doesn't support stashing, and (4) re-implementing the entire mailbox creation process.
After going over Akka JVM's implementation over and over again for hours, I actually think I got it sorted out. :) (Note: I think :). As you say, there are a traits upon traits... I think I can simplify it a bit, so I'll take a stab at it.
In their implementation, there is only one Mailbox used (well, actually one all-purpose, and three used for specific purposes: SharingMailbox for BalancingDispatcher; DeadletterMailbox; CallingThreadMailbox for CallingThreadDispatcher) but many MessageQueue implementations. These are rather small and easy to implement.
Regarding your remarks:
I'll make a try and see how it goes. :)
Go for it - if you can simplify items 1-4, then it's probably worthwhile making the tradeoffs.
Does the Deque need to be thread-safe? I see that the JVM implementation is using BlockingDeque in some places, and a normal Deque in others, and I'm not entirely sure why.
Isn't there always the possibility that multiple writers (including the actor itself, in the stashing case) will be appending or prepending to the queue at the same time?
@mattnischan I think the answer to that question depends on the mailbox implementation.
This is not implemented - any further stashing changes should be discussed on #429
This is now implemented, whoops.
We have stashing somewhat implemented. However it does not work as unstashing appends to the mailbox queue instead of prepends.
https://github.com/akkadotnet/akka.net/blob/dev/src/core/Akka/Actor/Stash.cs#L393
We need to add a mailbox that has this ability and make sure that it is used when the actor wants stash support.
In Akka JVM this is mainly handled in
Discussion
We have the abstract class
Mailbox
andConcurrentQueueMailbox
that uses ConcurrentQueue.Akka JVM also has Mailbox (a trait) that takes a MessageQueue in the constructor. There are many implementations of MessageQueue. Akka JVM has MailboxType which is a factory for creating mailboxes. It is a trait, and the concrete classes are the ones specified in the config.
The dispatcher is responsible for creating a mailbox.
Should we use the same separation?