MediaWiki  REL1_21
DBABagOStuff.php
Go to the documentation of this file.
00001 <?php
00035 class DBABagOStuff extends BagOStuff {
00036         var $mHandler, $mFile, $mReader, $mWriter, $mDisabled;
00037 
00041         public function __construct( $params ) {
00042                 global $wgDBAhandler;
00043 
00044                 if ( !isset( $params['dir'] ) ) {
00045                         $params['dir'] = wfTempDir();
00046                 }
00047 
00048                 $this->mFile = $params['dir'] . '/mw-cache-' . wfWikiID() . '.db';
00049                 wfDebug( __CLASS__ . ": using cache file {$this->mFile}\n" );
00050                 $this->mHandler = $wgDBAhandler;
00051         }
00052 
00060         protected function encode( $value, $expiry ) {
00061                 # Convert to absolute time
00062                 $expiry = $this->convertExpiry( $expiry );
00063 
00064                 return sprintf( '%010u', intval( $expiry ) ) . ' ' . serialize( $value );
00065         }
00066 
00071         protected function decode( $blob ) {
00072                 if ( !is_string( $blob ) ) {
00073                         return array( false, 0 );
00074                 } else {
00075                         return array(
00076                                 unserialize( substr( $blob, 11 ) ),
00077                                 intval( substr( $blob, 0, 10 ) )
00078                         );
00079                 }
00080         }
00081 
00085         protected function getReader() {
00086                 if ( file_exists( $this->mFile ) ) {
00087                         $handle = dba_open( $this->mFile, 'rl', $this->mHandler );
00088                 } else {
00089                         $handle = $this->getWriter();
00090                 }
00091 
00092                 if ( !$handle ) {
00093                         wfDebug( "Unable to open DBA cache file {$this->mFile}\n" );
00094                 }
00095 
00096                 return $handle;
00097         }
00098 
00102         protected function getWriter() {
00103                 $handle = dba_open( $this->mFile, 'cl', $this->mHandler );
00104 
00105                 if ( !$handle ) {
00106                         wfDebug( "Unable to open DBA cache file {$this->mFile}\n" );
00107                 }
00108 
00109                 return $handle;
00110         }
00111 
00117         public function get( $key, &$casToken = null ) {
00118                 wfProfileIn( __METHOD__ );
00119                 wfDebug( __METHOD__ . "($key)\n" );
00120 
00121                 $handle = $this->getReader();
00122                 if ( !$handle ) {
00123                         wfProfileOut( __METHOD__ );
00124                         return false;
00125                 }
00126 
00127                 $val = dba_fetch( $key, $handle );
00128                 list( $val, $expiry ) = $this->decode( $val );
00129 
00130                 # Must close ASAP because locks are held
00131                 dba_close( $handle );
00132 
00133                 if ( $val !== false && $expiry && $expiry < time() ) {
00134                         # Key is expired, delete it
00135                         $handle = $this->getWriter();
00136                         dba_delete( $key, $handle );
00137                         dba_close( $handle );
00138                         wfDebug( __METHOD__ . ": $key expired\n" );
00139                         $val = false;
00140                 }
00141 
00142                 $casToken = $val;
00143 
00144                 wfProfileOut( __METHOD__ );
00145 
00146                 return $val;
00147         }
00148 
00155         public function set( $key, $value, $exptime = 0 ) {
00156                 wfProfileIn( __METHOD__ );
00157                 wfDebug( __METHOD__ . "($key)\n" );
00158 
00159                 $blob = $this->encode( $value, $exptime );
00160 
00161                 $handle = $this->getWriter();
00162                 if ( !$handle ) {
00163                         wfProfileOut( __METHOD__ );
00164                         return false;
00165                 }
00166 
00167                 $ret = dba_replace( $key, $blob, $handle );
00168                 dba_close( $handle );
00169 
00170                 wfProfileOut( __METHOD__ );
00171                 return $ret;
00172         }
00173 
00181         public function cas( $casToken, $key, $value, $exptime = 0 ) {
00182                 wfProfileIn( __METHOD__ );
00183                 wfDebug( __METHOD__ . "($key)\n" );
00184 
00185                 $blob = $this->encode( $value, $exptime );
00186 
00187                 $handle = $this->getWriter();
00188                 if ( !$handle ) {
00189                         wfProfileOut( __METHOD__ );
00190                         return false;
00191                 }
00192 
00193                 // DBA is locked to any other write connection, so we can safely
00194                 // compare the current & previous value before saving new value
00195                 $val = dba_fetch( $key, $handle );
00196                 list( $val, $exptime ) = $this->decode( $val );
00197                 if ( $casToken !== $val ) {
00198                         dba_close( $handle );
00199                         wfProfileOut( __METHOD__ );
00200                         return false;
00201                 }
00202 
00203                 $ret = dba_replace( $key, $blob, $handle );
00204                 dba_close( $handle );
00205 
00206                 wfProfileOut( __METHOD__ );
00207                 return $ret;
00208         }
00209 
00215         public function delete( $key, $time = 0 ) {
00216                 wfProfileIn( __METHOD__ );
00217                 wfDebug( __METHOD__ . "($key)\n" );
00218 
00219                 $handle = $this->getWriter();
00220                 if ( !$handle ) {
00221                         wfProfileOut( __METHOD__ );
00222                         return false;
00223                 }
00224 
00225                 $ret = !dba_exists( $key, $handle ) || dba_delete( $key, $handle );
00226                 dba_close( $handle );
00227 
00228                 wfProfileOut( __METHOD__ );
00229                 return $ret;
00230         }
00231 
00238         public function add( $key, $value, $exptime = 0 ) {
00239                 wfProfileIn( __METHOD__ );
00240 
00241                 $blob = $this->encode( $value, $exptime );
00242 
00243                 $handle = $this->getWriter();
00244 
00245                 if ( !$handle ) {
00246                         wfProfileOut( __METHOD__ );
00247                         return false;
00248                 }
00249 
00250                 $ret = dba_insert( $key, $blob, $handle );
00251 
00252                 # Insert failed, check to see if it failed due to an expired key
00253                 if ( !$ret ) {
00254                         list( , $expiry ) = $this->decode( dba_fetch( $key, $handle ) );
00255 
00256                         if ( $expiry && $expiry < time() ) {
00257                                 # Yes expired, delete and try again
00258                                 dba_delete( $key, $handle );
00259                                 $ret = dba_insert( $key, $blob, $handle );
00260                                 # This time if it failed then it will be handled by the caller like any other race
00261                         }
00262                 }
00263 
00264                 dba_close( $handle );
00265 
00266                 wfProfileOut( __METHOD__ );
00267                 return $ret;
00268         }
00269 
00275         public function incr( $key, $step = 1 ) {
00276                 wfProfileIn( __METHOD__ );
00277 
00278                 $handle = $this->getWriter();
00279 
00280                 if ( !$handle ) {
00281                         wfProfileOut( __METHOD__ );
00282                         return false;
00283                 }
00284 
00285                 list( $value, $expiry ) = $this->decode( dba_fetch( $key, $handle ) );
00286                 if ( $value !== false ) {
00287                         if ( $expiry && $expiry < time() ) {
00288                                 # Key is expired, delete it
00289                                 dba_delete( $key, $handle );
00290                                 wfDebug( __METHOD__ . ": $key expired\n" );
00291                                 $value = false;
00292                         } else {
00293                                 $value += $step;
00294                                 $blob = $this->encode( $value, $expiry );
00295 
00296                                 $ret = dba_replace( $key, $blob, $handle );
00297                                 $value = $ret ? $value : false;
00298                         }
00299                 }
00300 
00301                 dba_close( $handle );
00302 
00303                 wfProfileOut( __METHOD__ );
00304 
00305                 return ( $value === false ) ? false : (int)$value;
00306         }
00307 }