How does the session locks work in Moodle (part 2)?

In part 1 we have learned how the session locks work in PHP. Now let’s apply it in the Moodle context.

We start with the simplest possible Moodle page. We only bootstrap Moodle, start, sleep for 5 seconds and finish.

I have created page1.php and page2.php both with the same content:

require_once("config.php");

echo "Time start: " . date("H:i:s") . "<br />";
sleep(5);
echo "Time end: " . date("H:i:s") . "<br />";

And then I have opened both in separate tabs. One after another. The results:

Time start: 17:21:50
Time end: 17:21:55
Time start: 17:21:55
Time end: 17:22:00

We can clearly see that the second script stated running only after the first one has finished. This is because Moodle has initiated the session while bootstraping. It happened when we included config.php.

Now let’s imitate the session_close() mechanism - in Moodle we can use manager::write_close():

require_once("config.php");

echo "Time start: " . date("H:i:s") . "<br />";
sleep(2);
core\session\manager::write_close();
sleep(3);
echo "Time end: " . date("H:i:s") . "<br />";

Now when I run both scrips:

Time start: 18:53:47
Time end: 18:53:52
Time start: 18:53:49
Time end: 18:53:54

I have launched both of them in the same second. This time my code in the second script started just 2 seconds after the first one.

Closing the session is used in Moodle in several places. For example the last lines of the code in file.php - a script that is used to send a file to user, are:

// ========================================
// finally send the file
// ========================================
\core\session\manager::write_close(); // Unlock session during file serving.
send_stored_file($file, null, $CFG->filteruploadedfiles, $forcedownload);

This makes sense - imagine what would happen if sending a big file for the download would keep the session locked! A teacher would not be able to access any other page while downloading that big PDF assignment file.

The default and simplest implementation of session and session locks in your LAMP stack is the default PHP implementation - which means file based sessions. Moodle overwrites the location of the PHP session files, and you can find them in moodle_data/sessions directory. This is implemented in \core\session\file class.

If I run page1.php and page2.php at the same time, and I know the name of the session file, I can interrogate it on the server side:

 sudo fuser sess_k8pm2bug3rkk93ldhvu47aih62 
/opt/data/vanilla39/sessions/sess_k8pm2bug3rkk93ldhvu47aih62:  9944  9953

 sudo lsof sess_k8pm2bug3rkk93ldhvu47aih62  
COMMAND  PID     USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
apache2 9944 www-data   13u   REG  259,6     4900 16132983 sess_k8pm2bug3rkk93ldhvu47aih62
apache2 9953 www-data   13uW  REG  259,6     4900 16132983 sess_k8pm2bug3rkk93ldhvu47aih62

fuser is showing me the IDs of the processes using the file. From lsof we can see that process 9953 has currently the session lock - as it has the writeable flag (W) set. So apache2 process 9944 must be waiting for the lock.

As administrator, you can go to “Site administration -> Server -> Session handling” and set “Use database for session information” (dbsessions). This will change the implementation of sessions to class:
\core\session\database

Now the session locks are handled by the database. Each driver will implement its own method, for example MySQL uses its RELEASE_LOCK() and PostgreSQL uses pg_advisory_lock() function.

There are other implementations of sessions, like memcached or redis. To switch to those, you need to configure $CFG->session_handler_class in config.php.

Have a look at the last part 3.