# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html
-
-# Simple generic object store
-# interface is intended to be more or less compatible with
-# the PHP memcached client.
-#
-# backends for local hash array and SQL table included:
-# $bag = new HashBagOStuff();
-# $bag = new MysqlBagOStuff($tablename); # connect to db first
-
-class /* abstract */ BagOStuff {
+/**
+ *
+ * @package MediaWiki
+ */
+
+/**
+ * Simple generic object store
+ *
+ * interface is intended to be more or less compatible with
+ * the PHP memcached client.
+ *
+ * backends for local hash array and SQL table included:
+ * $bag = new HashBagOStuff();
+ * $bag = new MysqlBagOStuff($tablename); # connect to db first
+ *
+ * @package MediaWiki
+ * @abstract
+ */
+class BagOStuff {
var $debugmode;
function BagOStuff() {
- set_debug( false );
+ $this->set_debug( false );
}
function set_debug($bool) {
return false;
}
+ function lock($key, $timeout = 0) {
+ /* stub */
+ return true;
+ }
+
+ function unlock($key) {
+ /* stub */
+ return true;
+ }
+
/* *** Emulated functions *** */
/* Better performance can likely be got with custom written versions */
function get_multi($keys) {
}
function incr($key, $value=1) {
+ if ( !$this->lock($key) ) {
+ return false;
+ }
$value = intval($value);
if($value < 0) $value = 0;
+
+ $n = false;
if( ($n = $this->get($key)) !== false ) {
- $this->set($key, $n+$value); // exptime?
- return $n+$value;
- } else {
- return false;
+ $n += $value;
+ $this->set($key, $n); // exptime?
}
+ $this->unlock($key);
+ return $n;
}
function decr($key, $value=1) {
+ if ( !$this->lock($key) ) {
+ return false;
+ }
$value = intval($value);
if($value < 0) $value = 0;
+
+ $m = false;
if( ($n = $this->get($key)) !== false ) {
$m = $n - $value;
if($m < 0) $m = 0;
$this->set($key, $m); // exptime?
- return $m;
- } else {
- return false;
}
+ $this->unlock($key);
+ return $m;
}
function _debug($text) {
}
-/* Functional versions! */
+/**
+ * Functional versions!
+ * @todo document
+ * @package MediaWiki
+ */
class HashBagOStuff extends BagOStuff {
/*
This is a test of the interface, mainly. It stores
key (exptime)
);
*/
-class /* abstract */ SqlBagOStuff extends BagOStuff {
+
+/**
+ * @todo document
+ * @abstract
+ * @package MediaWiki
+ */
+class SqlBagOStuff extends BagOStuff {
var $table;
- function SqlBagOStuff($tablename = "objectcache") {
+
+ function SqlBagOStuff($tablename = 'objectcache') {
$this->table = $tablename;
}
}
if($row=$this->_fetchobject($res)) {
$this->_debug("get: retrieved data; exp time is " . $row->exptime);
- return unserialize($row->value);
+ return $this->_unserialize($row->value);
} else {
- $this->_debug("get: no matching rows");
+ $this->_debug('get: no matching rows');
}
return false;
}
$this->delete( $key );
$this->_query(
"INSERT INTO $0 (keyname,value,exptime) VALUES('$1','$2','$exp')",
- $key, serialize(&$value));
+ $key, $this->_serialize($value));
return true; /* ? */
}
return true; /* ? */
}
+ function getTableName() {
+ return $this->table;
+ }
+
function _query($sql) {
$reps = func_get_args();
- $reps[0] = $this->table;
+ $reps[0] = $this->getTableName();
// ewwww
for($i=0;$i<count($reps);$i++) {
$sql = str_replace(
- "$" . $i,
+ '$' . $i,
$this->_strencode($reps[$i]),
$sql);
}
$res = $this->_doquery($sql);
if($res == false) {
- $this->_debug("query failed: " . $this->_dberror($res));
+ $this->_debug('query failed: ' . $this->_dberror($res));
}
return $res;
}
}
function _doquery($sql) {
- die( "abstract function SqlBagOStuff::_doquery() must be defined" );
+ die( 'abstract function SqlBagOStuff::_doquery() must be defined' );
}
function _fetchrow($res) {
- die( "abstract function SqlBagOStuff::_fetchrow() must be defined" );
+ die( 'abstract function SqlBagOStuff::_fetchrow() must be defined' );
}
function _freeresult($result) {
function _dberror($result) {
/* stub */
- return "unknown error";
+ return 'unknown error';
}
function _maxdatetime() {
- die( "abstract function SqlBagOStuff::_maxdatetime() must be defined" );
+ die( 'abstract function SqlBagOStuff::_maxdatetime() must be defined' );
}
function _fromunixtime() {
- die( "abstract function SqlBagOStuff::_fromunixtime() must be defined" );
+ die( 'abstract function SqlBagOStuff::_fromunixtime() must be defined' );
}
function expireall() {
/* Clear *all* items from cache table */
$this->_query( "DELETE FROM $0" );
}
+
+ /**
+ * Serialize an object and, if possible, compress the representation.
+ * On typical message and page data, this can provide a 3X decrease
+ * in storage requirements.
+ *
+ * @param mixed $data
+ * @return string
+ */
+ function _serialize( &$data ) {
+ $serial = serialize( $data );
+ if( function_exists( 'gzdeflate' ) ) {
+ return gzdeflate( $serial );
+ } else {
+ return $serial;
+ }
+ }
+
+ /**
+ * Unserialize and, if necessary, decompress an object.
+ * @param string $serial
+ * @return mixed
+ */
+ function &_unserialize( $serial ) {
+ if( function_exists( 'gzinflate' ) ) {
+ $decomp = @gzinflate( $serial );
+ if( false !== $decomp ) {
+ $serial = $decomp;
+ }
+ }
+ return unserialize( $serial );
+ }
}
+/**
+ * @todo document
+ * @package MediaWiki
+ */
class MediaWikiBagOStuff extends SqlBagOStuff {
+ var $tableInitialised = false;
+
function _doquery($sql) {
- return wfQuery($sql, DB_READ, "MediaWikiBagOStuff:_doquery");
+ $dbw =& wfGetDB( DB_MASTER );
+ return $dbw->query($sql, 'MediaWikiBagOStuff:_doquery');
}
function _fetchobject($result) {
- return wfFetchObject($result);
+ $dbw =& wfGetDB( DB_MASTER );
+ return $dbw->fetchObject($result);
}
function _freeresult($result) {
- return wfFreeResult($result);
+ $dbw =& wfGetDB( DB_MASTER );
+ return $dbw->freeResult($result);
}
function _dberror($result) {
- return wfLastError();
+ $dbw =& wfGetDB( DB_MASTER );
+ return $dbw->lastError();
}
function _maxdatetime() {
- return "9999-12-31 12:59:59";
+ return '9999-12-31 12:59:59';
}
function _fromunixtime($ts) {
- return gmdate( "Y-m-d H:i:s", $ts );
+ return gmdate( 'Y-m-d H:i:s', $ts );
}
function _strencode($s) {
- return wfStrEncode($s);
+ $dbw =& wfGetDB( DB_MASTER );
+ return $dbw->strencode($s);
+ }
+ function getTableName() {
+ if ( !$this->tableInitialised ) {
+ $dbw =& wfGetDB( DB_MASTER );
+ $this->table = $dbw->tableName( $this->table );
+ $this->tableInitialised = true;
+ }
+ return $this->table;
}
}
+/**
+ * This is a wrapper for Turck MMCache's shared memory functions.
+ *
+ * You can store objects with mmcache_put() and mmcache_get(), but Turck seems
+ * to use a weird custom serializer that randomly segfaults. So we wrap calls
+ * with serialize()/unserialize().
+ *
+ * The thing I noticed about the Turck serialized data was that unlike ordinary
+ * serialize(), it contained the names of methods, and judging by the amount of
+ * binary data, perhaps even the bytecode of the methods themselves. It may be
+ * that Turck's serializer is faster, so a possible future extension would be
+ * to use it for arrays but not for objects.
+ *
+ * @package MediaWiki
+ */
+class TurckBagOStuff extends BagOStuff {
+ function get($key) {
+ $val = mmcache_get( $key );
+ if ( is_string( $val ) ) {
+ $val = unserialize( $val );
+ }
+ return $val;
+ }
+
+ function set($key, $value, $exptime=0) {
+ mmcache_put( $key, serialize( $value ), $exptime );
+ return true;
+ }
+
+ function delete($key, $time=0) {
+ mmcache_rm( $key );
+ return true;
+ }
+
+ function lock($key, $waitTimeout = 0 ) {
+ mmcache_lock( $key );
+ return true;
+ }
+
+ function unlock($key) {
+ mmcache_unlock( $key );
+ return true;
+ }
+}
?>