Limit squid purging
[lhc/web/wiklou.git] / includes / SquidUpdate.php
1 <?php
2 # See deferred.doc
3
4 class SquidUpdate {
5 var $urlArr, $mMaxTitles;
6
7 function SquidUpdate( $urlArr = Array(), $maxTitles = false ) {
8 global $wgMaxSquidPurgeTitles;
9 if ( $maxTitles === false ) {
10 $this->mMaxTitles = $wgMaxSquidPurgeTitles;
11 } else {
12 $this->mMaxTitles = $maxTitles;
13 }
14 if ( count( $urlArr ) > $this->mMaxTitles ) {
15 $urlArr = array_slice( $urlArr, 0, $this->mMaxTitles );
16 }
17 $this->urlArr = $urlArr;
18 }
19
20 /* static */ function newFromLinksTo( &$title ) {
21 # Get a list of URLs linking to this page
22 $id = $title->getArticleID();
23 $sql = "SELECT cur_namespace,cur_title FROM links,cur WHERE l_to={$id} and l_from=cur_id" ;
24 $res = wfQuery ( $sql, DB_READ ) ;
25 $blurlArr = $title->getSquidURLs();
26 if ( wfNumRows( $res ) <= $this->mMaxTitles ) {
27 while ( $BL = wfFetchObject ( $res ) )
28 {
29 $tobj = Title::makeTitle( $BL->cur_namespace, $BL->cur_title ) ;
30 $blurlArr[] = $tobj->getInternalURL();
31 }
32 }
33 wfFreeResult ( $res ) ;
34 return new SquidUpdate( $blurlArr );
35 }
36
37 /* static */ function newFromBrokenLinksTo( &$title ) {
38 # Get a list of URLs linking to this (currently non-existent) page
39 $encTitle = $title->getPrefixedDBkey();
40 $sql = "SELECT cur_namespace,cur_title FROM brokenlinks,cur WHERE bl_to={$encTitle} AND bl_from=cur_id";
41 $res = wfQuery( $sql, DB_READ );
42 $blurlArr = array();
43 if ( wfNumRows( $res ) <= $this->mMaxTitles ) {
44 while ( $BL = wfFetchObject( $res ) )
45 {
46 $tobj = Title::makeTitle( $BL->cur_namespace, $BL->cur_title );
47 $blurlArr[] = $tobj->getInternalURL();
48 }
49 }
50 wfFreeResult( $res );
51 return new SquidUpdate( $blurlArr );
52 }
53
54 /* static */ function newSimplePurge( &$title ) {
55 $urlArr = $title->getSquidURLs();
56 return new SquidUpdate( $blurlArr );
57 }
58
59 function doUpdate() {
60 SquidUpdate::purge( $this->urlArr );
61 }
62
63 /* Purges a list of Squids defined in $wgSquidServers.
64 $urlArr should contain the full URLs to purge as values
65 (example: $urlArr[] = 'http://my.host/something')
66 XXX report broken Squids per mail or log */
67
68 /* static */ function purge( $urlArr ) {
69 global $wgSquidServers;
70
71 if ( $wgSquidServers == "echo" ) {
72 echo implode("<br>\n", $urlArr);
73 return;
74 }
75
76 $maxsocketspersquid = 8; // socket cap per Squid
77 $urlspersocket = 400; // 400 seems to be a good tradeoff, opening a socket takes a while
78 $firsturl = $urlArr[0];
79 unset($urlArr[0]);
80 $urlArr = array_values($urlArr);
81 $sockspersq = max(ceil(count($urlArr) / $urlspersocket ),1);
82 if ($sockspersq == 1) {
83 /* the most common case */
84 $urlspersocket = count($urlArr);
85 } else if ($sockspersq > $maxsocketspersquid ) {
86 $urlspersocket = ceil(count($urlArr) / $maxsocketspersquid);
87 $sockspersq = $maxsocketspersquid;
88 }
89 $totalsockets = count($wgSquidServers) * $sockspersq;
90 $sockets = Array();
91
92 /* this sets up the sockets and tests the first socket for each server. */
93 for ($ss=0;$ss < count($wgSquidServers);$ss++) {
94 $failed = false;
95 $so = 0;
96 while ($so < $sockspersq && !$failed) {
97 if ($so == 0) {
98 /* first socket for this server, do the tests */
99 @list($server, $port) = explode(':', $wgSquidServers[$ss]);
100 if(!isset($port)) $port = 80;
101 $this->debug("Opening socket to $server:$port");
102 $socket = @fsockopen($server, $port, $error, $errstr, 3);
103 $this->debug("\n");
104 if (!$socket) {
105 $failed = true;
106 $totalsockets -= $sockspersq;
107 } else {
108 $msg ="PURGE " . $firsturl . " HTTP/1.0\r\n".
109 "Connection: Keep-Alive\r\n\r\n";
110 $this->debug($msg);
111 @fputs($socket,$msg);
112 $this->debug("...");
113 $res = @fread($socket,512);
114 $this->debug("\n");
115 /* Squid only returns http headers with 200 or 404 status,
116 if there's more returned something's wrong */
117 if (strlen($res) > 250) {
118 fclose($socket);
119 $failed = true;
120 $totalsockets -= $sockspersq;
121 } else {
122 @stream_set_blocking($socket,false);
123 $sockets[] = $socket;
124 }
125 }
126 } else {
127 /* open the remaining sockets for this server */
128 list($server, $port) = explode(':', $wgSquidServers[$ss]);
129 if(!isset($port)) $port = 80;
130 $sockets[] = @fsockopen($server, $port, $error, $errstr, 2);
131 @stream_set_blocking($sockets[$s],false);
132 }
133 $so++;
134 }
135 }
136
137 if ($urlspersocket > 0) {
138 /* now do the heavy lifting. The fread() relies on Squid returning only the headers */
139 for ($r=0;$r < $urlspersocket;$r++) {
140 for ($s=0;$s < $totalsockets;$s++) {
141 if($r != 0) {
142 $res = '';
143 $esc = 0;
144 while (strlen($res) < 100 && $esc < 200 ) {
145 $res .= @fread($sockets[$s],512);
146 $esc++;
147 usleep(20);
148 }
149 }
150 $urindex = $r + $urlspersocket * ($s - $sockspersq * floor($s / $sockspersq));
151 $msg = "PURGE " . $urlArr[$urindex] . " HTTP/1.0\r\n".
152 "Connection: Keep-Alive\r\n\r\n";
153 $this->debug($msg);
154 @fputs($sockets[$s],$msg);
155 $this->debug("\n");
156 }
157 }
158 }
159 $this->debug("Reading response...");
160 foreach ($sockets as $socket) {
161 $res = '';
162 $esc = 0;
163 while (strlen($res) < 100 && $esc < 200 ) {
164 $res .= @fread($socket,1024);
165 $esc++;
166 usleep(20);
167 }
168
169 @fclose($socket);
170 }
171 $this->debug("\n");
172 }
173
174 function debug( $text ) {
175 global $wgDebugSquid;
176 if ( $wgDebugSquid ) {
177 wfDebug( $text );
178 }
179 }
180 }
181 ?>