From 06e6cd5d995ea7d52d1c17e663ff8e13218192dd Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Sun, 13 Mar 2005 15:00:59 +0000 Subject: [PATCH] * Appllied patch for bug 1686, image metadata cache by Andrius Ramanauskas. * Changed memcached invalidation style in this patch to recache instead of deleting, which is better for concurrency * Added a fix for the media link problem, differnet to my fix for the same problem in REL1_4 but either should work. * Fixed image deletion, it didn't work at all. Not sure when it was broken or if it's been reported. It was working in REL1_4. It was a trivial error. --- includes/DefaultSettings.php | 2 + includes/Image.php | 166 +++++++++++++++++++++++++---------- includes/ImagePage.php | 9 +- includes/SpecialUndelete.php | 8 +- includes/SpecialUpload.php | 4 + 5 files changed, 143 insertions(+), 46 deletions(-) diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 4f8da743e5..c36ef056f6 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -126,6 +126,8 @@ $wgUseSharedUploads = false; $wgSharedUploadPath = "http://commons.wikimedia.org/shared/images"; /** Path on the file system where shared uploads can be found */ $wgSharedUploadDirectory = "/var/www/wiki3/images"; +/** Path on the file system where shared uploads can be found */ +$wgSharedUploadDBname = "commons"; /** * Set the following to false especially if you have a set of files that need to diff --git a/includes/Image.php b/includes/Image.php index de25a38103..4269464c0b 100644 --- a/includes/Image.php +++ b/includes/Image.php @@ -36,70 +36,139 @@ class Image * Create an Image object from an image name * * @param string $name name of the image, used to create a title object using Title::makeTitleSafe + * @param bool $recache if true, ignores anything in memcached and sets the updated metadata * @access public */ - function Image( $name ) { + function Image( $name, $recache = false ) { - global $wgUseSharedUploads, $wgUseLatin1, $wgSharedLatin1, $wgLang; + global $wgUseSharedUploads, $wgUseLatin1, $wgSharedLatin1, $wgLang, $wgMemc, $wgDBname; $this->name = $name; $this->title = Title::makeTitleSafe( NS_IMAGE, $this->name ); $this->fromSharedDirectory = false; $this->imagePath = $this->getFullPath(); - $this->fileExists = file_exists( $this->imagePath); + + $n = strrpos( $name, '.' ); + $this->extension = strtolower( $n ? substr( $name, $n + 1 ) : '' ); + $gis = false; + $hashedName = md5($this->name); + $cacheKey = "$wgDBname:Image:".$hashedName; + $foundCached = false; - # If the file is not found, and a shared upload directory - # like the Wikimedia Commons is used, look for it there. - if (!$this->fileExists && $wgUseSharedUploads) { - - # In case we're on a wgCapitalLinks=false wiki, we - # capitalize the first letter of the filename before - # looking it up in the shared repository. - $this->name= $wgLang->ucfirst($name); - - # Encode the filename if we're on a Latin1 wiki and the - # shared repository is UTF-8 - if($wgUseLatin1 && !$wgSharedLatin1) { - $this->name = utf8_encode($name); + if ( !$recache ) { + $cachedValues = $wgMemc->get( $cacheKey ); + + if (!empty($cachedValues) && is_array($cachedValues)) { + if ($wgUseSharedUploads && $cachedValues['fromShared']) { + # if this is shared file, we need to check if image + # in shared repository has not changed + $commonsCachedValues = $wgMemc->get( "$wgSharedUploadDBname:Image:".$hashedName ); + if (!empty($commonsCachedValues) && is_array($commonsCachedValues)) { + $this->name = $commonsCachedValues['name']; + $this->imagePath = $commonsCachedValues['imagePath']; + $this->fileExists = $commonsCachedValues['fileExists']; + $this->fromSharedDirectory = true; + $gis = $commonsCachedValues['gis']; + $foundCached = true; + } + } + else { + $this->name = $cachedValues['name']; + $this->imagePath = $cachedValues['imagePath']; + $this->fileExists = $cachedValues['fileExists']; + $this->fromSharedDirectory = false; + $gis = $cachedValues['gis']; + $foundCached = true; + } } - - $this->imagePath = $this->getFullPath(true); - $this->fileExists = file_exists( $this->imagePath); - $this->fromSharedDirectory = true; - $name=$this->name; - } - if($this->fileExists) { - $this->url = $this->wfImageUrl( $this->name, $this->fromSharedDirectory ); - } else { - $this->url=''; - } - - $n = strrpos( $name, '.' ); - $this->extension = strtolower( $n ? substr( $name, $n + 1 ) : '' ); - - if ( $this->fileExists ) { - if( $this->extension == 'svg' ) { - @$gis = getSVGsize( $this->imagePath ); - } else { - @$gis = getimagesize( $this->imagePath ); + if (!$foundCached) { + $this->fileExists = file_exists( $this->imagePath); + + # If the file is not found, and a shared upload directory + # like the Wikimedia Commons is used, look for it there. + if (!$this->fileExists && $wgUseSharedUploads) { + + # In case we're on a wgCapitalLinks=false wiki, we + # capitalize the first letter of the filename before + # looking it up in the shared repository. + $this->name= $wgLang->ucfirst($name); + + # Encode the filename if we're on a Latin1 wiki and the + # shared repository is UTF-8 + if($wgUseLatin1 && !$wgSharedLatin1) { + $this->name = utf8_encode($name); + } + + $this->imagePath = $this->getFullPath(true); + $this->fileExists = file_exists( $this->imagePath); + $this->fromSharedDirectory = true; + $name=$this->name; } - if( $gis !== false ) { - $this->width = $gis[0]; - $this->height = $gis[1]; - $this->type = $gis[2]; - $this->attr = $gis[3]; - if ( isset( $gis['bits'] ) ) { - $this->bits = $gis['bits']; + + if ( $this->fileExists ) { + # Don't try to get the size of sound and video files, that's bad for performance + if ( !Image::isKnownImageExtension( $this->extension ) ) { + $gis = false; + } elseif( $this->extension == 'svg' ) { + wfSuppressWarnings(); + $gis = getSVGsize( $this->imagePath ); + wfRestoreWarnings(); } else { - $this->bits = 0; + wfSuppressWarnings(); + $gis = getimagesize( $this->imagePath ); + wfRestoreWarnings(); } } + + $cachedValues = array('name' => $this->name, + 'imagePath' => $this->imagePath, + 'fileExists' => $this->fileExists, + 'fromShared' => $this->fromSharedDirectory, + 'gis' => $gis); + + $wgMemc->set( $cacheKey, $cachedValues ); + + if ($wgUseSharedUploads && $this->fromSharedDirectory) { + $cachedValues['fromShared'] = false; + $wgMemc->set( "$wgSharedUploadDBname:Image:".$hashedName, $cachedValues ); + } + } + + if( $gis !== false ) { + $this->width = $gis[0]; + $this->height = $gis[1]; + $this->type = $gis[2]; + $this->attr = $gis[3]; + if ( isset( $gis['bits'] ) ) { + $this->bits = $gis['bits']; + } else { + $this->bits = 0; + } + } + + if($this->fileExists) { + $this->url = $this->wfImageUrl( $this->name, $this->fromSharedDirectory ); + } else { + $this->url=''; } $this->historyLine = 0; } + /** + * Remove image metadata from cache if any + * + * Don't call this, use the $recache parameter of Image::Image() instead + * + * @param string $name the title of an image + * @static + */ + function invalidateMetadataCache( $name ) { + global $wgMemc, $wgDBname; + $wgMemc->delete("$wgDBname:Image:".md5($name)); + } + /** * Factory function * @@ -588,6 +657,15 @@ class Image return $fullpath; } + /** + * @return bool + * @static + */ + function isKnownImageExtension( $ext ) { + static $extensions = array( 'svg', 'png', 'jpg', 'jpeg', 'gif', 'bmp', 'xbm' ); + return in_array( $ext, $extensions ); + } + } //class diff --git a/includes/ImagePage.php b/includes/ImagePage.php index 105eb895e9..d0285e8960 100644 --- a/includes/ImagePage.php +++ b/includes/ImagePage.php @@ -187,7 +187,7 @@ class ImagePage extends Article { { global $wgUser, $wgOut, $wgRequest; - $confirm = $wgRequest->getBool( 'wpConfirm' ); + $confirm = $wgRequest->getBool( 'wpConfirmB' ); $image = $wgRequest->getVal( 'image' ); $oldimage = $wgRequest->getVal( 'oldimage' ); @@ -307,6 +307,9 @@ class ImagePage extends Article { $article = new Article( $nt ); $article->doDeleteArticle( $reason ); # ignore errors + /* refresh image metadata cache */ + new Image( $image, true ); + $deleted = $image; } @@ -404,6 +407,10 @@ class ImagePage extends Article { $wgOut->fileCopyError( "${archive}/{$oldimage}", $curfile ); } wfRecordUpload( $name, $oldver, $size, wfMsg( "reverted" ) ); + + /* refresh image metadata cache */ + new Image( $name, true ); + # Squid purging if ( $wgUseSquid ) { $urlArr = Array( diff --git a/includes/SpecialUndelete.php b/includes/SpecialUndelete.php index 91b3273556..648efdcc8b 100644 --- a/includes/SpecialUndelete.php +++ b/includes/SpecialUndelete.php @@ -259,7 +259,7 @@ class PageArchive { $reason = wfMsg( 'undeletedrevisions', $restoreRevisions ); } $log->addEntry( 'restore', $this->title, $reason ); - + return true; } } @@ -429,6 +429,12 @@ class UndeleteForm { $archive = new PageArchive( $this->mTargetObj ); if( $archive->undelete( $this->mTargetTimestamp ) ) { $wgOut->addWikiText( wfMsg( "undeletedtext", $this->mTarget ) ); + + if (NS_IMAGE == $this->mTargetObj->getNamespace()) { + /* refresh image metadata cache */ + new Image( $this->mTargetObj->getText(), true ); + } + return true; } } diff --git a/includes/SpecialUpload.php b/includes/SpecialUpload.php index 9aa57b8e5d..a5b32f0971 100644 --- a/includes/SpecialUpload.php +++ b/includes/SpecialUpload.php @@ -270,6 +270,10 @@ class UploadForm { $this->mUploadDescription, $this->mUploadCopyStatus, $this->mUploadSource ); + + /* refresh image metadata cache */ + new Image( $this->mUploadSaveName, true ); + $this->showSuccess(); } } -- 2.20.1