diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2013-12-08 09:55:49 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2013-12-08 09:55:49 +0100 |
commit | 4ac9fa081a7c045f6a9f1cfc529d82423f485b2e (patch) | |
tree | af68743f2f4a47d13f2b0eb05f5c4aaf86d8ea37 /includes/externalstore/ExternalStoreDB.php | |
parent | af4da56f1ad4d3ef7b06557bae365da2ea27a897 (diff) |
Update to MediaWiki 1.22.0
Diffstat (limited to 'includes/externalstore/ExternalStoreDB.php')
-rw-r--r-- | includes/externalstore/ExternalStoreDB.php | 142 |
1 files changed, 122 insertions, 20 deletions
diff --git a/includes/externalstore/ExternalStoreDB.php b/includes/externalstore/ExternalStoreDB.php index 196e7f2c..46a89379 100644 --- a/includes/externalstore/ExternalStoreDB.php +++ b/includes/externalstore/ExternalStoreDB.php @@ -30,21 +30,13 @@ */ class ExternalStoreDB extends ExternalStoreMedium { /** - * The URL returned is of the form of the form DB://cluster/id + * The provided URL is in the form of DB://cluster/id * or DB://cluster/id/itemid for concatened storage. * * @see ExternalStoreMedium::fetchFromURL() */ public function fetchFromURL( $url ) { - $path = explode( '/', $url ); - $cluster = $path[2]; - $id = $path[3]; - if ( isset( $path[4] ) ) { - $itemID = $path[4]; - } else { - $itemID = false; - } - + list( $cluster, $id, $itemID ) = $this->parseURL( $url ); $ret =& $this->fetchBlob( $cluster, $id, $itemID ); if ( $itemID !== false && $ret !== false ) { @@ -54,6 +46,41 @@ class ExternalStoreDB extends ExternalStoreMedium { } /** + * Fetch data from given external store URLs. + * The provided URLs are in the form of DB://cluster/id + * or DB://cluster/id/itemid for concatened storage. + * + * @param array $urls An array of external store URLs + * @return array A map from url to stored content. Failed results + * are not represented. + */ + public function batchFetchFromURLs( array $urls ) { + $batched = $inverseUrlMap = array(); + foreach ( $urls as $url ) { + list( $cluster, $id, $itemID ) = $this->parseURL( $url ); + $batched[$cluster][$id][] = $itemID; + // false $itemID gets cast to int, but should be ok + // since we do === from the $itemID in $batched + $inverseUrlMap[$cluster][$id][$itemID] = $url; + } + $ret = array(); + foreach ( $batched as $cluster => $batchByCluster ) { + $res = $this->batchFetchBlobs( $cluster, $batchByCluster ); + foreach ( $res as $id => $blob ) { + foreach ( $batchByCluster[$id] as $itemID ) { + $url = $inverseUrlMap[$cluster][$id][$itemID]; + if ( $itemID === false ) { + $ret[$url] = $blob; + } else { + $ret[$url] = $blob->getItem( $itemID ); + } + } + } + } + return $ret; + } + + /** * @see ExternalStoreMedium::store() */ public function store( $cluster, $data ) { @@ -64,7 +91,7 @@ class ExternalStoreDB extends ExternalStoreMedium { __METHOD__ ); $id = $dbw->insertId(); if ( !$id ) { - throw new MWException( __METHOD__.': no insert ID' ); + throw new MWException( __METHOD__ . ': no insert ID' ); } if ( $dbw->getFlag( DBO_TRX ) ) { $dbw->commit( __METHOD__ ); @@ -152,25 +179,31 @@ class ExternalStoreDB extends ExternalStoreMedium { static $externalBlobCache = array(); $cacheID = ( $itemID === false ) ? "$cluster/$id" : "$cluster/$id/"; - if( isset( $externalBlobCache[$cacheID] ) ) { - wfDebugLog( 'ExternalStoreDB-cache', "ExternalStoreDB::fetchBlob cache hit on $cacheID\n" ); + if ( isset( $externalBlobCache[$cacheID] ) ) { + wfDebugLog( 'ExternalStoreDB-cache', + "ExternalStoreDB::fetchBlob cache hit on $cacheID\n" ); return $externalBlobCache[$cacheID]; } - wfDebugLog( 'ExternalStoreDB-cache', "ExternalStoreDB::fetchBlob cache miss on $cacheID\n" ); + wfDebugLog( 'ExternalStoreDB-cache', + "ExternalStoreDB::fetchBlob cache miss on $cacheID\n" ); $dbr =& $this->getSlave( $cluster ); - $ret = $dbr->selectField( $this->getTable( $dbr ), 'blob_text', array( 'blob_id' => $id ), __METHOD__ ); + $ret = $dbr->selectField( $this->getTable( $dbr ), + 'blob_text', array( 'blob_id' => $id ), __METHOD__ ); if ( $ret === false ) { - wfDebugLog( 'ExternalStoreDB', "ExternalStoreDB::fetchBlob master fallback on $cacheID\n" ); + wfDebugLog( 'ExternalStoreDB', + "ExternalStoreDB::fetchBlob master fallback on $cacheID\n" ); // Try the master $dbw =& $this->getMaster( $cluster ); - $ret = $dbw->selectField( $this->getTable( $dbw ), 'blob_text', array( 'blob_id' => $id ), __METHOD__ ); - if( $ret === false) { - wfDebugLog( 'ExternalStoreDB', "ExternalStoreDB::fetchBlob master failed to find $cacheID\n" ); + $ret = $dbw->selectField( $this->getTable( $dbw ), + 'blob_text', array( 'blob_id' => $id ), __METHOD__ ); + if ( $ret === false ) { + wfDebugLog( 'ExternalStoreDB', + "ExternalStoreDB::fetchBlob master failed to find $cacheID\n" ); } } - if( $itemID !== false && $ret !== false ) { + if ( $itemID !== false && $ret !== false ) { // Unserialise object; caller extracts item $ret = unserialize( $ret ); } @@ -178,4 +211,73 @@ class ExternalStoreDB extends ExternalStoreMedium { $externalBlobCache = array( $cacheID => &$ret ); return $ret; } + + /** + * Fetch multiple blob items out of the database + * + * @param string $cluster A cluster name valid for use with LBFactory + * @param array $ids A map from the blob_id's to look for to the requested itemIDs in the blobs + * @return array A map from the blob_id's requested to their content. Unlocated ids are not represented + */ + function batchFetchBlobs( $cluster, array $ids ) { + $dbr = $this->getSlave( $cluster ); + $res = $dbr->select( $this->getTable( $dbr ), + array( 'blob_id', 'blob_text' ), array( 'blob_id' => array_keys( $ids ) ), __METHOD__ ); + $ret = array(); + if ( $res !== false ) { + $this->mergeBatchResult( $ret, $ids, $res ); + } + if ( $ids ) { + wfDebugLog( __CLASS__, __METHOD__ . + " master fallback on '$cluster' for: " . + implode( ',', array_keys( $ids ) ) . "\n" ); + // Try the master + $dbw = $this->getMaster( $cluster ); + $res = $dbw->select( $this->getTable( $dbr ), + array( 'blob_id', 'blob_text' ), + array( 'blob_id' => array_keys( $ids ) ), + __METHOD__ ); + if ( $res === false ) { + wfDebugLog( __CLASS__, __METHOD__ . " master failed on '$cluster'\n" ); + } else { + $this->mergeBatchResult( $ret, $ids, $res ); + } + } + if ( $ids ) { + wfDebugLog( __CLASS__, __METHOD__ . + " master on '$cluster' failed locating items: " . + implode( ',', array_keys( $ids ) ) . "\n" ); + } + return $ret; + } + + /** + * Helper function for self::batchFetchBlobs for merging master/slave results + * @param array &$ret Current self::batchFetchBlobs return value + * @param array &$ids Map from blob_id to requested itemIDs + * @param mixed $res DB result from DatabaseBase::select + */ + private function mergeBatchResult( array &$ret, array &$ids, $res ) { + foreach ( $res as $row ) { + $id = $row->blob_id; + $itemIDs = $ids[$id]; + unset( $ids[$id] ); // to track if everything is found + if ( count( $itemIDs ) === 1 && reset( $itemIDs ) === false ) { + // single result stored per blob + $ret[$id] = $row->blob_text; + } else { + // multi result stored per blob + $ret[$id] = unserialize( $row->blob_text ); + } + } + } + + protected function parseURL( $url ) { + $path = explode( '/', $url ); + return array( + $path[2], // cluster + $path[3], // id + isset( $path[4] ) ? $path[4] : false // itemID + ); + } } |