MediaWiki
REL1_22
|
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 }