MaxSem
Joined 19 January 2012
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @since 1.23
*/
/**
* Base class for generic key-value store
*/
abstract class DataStore {
/**
* Maximum key length. Must be enforced in all implementations to guarantee data portability
*/
const MAX_KEY_LENGTH = 255;
private static $stores = array();
/**
* Default constructor, sets class properties from config array
* @param array $config: Associative array of store configuration
*/
public function __construct( array $config ) {
foreach ( $config as $name => $value ) {
$this->$name = $value;
}
}
/**
* Creates a store with a given name
* The store must be configured in $wgDataStores
*
* @param string $name
* @return DataStore
*/
public static function getStore( $name = 'default' ) {
if ( isset( self::$stores[$name] ) ) {
return self::$stores[$name];
}
global $wgDataStores;
wfProfileIn( __METHOD__ );
if ( !isset( $wgDataStores[$name] ) ) {
throw new MWException( "Unrecognised data store '$name'" );
}
$config = $wgDataStores[$name];
$store = new $config['class']( $config );
self::$stores[$name] = $store;
wfProfileOut( __METHOD__ );
return $store;
}
/**
* Returns value for a given key or null if not found
*
* @param string|array $key: Storage key
* @param bool $latest: Whether a replicated or distributed store should ensure that the data returned is latest
* @return mixed
*/
public abstract function get( $key, $latest = false );
/**
* Gets multiple values at once.
* The default implementation is a slow fallback that calls get() multiple times.
* Ideally, it should be overridden with something faster.
*
* @param array $keys: Array of keys
* @param bool $latest: Whether a replicated or distributed store should ensure that the data returned is latest
*
* @return array: Associative array of key => value. If a key wasn't found, it will be omitted
*/
public function getMulti( array $keys, $latest = false ) {
wfProfileIn( __METHOD__ );
$result = array();
foreach ( $keys as $key ) {
$value = $this->get( $key, $latest );
if ( $value !== null ) {
$result[$key] = $value;
}
}
wfProfileOut( __METHOD__ );
return $result;
}
/**
* Sets value for a given key or keys
*
* @param string $key
* @param mixed $value
*/
public abstract function set( $key, $value );
/**
* Sets multiple values at once.
* The default implementation is a slow fallback that calls set() multiple times.
* Ideally, it should be overridden with something faster.
*
* @param array $data: Associative array of key => value pairs to be set
*/
public function setMulti( array $data ) {
wfProfileIn( __METHOD__ );
foreach ( $data as $key => $value ) {
$this->set( $key, $value );
}
wfProfileOut( __METHOD__ );
}
/**
* Returns all values whose keys start with a given string
*
* @param string $prefix
* @param bool $latest: Whether a replicated or distributed store should ensure that the data returned is latest
* @return Iterator
*/
public abstract function getByPrefix( $prefix, $latest = false );
/**
* Deletes value with the specified key
*
* @param string $key
*/
public abstract function delete( $key );
/**
* Deletes all values with keys matching the given key
*
* @param string $prefix
*/
public final function deleteByPrefix( $prefix ) {
if ( $prefix === '' ) {
throw new MWException( 'Fool-proof against deletion of everything' );
}
$this->deleteByPrefixInternal( $prefix );
}
/**
* Deletes all values with keys starting with a given prefix
* @param $prefix
*/
protected abstract function deleteByPrefixInternal( $prefix );
/**
* Generates a storage key from several parts
* @return string
*/
public function key( /*...*/ ) {
$keys = func_get_args();
$key = implode( ':', $keys );
if ( strlen( $key ) > self::MAX_KEY_LENGTH ) {
throw new MWException( "Key '$key' is too long" );
}
return $key;
}
/**
* Encodes data to be stored in a format suitable for current store.
* Default implementation attempts to store primitive types in a non-serialized format.
*
* @param mixed $data: Data to encode
* @return mixed
*/
protected function encodeValue( $data ) {
if ( is_array( $data ) || is_object( $data ) ) {
return serialize( $data );
}
return $data;
}
};