Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/matcher.js

Issue 30001564: Issue 7267 - Optimize memory layout of filter domain maps in matcher (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Add tests Created Feb. 8, 2019, 5:20 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/matcher.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 233
234 for (let type of nonDefaultTypes(filter.contentType)) 234 for (let type of nonDefaultTypes(filter.contentType))
235 { 235 {
236 let map = this._filterMapsByType.get(type); 236 let map = this._filterMapsByType.get(type);
237 if (!map) 237 if (!map)
238 this._filterMapsByType.set(type, map = new Map()); 238 this._filterMapsByType.set(type, map = new Map());
239 239
240 addFilterByKeyword(filter, keyword, map); 240 addFilterByKeyword(filter, keyword, map);
241 } 241 }
242 242
243 let {domains} = filter;
244
243 let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword); 245 let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword);
244 if (!filtersByDomain) 246 if (!filtersByDomain)
245 this._filterDomainMapsByKeyword.set(keyword, filtersByDomain = new Map()); 247 {
248 // In most cases, there is only one pure generic filter to a keyword.
249 // Instead of Map { "foo" => Map { "" => Map { filter => true } } }, we
250 // can just reduce it to Map { "foo" => filter } and save a lot of
251 // memory.
252 if (!domains)
253 {
254 this._filterDomainMapsByKeyword.set(keyword, filter);
255 return;
256 }
246 257
247 for (let [domain, include] of filter.domains || defaultDomains) 258 filtersByDomain = new Map();
259 this._filterDomainMapsByKeyword.set(keyword, filtersByDomain);
260 }
261 else if (!(filtersByDomain instanceof Map))
262 {
263 filtersByDomain = new Map([["", filtersByDomain]]);
264 this._filterDomainMapsByKeyword.set(keyword, filtersByDomain);
265 }
266
267 for (let [domain, include] of domains || defaultDomains)
248 { 268 {
249 if (!include && domain == "") 269 if (!include && domain == "")
250 continue; 270 continue;
251 271
252 let map = filtersByDomain.get(domain); 272 let map = filtersByDomain.get(domain);
253 if (!map) 273 if (!map)
254 { 274 {
255 filtersByDomain.set(domain, include ? filter : 275 filtersByDomain.set(domain, include ? filter :
256 map = new Map([[filter, false]])); 276 map = new Map([[filter, false]]));
257 } 277 }
258 else if (map.size == 1 && !(map instanceof Map)) 278 else if (map.size == 1 && !(map instanceof Map))
259 { 279 {
260 if (filter != map) 280 if (filter != map)
261 { 281 {
262 filtersByDomain.set(domain, new Map([[map, true], 282 filtersByDomain.set(domain, new Map([[map, true],
263 [filter, include]])); 283 [filter, include]]));
264 } 284 }
265 } 285 }
266 else 286 else
(...skipping 27 matching lines...) Expand all
294 for (let type of nonDefaultTypes(filter.contentType)) 314 for (let type of nonDefaultTypes(filter.contentType))
295 { 315 {
296 let map = this._filterMapsByType.get(type); 316 let map = this._filterMapsByType.get(type);
297 if (map) 317 if (map)
298 removeFilterByKeyword(filter, keyword, map); 318 removeFilterByKeyword(filter, keyword, map);
299 } 319 }
300 320
301 let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword); 321 let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword);
302 if (filtersByDomain) 322 if (filtersByDomain)
303 { 323 {
324 // Because of the memory optimization in the add function, most of the
325 // time this will be a filter rather than a map.
326 if (!(filtersByDomain instanceof Map))
327 {
328 this._filterDomainMapsByKeyword.delete(keyword);
329 return;
330 }
331
304 let domains = filter.domains || defaultDomains; 332 let domains = filter.domains || defaultDomains;
305 for (let domain of domains.keys()) 333 for (let domain of domains.keys())
306 { 334 {
307 let map = filtersByDomain.get(domain); 335 let map = filtersByDomain.get(domain);
308 if (map) 336 if (map)
309 { 337 {
310 if (map.size > 1 || map instanceof Map) 338 if (map.size > 1 || map instanceof Map)
311 { 339 {
312 map.delete(filter); 340 map.delete(filter);
313 341
314 if (map.size == 0) 342 if (map.size == 0)
343 {
315 filtersByDomain.delete(domain); 344 filtersByDomain.delete(domain);
345 }
346 else if (map.size == 1)
347 {
348 for (let [lastFilter, include] of map)
349 {
350 // Reduce Map { "example.com" => Map { filter => true } } to
351 // Map { "example.com" => filter }
352 if (include)
353 filtersByDomain.set(domain, lastFilter);
354
355 break;
356 }
357 }
316 } 358 }
317 else if (filter == map) 359 else if (filter == map)
318 { 360 {
319 filtersByDomain.delete(domain); 361 filtersByDomain.delete(domain);
320 } 362 }
321 } 363 }
322 } 364 }
365
366 if (filtersByDomain.size == 0)
367 {
368 this._filterDomainMapsByKeyword.delete(keyword);
369 }
370 else if (filtersByDomain.size == 1)
371 {
372 for (let [lastDomain, map] of filtersByDomain)
373 {
374 // Reduce Map { "foo" => Map { "" => filter } } to
375 // Map { "foo" => filter }
376 if (lastDomain == "" && !(map instanceof Map))
377 this._filterDomainMapsByKeyword.set(keyword, map);
378
379 break;
380 }
381 }
323 } 382 }
324 } 383 }
325 384
326 /** 385 /**
327 * Chooses a keyword to be associated with the filter 386 * Chooses a keyword to be associated with the filter
328 * @param {Filter} filter 387 * @param {Filter} filter
329 * @returns {string} keyword or an empty string if no keyword could be found 388 * @returns {string} keyword or an empty string if no keyword could be found
330 * @protected 389 * @protected
331 */ 390 */
332 findKeyword(filter) 391 findKeyword(filter)
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 476
418 return null; 477 return null;
419 } 478 }
420 479
421 _checkEntryMatchByDomain(keyword, location, typeMask, docDomain, thirdParty, 480 _checkEntryMatchByDomain(keyword, location, typeMask, docDomain, thirdParty,
422 sitekey, specificOnly, collection) 481 sitekey, specificOnly, collection)
423 { 482 {
424 let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword); 483 let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword);
425 if (filtersByDomain) 484 if (filtersByDomain)
426 { 485 {
427 // The code in this block is similar to the generateStyleSheetForDomain 486 // Because of the memory optimization in the add function, most of the
428 // function in lib/elemHide.js. 487 // time this will be a filter rather than a map.
488 if (!(filtersByDomain instanceof Map))
489 {
490 if (filtersByDomain.matchesWithoutDomain(location, typeMask,
491 thirdParty, sitekey))
492 {
493 if (!collection)
494 return filtersByDomain;
495
496 collection.push(filtersByDomain);
497 }
498
499 return null;
500 }
429 501
430 if (docDomain) 502 if (docDomain)
431 { 503 {
432 if (docDomain[docDomain.length - 1] == ".") 504 if (docDomain[docDomain.length - 1] == ".")
433 docDomain = docDomain.replace(/\.+$/, ""); 505 docDomain = docDomain.replace(/\.+$/, "");
434 506
435 docDomain = docDomain.toLowerCase(); 507 docDomain = docDomain.toLowerCase();
436 } 508 }
437 509
438 let excluded = new Set(); 510 let excluded = new Set();
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 893
822 exports.CombinedMatcher = CombinedMatcher; 894 exports.CombinedMatcher = CombinedMatcher;
823 895
824 /** 896 /**
825 * Shared {@link CombinedMatcher} instance that should usually be used. 897 * Shared {@link CombinedMatcher} instance that should usually be used.
826 * @type {CombinedMatcher} 898 * @type {CombinedMatcher}
827 */ 899 */
828 let defaultMatcher = new CombinedMatcher(); 900 let defaultMatcher = new CombinedMatcher();
829 901
830 exports.defaultMatcher = defaultMatcher; 902 exports.defaultMatcher = defaultMatcher;
OLDNEW
« no previous file with comments | « no previous file | test/matcher.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld