[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Phpgroupware-cvs] phpgwapi/inc class.shm.inc.php
From: |
Sigurd Nes |
Subject: |
[Phpgroupware-cvs] phpgwapi/inc class.shm.inc.php |
Date: |
Tue, 04 Jul 2006 13:06:12 +0000 |
CVSROOT: /sources/phpgwapi
Module name: phpgwapi
Changes by: Sigurd Nes <sigurdne> 06/07/04 13:06:12
Added files:
inc : class.shm.inc.php
Log message:
Support for loading data into shared memory
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/inc/class.shm.inc.php?cvsroot=phpgwapi&rev=1.1
Patches:
Index: class.shm.inc.php
===================================================================
RCS file: class.shm.inc.php
diff -N class.shm.inc.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ class.shm.inc.php 4 Jul 2006 13:06:12 -0000 1.1
@@ -0,0 +1,315 @@
+<?php
+/*
+ Release under the GNU public license
+ Copyright Adam Stevenson adamstevenson@ _no_spam_
gmail.com (www.adamstevenson.net)
+ If you use this script please send me an email, and let
me know how it works for you,
+ or any bugs you find. Also, if you want to link to my
site I won't complain.
+
+ Basically this is just a hash table over shared memory
for caching php pages and
+ serialized objects. You need to have php compiled with
shared memory enabled.
+ Simple garbage collection is implemented, but is only
run when storing data in the
+ cache and not returning pages to improve performance.
+
+ It is very very fast.
+ When caching was in place I was getting 55k byte pages
returned over a local network
+ in 0.02 ms, where before it was about 2.00 seconds.
+
+ There is some support for debugging, but it is all
commented out to gain a little
+ more in performance.
+
+
+ Note: Versions of Windows previous to Windows 2000 do
not support shared memory.
+ Under Windows, Shmop will only work when PHP is running
as a web server module,
+ such as Apache or IIS (CLI and CGI will not work).
+
+ Basic usage:
+
+ For caching php rendered pages
+ include 'mycached.php';
+ do_cache();
+
+ do_cache will automatically handle the garbage
collection when storing pages.
+
+
+ For caching php objects, you can use the store_value
and get_value functions.
+
+ store_value takes a key and value like any hashtable,
and get_value just takes
+ the key and returns the value if there is one.
+
+ store_value('my_unique_key', $var);
+ $var = get_value('my_unique_key');
+
+ Directly accessing the store_value and get_value
function does not do any
+ garbage collection. You can do this yourself by
calling garbage_collection();
+ in your scripts.
+
+
+ To clear all the shared memory when testing, or what
not you can use the unix
+ command ipcs, and ipcrm. Here is what I use which
removes the shared memory
+ segments, and also semaphores
+ ipcs | cut -d" " -f2 | xargs -n1 ipcrm -s
+ ipcs | cut -d" " -f2 | xargs -n1 ipcrm -m
+
+
+ For even more robust caching, check out
http://www.danga.com/memcached/
+
+*/
+ /**
+ * Handles shared memory
+ * @author Adam Stevenson <adamstevenson@ _no_spam_ gmail.com>
+ * @author Sigurd Nes <address@hidden>
+ * @copyright Copyright (C) 2003-2005 Free Software Foundation, Inc.
http://www.fsf.org/
+ * @license http://www.gnu.org/licenses/gpl.html GNU General Public
License
+ * @internal Development of this application was funded by
http://www.bergen.kommune.no/bbb_/ekstern/
+ * @package phpgwapi
+ * @subpackage application
+ * @version $Id: class.shm.inc.php,v 1.1 2006/07/04 13:06:12 sigurdne
Exp $
+ */
+
+ class shm
+ {
+ /**
+ * @var string $hashid the hash_table_key - example: 'lang_en'
+ */
+ var $hashid;
+
+ function shm()
+ {
+
+ DEFINE('CACHE_SECONDS', 60 * 60);
+ DEFINE('LOG', false);
+ DEFINE('LOG_FILE', '/tmp/debug.log' );
+ DEFINE('HASH_PRIME', 2147483647); //2^31 -1
+ DEFINE('LOCK', '/');
+ // DEFINE('HASHID', 'hash_table_key');
+ }
+
+ function log_this($log_string)
+ {
+ if(!LOG) return;
+ $file = fopen(LOG_FILE, "a");
+ fwrite($file, $log_string);
+ fclose($file);
+ return;
+ }
+
+ function delete_mem($id)
+ {
+ if (!shmop_delete($id))
+ {
+ //$this->log_this("Couldn't mark shared memory
block for deletion.\n");
+ }
+ }
+
+ function &read_mem($id)
+ {
+ return shmop_read($id, 0, shmop_size($id));
+ }
+
+ function write_mem($id, $data)
+ {
+ if(shmop_size($id)< strlen($data))
+ {
+ return false;
+ }
+
+ if(!shmop_write($id, $data, 0))
+ {
+ //$this->log_this("Could not write to shared
memory segment\n");
+ return false;
+ }
+ return true;
+ }
+
+ function create_mem($key, $size)
+ {
+ $id = @shmop_open($key, "n", 0644, $size);
+ if (!$id)
+ {
+ //$this->log_this("Couldn't create shared
memory segment with key = $key\n");
+ }
+ return $id;
+ }
+
+ function mem_exist($key)
+ {
+ if(!$id = @shmop_open($key, "a", 0644, 100))
+ {
+ //$this->log_this("Couldn't find shared memory
segment with key = $key\n");
+ return 0;
+ }
+ //$this->log_this("Memory segment exists with key =
$key\n");
+ return $id;
+ }
+
+ function close_mem($id)
+ {
+ if($id!=0) shmop_close($id);
+ }
+
+ function &get_value($key)
+ {
+ $hash_id =& $this->hash($key);
+ $value = array();
+ $id =& $this->mem_exist($hash_id);
+ while($value['key']!=$key)
+ {
+ if($id!=0)
+ {
+ $value =&
unserialize($this->read_mem($id));
+ if($value['key']!=$key) $id =&
$this->mem_exist($this->hash($hash_id));
+ }
+ else
+ {
+ //$this->log_this("no key in hash
table\n");
+ $this->close_mem($id);
+ return "";
+ }
+ }
+ $this->close_mem($id);
+ return $value['value'];
+ }
+
+ function store_value($key,$value)
+ {
+ $SHM_KEY = ftok(LOCK, 'R');
+ $shmid = @sem_get($SHM_KEY, 1024, 0644 | IPC_CREAT);
+ sem_acquire($shmid);
+ $hash_id = $this->hash($key);
+ $store_value = array();
+ $store_value['key'] = trim($key);
+ $store_value['value'] = $value;
+ $store_value['time'] = time();
+ $id = $this->mem_exist($hash_id);
+ while($id!=0)
+ {
+ $value = unserialize($this->read_mem($id));
+ if($value['key']==$key)
+ {
+ //$this->log_this("Key " . $key . "
$hash_id(" . dechex($hash_id) .") already in hash table, replacing with new
contents\n");
+ $this->delete_mem($id);
+ $this->close_mem($id);
+ $contents = serialize($store_value);
+ $id =
$this->create_mem($hash_id,strlen($contents));
+ $this->write_mem($id, $contents); //
place into memory
+ $this->close_mem($id);
+ sem_release($shmid);
+ return $hash_id;
+ }
+ $this->close_mem($id);
+ //$this->log_this("Collision while trying to
store key=$key in hash table\n");
+ $hash_id = $this->hash($hash_id);
+ $id = $this->mem_exist($hash_id);
+ }
+ $contents = serialize($store_value);
+ $id = $this->create_mem($hash_id,strlen($contents));
+ $this->write_mem($id, &$contents); // place into memory
+ $this->close_mem($id);
+ sem_release($shmid);
+ return $hash_id;
+ }
+
+ function update_keys($key, $id)
+ {
+ $SHM_KEY = ftok(LOCK, 'R');
+ $shmid = @sem_get($SHM_KEY, 1024, 0644 | IPC_CREAT);
+ sem_acquire($shmid);
+ $temp =& $this->get_value($this->hashid);
+ $temp[$key] = array('shmid' => $id, 'time' => time());
+ $this->store_value($this->hashid,$temp);
+ sem_release($shmid);
+ }
+
+ function &hash($hash_string)
+ {
+ $hash =& fmod(hexdec(md5($hash_string)), HASH_PRIME);
+ //$this->log_this("Hashing " . $hash_string . " to " .
$hash . "\n");
+ return $hash;
+ }
+
+ function cache_end($contents)
+ {
+ if(trim($contents))
+ {
+ $datasize = strlen($contents);
+ $hash_string =
"http://".$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"].serialize($_POST);
+ $shmid =
$this->store_value($hash_string,$contents);
+ $this->update_keys($hash_string,$shmid);
+ }
+ return $contents; //display
+ }
+
+ function delete_key($key)
+ {
+ $SHM_KEY = ftok(LOCK, 'R');
+ $shmid = @sem_get($SHM_KEY, 1024, 0644 | IPC_CREAT);
+
+ sem_acquire($shmid);
+ $data = $this->get_value($key);
+
+ if(isset($data))
+ {
+ $v = $data[$key];
+ $id =& $this->mem_exist($this->hash($hash_id));
+ $this->delete_mem($id);
+ $this->close_mem($id);
+ unset($data);
+ $this->store_value($key, $data);
+ }
+ sem_release($shmid);
+ }
+
+ function clear_cache()
+ {
+ $SHM_KEY = ftok(LOCK, 'R');
+ $shmid = @sem_get($SHM_KEY, 1024, 0644 | IPC_CREAT);
+ sem_acquire($shmid);
+ $data = $this->get_value($this->hashid);
+ _debug_array($data);
+ foreach ($data as $k => $v)
+ {
+ $id = $this->mem_exist($v['shmid']);
+ $this->delete_mem($id);
+ $this->close_mem($id);
+ }
+ $data = array();
+ $this->store_value($this->hashid, $data);
+ sem_release($shmid);
+ }
+
+
+ function garbage_collection()
+ {
+ $SHM_KEY = ftok(LOCK, 'R');
+ $shmid = @sem_get($SHM_KEY, 1024, 0644 | IPC_CREAT);
+ sem_acquire($shmid);
+ $data = $this->get_value($this->hashid);
+ foreach ($data as $k => $v)
+ {
+ if(time() - $v['time'] > CACHE_SECONDS)
+ {
+ //$this->log_this("garbage collection
found expired key $k, value $v[shmid] in hash table... deleting\n");
+ $id = $this->mem_exist($v['shmid']);
+ $this->delete_mem($id);
+ $this->close_mem($id);
+ unset($data[$k]);
+ }
+ $this->store_value($this->hashid, $data);
+ }
+ sem_release($shmid);
+ }
+
+ function do_cache()
+ {
+ $key =
"http://".$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"].serialize($_POST);
+ $contents =& $this->get_value($key);
+ if($contents)
+ {
+ //$this->log_this("Cache hit for " . $key .
"\n");
+ print $contents;
+ exit;
+ }
+ $this->garbage_collection();
+ ob_start("cache_end"); // callback
+ }
+ }
- [Phpgroupware-cvs] phpgwapi/inc class.shm.inc.php,
Sigurd Nes <=