Friday, June 20, 2014

Homemade Internet Service Relay (VI)


Before we proceed to the detailed design of the service, I must confess I screwed up in the initial versions. I underestimate how difficult it is to code this up. On one hand, there isn’t much logic at all, this is not graph matching algorithm, or assembly hacking techniques. On the other hand, there are many threads, and at any time there are incomplete messages, and error conditions. Complexity grows exponentially when all these get coupled together. We must decouple them.

My first revision involves re-thinking about concurrency. At its core our concurrency problem is about shared mutable states, and if we can be sure no such thing existed, we can freely code without concerning about concurrent edits.

Think about the human world, everyone thinks at the same time, that’s okay because brains are not shared, they don’t interfere. When a group of people work together, they talks and listen, and that message is shared. However, it is immutable and is therefore also safe. We can model our computation as such. Actors are objects that receives message, access it only by reading it, and can freely modify its own state. They can also send messages, but they never reach each other directly without going through messages. That way we can guarantee the no shared mutable state guarantee.

In typical actor system implementation – such as Akka, these constraints (e.g. always send message, don’t call methods, messages are immutable) are enforced by the framework though various means (e.g. encapsulating the actor object instances, staying immutable in a functional language, serializing the message), but in mine, it is only the spirit that is important. I enforced these constraint simply by following them myself, this is done so because they is no need to invest in a framework, and in general that is more performant.
Each actor is simply modeled as a concurrent safe queue of messages called a mailbox, each actor override the OnReceiveMessage() method to respond to the message object, make sure it don’t modify the message object, and that’s it. When a message is sent to an actor, if the actor is not already processing a message, a thread is requested from the ThreadPool and will call the OnReceiveMessage() on it.

Last but not least, an actor can voluntarily terminate itself, which is done by returning ActorContinuation.Done in the OnReceiveMessage call, otherwise the actor should return ActorContinuation.BlockOnReceive to get itself ready to process another message.

With this programming model, I can focus on the next level without worrying about concurrency now.

No comments :

Post a Comment