Index: trunk/phase3/includes/MessageCache.php |
— | — | @@ -30,6 +30,7 @@ |
31 | 31 | var $mDeferred = true; |
32 | 32 | |
33 | 33 | function initialise( &$memCached, $useDB, $expiry, $memcPrefix) { |
| 34 | + global $wgLocalMessageCache; |
34 | 35 | $fname = 'MessageCache::initialise'; |
35 | 36 | wfProfileIn( $fname ); |
36 | 37 | |
— | — | @@ -58,13 +59,65 @@ |
59 | 60 | wfProfileOut( $fname ); |
60 | 61 | } |
61 | 62 | |
| 63 | + /** |
| 64 | + * Try to load the cache from a local file |
| 65 | + */ |
| 66 | + function loadFromLocal( $hash ) { |
| 67 | + global $wgLocalMessageCache, $wgDBname; |
| 68 | + |
| 69 | + $this->mCache = false; |
| 70 | + if ( $wgLocalMessageCache === false ) { |
| 71 | + return; |
| 72 | + } |
| 73 | + |
| 74 | + $filename = "$wgLocalMessageCache/messages-$wgDBname"; |
| 75 | + |
| 76 | + $file = fopen( $filename, 'r' ); |
| 77 | + if ( !$file ) { |
| 78 | + return; |
| 79 | + } |
| 80 | + |
| 81 | + // Check to see if the file has the hash specified |
| 82 | + $localHash = fread( $file, 32 ); |
| 83 | + if ( $hash == $localHash ) { |
| 84 | + // All good, get the rest of it |
| 85 | + $serialized = fread( $file, 1000000 ); |
| 86 | + $this->mCache = unserialize( $serialized ); |
| 87 | + } |
| 88 | + fclose( $file ); |
| 89 | + } |
| 90 | + |
62 | 91 | /** |
| 92 | + * Save the cache to a local file |
| 93 | + */ |
| 94 | + function saveToLocal( $serialized, $hash ) { |
| 95 | + global $wgLocalMessageCache, $wgDBname; |
| 96 | + |
| 97 | + if ( $wgLocalMessageCache === false ) { |
| 98 | + return; |
| 99 | + } |
| 100 | + |
| 101 | + $filename = "$wgLocalMessageCache/messages-$wgDBname"; |
| 102 | + wfMkdirParents( $wgLocalMessageCache, 0777 ); |
| 103 | + |
| 104 | + $file = fopen( $filename, 'w' ); |
| 105 | + if ( !$file ) { |
| 106 | + wfDebug( "Unable to open local cache file for writing\n" ); |
| 107 | + return; |
| 108 | + } |
| 109 | + |
| 110 | + fwrite( $file, $hash . $serialized ); |
| 111 | + fclose( $file ); |
| 112 | + } |
| 113 | + |
| 114 | + |
| 115 | + /** |
63 | 116 | * Loads messages either from memcached or the database, if not disabled |
64 | 117 | * On error, quietly switches to a fallback mode |
65 | 118 | * Returns false for a reportable error, true otherwise |
66 | 119 | */ |
67 | 120 | function load() { |
68 | | - global $wgAllMessagesEn; |
| 121 | + global $wgAllMessagesEn, $wgLocalMessageCache; |
69 | 122 | |
70 | 123 | if ( $this->mDisable ) { |
71 | 124 | static $shownDisabled = false; |
— | — | @@ -79,10 +132,34 @@ |
80 | 133 | $success = true; |
81 | 134 | |
82 | 135 | if ( $this->mUseCache ) { |
83 | | - wfProfileIn( $fname.'-fromcache' ); |
84 | | - $this->mCache = $this->mMemc->get( $this->mMemcKey ); |
85 | | - wfProfileOut( $fname.'-fromcache' ); |
| 136 | + $this->mCache = false; |
86 | 137 | |
| 138 | + # Try local cache |
| 139 | + wfProfileIn( $fname.'-fromlocal' ); |
| 140 | + $hash = $this->mMemc->get( "{$this->mMemcKey}-hash" ); |
| 141 | + if ( $hash ) { |
| 142 | + $this->loadFromLocal( $hash ); |
| 143 | + } |
| 144 | + wfProfileOut( $fname.'-fromlocal' ); |
| 145 | + |
| 146 | + # Try memcached |
| 147 | + if ( !$this->mCache ) { |
| 148 | + wfProfileIn( $fname.'-fromcache' ); |
| 149 | + $this->mCache = $this->mMemc->get( $this->mMemcKey ); |
| 150 | + |
| 151 | + # Save to local cache |
| 152 | + if ( $wgLocalMessageCache !== false ) { |
| 153 | + $serialized = serialize( $this->mCache ); |
| 154 | + if ( !$hash ) { |
| 155 | + $hash = md5( $serialized ); |
| 156 | + $this->mMemc->set( "{$this->mMemcKey}-hash", $hash, $this->mExpiry ); |
| 157 | + } |
| 158 | + $this->saveToLocal( $serialized, $hash ); |
| 159 | + } |
| 160 | + wfProfileOut( $fname.'-fromcache' ); |
| 161 | + } |
| 162 | + |
| 163 | + |
87 | 164 | # If there's nothing in memcached, load all the messages from the database |
88 | 165 | if ( !$this->mCache ) { |
89 | 166 | wfDebug( "MessageCache::load(): loading all messages\n" ); |
— | — | @@ -93,6 +170,7 @@ |
94 | 171 | wfProfileIn( $fname.'-load' ); |
95 | 172 | $this->loadFromDB(); |
96 | 173 | wfProfileOut( $fname.'-load' ); |
| 174 | + |
97 | 175 | # Save in memcached |
98 | 176 | # Keep trying if it fails, this is kind of important |
99 | 177 | wfProfileIn( $fname.'-save' ); |
— | — | @@ -101,6 +179,15 @@ |
102 | 180 | $i++ ) { |
103 | 181 | usleep(mt_rand(500000,1500000)); |
104 | 182 | } |
| 183 | + |
| 184 | + # Save to local cache |
| 185 | + if ( $wgLocalMessageCache !== false ) { |
| 186 | + $serialized = serialize( $this->mCache ); |
| 187 | + $hash = md5( $serialized ); |
| 188 | + $this->mMemc->set( "{$this->mMemcKey}-hash", $hash, $this->mExpiry ); |
| 189 | + $this->saveToLocal( $serialized, $hash ); |
| 190 | + } |
| 191 | + |
105 | 192 | wfProfileOut( $fname.'-save' ); |
106 | 193 | if ( $i == 20 ) { |
107 | 194 | $this->mMemc->set( $this->mMemcKey.'-status', 'error', 60*5 ); |
— | — | @@ -199,11 +286,23 @@ |
200 | 287 | } |
201 | 288 | |
202 | 289 | function replace( $title, $text ) { |
| 290 | + global $wgLocalMessageCache; |
| 291 | + |
203 | 292 | $this->lock(); |
204 | 293 | $this->load(); |
205 | 294 | if ( is_array( $this->mCache ) ) { |
206 | 295 | $this->mCache[$title] = $text; |
207 | 296 | $this->mMemc->set( $this->mMemcKey, $this->mCache, $this->mExpiry ); |
| 297 | + |
| 298 | + # Save to local cache |
| 299 | + if ( $wgLocalMessageCache !== false ) { |
| 300 | + $serialized = serialize( $this->mCache ); |
| 301 | + $hash = md5( $serialized ); |
| 302 | + $this->mMemc->set( "{$this->mMemcKey}-hash", $hash, $this->mExpiry ); |
| 303 | + $this->saveToLocal( $serialized, $hash ); |
| 304 | + } |
| 305 | + |
| 306 | + |
208 | 307 | } |
209 | 308 | $this->unlock(); |
210 | 309 | } |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -533,6 +533,10 @@ |
534 | 534 | $wgMemCachedServers = array( '127.0.0.1:11000' ); |
535 | 535 | $wgMemCachedDebug = false; |
536 | 536 | |
| 537 | +/** |
| 538 | + * Directory for local copy of message cache, for use in addition to memcached |
| 539 | + */ |
| 540 | +$wgLocalMessageCache = false; |
537 | 541 | |
538 | 542 | |
539 | 543 | # Language settings |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -212,8 +212,9 @@ |
213 | 213 | * Require POST for action=purge, to stop bots from purging the cache |
214 | 214 | * (bug 3817) Use localized date formats in preferences; 'no preference' option |
215 | 215 | localizable as 'datedefault' message. Tweaked lots of languages files... |
| 216 | +* Added local message cache feature ($wgLocalMessageCache), to reduce bandwidth |
| 217 | + requirements to the memcached server. |
216 | 218 | |
217 | | - |
218 | 219 | === Caveats === |
219 | 220 | |
220 | 221 | Some output, particularly involving user-supplied inline HTML, may not |