If chatroomread.php would directly support apc cache it would again become more scaleable.

Comments

Anonymous’s picture

how about this totally untested code idea?

its missing code to cache messages as they are read, and to put a user object in APC with a list of the chat's they have access to, but they would both be pretty simple. on a windoze machine, so no patch yet...

/**
 * Whether or not we have APC functionality.
 */
define('CHATROOM_APC_ENABLED', function_exists('apc_fetch'));

/**
 * @file
 * Process chatroom polling requests.
 *
 * This file is a performance hack, aimed at making moderately sized rooms
 * possible with this module.
 * 
 * The intent is to handle the polling requests from chatrooms without doing 
 * a full Drupal bootstrap unless absolutely necessary. All simple polling 
 * requests are handled by this script, as they are by far the most common 
 * type of request, and are very easy to check against a cache.
 *
 * First, we check to see if the last message seen in a given chat client-side
 * is older than the latest message in that chat server-side. 
 *
 * Only if the chat being polled has messages newer than what the requesting
 * client has seen do we bootstrap Drupal. 
 */

// We need the $latest_msg_id, $chat_id and $chat_cache_file to check the
// cache for this chat. 
if (!isset($_POST['latest_msg_id']) || !preg_match('/^\d+$/', $_POST['latest_msg_id'])) {
  exit;
}
$client_latest_msg_id = $_POST['latest_msg_id'];
$server_latest_message_id = FALSE;

if (!isset($_POST['chat_id']) || !preg_match('/^\d+$/', $_POST['chat_id'])) {
  exit;
}
$chat_id = $_POST['chat_id'];

if (!isset($_POST['chat_cache_directory']) || !is_dir($_POST['chat_cache_directory'])) {
  exit;
}
$chat_cache_file = $_POST['chat_cache_directory'] . '/chatroom.chat.' . $chat_id . '.cache';

if (!isset($_POST['skip_cache'])) {
  exit;
}
$skip_cache = $_POST['skip_cache'] == 1 ? TRUE : FALSE;

// We let the client signal that we should skip the cache. Right now we're 
// using this to make sure users last-seen time is updated, and there may 
// be more uses for it down the track.
if (!$skip_cache && file_exists($chat_cache_file)) {

  // Do a quick DoS check - we don't validate the path, so we have to make
  // sure we're not reading arbitrarily big files into memory. Our cache file 
  // should contain a single numeric id. So, if the file is bigger than 25 
  // bytes, something is fishy, and we should just bail out.
  $file_stats = stat($chat_cache_file);
  if ($file_stats['size'] > 25) {
    exit;
  }

  $server_latest_msg_id = trim(file_get_contents($chat_cache_file));
  if ($server_latest_msg_id == $client_latest_msg_id) {
    print json_encode(array('data' => array('cacheHit' => 1, 'messages' => array())));
    exit;
  }
}

if ($chat_user = chatroom_get_cached_user()) {
  if (in_array($chat_id, $chat_user->allowed_chats)) {
    // Try to get messages from our cache.
    if ($cached_messages = chatroom_get_cached_messages($chat_id, $client_latest_message_id)) {
      print json_encode(array('data' => array('cacheHit' => 1, 'messages' => $cached_messages)));
      exit;
    }
  }
}

/**
 * Get a cached user object to check access for the given chat.
 */
function chatroom_get_cached_user() {  
  if (!CHATROOM_APC_ENABLED) {
    return FALSE;
  }
  require_once './includes/bootstrap.php';
  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
  return apc_fetch('chatroom_user_cache_' . $_COOKIE[session_name()]);
}

/**
 * Get cached messages for the given chat newer than $client_latest_message_id.
 */
function chatroom_get_cached_messages($chat_id, $client_latest_message_id) {
  if (!CHATROOM_APC_ENABLED) {
    return FALSE;
  }
  $valid_cached_messages = array();
  if ($cached_messages = apc_fetch('chatroom_message_cache_' . $chat_id)) {
    foreach ($cached_messages as $message) {      
      if ($message->id > $client_latest_message_id) {
        $valid_cached_messages[] = $message;
      } 
    }
  }
  return $valid_cached_messages;
}

// Make this look like a normal request to Drupal, then execute index.php.
$_GET['q'] = "chatroom/chat/get/latest/messages/$chat_id/$client_latest_msg_id";
require_once './index.php';
Anonymous’s picture

Assigned: Unassigned »
Anonymous’s picture

working on this, patch coming soon. *much* faster now.

Anonymous’s picture

Status: Active » Needs review

i've committed early support for this:

http://drupal.org/cvs?commit=341232

much faster, please test.

miro_dietiker’s picture

Sounds cool, man! Going to test this ASAP in deep detail.

Farreres’s picture

@justinrandell: I have tested the dev version with apc cache support. It runs incredibly smooth and even more, now the php threads per chat copy aren't generated. It seens php is no more called to solve chat refresh. I have tried the same experiment as I did. I have opened 10 browser tabs all with the same chat and I have written a text in one of them. I have been checking ps to see if php was beeing called like before and no. I hope more people test it so possible bugs are detected, but this dev version should see stable state as soon as possible.

Anonymous’s picture

Status: Needs review » Fixed

closing, as i've released 6.x-2.8 with this feature included.

miro_dietiker’s picture

justinrandell - note that your 2.x-dev changes are not jet applied to 3.x-dev branch. This branch wasn't updated for a while (while i was confused you've committed this to 2.x - although you state 3.x was the feature branch regarding project page.)

Anonymous’s picture

@miro_dietiker yep, sorry for the confusion. are you using the dev branch? have you tried the new cache setup?

miro_dietiker’s picture

justinrandell - we're using a DRUPAL-6--2 checkout in production.
Any issues - if any - will/would be reported very soon. ;-)

miro_dietiker’s picture

Status: Fixed » Active

Justinrandell
I understand your implementation of the apc interface. However i wonder why we're not relying on drupal core cache_get and cache_set methods that are being bound to e.g. apc if you use some cache replacement like cacherouter.
This approach would allow us to support any caching mechanism that is supported by drupal and its extensions without chatroom specific code.
This might look like some further overhead as long as you don't enable any specific custom speedup cache like apc, memcached, .... Note it also supports filebased cache.

miro_dietiker’s picture

Status: Active » Fixed

OK, performance is the answer. Chatroom now has its own pluggable cache to be speedy. According to justinrandell it would need to bootstrap to a higher heavyer level to get drupal cache functions work.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.