MyBB Community Forums

Full Version: Caching Problems...
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi everyone, I'm looking for some feedback from some fellow PHP developers.

First off, let me say that I am very focused on efficiency, specifically minimizing the bandwidth footprint, processing time, and memory size of my website. I have multiple services that run on a single server that constantly use bandwidth and processing power, so everything needs to be optimized.

Now, let's get to the problem. For my main page, I have created a custom script that pulls threads and comments from a specific forum. These display as "News". Now, the query that is used to pull this information from MySQL is rather complex, consisting of multiple JOINs. This page needs to be cached, since preforming this query every time someone visits the site or reloads the news page is highly inefficient, as the news does not change very often. Now, the traditional way to solve this is just have a cache that expires in a few minutes. However, due to the low traffic of my site currently, having the cache expire every few minutes would do little good. Also, setting the expiration time too high would be counter-intuitive, since the "News" will be old.

So, this was my quandary. I needed a cache that only expires when it needs to expire, when the news forum changes.

To do this, I have created a MyBB plugin. It hooks into the various features of MyBB (specifically, the new thread, new reply, and moderation functions), which allows it to delete the cache file once something in the news forum gets changed. (I'll include the plugin code at the end of this post as a reference or for anyone that might need it.)

However, something still doesn't seem right. I can't explain it, but the solution seems "off". So, that's why I have posted here, to get some more eyes to take a look at my solution and give feedback.

Thanks in advance, everyone.

Here's the Plugin Code:
mecache.php
<?php
/*
	Plugin By: Blue
	http://community.mybboard.net/member.php?action=profile&uid=671
*/
if(!defined('IN_MYBB'))
{
    die('Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.');
}

$plugins->add_hook('newreply_do_newreply_end', 'mecache_newreply');
$plugins->add_hook('newthread_do_newthread_end', 'mecache_newthread');
$plugins->add_hook('moderation_stick', 'mecache_moderation');
$plugins->add_hook('moderation_multistickthreads', 'mecache_moderation');
$plugins->add_hook('moderation_multiunstickthreads', 'mecache_moderation');
$plugins->add_hook('moderation_do_deletethread', 'mecache_moderation');
$plugins->add_hook('moderation_do_multideletethreads', 'mecache_moderation');
$plugins->add_hook('moderation_do_deleteposts', 'mecache_moderation');
$plugins->add_hook('moderation_do_multideleteposts', 'mecache_moderation');
$plugins->add_hook('admin_index_navigation_end', 'mecache_adminnavigation');
$plugins->add_hook('admin_maintenance_start', 'mecache_adminupdate');

/*
	General Functions
*/
function mecache_info()
{
    return array(
        'name'          => 'News Cache Updater',
        'description'   => 'Updates the news front page cache on new posts in news forum.',
        'website'       => '',
        'author'        => 'Blue',
        'authorsite'    => '',
        'version'       => '1.0',
    );
}
function mecache_activate() 
{

	global $db;
	$group = array(
        "gid"            => "NULL",
        "title"          => "News Cache Updater",
        "name"           => "mecache",
        "description"    => "Settings for News Cache Updater system.",
        "disporder"      => "20",
        "isdefault"      => "no"
    	);
    
   	$db->insert_query(TABLE_PREFIX."settinggroups", $group);
   	$gid = $db->insert_id(); //This will get the id of the just added record in the db

	$newsetting1 = array(
		'name'			=> 'mecachefid',
		'title'			=> 'Forum ID',
		'description'	=> 'Insert the forum id of the news forum.',
		'optionscode'	=> 'text',
		'value'			=> '',
		'disporder'		=> 1,
		'gid'			=> $gid
	);

	$db->insert_query(TABLE_PREFIX.'settings', $newsetting1);
	
	$newsetting2 = array(
		'name'			=> 'mecachepath',
		'title'			=> 'Cache Path',
		'description'	=> 'Insert the full path to the cache folder.',
		'optionscode'	=> 'text',
		'value'			=> '',
		'disporder'		=> 2,
		'gid'			=> $gid
	);
	$db->insert_query(TABLE_PREFIX.'settings', $newsetting2);
	
	$newsetting3 = array(
		'name'			=> 'mecacheid',
		'title'			=> 'Cache ID',
		'description'	=> 'The file name of the cache file.',
		'optionscode'	=> 'text',
		'value'			=> '',
		'disporder'		=> 3,
		'gid'			=> $gid
	);

	$db->insert_query(TABLE_PREFIX.'settings', $newsetting3);

	rebuildsettings();

}
function mecache_deactivate() 
{

	global $db;

$db->query('DELETE FROM '.TABLE_PREFIX.'settings WHERE name=\'mecachefid\' OR name=\'mecachepath\' OR name=\'mecacheid\'');
	$db->query('DELETE FROM '.TABLE_PREFIX.'settinggroups WHERE name=\'mecache\'');


	rebuildsettings();

}
/*
	End General Functions


	Plugin Hook Functions
*/
function mecache_newreply()
{
	global $post, $mybb;
	if(!empty($mybb->settings['mecachefid']) && !empty($mybb->settings['mecachepath']) 
&& !empty($mybb->settings['mecacheid']) && $post['fid'] == $mybb->settings['mecachefid'])
	{
		if(file_exists($mybb->settings['mecachepath'] . $mybb->settings['mecacheid'])) { 
				unlink($mybb->settings['mecachepath'] . $mybb->settings['mecacheid']); 
		}
	}
}
function mecache_newthread()
{
	global $new_thread, $mybb;
	if(!empty($mybb->settings['mecachefid']) && !empty($mybb->settings['mecachepath']) 
&& !empty($mybb->settings['mecacheid']) && $new_thread['fid'] == $mybb->settings['mecachefid'])
	{
		if(file_exists($mybb->settings['mecachepath'] . $mybb->settings['mecacheid'])) { 
				unlink($mybb->settings['mecachepath'] . $mybb->settings['mecacheid']); 
		}
	}
}
function mecache_moderation()
{
	global $fid, $mybb;
	if(!empty($mybb->settings['mecachefid']) && !empty($mybb->settings['mecachepath']) 
&& !empty($mybb->settings['mecacheid']) && $fid == $mybb->settings['mecachefid'])
	{
		if(file_exists($mybb->settings['mecachepath'] . $mybb->settings['mecacheid'])) { 
				unlink($mybb->settings['mecachepath'] . $mybb->settings['mecacheid']); 
		}
	}
}
function mecache_adminnavigation()
{
	global $menu;
	$menu[10]['items'][100] = array("title" => "Rebuild News Cache", "url" => "maintenance.php?".SID."&amp;action=rebuildfnc");
}
function mecache_adminupdate()
{
	global $mybb;
	if($mybb->input['action'] == 'rebuildfnc')
	{
		if(file_exists($mybb->settings['mecachepath'] . $mybb->settings['mecacheid'])) { 
				unlink($mybb->settings['mecachepath'] . $mybb->settings['mecacheid']); 
		}
		cpredirect("index.php?".SID."&action=home", "The front page news cache has been updated.");
	}	
}
/*
	End Plugin Hook Functions
*/
?>
Hi,

Is that all your code? Because if so, there doesn't seem to be anything that actually rebuilds the cache, only deleting a file.

For simplicity, might I suggest using MyBB's cache instead?
You can also redirect the plugin hooks to the same function, so you don't have to copy and paste the same thing over and over again.
ZiNgA BuRgA Wrote:Hi,

Is that all your code? Because if so, there doesn't seem to be anything that actually rebuilds the cache, only deleting a file.

For simplicity, might I suggest using MyBB's cache instead?
You can also redirect the plugin hooks to the same function, so you don't have to copy and paste the same thing over and over again.

No, it's not. My templating class is used for rebuilding the cache (which is run whenever the cache'd file isn't found, thus deleting the cache rebuilds the cache).

Also, I make sure not to call any MyBB files for any non-forums scripts, since they would add overhead. Anything that I need done that requires MyBB is custom coded.

Finally, all the moderation hooks use one function, mecache_moderation. The newreply and newthread hooks need separate functions since they need different variables to determine the fid ($post for newreply, $new_thread for newthread).

Thanks for the reply.

[edit] Forgot to include, my template class is based on the one in this article with modifications to meet my own needs (and to speed it up in places).
Blue Wrote:No, it's not. My templating class is used for rebuilding the cache (which is run whenever the cache'd file isn't found, thus deleting the cache rebuilds the cache).

Also, I make sure not to call any MyBB files for any non-forums scripts, since they would add overhead. Anything that I need done that requires MyBB is custom coded.
Oh okay.
Could you try to explain what you mean by "off"? For example, maybe the cache doesn't update when you make a new post?

Blue Wrote:Finally, all the moderation hooks use one function, mecache_moderation. The newreply and newthread hooks need separate functions since they need different variables to determine the fid ($post for newreply, $new_thread for newthread).
I'd personally extract the fid part and put everything into a separate function Toungue
ZiNgA BuRgA Wrote:
Blue Wrote:No, it's not. My templating class is used for rebuilding the cache (which is run whenever the cache'd file isn't found, thus deleting the cache rebuilds the cache).

Also, I make sure not to call any MyBB files for any non-forums scripts, since they would add overhead. Anything that I need done that requires MyBB is custom coded.
Oh okay.
Could you try to explain what you mean by "off"? For example, maybe the cache doesn't update when you make a new post?

I'm not sure. It does everything correctly, but it just doesn't feel good. It goes against everything I've ever done with caches. Usually, I'll have a cache expire in a few minutes... but a cache that never expires? I was just wondering if other experienced programmers had any opinions or suggestions to improve upon it.

ZiNgA BuRgA Wrote:
Blue Wrote:Finally, all the moderation hooks use one function, mecache_moderation. The newreply and newthread hooks need separate functions since they need different variables to determine the fid ($post for newreply, $new_thread for newthread).
I'd personally extract the fid part and put everything into a separate function Toungue
True, you could do it like that, but for simplicities sake I'd rather have three functions.
Oh okay, I understand now. Gut feeling =P

If you want, check the timestamp when using the cache, and if it's too old, destroy and regenerate it.
I'm not sure if I can help you anymore though Toungue
ZiNgA BuRgA Wrote:Oh okay, I understand now. Gut feeling =P

If you want, check the timestamp when using the cache, and if it's too old, destroy and regenerate it.
I'm not sure if I can help you anymore though Toungue

Well, from what I've seen while looking around, you seem to be an excellent coder. So, if you don't see any glaring problems, my feeling is probably wrong.

Thank you for all the help. Smile
Since I haven't seen all the code, I can't say too much, but it looks like it's achieving its purpose well Toungue

Just let it run for a while, and if no problems crop up after a while, I'd say it's all good Smile