]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/SquidUpdate.php
MediaWiki 1.5.8 (initial commit)
[autoinstallsdev/mediawiki.git] / includes / SquidUpdate.php
1 <?php
2 /**
3  * See deferred.txt
4  * @package MediaWiki
5  */
6
7 /**
8  *
9  * @package MediaWiki
10  */
11 class SquidUpdate {
12         var $urlArr, $mMaxTitles;
13
14         function SquidUpdate( $urlArr = Array(), $maxTitles = false ) {
15                 global $wgMaxSquidPurgeTitles;
16                 if ( $maxTitles === false ) {
17                         $this->mMaxTitles = $wgMaxSquidPurgeTitles;
18                 } else {
19                         $this->mMaxTitles = $maxTitles;
20                 }
21                 if ( count( $urlArr ) > $this->mMaxTitles ) {
22                         $urlArr = array_slice( $urlArr, 0, $this->mMaxTitles );
23                 }
24                 $this->urlArr = $urlArr;
25         }
26
27         /* static */ function newFromLinksTo( &$title ) {
28                 $fname = 'SquidUpdate::newFromLinksTo';
29                 wfProfileIn( $fname );
30
31                 # Get a list of URLs linking to this page
32                 $id = $title->getArticleID();
33
34                 $dbr =& wfGetDB( DB_SLAVE );
35                 $links = $dbr->tableName( 'links' );
36                 $page = $dbr->tableName( 'page' );
37
38                 $res = $dbr->select( array( 'links', 'page' ),
39                         array( 'page_namespace', 'page_title' ),
40                         array(
41                                 'pl_namespace' => $title->getNamespace(),
42                                 'pl_title'     => $title->getDbKey(),
43                                 'pl_from=page_id' ),
44                         $fname );
45                 $blurlArr = $title->getSquidURLs();
46                 if ( $dbr->numRows( $res ) <= $this->mMaxTitles ) {
47                         while ( $BL = $dbr->fetchObject ( $res ) )
48                         {
49                                 $tobj = Title::makeTitle( $BL->page_namespace, $BL->page_title ) ; 
50                                 $blurlArr[] = $tobj->getInternalURL();
51                         }
52                 }
53                 $dbr->freeResult ( $res ) ;
54
55                 wfProfileOut( $fname );
56                 return new SquidUpdate( $blurlArr );
57         }
58
59         /* static */ function newFromTitles( &$titles, $urlArr = array() ) {
60                 foreach ( $titles as $title ) {
61                         $urlArr[] = $title->getInternalURL();
62                 }
63                 return new SquidUpdate( $urlArr );
64         }
65
66         /* static */ function newSimplePurge( &$title ) {
67                 $urlArr = $title->getSquidURLs();
68                 return new SquidUpdate( $blurlArr );
69         }
70
71         function doUpdate() {
72                 SquidUpdate::purge( $this->urlArr );
73         }
74
75         /* Purges a list of Squids defined in $wgSquidServers.
76         $urlArr should contain the full URLs to purge as values 
77         (example: $urlArr[] = 'http://my.host/something')
78         XXX report broken Squids per mail or log */
79
80         /* static */ function purge( $urlArr ) {
81                 global $wgSquidServers, $wgHTCPMulticastAddress, $wgHTCPPort;
82
83                 if ( $wgSquidServers == 'echo' ) {
84                         echo implode("<br />\n", $urlArr);
85                         return;
86                 }
87
88                 if ( $wgHTCPMulticastAddress && $wgHTCPPort )
89                         SquidUpdate::HTCPPurge( $urlArr );
90
91                 $fname = 'SquidUpdate::purge';
92                 wfProfileIn( $fname );
93                 
94                 $maxsocketspersquid = 8; //  socket cap per Squid
95                 $urlspersocket = 400; // 400 seems to be a good tradeoff, opening a socket takes a while
96                 $firsturl = $urlArr[0];
97                 unset($urlArr[0]);
98                 $urlArr = array_values($urlArr);
99                 $sockspersq =  max(ceil(count($urlArr) / $urlspersocket ),1);
100                 if ($sockspersq == 1) {
101                         /* the most common case */
102                         $urlspersocket = count($urlArr);
103                 } else if ($sockspersq > $maxsocketspersquid ) {
104                         $urlspersocket = ceil(count($urlArr) / $maxsocketspersquid);
105                         $sockspersq = $maxsocketspersquid;
106                 }
107                 $totalsockets = count($wgSquidServers) * $sockspersq;
108                 $sockets = Array();
109
110                 /* this sets up the sockets and tests the first socket for each server. */
111                 for ($ss=0;$ss < count($wgSquidServers);$ss++) {
112                         $failed = false;
113                         $so = 0;
114                         while ($so < $sockspersq && !$failed) {
115                                 if ($so == 0) {
116                                         /* first socket for this server, do the tests */
117                                         @list($server, $port) = explode(':', $wgSquidServers[$ss]);
118                                         if(!isset($port)) $port = 80;
119                                         #$this->debug("Opening socket to $server:$port");
120                                         $socket = @fsockopen($server, $port, $error, $errstr, 3);
121                                         #$this->debug("\n");
122                                         if (!$socket) {
123                                                 $failed = true;
124                                                 $totalsockets -= $sockspersq;
125                                         } else {
126                                                 $msg = 'PURGE ' . $firsturl . " HTTP/1.0\r\n".
127                                                 "Connection: Keep-Alive\r\n\r\n";
128                                                 #$this->debug($msg);
129                                                 @fputs($socket,$msg);
130                                                 #$this->debug("...");
131                                                 $res = @fread($socket,512);
132                                                 #$this->debug("\n");
133                                                 /* Squid only returns http headers with 200 or 404 status, 
134                                                 if there's more returned something's wrong */
135                                                 if (strlen($res) > 250) {
136                                                         fclose($socket);
137                                                         $failed = true;
138                                                         $totalsockets -= $sockspersq;
139                                                 } else {
140                                                         @stream_set_blocking($socket,false);
141                                                         $sockets[] = $socket;
142                                                 }
143                                         } 
144                                 } else {
145                                         /* open the remaining sockets for this server */
146                                         list($server, $port) = explode(':', $wgSquidServers[$ss]);
147                                         if(!isset($port)) $port = 80;
148                                         $sockets[] = @fsockopen($server, $port, $error, $errstr, 2);
149                                         @stream_set_blocking($sockets[$s],false);
150                                 }
151                                 $so++;
152                         }
153                 }
154
155                 if ($urlspersocket > 0) {
156                         /* now do the heavy lifting. The fread() relies on Squid returning only the headers */
157                         for ($r=0;$r < $urlspersocket;$r++) {
158                                 for ($s=0;$s < $totalsockets;$s++) {
159                                         if($r != 0) {
160                                                 $res = '';
161                                                 $esc = 0;
162                                                 while (strlen($res) < 100 && $esc < 200  ) {
163                                                         $res .= @fread($sockets[$s],512);
164                                                         $esc++;
165                                                         usleep(20);
166                                                 }
167                                         }
168                                         $urindex = $r + $urlspersocket * ($s - $sockspersq * floor($s / $sockspersq));
169                                         $msg = 'PURGE ' . $urlArr[$urindex] . " HTTP/1.0\r\n".
170                                         "Connection: Keep-Alive\r\n\r\n";
171                                         #$this->debug($msg);
172                                         @fputs($sockets[$s],$msg);
173                                         #$this->debug("\n");
174                                 }
175                         }
176                 }
177                 #$this->debug("Reading response...");
178                 foreach ($sockets as $socket) {
179                         $res = '';
180                         $esc = 0;
181                         while (strlen($res) < 100 && $esc < 200  ) {
182                                 $res .= @fread($socket,1024);
183                                 $esc++;
184                                 usleep(20);
185                         }
186
187                         @fclose($socket);
188                 }
189                 #$this->debug("\n");
190                 wfProfileOut( $fname );
191         }
192
193         /* static */ function HTCPPurge( $urlArr ) {
194                 global $wgHTCPMulticastAddress, $wgHTCPMulticastTTL, $wgHTCPPort;
195                 $fname = 'SquidUpdate::HTCPPurge';
196                 wfProfileIn( $fname );
197
198                 $htcpOpCLR = 4;                 // HTCP CLR
199
200                 // FIXME PHP doesn't support these socket constants (include/linux/in.h)
201                 define( "IPPROTO_IP", 0 );
202                 define( "IP_MULTICAST_LOOP", 34 );
203                 define( "IP_MULTICAST_TTL", 33 );
204
205                 // pfsockopen doesn't work because we need set_sock_opt
206                 $conn = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
207                 if ( $conn ) {
208                         // Set socket options
209                         socket_set_option( $conn, IPPROTO_IP, IP_MULTICAST_LOOP, 0 );
210                         if ( $wgHTCPMulticastTTL != 1 )
211                                 socket_set_option( $conn, IPPROTO_IP, IP_MULTICAST_TTL,
212                                         $wgHTCPMulticastTTL );
213
214                         foreach ( $urlArr as $url ) {
215                                 // Construct a minimal HTCP request diagram
216                                 // as per RFC 2756
217                                 // Opcode 'CLR', no response desired, no auth
218                                 $htcpTransID = rand();
219
220                                 $htcpSpecifier = pack( 'na4na*na8n',
221                                         4, 'NONE', strlen( $url ), $url,
222                                         8, 'HTTP/1.0', 0 );
223
224                                 $htcpDataLen = 8 + 2 + strlen( $htcpSpecifier );
225                                 $htcpLen = 4 + $htcpDataLen + 2;
226
227                                 // Note! Squid gets the bit order of the first
228                                 // word wrong, wrt the RFC. Apparently no other
229                                 // implementation exists, so adapt to Squid
230                                 $htcpPacket = pack( 'nxxnCxNxxa*n',
231                                         $htcpLen, $htcpDataLen, $htcpOpCLR,
232                                         $htcpTransID, $htcpSpecifier, 2);
233
234                                 // Send out
235                                 wfDebug( "Purging URL $url via HTCP\n" );
236                                 socket_sendto( $conn, $htcpPacket, $htcpLen, 0,
237                                         $wgHTCPMulticastAddress, $wgHTCPPort );
238                         }
239                 } else {
240                         $errstr = socket_strerror( socket_last_error() );
241                         wfDebug( "SquidUpdate::HTCPPurge(): Error opening UDP socket: $errstr\n" );
242                 }
243                 wfProfileOut( $fname );
244         }
245
246         function debug( $text ) {
247                 global $wgDebugSquid;
248                 if ( $wgDebugSquid ) {
249                         wfDebug( $text );
250                 }
251         }
252 }
253 ?>