r4797 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r4796‎ | r4797 | r4798 >
Date:07:23, 15 August 2004
Author:timstarling
Status:old
Tags:
Comment:
Added FOR UPDATE mode to Block.php, to fix memcached concurrency problem in BlockCache.php. This should fix the regular reports from en of blocks not taking effect.
Modified paths:
  • /trunk/phase3/includes/Block.php (modified) (history)
  • /trunk/phase3/includes/BlockCache.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/BlockCache.php
@@ -7,8 +7,7 @@
88 {
99 var $mData = false, $mMemcKey;
1010
11 - function BlockCache( $deferLoad = false, $dbName = '' )
12 - {
 11+ function BlockCache( $deferLoad = false, $dbName = '' ) {
1312 global $wgDBname;
1413
1514 if ( $dbName == '' ) {
@@ -22,34 +21,38 @@
2322 }
2423 }
2524
26 - function load()
27 - {
 25+ # Load the blocks from the database and save them to memcached
 26+ function loadFromDB() {
2827 global $wgUseMemCached, $wgMemc;
 28+ $this->mData = array();
 29+ # Selecting FOR UPDATE is a convenient way to serialise the memcached and DB operations,
 30+ # which is necessary even though we don't update the DB
 31+ if ( $wgUseMemCached ) {
 32+ Block::enumBlocks( 'wfBlockCacheInsert', '', EB_FOR_UPDATE );
 33+ $wgMemc->set( $this->mMemcKey, $this->mData, 0 );
 34+ } else {
 35+ Block::enumBlocks( 'wfBlockCacheInsert', '' );
 36+ }
 37+ }
 38+
 39+ # Load the cache from memcached or, if that's not possible, from the DB
 40+ function load() {
 41+ global $wgUseMemCached, $wgMemc;
2942
3043 if ( $this->mData === false) {
31 - $saveMemc = false;
3244 # Try memcached
3345 if ( $wgUseMemCached ) {
3446 $this->mData = $wgMemc->get( $this->mMemcKey );
35 - if ( !$this->mData ) {
36 - $saveMemc = true;
37 - }
3847 }
3948
4049 if ( !is_array( $this->mData ) ) {
41 - # Load from DB
42 - $this->mData = array();
43 - Block::enumBlocks( 'wfBlockCacheInsert', '' ); # Calls $this->insert()
 50+ $this->loadFromDB();
4451 }
45 -
46 - if ( $saveMemc ) {
47 - $wgMemc->set( $this->mMemcKey, $this->mData, 0 );
48 - }
4952 }
5053 }
5154
52 - function insert( &$block )
53 - {
 55+ # Add a block to the cache
 56+ function insert( &$block ) {
5457 if ( $block->mUser == 0 ) {
5558 $nb = $block->getNetworkBits();
5659 $ipint = $block->getIntegerAddr();
@@ -62,9 +65,9 @@
6366 $this->mData[$nb][$index] = 1;
6467 }
6568 }
66 -
67 - function get( $ip )
68 - {
 69+
 70+ # Find out if a given IP address is blocked
 71+ function get( $ip ) {
6972 $this->load();
7073 $ipint = ip2long( $ip );
7174 $blocked = false;
@@ -90,24 +93,14 @@
9194 return $block;
9295 }
9396
94 - function clear()
95 - {
96 - global $wgUseMemCached, $wgMemc;
97 -
 97+ # Clear the local cache
 98+ # There was once a clear() to clear memcached too, but I deleted it
 99+ function clearLocal() {
98100 $this->mData = false;
99 - if ( $wgUseMemCached ) {
100 - $wgMemc->delete( $this->mMemcKey );
101 - }
102101 }
103 -
104 - function clearLocal()
105 - {
106 - $this->mData = false;
107 - }
108102 }
109103
110 -function wfBlockCacheInsert( $block, $tag )
111 -{
 104+function wfBlockCacheInsert( $block, $tag ) {
112105 global $wgBlockCache;
113106 $wgBlockCache->insert( $block );
114107 }
Index: trunk/phase3/includes/Block.php
@@ -10,10 +10,13 @@
1111
1212 # Globals used: $wgBlockCache, $wgAutoblockExpiry
1313
 14+define ( 'EB_KEEP_EXPIRED', 1 );
 15+define ( 'EB_FOR_UPDATE', 2 );
 16+
1417 class Block
1518 {
1619 /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry;
17 - /* private */ var $mNetworkBits, $mIntegerAddr;
 20+ /* private */ var $mNetworkBits, $mIntegerAddr, $mForUpdate;
1821
1922 function Block( $address = '', $user = '', $by = 0, $reason = '',
2023 $timestamp = '' , $auto = 0, $expiry = '' )
@@ -25,7 +28,8 @@
2629 $this->mTimestamp = $timestamp;
2730 $this->mAuto = $auto;
2831 $this->mExpiry = $expiry;
29 -
 32+
 33+ $this->mForUpdate = false;
3034 $this->initialiseRange();
3135 }
3236
@@ -49,27 +53,33 @@
5054
5155 $ret = false;
5256 $killed = false;
53 - $dbr =& wfGetDB( DB_SLAVE );
54 - $ipblocks = $dbr->tableName( 'ipblocks' );
 57+ if ( $this->forUpdate() ) {
 58+ $db =& wfGetDB( DB_MASTER );
 59+ $options = 'FOR UPDATE';
 60+ } else {
 61+ $db =& wfGetDB( DB_SLAVE );
 62+ $options = '';
 63+ }
 64+ $ipblocks = $db->tableName( 'ipblocks' );
5565
5666 if ( 0 == $user && $address=="" ) {
57 - $sql = "SELECT * from $ipblocks";
 67+ $sql = "SELECT * from $ipblocks $options";
5868 } elseif ($address=="") {
59 - $sql = "SELECT * FROM $ipblocks WHERE ipb_user={$user}";
 69+ $sql = "SELECT * FROM $ipblocks WHERE ipb_user={$user} $options";
6070 } elseif ($user=="") {
61 - $sql = "SELECT * FROM $ipblocks WHERE ipb_address='" . $dbr->strencode( $address ) . "'";
 71+ $sql = "SELECT * FROM $ipblocks WHERE ipb_address='" . $db->strencode( $address ) . "' $options";
6272 } else {
63 - $sql = "SELECT * FROM $ipblocks WHERE (ipb_address='" . $dbr->strencode( $address ) .
64 - "' OR ipb_user={$user})";
 73+ $sql = "SELECT * FROM $ipblocks WHERE (ipb_address='" . $db->strencode( $address ) .
 74+ "' OR ipb_user={$user}) $options";
6575 }
6676
67 - $res = $dbr->query( $sql, $fname );
68 - if ( 0 == $dbr->numRows( $res ) ) {
 77+ $res = $db->query( $sql, $fname );
 78+ if ( 0 == $db->numRows( $res ) ) {
6979 # User is not blocked
7080 $this->clear();
7181 } else {
7282 # Get first block
73 - $row = $dbr->fetchObject( $res );
 83+ $row = $db->fetchObject( $res );
7484 $this->initFromRow( $row );
7585
7686 if ( $killExpired ) {
@@ -77,7 +87,7 @@
7888 do {
7989 $killed = $this->deleteIfExpired();
8090 if ( $killed ) {
81 - $row = $dbr->fetchObject( $res );
 91+ $row = $db->fetchObject( $res );
8292 if ( $row ) {
8393 $this->initFromRow( $row );
8494 }
@@ -95,7 +105,7 @@
96106 $ret = true;
97107 }
98108 }
99 - $dbr->freeResult( $res );
 109+ $db->freeResult( $res );
100110 return $ret;
101111 }
102112
@@ -130,18 +140,25 @@
131141 }
132142
133143 # Callback with a Block object for every block
134 - /*static*/ function enumBlocks( $callback, $tag, $killExpired = true )
 144+ /*static*/ function enumBlocks( $callback, $tag, $flags = 0 )
135145 {
136 - $dbr =& wfGetDB( DB_SLAVE );
137 - $ipblocks = $dbr->tableName( 'ipblocks' );
 146+ $block = new Block();
 147+ if ( $flags & EB_FOR_UPDATE ) {
 148+ $db =& wfGetDB( DB_MASTER );
 149+ $options = 'FOR UPDATE';
 150+ $block->forUpdate( true );
 151+ } else {
 152+ $db =& wfGetDB( DB_SLAVE );
 153+ $options = '';
 154+ }
 155+ $ipblocks = $db->tableName( 'ipblocks' );
138156
139 - $sql = "SELECT * FROM $ipblocks ORDER BY ipb_timestamp DESC";
140 - $res = $dbr->query( $sql, 'Block::enumBans' );
141 - $block = new Block();
 157+ $sql = "SELECT * FROM $ipblocks ORDER BY ipb_timestamp DESC $options";
 158+ $res = $db->query( $sql, 'Block::enumBans' );
142159
143 - while ( $row = $dbr->fetchObject( $res ) ) {
 160+ while ( $row = $db->fetchObject( $res ) ) {
144161 $block->initFromRow( $row );
145 - if ( $killExpired ) {
 162+ if ( !( $flags & EB_KEEP_EXPIRED ) ) {
146163 if ( !$block->deleteIfExpired() ) {
147164 $callback( $block, $tag );
148165 }
@@ -232,7 +249,7 @@
233250 {
234251 global $wgBlockCache;
235252 if ( is_object( $wgBlockCache ) ) {
236 - $wgBlockCache->clear();
 253+ $wgBlockCache->loadFromDB();
237254 }
238255 }
239256
@@ -246,6 +263,10 @@
247264 return $this->mNetworkBits;
248265 }
249266
 267+ function forUpdate( $x = NULL ) {
 268+ return wfSetVar( $this->mForUpdate, $x );
 269+ }
 270+
250271 /* static */ function getAutoblockExpiry( $timestamp )
251272 {
252273 global $wgAutoblockExpiry;

Follow-up revisions

RevisionCommit summaryAuthorDate
r84332Remove some insanely ancient (~r4797) unused globals and variables, and make ...happy-melon16:41, 19 March 2011

Status & tagging log