Go Back   vb.org Archive > vBulletin Article Depository > Read An Article > vBulletin 3 Articles
FAQ Community Calendar Today's Posts Search

Reply
 
Thread Tools
Cache System Explanation (datastore)
Logikos
Join Date: Jan 2003
Posts: 2,924

 

Show Printable Version Email this Page Subscription
Logikos Logikos is offline 03-16-2006, 10:00 PM

I'm going to try and explain the datastore system used in vBulltin. This tutorial is based around users who are already familar with PHP and MySQL.
What is Cache?
A memory area where frequently accessed data can be stored for rapid access. (View Definitions). Basicly, you can store information into the database, and grab all this information with just using 1 query. Some may question this and say: "Isn't all information in the database retrived by queires?". Yup, all information in the database is retrived using MySQL queries, though the method used is diffrent when using the datastore system in vBulletin.
I'll show you way using the datastore is a better solution for you and the users who will use your hacks.

Datastore Method

Lets say you want to use a drop down form with 3 options to choose from. Obviously you would need to create alittle script to add, delete, and edit the information; and when you make this script. Where does the info go? Well it would go into the database. Lets call the MySQL table "dropdownoptions" with 3 fields. ID, Name, and Value.

Attachment 44423
Now everytime you add, edit, or delete your information, it will be changed in the database. Here is an example of the database tree. We have 3 rows of information.
  • ID = (1) Name = (Dog) Value(Dog)
  • ID = (2) Name = (Cat) Value(Cat)
  • ID = (3) Name = (Cow) Value(Cow)
Attachment 44424

After you insert this information into the database, the next step would be to insert this info in the datastore. You can do that like this.

PHP Code:
$query $vbulletin->db->query_read("
        SELECT *
        FROM " 
TABLE_PREFIX "dropdownmenu
        ORDER BY id DESC
"
);

while (
$variable $vbulletin->db->fetch_array($query))
{
        
$variable_array[] = $variable;
}

build_datastore('dropmenu'serialize($variable_array)); 
Let me go ahead and tell you exacly what the above does. What we did was just grab all in the information in the database from the table dropdownmenu. The while() function will loop the information from the begging to the end. While it's getting all this information, It's storing it all into the variable named $variable_array.

Then you need to use the function called build_datastore(). This function requires the following. build_datastore(1, 2). #1 is the name of your datastore item, and number two is the serialize information to store. This function will create a new datastore item with the name and all your info.

The serialize info will look like this...
Code:
a:3:{i:0;a:3:{s:2:"id";s:1:"1";s:4:"name";s:3:"Dog";s:5:"value";s:3:"Dog";}i:1;a:3:{s:2:"id";s:1:"2";s:4:"name";s:3:"Cat";s:5:"value";s:3:"Cat";}i:2;a:3:{s:2:"id";s:1:"3";s:4:"name";s:3:"Cow";s:5:"value";s:3:"Cow";}}
So now we have all our infomation stored in another area of the database, in one row. Heres a picture so you can compair it to the other ones.

Attachment 44425

Don't let the serialize data freak you out. You don't really NEED to read that data. Though I kinda like doing it, so I'll break it down alittle for you. Here is a tree of the serialize data.

Code:
a:3:{
        i:0; a:3:{
                s:2:"id";s:1:"1";
                s:4:"name";s:3:"Dog";
                s:5:"value";s:3:"Dog";
        }

        i:1; a:3:{
                s:2:"id";s:1:"2";
                s:4:"name";s:3:"Cat";
                s:5:"value";s:3:"Cat";
        }

        i:2; a:3:{
                s:2:"id";s:1:"3";
                s:4:"name";s:3:"Cow";
                s:5:"value";s:3:"Cow";
        }
}
In PHP it would look like this.
PHP Code:
$data = array(
        
'0' => array(
                
'id' => '1',
                
'name' => 'Dog',
                
'value' => 'Dog'
        
),
        
'1' => array(
                
'id' => '2',
                
'name' => 'Cat',
                
'value' => 'Cat'
        
),
        
'2' => array(
                
'id' => '3',
                
'name' => 'Cow',
                
'value' => 'Cow'
        
),
); 
So now we have the info stored, lets get it back out in a readable formate. This is the easy part. This is the code I use.

PHP Code:
$vbulletin->dropmenu unserialize($vbulletin->dropmenu);
foreach (
$vbulletin->dropmenu AS $dropmenu)
{
        echo 
"(ID: "  $dropmenu['id'] . ") (Title: " $dropmenu['title'] . ") (Value: " $dropmenu['title'] . ")<br />";

This will print the following:
(ID: 1) (Title: Dog) (Value: Dog)
(ID: 2) (Title: Cat) (Value: Cat)
(ID: 3) (Title: Cow) (Value: Cow)

What your doing is simple. The variable $vbulletin->dropmenu holds the information though it's still serialize. The reason why $vbulletin->dropmenu is the variable is because you need to tell vBulletin which datastore row to get. In this case it is dropmenu because remember we stored it in there like this: build_datastore('dropmenu', serialize($variable_array));

Now in order for vBulletin to know about that specific row, you need to add it to the $specialtemplates array. Example:

PHP Code:
$specialtemplates = array(
        
'dropmenu'
); 
So now that you understand where the variable is coming from, we need to unserialize the data, cause it looks all ugly and weird.

So $vbulletin->dropmenu = unserialize($vbulletin->dropmenu); baiscly gets the serialize info and unserialize's it using the function called unserialize() Once that is finished you want to loop the info using a foreach() function. foreach ($vbulletin->dropmenu AS $dropmenu). Doing that is storing the array info into $dropmenu and you can get each one by using the following vaiables. $dropmenu['id'], $dropmenu['title'], and $dropmenu['value'].

The reason why this is better is because vBulletin allready runs one global query to get all the datatore information. So instead of running a query everytime you want to get the drop down information, you just get it from the datastore and save that query. Some may think this is kinda extreme when you can just run a query, though as your site grows; you want to save as many queires as possiable.

If your interested in saving queries and bandwidth. I would suggest taking a look at Trigunflames profile. He has released many hacks to help in these areas.

Copyright ?2004-2006 vBHackers.com All Rights Reserved.
This tutorial may not be redistributed in whole or significant part.
Reply With Quote
  #32  
Old 06-06-2008, 06:17 PM
seko3 seko3 is offline
 
Join Date: Jan 2007
Posts: 2
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by briansol View Post
With a couple tweaks (probably because this is 2 years old...), i've successfully got my first datastore plugin working

Thanks for the write up Ken. Never experienced with the datastore much.
Can you please share it with us. I am so tired of trying to make this work. It has been 5 days but I couldn't cache anything yet. It would be great to know how to cache sql queries.
Reply With Quote
  #33  
Old 06-06-2008, 08:10 PM
RobDog888's Avatar
RobDog888 RobDog888 is offline
 
Join Date: Apr 2007
Location: Degabah Swamp
Posts: 293
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by briansol View Post
With a couple tweaks (probably because this is 2 years old...), i've successfully got my first datastore plugin working

Thanks for the write up Ken. Never experienced with the datastore much.
What was different from the posted solutions?
Reply With Quote
  #34  
Old 06-06-2008, 08:15 PM
briansol's Avatar
briansol briansol is offline
 
Join Date: Apr 2006
Location: CT
Posts: 254
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

i'm still trying to figure out how to export this entire thing (with all my crons/ phrases etc) but no one is helping me out on .com
http://www.vbulletin.com/forum/showthread.php?t=274552
otherwise, i'd just post my entire product.


basically, this is what i did.

1) I made a cron job to populate a table from live post/thread table data. (Perhaps this table is useless now altogether, but i like having a table i can reference during testing. next version probably won't include this cache_ table at all)

Code:
<?php

error_reporting(E_ALL & ~E_NOTICE);
if (!is_object($vbulletin->db))
{
exit;
}

//clean up...
$vbulletin->db->query_write('TRUNCATE TABLE ' . TABLE_PREFIX . 'cache_activetopics');


$vbulletin->db->query_write('insert into ' . TABLE_PREFIX . 'cache_activetopics
/// my big select query here
');

// now, this loads that new data into an array, which is then shoved into the build datastore function:

$query = $vbulletin->db->query_read('SELECT * from ' . TABLE_PREFIX . 'cache_activetopics');

while ($variable = $vbulletin->db->fetch_array($query))
{
        $variable_array[] = $variable;
}

build_datastore('skm_active_cache', serialize($variable_array), true); 


log_cron_action('', $nextitem, 1);

?>
Again, you can skip truncating and building the table... just run the big query here as the $query = part to get your array/data.


Set up the cron job to run this script as you like.
Run it once manually to make sure you have data in the datastore row.

there will actually be a row with the name skm_active_cache in the datastore table.


2) from there, i have 4 plugins in my product
Quote:
Product : SKM - Active threads from past 24 hours
SKM Active Threads - Cache output templates cache_templates
SKM Active Threads - Cache Special Templates (datastore row) init_startup
SKM Active Threads - Parse and Print forumhome_complete
SKM Active Threads - Template Group template_groups
a) cache_templates hook : contains the simple caching of my custom template which prints 1 row of data (ie, <tr><td>1</td><td>2</td></tr> ) similar to the 'threadbits' template

it contains a simple line:
Code:
$globaltemplates[] = 'skm_activethreads24_forumhome';
b) init_startup hook : special templates is probably a mis-nomer at this point, as i'm NOT using the special templates array merge style.
This file pulls the datastore row into memory:
Code:
$datastore_fetch[] = "'skm_active_cache'";
note the quotes are important. This name should match what you ran in your cron under the build_datastore() function.

c) forumhome_complete hook : parse the data and print it to the template step. obviously, forumhome_complete should match the area you are trying to hook into. in my case, it was on the forum home.

Code:
foreach ($vbulletin->skm_active_cache AS $mycache)
{
	$output['threadid'] = $mycache['tid'];
	
	eval("\$mythreadbits .= \"".fetch_template('skm_activethreads24_forumhome')."\";");
}
d) the template will look for the $output array to print, ala:
Code:
<a href="showthread.php?t=$output[threadid]&amp;goto=newpost">
e) the template group is not required... just makes things easier to group when you have a lot of templates.


That's about it.

basically, you need to fill the datastore with your query, and pull with a foreach of the array once the data has been initialized.
Reply With Quote
  #35  
Old 01-02-2009, 08:21 PM
gabrielt gabrielt is offline
 
Join Date: Apr 2007
Posts: 89
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Hello,

Thank you so much for your tutorial. This was exactly what I was looking for. I write my own products/plugins (our forums is huge) and I was wondering how to cache stuff around.

However I faced one problem: I couldn't read data back.

The solution was to add a "1" parameter on the store command:

build_datastore('name',serialize($variable),1);

When retrieving you don't need to "unserialize" it.

Also I was trying to call my cached array inside a class that hasn't had $vbulletin as a global variable, so I needed to add:

global $vbulletin;

On the top of my plugin.

And I also needed to add a plugin for the init_startup hook, adding:

$datastore_fetch[]="'name'";

I hope this feedback helps other coders.

Cheers,
Gabriel.
Reply With Quote
  #36  
Old 02-11-2009, 03:20 PM
Jafo232 Jafo232 is offline
 
Join Date: May 2004
Posts: 1,122
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by gabrielt View Post

And I also needed to add a plugin for the init_startup hook, adding:

$datastore_fetch[]="'name'";
This should really be added to the first post. Took forever to figure this out.
Reply With Quote
  #37  
Old 04-21-2009, 05:42 PM
bananalive bananalive is offline
 
Join Date: Oct 2007
Location: UK
Posts: 2,802
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Is there a datastore per user?
Reply With Quote
  #38  
Old 04-21-2009, 09:23 PM
mokujin's Avatar
mokujin mokujin is offline
 
Join Date: Oct 2005
Location: Czech
Posts: 345
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

If you have this, now How can I delete one of the data (red below) ???
Code:
a:3:{
        i:0; a:3:{
                s:2:"id";s:1:"1";
                s:4:"name";s:3:"Dog";
                s:5:"value";s:3:"Dog";
        }

        i:1; a:3:{
                s:2:"id";s:1:"2";
                s:4:"name";s:3:"Cat";
                s:5:"value";s:3:"Cat";
        }

        i:2; a:3:{
                s:2:"id";s:1:"3";
                s:4:"name";s:3:"Cow";
                s:5:"value";s:3:"Cow";
        }
}
Reply With Quote
  #39  
Old 04-21-2009, 10:59 PM
rob01 rob01 is offline
 
Join Date: Sep 2008
Location: Mexico
Posts: 410
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

it could be possible to fetch more than 1 value

for example

(ID: 1) (Title: Dog) (Value: Dog , dog2, dog4)

and be able to delete dog4

(ID: 1) (Title: Dog) (Value: Dog , dog2)

or add more

any ideas?

maybe first check if its empty or :S?
Reply With Quote
  #40  
Old 05-11-2009, 05:22 AM
solita_ugc solita_ugc is offline
 
Join Date: Feb 2009
Posts: 2
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Hello,

I seem to be unable to persist the values in datastore. Variables built and stored to datastore in global_start plugin are lost in subsequent requests.

I wish the purpose, usage, lifecycle, limitations and performance of datastore would be discussed more in the article.

-Pete
Reply With Quote
  #41  
Old 05-22-2009, 09:58 AM
IdanB's Avatar
IdanB IdanB is offline
 
Join Date: May 2009
Location: Israel
Posts: 171
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by gabrielt View Post
And I also needed to add a plugin for the init_startup hook, adding:

$datastore_fetch[]="'name'";
Thank you for this, was pulling my hair out my head trying to get this to work.
That's what i was missing
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 12:03 AM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2024, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.12163 seconds
  • Memory Usage 2,368KB
  • Queries Executed 26 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (8)bbcode_code
  • (4)bbcode_php
  • (5)bbcode_quote
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)modsystem_article
  • (1)navbar
  • (4)navbar_link
  • (120)option
  • (1)pagenav
  • (1)pagenav_curpage
  • (3)pagenav_pagelink
  • (11)post_thanks_box
  • (1)post_thanks_box_bit
  • (11)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (1)post_thanks_postbit
  • (11)post_thanks_postbit_info
  • (10)postbit
  • (11)postbit_onlinestatus
  • (11)postbit_wrapper
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • fetch_musername
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • post_thanks_function_fetch_thanks_bit_start
  • post_thanks_function_show_thanks_date_start
  • post_thanks_function_show_thanks_date_end
  • post_thanks_function_fetch_thanks_bit_end
  • post_thanks_function_fetch_post_thanks_template_start
  • post_thanks_function_fetch_post_thanks_template_end
  • postbit_imicons
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • pagenav_page
  • pagenav_complete
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete