Tuesday, December 15, 2009

Erlang as Session Storage for PHP

In the last few days I been playing with the PHP extension mypeb which allows us to connect to Erlang from PHP. As a simple example to show what we can do with this extension I will create a PHP class that will be used as the session_save_hanlder for PHP. By deafult PHP stores the sessions in the file system, but if you want to share the sessions over several servers, then we have to resort to using a database or Memcached. I will like to try something different by using this class to interact with an Erlang node that will act as the in memory storage for our sessions using ETS tables.

To modify the session_save_hanlder we have to call the function session_set_save_handler and provide there six callbacks that will be used for the following actions: opening and closing a session, reading and writing to the session, destroying the sessions and garbage collect the sessions. You can read more about this function in the PHP manual.

Let's start by creating the open callback. In our example, we will have a method ErlangSessionHandler::open that will connect to the Erlang node.

public function open($save_path, $session_name)
{
if(null === $this->link)
{
$this->link = peb_connect($this->host, $this->erlang_cookie, $this->conn_timeout);
if(!$this->link)
{
throw new Exception(sprintf("Can't connect to the erlang node %s using erlang_cookie %s", $this->host, $this->erlang_cookie));
}
}
return $this->link;
}

There we use the function peb_connect that expects three parameters, the host to connect to, the Erlang secret cookie and an optional connection timeout. This function will return a resource identifier of the connection or false on failure. For our basic example we will define those three parameters as members of the class ErlangSessionHandler like this:

protected $host = 'server@127.0.0.1';
protected $erlang_cookie = 'ABCDEFGHI';
protected $conn_timeout = 5;

The method ErlangSessionHandler::close is very straightforward:

public function close()
{
if(is_resource($this->link))
{
peb_close($this->link);
}
}

When called it will close the connection to the Erlang node by calling: peb_close passing the resource identifier as parameter.

Then we have ErlangSessionHandler::read

public function read($session_id)
{
$x = peb_encode("[~s]", array(array($session_id)));
$result = peb_rpc("session_handler", "read", $x, $this->link);
$rs = peb_decode($result);
$data = $rs[0];
return is_array($data) ? '' : $data;
}

This method will be passed the $session_id which we will forward to the Erlang node. To accomplish that first we need to create an Erlang Message by calling the function peb_encode, which expects a format string and the value we want to encode into that format. In our case we need a list which will contain our session id as only element. Once we encoded the variable we will send it to Erlang by calling peb_rpc. This function works similar to the Erlang rpc:call function. We need to specify the Module and the Function to call as the first two parameters. The third parameter is the message we want to send, and the last parameter is the result identifier. This function will return the result of the RPC call or false on error. The session information will be the first element of the $rs variable. In case of an error in the Erlang side, $data will be an array instead of a string, that's why we return and empty string in that case. Take into account that the session read callback must return an empty string in the case that there is no session information for the provided id.

Now lets see the code for the ErlangSessionHandler::write method.

public function write($session_id, $session_data)
{
$x = peb_encode("[~s, ~s]", array(array($session_id, $session_data)));
$result = peb_rpc("session_handler", "write", $x, $this->link);
unset($result);
return true;
}

This method expects two parameters, the session id and the information to store. The code here is pretty similar to the one for ErlangSessionHandler::read. We encode the PHP variables as Erlang terms and we send them to the session server via peb_rpc.

Session destroy is also similar to the implementation of read, but we call peb_rpc("session_handler", "destroy", $x, $this->link); instead of "read":

public function destroy($session_id)
{
$x = peb_encode("[~s]", array(array($session_id)));
$result = peb_rpc("session_handler", "destroy", $x, $this->link);
unset($result);
return true;
}

The code for ErlangSessionHandler::gc is also simple:

public function gc($max_expire_time)
{
$x = peb_encode('[~i]', array(array($max_expirte_time)));
$result = peb_rpc("session_handler", "gc", $x, $this->link);
$rs = peb_decode($result);
return $rs;
}

Then to use the our class as session_handler we add this to our PHP code.

$sh = new ErlangSessionHandler();

session_set_save_handler(
array($sh,"open"),
array($sh,"close"),
array($sh,"read"),
array($sh,"write"),
array($sh,"destroy"),
array($sh,"gc")
);

session_start();

Then the final piece of the puzzle is to start the Erlang Session Server that is implemented in the file session_handler.erl.

$ erl -sname server
(server@localhost)1> c(session_handler).
(server@localhost)1> session_handler:start().

And that's it. We can start playing with our Erlang Session Storage Server.

NOTE:

First I want to make clear that this code is not meant to be used in production systems. Is just an example of what can be done with the mypeb extension.

I'm planning in writing a more robust session server in Erlang using the Mnesia database as a way to provide more reliable storage. With Mnesia we can easily distribute the session data across multiple servers, and in some of them store the sessions to disc.

Regarding the session save handler code, I would like to port it into the mypeb extension as native C code along with some php.ini settings that can provide the Erlang node to connect to, the secret cookie, connection timeout, etc.

As a final step I would like to do a small clean up to the API of the mypeb extension.

5 comments:

mygamebest said...

IM is already there and with jabber really well done, why not define several additional personal information meta data and assign external urls/services what not to it, so you can browse your buddys and show all the information lotro gold from several different sources if you like (maybe even in a nice context based Mabinogi Gold plasmoid view). You could even get the relevant information Maple story mesos from other services (local and private ones) hidden from the IM service, but only mapped by the client to your addressbook.

so .. lots Wow Power Leveling of good things, but the whole “it sucks because our graphics Rom Gold layer Ragnarok Zeny sucks” thing has really got me by the balls.

When all the feathers are gone, when Buy Aion Gold the blue sky,aion power leveling we, white clouds, when grasslands are gone, Ling Po stood up,buy aion gold etc., his heart to absorb the magic Shiratori finished after the ready to set off for the fifth floor, just as the blue sky, white clouds of regret has been disappearing grassland ,buy aion gold making, and innate goodness was his burial. Yes, he has Aion Power Leveling figured out that several war down, all in all, just as it sounds exactly the same as if he did not kill those monsters, then Dofus Kamas this time he does not have the opportunity to stand up again .

mygamebest said...

Cool heart, and shot on the mercy Dragonica Gold of, Ling Po crazy way to EVE Isk kill, he began to love the taste of blood, like to see these cowardly FFXI GIL monsters in front of him like the poor, like the thrill of the muscles across the Bing Ren ... ...

He entered the 49th floor, the Lineage 2 Adena iron front of the room was familiar. The middle of the Last Chaos Gold room there is an old man sitting there, is close their eyes meditatively. It Knight Online Gold seemed that the advent of Ivy Ling Po do not know.

Ivy Ling Po stood there quietly, he Flyff Penya has felt the old man out of a strong body radiates a gas, he stared at the old man: "When I first arrived someone asked EQ2 Gold me to defeat the forty-nine-story monster, now left This last layer of the, no one thought was a powerful human masters, could I then, he 2Moons Dil takes a fight? "Ivy Ling Po Zi Cun," Although I experienced 48 times the fighting, but also learn many new moves can be With my present strength, but also far behind him, it appears was a World War II had.

mygamebest said...

"How do you no want to Cabal Alz know? For example,aion gold of, why you will enter Metin2 Yang into this devil's tower, for example, why you Perfect World gold would black light, such as ... ..."

Thank you for your timely buy wow gold consideration of this request and your rom gold leadership to move the renewable fuel industry into the 21st century. Please feel free to contact our offices if we can provide atlantica gold additional information on the importance of the biodiesel tax credit.

We write to last chaos gold urge quick passage of the knight online gold biodiesel tax credit as soon as the House begins the second session Knight Online Gold of the 111th Congress.

mygamebest said...

Noch nicht das Tor betrat, fühlte eve isk Po Ling Yi Gu Hitze auf den ersten Blick schnell nach unten, sein Gesicht brennenden Schmerzen. Block vor seiner metin2 yang Hände, sahen wir in ein Meer des Feuers. Es gibt in voller Flamme mannshoch, Flammen wow gold huschen, Wärme-Wellen, ungeheuerlich. "Ming ... ...", hörte ich rufen und von den Flammen im Inneren gehört. Ein ffxi gil großer Zahl in die Flammen zu sehen.

"Wie könnte die maple story mesos Dinosaurier ... ... ... ..." Lingbo aion power leveling dachte: "Sie sind aion kinah nicht ausgestorben, bevor lange, wie könnte dofus kamas hier?"

andre said...

Hi

Did you do any more work on erlang as a session storage for PHP? I'm interested in implementing this myself, and I've just found a copy of your post in the mypeb wiki, so I figured I could use your work as a starting point.

Thanks!