MediaWiki  REL1_20
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 
00116         public function get( $key ) {
00117                 wfProfileIn( __METHOD__ );
00118                 wfDebug( __METHOD__ . "($key)\n" );
00119 
00120                 $handle = $this->getReader();
00121                 if ( !$handle ) {
00122                         wfProfileOut( __METHOD__ );
00123                         return false;
00124                 }
00125 
00126                 $val = dba_fetch( $key, $handle );
00127                 list( $val, $expiry ) = $this->decode( $val );
00128 
00129                 # Must close ASAP because locks are held
00130                 dba_close( $handle );
00131 
00132                 if ( $val !== false && $expiry && $expiry < time() ) {
00133                         # Key is expired, delete it
00134                         $handle = $this->getWriter();
00135                         dba_delete( $key, $handle );
00136                         dba_close( $handle );
00137                         wfDebug( __METHOD__ . ": $key expired\n" );
00138                         $val = false;
00139                 }
00140 
00141                 wfProfileOut( __METHOD__ );
00142                 return $val;
00143         }
00144 
00151         public function set( $key, $value, $exptime = 0 ) {
00152                 wfProfileIn( __METHOD__ );
00153                 wfDebug( __METHOD__ . "($key)\n" );
00154 
00155                 $blob = $this->encode( $value, $exptime );
00156 
00157                 $handle = $this->getWriter();
00158                 if ( !$handle ) {
00159                         wfProfileOut( __METHOD__ );
00160                         return false;
00161                 }
00162 
00163                 $ret = dba_replace( $key, $blob, $handle );
00164                 dba_close( $handle );
00165 
00166                 wfProfileOut( __METHOD__ );
00167                 return $ret;
00168         }
00169 
00175         public function delete( $key, $time = 0 ) {
00176                 wfProfileIn( __METHOD__ );
00177                 wfDebug( __METHOD__ . "($key)\n" );
00178 
00179                 $handle = $this->getWriter();
00180                 if ( !$handle ) {
00181                         wfProfileOut( __METHOD__ );
00182                         return false;
00183                 }
00184 
00185                 $ret = !dba_exists( $key, $handle ) || dba_delete( $key, $handle );
00186                 dba_close( $handle );
00187 
00188                 wfProfileOut( __METHOD__ );
00189                 return $ret;
00190         }
00191 
00198         public function add( $key, $value, $exptime = 0 ) {
00199                 wfProfileIn( __METHOD__ );
00200 
00201                 $blob = $this->encode( $value, $exptime );
00202 
00203                 $handle = $this->getWriter();
00204 
00205                 if ( !$handle ) {
00206                         wfProfileOut( __METHOD__ );
00207                         return false;
00208                 }
00209 
00210                 $ret = dba_insert( $key, $blob, $handle );
00211 
00212                 # Insert failed, check to see if it failed due to an expired key
00213                 if ( !$ret ) {
00214                         list( $value, $expiry ) = $this->decode( dba_fetch( $key, $handle ) );
00215 
00216                         if ( $expiry && $expiry < time() ) {
00217                                 # Yes expired, delete and try again
00218                                 dba_delete( $key, $handle );
00219                                 $ret = dba_insert( $key, $blob, $handle );
00220                                 # This time if it failed then it will be handled by the caller like any other race
00221                         }
00222                 }
00223 
00224                 dba_close( $handle );
00225 
00226                 wfProfileOut( __METHOD__ );
00227                 return $ret;
00228         }
00229 
00235         public function incr( $key, $step = 1 ) {
00236                 wfProfileIn( __METHOD__ );
00237 
00238                 $handle = $this->getWriter();
00239 
00240                 if ( !$handle ) {
00241                         wfProfileOut( __METHOD__ );
00242                         return false;
00243                 }
00244 
00245                 list( $value, $expiry ) = $this->decode( dba_fetch( $key, $handle ) );
00246                 if ( $value !== false ) {
00247                         if ( $expiry && $expiry < time() ) {
00248                                 # Key is expired, delete it
00249                                 dba_delete( $key, $handle );
00250                                 wfDebug( __METHOD__ . ": $key expired\n" );
00251                                 $value = false;
00252                         } else {
00253                                 $value += $step;
00254                                 $blob = $this->encode( $value, $expiry );
00255 
00256                                 $ret = dba_replace( $key, $blob, $handle );
00257                                 $value = $ret ? $value : false;
00258                         }
00259                 }
00260 
00261                 dba_close( $handle );
00262 
00263                 wfProfileOut( __METHOD__ );
00264 
00265                 return ( $value === false ) ? false : (int)$value;
00266         }
00267 
00268         function keys() {
00269                 $reader = $this->getReader();
00270                 $k1 = dba_firstkey( $reader );
00271 
00272                 if ( !$k1 ) {
00273                         return array();
00274                 }
00275 
00276                 $result[] = $k1;
00277 
00278                 $key = dba_nextkey( $reader );
00279                 while ( $key ) {
00280                         $result[] = $key;
00281                         $key = dba_nextkey( $reader );
00282                 }
00283 
00284                 return $result;
00285         }
00286 }