[erlang-questions] OpenPoker v2: The bestest and most scalable poker server ever

10 views
Skip to first unread message

Joel Reymont

unread,
Oct 29, 2008, 11:15:46 PM10/29/08
to erlang-q...@erlang.org
http://tinyurl.com/5exq4c

This is the final architecture as I'm sick of rewriting the thing and
I don't think I can simplify it further!

The first version I wrote back in 2005 used processes for everything.
Seats, games, players, bots, games, pots, hands, all were processes.
Moreover, they were all gen_servers.

My cardgame "uber gen_fsm" was of particular interest and gave me the
ability to put a stack of gen_fsm modules together. The cardgame
driver would pop modules off the stack as they finished and modules
could also tell the driver to re-run them, restart from the top of the
full stack or go to the last module.

The implementation was fugly but gave me the ability to put card game
logic together from a set of betting, card dealing, etc. modules.
Texas Hold'em, for example, uses a stack that looks like this:
wait_for_players, blinds, deal_cards, betting, deal_cards, etc.

Another feature was mapping process ids to integers by using
gen_server:call on the pid at serialization time and looking up the
integer in Mnesia when interpreting the packets.

Last but not least, games freely gen_server:called players and vise
versa, a recipe for disaster as I discovered under very high load.
Yes, Virginia you can deadlock in Erlang!

A great example of deadlock waiting to happen is firing off a timer
from a game process and asking the player process for its id while the
player is waiting for something from the game after a gen_server:call
of its own.

There are only two process types left in this latest version of
OpenPoker: games and players. State machine logic is integrated into
the game gen_server and I'm happy to say that the implementation is
beautiful and still uses a stack of modules, albeit much smaller and
simpler.

Game gen_servers never ever call players and all processes are
globally registered as {game, N} and {player, N} respectively. All
packets go out with the integer ids in them since they are known at
the source. Incoming messages are simply addressed to {player,
<integer id}. This works, scales and is darn fast! It does rely on the
"global" infrastructure but it hasn't let me down yet.

Everything else is just record "mutation", no message passing
whatsoever.

I'm throwing down the gauntlet here. I'll bloody switch to Lisp and
libevent-based single-threaded servers if this OpenPoker cannot handle
mover than 10k games and 50K players on a single server!

--
wagerlabs.com

_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions

Rapsey

unread,
Oct 30, 2008, 4:27:16 AM10/30/08
to erlang-q...@erlang.org
Why R11B3?


Sergej

Joel Reymont

unread,
Oct 30, 2008, 4:40:54 AM10/30/08
to Rapsey, erlang-q...@erlang.org
It's R12B3, my bad. I suppose you can use R12B4 as well.

On Oct 30, 2008, at 8:27 AM, Rapsey wrote:

> Why R11B3?

Jean Sagi

unread,
Oct 30, 2008, 8:24:47 AM10/30/08
to Joel Reymont, erlang-q...@erlang.org
Isn't it said that perfection is achieved when there is nothing left to take away ;)


J.

2008/10/29 Joel Reymont <joe...@gmail.com>
Reply all
Reply to author
Forward
0 new messages