Isn't it said that perfection is achieved when there is nothing left to take away ;)<br><br><div><br><div>J.</div><div><br><div class="gmail_quote">2008/10/29 Joel Reymont <span dir="ltr"><<a href="mailto:joelr1@gmail.com">joelr1@gmail.com</a>></span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><a href="http://tinyurl.com/5exq4c" target="_blank">http://tinyurl.com/5exq4c</a><br>
<br>
This is the final architecture as I'm sick of rewriting the thing and<br>
I don't think I can simplify it further!<br>
<br>
The first version I wrote back in 2005 used processes for everything.<br>
Seats, games, players, bots, games, pots, hands, all were processes.<br>
Moreover, they were all gen_servers.<br>
<br>
My cardgame "uber gen_fsm" was of particular interest and gave me the<br>
ability to put a stack of gen_fsm modules together. The cardgame<br>
driver would pop modules off the stack as they finished and modules<br>
could also tell the driver to re-run them, restart from the top of the<br>
full stack or go to the last module.<br>
<br>
The implementation was fugly but gave me the ability to put card game<br>
logic together from a set of betting, card dealing, etc. modules.<br>
Texas Hold'em, for example, uses a stack that looks like this:<br>
wait_for_players, blinds, deal_cards, betting, deal_cards, etc.<br>
<br>
Another feature was mapping process ids to integers by using<br>
gen_server:call on the pid at serialization time and looking up the<br>
integer in Mnesia when interpreting the packets.<br>
<br>
Last but not least, games freely gen_server:called players and vise<br>
versa, a recipe for disaster as I discovered under very high load.<br>
Yes, Virginia you can deadlock in Erlang!<br>
<br>
A great example of deadlock waiting to happen is firing off a timer<br>
from a game process and asking the player process for its id while the<br>
player is waiting for something from the game after a gen_server:call<br>
of its own.<br>
<br>
There are only two process types left in this latest version of<br>
OpenPoker: games and players. State machine logic is integrated into<br>
the game gen_server and I'm happy to say that the implementation is<br>
beautiful and still uses a stack of modules, albeit much smaller and<br>
simpler.<br>
<br>
Game gen_servers never ever call players and all processes are<br>
globally registered as {game, N} and {player, N} respectively. All<br>
packets go out with the integer ids in them since they are known at<br>
the source. Incoming messages are simply addressed to {player,<br>
<integer id}. This works, scales and is darn fast! It does rely on the<br>
"global" infrastructure but it hasn't let me down yet.<br>
<br>
Everything else is just record "mutation", no message passing<br>
whatsoever.<br>
<br>
I'm throwing down the gauntlet here. I'll bloody switch to Lisp and<br>
libevent-based single-threaded servers if this OpenPoker cannot handle<br>
mover than 10k games and 50K players on a single server!<br>
<font color="#888888"><br>
--<br>
<a href="http://wagerlabs.com" target="_blank">wagerlabs.com</a><br>
<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
<a href="http://www.erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://www.erlang.org/mailman/listinfo/erlang-questions</a><br>
</font></blockquote></div><br>-- <br><br>J.!<br><a href="mailto:jeansagi@gmail.com">jeansagi@gmail.com</a><br><a href="mailto:jeansagi@myrealbox.com">jeansagi@myrealbox.com</a><br>
</div></div>