a4e97d5fa5624a94acd264e7d117bbc6d1bf62af
[lhc/web/wiklou.git] / includes / BlockCache.php
1 <?php
2 /**
3 * Contain the blockcache class
4 */
5
6 /**
7 * Object for fast lookup of IP blocks
8 * Represents a memcached value, and in some sense, the entire ipblocks table
9 */
10 class BlockCache
11 {
12 var $mData = false, $mMemcKey;
13
14 function BlockCache( $deferLoad = false, $dbName = '' ) {
15 global $wgDBname;
16
17 if ( $dbName == '' ) {
18 $dbName = $wgDBname;
19 }
20
21 $this->mMemcKey = $dbName.':ipblocks';
22
23 if ( !$deferLoad ) {
24 $this->load();
25 }
26 }
27
28 # Load the blocks from the database and save them to memcached
29 function loadFromDB() {
30 global $wgUseMemCached, $wgMemc;
31 $this->mData = array();
32 # Selecting FOR UPDATE is a convenient way to serialise the memcached and DB operations,
33 # which is necessary even though we don't update the DB
34 if ( $wgUseMemCached ) {
35 Block::enumBlocks( 'wfBlockCacheInsert', '', EB_FOR_UPDATE );
36 $wgMemc->set( $this->mMemcKey, $this->mData, 0 );
37 } else {
38 Block::enumBlocks( 'wfBlockCacheInsert', '' );
39 }
40 }
41
42 # Load the cache from memcached or, if that's not possible, from the DB
43 function load() {
44 global $wgUseMemCached, $wgMemc;
45
46 if ( $this->mData === false) {
47 # Try memcached
48 if ( $wgUseMemCached ) {
49 $this->mData = $wgMemc->get( $this->mMemcKey );
50 }
51
52 if ( !is_array( $this->mData ) ) {
53 $this->loadFromDB();
54 }
55 }
56 }
57
58 # Add a block to the cache
59 function insert( &$block ) {
60 if ( $block->mUser == 0 ) {
61 $nb = $block->getNetworkBits();
62 $ipint = $block->getIntegerAddr();
63 $index = $ipint >> ( 32 - $nb );
64
65 if ( !array_key_exists( $nb, $this->mData ) ) {
66 $this->mData[$nb] = array();
67 }
68
69 $this->mData[$nb][$index] = 1;
70 }
71 }
72
73 # Find out if a given IP address is blocked
74 function get( $ip ) {
75 $this->load();
76 $ipint = ip2long( $ip );
77 $blocked = false;
78
79 foreach ( $this->mData as $networkBits => $blockInts ) {
80 if ( array_key_exists( $ipint >> ( 32 - $networkBits ), $blockInts ) ) {
81 $blocked = true;
82 break;
83 }
84 }
85 if ( $blocked ) {
86 # Clear low order bits
87 if ( $networkBits != 32 ) {
88 $ip .= '/'.$networkBits;
89 $ip = Block::normaliseRange( $ip );
90 }
91 $block = new Block();
92 $block->load( $ip );
93 } else {
94 $block = false;
95 }
96
97 return $block;
98 }
99
100 # Clear the local cache
101 # There was once a clear() to clear memcached too, but I deleted it
102 function clearLocal() {
103 $this->mData = false;
104 }
105 }
106
107 function wfBlockCacheInsert( $block, $tag ) {
108 global $wgBlockCache;
109 $wgBlockCache->insert( $block );
110 }