Index: trunk/phase3/maintenance/dumpInterwiki.inc |
— | — | @@ -201,7 +201,7 @@ |
202 | 202 | array_key_exists($entry['iw_prefix'],$prefixRewrites[$source])) |
203 | 203 | $entry['iw_prefix'] = $prefixRewrites[$source][$entry['iw_prefix']]; |
204 | 204 | if ($dbFile) |
205 | | - dba_insert("{$source}:{$entry['iw_prefix']}", trim("{$entry['iw_local']} {$entry['iw_url']}"),$dbFile); |
| 205 | + $dbFile->set( "{$source}:{$entry['iw_prefix']}", trim("{$entry['iw_local']} {$entry['iw_url']}") ); |
206 | 206 | else |
207 | 207 | print "{$source}:{$entry['iw_prefix']} {$entry['iw_url']} {$entry['iw_local']}\n"; |
208 | 208 | |
Index: trunk/phase3/maintenance/dumpInterwiki.php |
— | — | @@ -19,7 +19,7 @@ |
20 | 20 | # Output |
21 | 21 | if ( isset( $options['o'] ) ) { |
22 | 22 | # To database specified with -o |
23 | | - $dbFile = dba_open( $options['o'], "n", "cdb_make" ); |
| 23 | + $dbFile = CdbWriter::open( $options['o'] ); |
24 | 24 | } |
25 | 25 | |
26 | 26 | getRebuildInterwikiDump(); |
Index: trunk/phase3/includes/Interwiki.php |
— | — | @@ -104,24 +104,24 @@ |
105 | 105 | |
106 | 106 | wfDebug( __METHOD__ . "( $prefix )\n" ); |
107 | 107 | if( !$db ) { |
108 | | - $db = dba_open( $wgInterwikiCache, 'r', 'cdb' ); |
| 108 | + $db = CdbReader::open( $wgInterwikiCache ); |
109 | 109 | } |
110 | 110 | /* Resolve site name */ |
111 | 111 | if( $wgInterwikiScopes>=3 && !$site ) { |
112 | | - $site = dba_fetch( '__sites:' . wfWikiID(), $db ); |
| 112 | + $site = $db->get( '__sites:' . wfWikiID() ); |
113 | 113 | if ( $site == '' ) { |
114 | 114 | $site = $wgInterwikiFallbackSite; |
115 | 115 | } |
116 | 116 | } |
117 | 117 | |
118 | | - $value = dba_fetch( wfMemcKey( $prefix ), $db ); |
| 118 | + $value = $db->get( wfMemcKey( $prefix ) ); |
119 | 119 | // Site level |
120 | 120 | if ( $value == '' && $wgInterwikiScopes >= 3 ) { |
121 | | - $value = dba_fetch( "_{$site}:{$prefix}", $db ); |
| 121 | + $value = $db->get( "_{$site}:{$prefix}" ); |
122 | 122 | } |
123 | 123 | // Global Level |
124 | 124 | if ( $value == '' && $wgInterwikiScopes >= 2 ) { |
125 | | - $value = dba_fetch( "__global:{$prefix}", $db ); |
| 125 | + $value = $db->get( "__global:{$prefix}" ); |
126 | 126 | } |
127 | 127 | if ( $value == 'undef' ) |
128 | 128 | $value = ''; |
Index: trunk/phase3/includes/Cdb_PHP.php |
— | — | @@ -0,0 +1,388 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * This is a port of D.J. Bernstein's CDB to PHP. It's based on the copy that |
| 6 | + * appears in PHP 5.3. Changes are: |
| 7 | + * * Error returns replaced with exceptions |
| 8 | + * * Exception thrown if sizes or offsets are between 2GB and 4GB |
| 9 | + * * Some variables renamed |
| 10 | + */ |
| 11 | + |
| 12 | +/** |
| 13 | + * Common functions for readers and writers |
| 14 | + */ |
| 15 | +class CdbFunctions { |
| 16 | + /** |
| 17 | + * Do a sum of 32-bit signed integers with 2's complement overflow. |
| 18 | + * |
| 19 | + * PHP has broken plus and minus operators, but the bitwise operators |
| 20 | + * (&, |, ^, ~, <<, >>) are all implemented as a simple wrapper around the |
| 21 | + * underlying C operator. The algorithm here uses a binary view of addition |
| 22 | + * to simulate 32-bit addition using 31-bit registers. |
| 23 | + */ |
| 24 | + public static function sumWithOverflow( $a, $b ) { |
| 25 | + $sum = $a + $b; |
| 26 | + if ( is_float( $sum ) ) { |
| 27 | + // Use the plus operator to do a sum of the lowest 30 bits to produce a 31-bit result |
| 28 | + $lowA = $a & 0x3fffffff; |
| 29 | + $lowB = $b & 0x3fffffff; |
| 30 | + $sum = $lowA + $lowB; |
| 31 | + |
| 32 | + // Strip off the carry bit |
| 33 | + $carry = ($sum & 0x40000000) >> 30; |
| 34 | + $sum = $sum & 0x3fffffff; |
| 35 | + |
| 36 | + // Get the last two bits |
| 37 | + $highA = self::unsignedShiftRight( $a, 30 ); |
| 38 | + $highB = self::unsignedShiftRight( $b, 30 ); |
| 39 | + |
| 40 | + // Add with carry |
| 41 | + $highSum = $carry + $highA + $highB; |
| 42 | + |
| 43 | + // Recombine |
| 44 | + $sum = $sum | ( $highSum << 30 ); |
| 45 | + } |
| 46 | + return $sum; |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * Take a modulo of a signed integer as if it were an unsigned integer. |
| 51 | + * $b must be less than 0x40000000 and greater than 0 |
| 52 | + */ |
| 53 | + public static function unsignedMod( $a, $b ) { |
| 54 | + if ( $a < 0 ) { |
| 55 | + $m = ( $a & 0x7fffffff ) % $b + 2 * ( 0x40000000 % $b ); |
| 56 | + return $m % $b; |
| 57 | + } else { |
| 58 | + return $a % $b; |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + /** |
| 63 | + * Shift a signed integer right as if it were unsigned |
| 64 | + */ |
| 65 | + public static function unsignedShiftRight( $a, $b ) { |
| 66 | + if ( $b == 0 ) { |
| 67 | + return $a; |
| 68 | + } |
| 69 | + if ( $a < 0 ) { |
| 70 | + return ( ( $a & 0x7fffffff ) >> $b ) | ( 0x40000000 >> ( $b - 1 ) ); |
| 71 | + } else { |
| 72 | + return $a >> $b; |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + public static function hash( $s ) { |
| 77 | + $h = 5381; |
| 78 | + for ( $i = 0; $i < strlen( $s ); $i++ ) { |
| 79 | + $h = self::sumWithOverflow( $h, $h << 5 ) ^ ord( $s[$i] ); |
| 80 | + } |
| 81 | + return $h; |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +/** |
| 86 | + * CDB reader class |
| 87 | + */ |
| 88 | +class CdbReader_PHP extends CdbReader { |
| 89 | + /** The file handle */ |
| 90 | + var $handle; |
| 91 | + |
| 92 | + /* number of hash slots searched under this key */ |
| 93 | + var $loop; |
| 94 | + |
| 95 | + /* initialized if loop is nonzero */ |
| 96 | + var $khash; |
| 97 | + |
| 98 | + /* initialized if loop is nonzero */ |
| 99 | + var $kpos; |
| 100 | + |
| 101 | + /* initialized if loop is nonzero */ |
| 102 | + var $hpos; |
| 103 | + |
| 104 | + /* initialized if loop is nonzero */ |
| 105 | + var $hslots; |
| 106 | + |
| 107 | + /* initialized if findNext() returns true */ |
| 108 | + var $dpos; |
| 109 | + |
| 110 | + /* initialized if cdb_findnext() returns 1 */ |
| 111 | + var $dlen; |
| 112 | + |
| 113 | + function __construct( $fileName ) { |
| 114 | + $this->handle = fopen( $fileName, 'rb' ); |
| 115 | + if ( !$this->handle ) { |
| 116 | + throw new MWException( 'Unable to open DB file "' . $fileName . '"' ); |
| 117 | + } |
| 118 | + $this->findStart(); |
| 119 | + } |
| 120 | + |
| 121 | + function close() { |
| 122 | + fclose( $this->handle ); |
| 123 | + unset( $this->handle ); |
| 124 | + } |
| 125 | + |
| 126 | + public function get( $key ) { |
| 127 | + // strval is required |
| 128 | + if ( $this->find( strval( $key ) ) ) { |
| 129 | + return $this->read( $this->dlen, $this->dpos ); |
| 130 | + } else { |
| 131 | + return false; |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + protected function match( $key, $pos ) { |
| 136 | + $buf = $this->read( strlen( $key ), $pos ); |
| 137 | + return $buf === $key; |
| 138 | + } |
| 139 | + |
| 140 | + protected function findStart() { |
| 141 | + $this->loop = 0; |
| 142 | + } |
| 143 | + |
| 144 | + protected function read( $length, $pos ) { |
| 145 | + if ( fseek( $this->handle, $pos ) == -1 ) { |
| 146 | + // This can easily happen if the internal pointers are incorrect |
| 147 | + throw new MWException( __METHOD__.': seek failed, file may be corrupted.' ); |
| 148 | + } |
| 149 | + |
| 150 | + if ( $length == 0 ) { |
| 151 | + return ''; |
| 152 | + } |
| 153 | + |
| 154 | + $buf = fread( $this->handle, $length ); |
| 155 | + if ( $buf === false || strlen( $buf ) !== $length ) { |
| 156 | + throw new MWException( __METHOD__.': read from cdb file failed, file may be corrupted' ); |
| 157 | + } |
| 158 | + return $buf; |
| 159 | + } |
| 160 | + |
| 161 | + /** |
| 162 | + * Unpack an unsigned integer and throw an exception if it needs more than 31 bits |
| 163 | + */ |
| 164 | + protected function unpack31( $s ) { |
| 165 | + $data = unpack( 'V', $s ); |
| 166 | + if ( $data[1] > 0x7fffffff ) { |
| 167 | + throw new MWException( __METHOD__.': error in CDB file, integer too big' ); |
| 168 | + } |
| 169 | + return $data[1]; |
| 170 | + } |
| 171 | + |
| 172 | + /** |
| 173 | + * Unpack a 32-bit signed integer |
| 174 | + */ |
| 175 | + protected function unpackSigned( $s ) { |
| 176 | + $data = unpack( 'va/vb', $s ); |
| 177 | + return $data['a'] | ( $data['b'] << 16 ); |
| 178 | + } |
| 179 | + |
| 180 | + protected function findNext( $key ) { |
| 181 | + if ( !$this->loop ) { |
| 182 | + $u = CdbFunctions::hash( $key ); |
| 183 | + $buf = $this->read( 8, ( $u << 3 ) & 2047 ); |
| 184 | + $this->hslots = $this->unpack31( substr( $buf, 4 ) ); |
| 185 | + if ( !$this->hslots ) { |
| 186 | + return false; |
| 187 | + } |
| 188 | + $this->hpos = $this->unpack31( substr( $buf, 0, 4 ) ); |
| 189 | + $this->khash = $u; |
| 190 | + $u = CdbFunctions::unsignedShiftRight( $u, 8 ); |
| 191 | + $u = CdbFunctions::unsignedMod( $u, $this->hslots ); |
| 192 | + $u <<= 3; |
| 193 | + $this->kpos = $this->hpos + $u; |
| 194 | + } |
| 195 | + |
| 196 | + while ( $this->loop < $this->hslots ) { |
| 197 | + $buf = $this->read( 8, $this->kpos ); |
| 198 | + $pos = $this->unpack31( substr( $buf, 4 ) ); |
| 199 | + if ( !$pos ) { |
| 200 | + return false; |
| 201 | + } |
| 202 | + $this->loop += 1; |
| 203 | + $this->kpos += 8; |
| 204 | + if ( $this->kpos == $this->hpos + ( $this->hslots << 3 ) ) { |
| 205 | + $this->kpos = $this->hpos; |
| 206 | + } |
| 207 | + $u = $this->unpackSigned( substr( $buf, 0, 4 ) ); |
| 208 | + if ( $u === $this->khash ) { |
| 209 | + $buf = $this->read( 8, $pos ); |
| 210 | + $keyLen = $this->unpack31( substr( $buf, 0, 4 ) ); |
| 211 | + if ( $keyLen == strlen( $key ) && $this->match( $key, $pos + 8 ) ) { |
| 212 | + // Found |
| 213 | + $this->dlen = $this->unpack31( substr( $buf, 4 ) ); |
| 214 | + $this->dpos = $pos + 8 + $keyLen; |
| 215 | + return true; |
| 216 | + } |
| 217 | + } |
| 218 | + } |
| 219 | + return false; |
| 220 | + } |
| 221 | + |
| 222 | + protected function find( $key ) { |
| 223 | + $this->findStart(); |
| 224 | + return $this->findNext( $key ); |
| 225 | + } |
| 226 | +} |
| 227 | + |
| 228 | +/** |
| 229 | + * CDB writer class |
| 230 | + */ |
| 231 | +class CdbWriter_PHP extends CdbWriter { |
| 232 | + var $handle, $realFileName, $tmpFileName; |
| 233 | + |
| 234 | + var $hplist; |
| 235 | + var $numEntries, $pos; |
| 236 | + |
| 237 | + function __construct( $fileName ) { |
| 238 | + $this->realFileName = $fileName; |
| 239 | + $this->tmpFileName = $fileName . '.tmp.' . mt_rand( 0, 0x7fffffff ); |
| 240 | + $this->handle = fopen( $this->tmpFileName, 'wb' ); |
| 241 | + if ( !$this->handle ) { |
| 242 | + throw new MWException( 'Unable to open DB file for write "' . $fileName . '"' ); |
| 243 | + } |
| 244 | + $this->hplist = array(); |
| 245 | + $this->numentries = 0; |
| 246 | + $this->pos = 2048; // leaving space for the pointer array, 256 * 8 |
| 247 | + if ( fseek( $this->handle, $this->pos ) == -1 ) { |
| 248 | + throw new MWException( __METHOD__.': fseek failed' ); |
| 249 | + } |
| 250 | + } |
| 251 | + |
| 252 | + function __destruct() { |
| 253 | + if ( isset( $this->handle ) ) { |
| 254 | + $this->close(); |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + public function set( $key, $value ) { |
| 259 | + if ( strval( $key ) === '' ) { |
| 260 | + // DBA cross-check hack |
| 261 | + return; |
| 262 | + } |
| 263 | + $this->addbegin( strlen( $key ), strlen( $value ) ); |
| 264 | + $this->write( $key ); |
| 265 | + $this->write( $value ); |
| 266 | + $this->addend( strlen( $key ), strlen( $value ), CdbFunctions::hash( $key ) ); |
| 267 | + } |
| 268 | + |
| 269 | + public function close() { |
| 270 | + $this->finish(); |
| 271 | + fclose( $this->handle ); |
| 272 | + if ( wfIsWindows() ) { |
| 273 | + unlink( $this->realFileName ); |
| 274 | + } |
| 275 | + if ( !rename( $this->tmpFileName, $this->realFileName ) ) { |
| 276 | + throw new MWException( 'Unable to move the new CDB file into place.' ); |
| 277 | + } |
| 278 | + unset( $this->handle ); |
| 279 | + } |
| 280 | + |
| 281 | + protected function write( $buf ) { |
| 282 | + $len = fwrite( $this->handle, $buf ); |
| 283 | + if ( $len !== strlen( $buf ) ) { |
| 284 | + throw new MWException( 'Error writing to CDB file.' ); |
| 285 | + } |
| 286 | + } |
| 287 | + |
| 288 | + protected function posplus( $len ) { |
| 289 | + $newpos = $this->pos + $len; |
| 290 | + if ( $newpos > 0x7fffffff ) { |
| 291 | + throw new MWException( 'A value in the CDB file is too large' ); |
| 292 | + } |
| 293 | + $this->pos = $newpos; |
| 294 | + } |
| 295 | + |
| 296 | + protected function addend( $keylen, $datalen, $h ) { |
| 297 | + $this->hplist[] = array( |
| 298 | + 'h' => $h, |
| 299 | + 'p' => $this->pos |
| 300 | + ); |
| 301 | + |
| 302 | + $this->numentries++; |
| 303 | + $this->posplus( 8 ); |
| 304 | + $this->posplus( $keylen ); |
| 305 | + $this->posplus( $datalen ); |
| 306 | + } |
| 307 | + |
| 308 | + protected function addbegin( $keylen, $datalen ) { |
| 309 | + if ( $keylen > 0x7fffffff ) { |
| 310 | + throw new MWException( __METHOD__.': key length too long' ); |
| 311 | + } |
| 312 | + if ( $datalen > 0x7fffffff ) { |
| 313 | + throw new MWException( __METHOD__.': data length too long' ); |
| 314 | + } |
| 315 | + $buf = pack( 'VV', $keylen, $datalen ); |
| 316 | + $this->write( $buf ); |
| 317 | + } |
| 318 | + |
| 319 | + protected function finish() { |
| 320 | + // Hack for DBA cross-check |
| 321 | + $this->hplist = array_reverse( $this->hplist ); |
| 322 | + |
| 323 | + // Calculate the number of items that will be in each hashtable |
| 324 | + $counts = array_fill( 0, 256, 0 ); |
| 325 | + foreach ( $this->hplist as $item ) { |
| 326 | + ++ $counts[ 255 & $item['h'] ]; |
| 327 | + } |
| 328 | + |
| 329 | + // Fill in $starts with the *end* indexes |
| 330 | + $starts = array(); |
| 331 | + $pos = 0; |
| 332 | + for ( $i = 0; $i < 256; ++$i ) { |
| 333 | + $pos += $counts[$i]; |
| 334 | + $starts[$i] = $pos; |
| 335 | + } |
| 336 | + |
| 337 | + // Excessively clever and indulgent code to simultaneously fill $packedTables |
| 338 | + // with the packed hashtables, and adjust the elements of $starts |
| 339 | + // to actually point to the starts instead of the ends. |
| 340 | + $packedTables = array_fill( 0, $this->numentries, false ); |
| 341 | + foreach ( $this->hplist as $item ) { |
| 342 | + $packedTables[--$starts[255 & $item['h']]] = $item; |
| 343 | + } |
| 344 | + |
| 345 | + $final = ''; |
| 346 | + for ( $i = 0; $i < 256; ++$i ) { |
| 347 | + $count = $counts[$i]; |
| 348 | + |
| 349 | + // The size of the hashtable will be double the item count. |
| 350 | + // The rest of the slots will be empty. |
| 351 | + $len = $count + $count; |
| 352 | + $final .= pack( 'VV', $this->pos, $len ); |
| 353 | + |
| 354 | + $hashtable = array(); |
| 355 | + for ( $u = 0; $u < $len; ++$u ) { |
| 356 | + $hashtable[$u] = array( 'h' => 0, 'p' => 0 ); |
| 357 | + } |
| 358 | + |
| 359 | + // Fill the hashtable, using the next empty slot if the hashed slot |
| 360 | + // is taken. |
| 361 | + for ( $u = 0; $u < $count; ++$u ) { |
| 362 | + $hp = $packedTables[$starts[$i] + $u]; |
| 363 | + $where = CdbFunctions::unsignedMod( |
| 364 | + CdbFunctions::unsignedShiftRight( $hp['h'], 8 ), $len ); |
| 365 | + while ( $hashtable[$where]['p'] ) |
| 366 | + if ( ++$where == $len ) |
| 367 | + $where = 0; |
| 368 | + $hashtable[$where] = $hp; |
| 369 | + } |
| 370 | + |
| 371 | + // Write the hashtable |
| 372 | + for ( $u = 0; $u < $len; ++$u ) { |
| 373 | + $buf = pack( 'vvV', |
| 374 | + $hashtable[$u]['h'] & 0xffff, |
| 375 | + CdbFunctions::unsignedShiftRight( $hashtable[$u]['h'], 16 ), |
| 376 | + $hashtable[$u]['p'] ); |
| 377 | + $this->write( $buf ); |
| 378 | + $this->posplus( 8 ); |
| 379 | + } |
| 380 | + } |
| 381 | + |
| 382 | + // Write the pointer array at the start of the file |
| 383 | + rewind( $this->handle ); |
| 384 | + if ( ftell( $this->handle ) != 0 ) { |
| 385 | + throw new MWException( __METHOD__.': Error rewinding to start of file' ); |
| 386 | + } |
| 387 | + $this->write( $final ); |
| 388 | + } |
| 389 | +} |
Property changes on: trunk/phase3/includes/Cdb_PHP.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 390 | + native |
Index: trunk/phase3/includes/Cdb.php |
— | — | @@ -0,0 +1,147 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Read from a CDB file. |
| 6 | + * Native and pure PHP implementations are provided. |
| 7 | + * http://cr.yp.to/cdb.html |
| 8 | + */ |
| 9 | +abstract class CdbReader { |
| 10 | + /** |
| 11 | + * Open a file and return a subclass instance |
| 12 | + */ |
| 13 | + public static function open( $fileName ) { |
| 14 | + if ( self::haveExtension() ) { |
| 15 | + return new CdbReader_DBA( $fileName ); |
| 16 | + } else { |
| 17 | + wfDebug( 'Warning: no dba extension found, using emulation.' ); |
| 18 | + return new CdbReader_PHP( $fileName ); |
| 19 | + } |
| 20 | + } |
| 21 | + |
| 22 | + /** |
| 23 | + * Returns true if the native extension is available |
| 24 | + */ |
| 25 | + public static function haveExtension() { |
| 26 | + if ( !function_exists( 'dba_handlers' ) ) { |
| 27 | + return false; |
| 28 | + } |
| 29 | + $handlers = dba_handlers(); |
| 30 | + if ( !in_array( 'cdb', $handlers ) || !in_array( 'cdb_make', $handlers ) ) { |
| 31 | + return false; |
| 32 | + } |
| 33 | + return true; |
| 34 | + } |
| 35 | + |
| 36 | + /** |
| 37 | + * Construct the object and open the file |
| 38 | + */ |
| 39 | + abstract function __construct( $fileName ); |
| 40 | + |
| 41 | + /** |
| 42 | + * Close the file. Optional, you can just let the variable go out of scope. |
| 43 | + */ |
| 44 | + abstract function close(); |
| 45 | + |
| 46 | + /** |
| 47 | + * Get a value with a given key. Only string values are supported. |
| 48 | + */ |
| 49 | + abstract public function get( $key ); |
| 50 | +} |
| 51 | + |
| 52 | +/** |
| 53 | + * Write to a CDB file. |
| 54 | + * Native and pure PHP implementations are provided. |
| 55 | + */ |
| 56 | +abstract class CdbWriter { |
| 57 | + /** |
| 58 | + * Open a writer and return a subclass instance. |
| 59 | + * The user must have write access to the directory, for temporary file creation. |
| 60 | + */ |
| 61 | + public static function open( $fileName ) { |
| 62 | + if ( CdbReader::haveExtension() ) { |
| 63 | + return new CdbWriter_DBA( $fileName ); |
| 64 | + } else { |
| 65 | + wfDebug( 'Warning: no dba extension found, using emulation.' ); |
| 66 | + return new CdbWriter_PHP( $fileName ); |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * Create the object and open the file |
| 72 | + */ |
| 73 | + abstract function __construct( $fileName ); |
| 74 | + |
| 75 | + /** |
| 76 | + * Set a key to a given value. The value will be converted to string. |
| 77 | + */ |
| 78 | + abstract public function set( $key, $value ); |
| 79 | + |
| 80 | + /** |
| 81 | + * Close the writer object. You should call this function before the object |
| 82 | + * goes out of scope, to write out the final hashtables. |
| 83 | + */ |
| 84 | + abstract public function close(); |
| 85 | +} |
| 86 | + |
| 87 | + |
| 88 | +/** |
| 89 | + * Reader class which uses the DBA extension |
| 90 | + */ |
| 91 | +class CdbReader_DBA { |
| 92 | + var $handle; |
| 93 | + |
| 94 | + function __construct( $fileName ) { |
| 95 | + $this->handle = dba_open( $fileName, 'r-', 'cdb' ); |
| 96 | + if ( !$this->handle ) { |
| 97 | + throw new MWException( 'Unable to open DB file "' . $fileName . '"' ); |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + function close() { |
| 102 | + dba_close( $this->handle ); |
| 103 | + unset( $this->handle ); |
| 104 | + } |
| 105 | + |
| 106 | + function get( $key ) { |
| 107 | + return dba_fetch( $key, $this->handle ); |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | + |
| 112 | +/** |
| 113 | + * Writer class which uses the DBA extension |
| 114 | + */ |
| 115 | +class CdbWriter_DBA { |
| 116 | + var $handle, $realFileName, $tmpFileName; |
| 117 | + |
| 118 | + function __construct( $fileName ) { |
| 119 | + $this->realFileName = $fileName; |
| 120 | + $this->tmpFileName = $fileName . '.tmp.' . mt_rand( 0, 0x7fffffff ); |
| 121 | + $this->handle = dba_open( $this->tmpFileName, 'n', 'cdb_make' ); |
| 122 | + if ( !$this->handle ) { |
| 123 | + throw new MWException( 'Unable to open DB file for write "' . $fileName . '"' ); |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + function set( $key, $value ) { |
| 128 | + return dba_insert( $key, $value, $this->handle ); |
| 129 | + } |
| 130 | + |
| 131 | + function close() { |
| 132 | + dba_close( $this->handle ); |
| 133 | + if ( wfIsWindows() ) { |
| 134 | + unlink( $this->realFileName ); |
| 135 | + } |
| 136 | + if ( !rename( $this->tmpFileName, $this->realFileName ) ) { |
| 137 | + throw new MWException( 'Unable to move the new CDB file into place.' ); |
| 138 | + } |
| 139 | + unset( $this->handle ); |
| 140 | + } |
| 141 | + |
| 142 | + function __destruct() { |
| 143 | + if ( isset( $this->handle ) ) { |
| 144 | + $this->close(); |
| 145 | + } |
| 146 | + } |
| 147 | +} |
| 148 | + |
Property changes on: trunk/phase3/includes/Cdb.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 149 | + native |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -27,6 +27,13 @@ |
28 | 28 | 'Categoryfinder' => 'includes/Categoryfinder.php', |
29 | 29 | 'CategoryPage' => 'includes/CategoryPage.php', |
30 | 30 | 'CategoryViewer' => 'includes/CategoryPage.php', |
| 31 | + 'CdbFunctions' => 'includes/Cdb_PHP.php', |
| 32 | + 'CdbReader' => 'includes/Cdb.php', |
| 33 | + 'CdbReader_DBA' => 'includes/Cdb.php', |
| 34 | + 'CdbReader_PHP' => 'includes/Cdb_PHP.php', |
| 35 | + 'CdbWriter' => 'includes/Cdb.php', |
| 36 | + 'CdbWriter_DBA' => 'includes/Cdb.php', |
| 37 | + 'CdbWriter_PHP' => 'includes/Cdb_PHP.php', |
31 | 38 | 'ChangesList' => 'includes/ChangesList.php', |
32 | 39 | 'ChangesFeed' => 'includes/ChangesFeed.php', |
33 | 40 | 'ChangeTags' => 'includes/ChangeTags.php', |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -89,7 +89,10 @@ |
90 | 90 | * Add $wgRevokePermissions as a means of restricting a group's rights. The syntax is |
91 | 91 | identical to $wgGroupPermissions, but users in these groups will have these rights |
92 | 92 | stripped from them. |
| 93 | +* Added a PHP port of CDB (constant database), for improved local caching when |
| 94 | + the DBA extension is not available. |
93 | 95 | |
| 96 | + |
94 | 97 | === Bug fixes in 1.16 === |
95 | 98 | |
96 | 99 | * (bug 18031) Make namespace selector on Special:Export remember the previous |