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

Delta Between Two Patch Sets: lib/filterStorage.js

Issue 29935568: Issue 7096 - Make it possible to lazy initialize a filter's subscriptions (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Small update Created Nov. 3, 2018, 9:34 p.m.
Right Patch Set: Use new methods in two more places Created Nov. 18, 2018, 4:57 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « lib/filterListener.js ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 /** 121 /**
122 * The number of subscriptions in the storage. 122 * The number of subscriptions in the storage.
123 * @type {number} 123 * @type {number}
124 */ 124 */
125 get subscriptionCount() 125 get subscriptionCount()
126 { 126 {
127 return this.knownSubscriptions.size; 127 return this.knownSubscriptions.size;
128 } 128 }
129 129
130 /** 130 /**
131 * Adds any subscriptions to which a filter belongs to the filter. 131 * Yields subscriptions in the storage to which the given filter belongs.
132 * @param {Filter} filter 132 * @param {Filter} filter
133 */ 133 * @yields {Subscription}
134 addSubscriptionsToFilter(filter) 134 */
135 { 135 *subscriptionsForFilter(filter)
136 for (let subscription of this.subscriptions()) 136 {
137 { 137 if (!filter.subscriptionsAdded)
138 if (subscription.filters.indexOf(filter) != -1) 138 addSubscriptionsToFilter(filter);
hub 2018/11/10 04:33:21 this is quite an expensive search, isn't it?
Manish Jethani 2018/11/15 22:58:52 Yes, so here's the thing: 1. This function will
hub 2018/11/16 17:04:39 So shall we make sure the review 29934588 lands fi
Manish Jethani 2018/11/17 19:49:17 OK, let's do this one first instead, it's easier:
139 filter.addSubscription(subscription); 139
140 } 140 yield* filter.subscriptions();
141 141 }
142 filter.subscriptionsAssigned = true; 142
143 /**
144 * Returns the number of subscriptions in the storage to which the given
145 * filter belongs.
146 * @param {Filter} filter
147 * @return {number}
148 */
149 getSubscriptionCountForFilter(filter)
150 {
151 if (!filter.subscriptionsAdded)
152 addSubscriptionsToFilter(filter);
153
154 return filter.subscriptionCount;
143 } 155 }
144 156
145 /** 157 /**
146 * Finds the filter group that a filter should be added to by default. Will 158 * Finds the filter group that a filter should be added to by default. Will
147 * return <code>null</code> if this group doesn't exist yet. 159 * return <code>null</code> if this group doesn't exist yet.
148 * @param {Filter} filter 160 * @param {Filter} filter
149 * @returns {?SpecialSubscription} 161 * @returns {?SpecialSubscription}
150 */ 162 */
151 getGroupForFilter(filter) 163 getGroupForFilter(filter)
152 { 164 {
(...skipping 23 matching lines...) Expand all
176 */ 188 */
177 addSubscription(subscription) 189 addSubscription(subscription)
178 { 190 {
179 if (this.knownSubscriptions.has(subscription.url)) 191 if (this.knownSubscriptions.has(subscription.url))
180 return; 192 return;
181 193
182 this.knownSubscriptions.set(subscription.url, subscription); 194 this.knownSubscriptions.set(subscription.url, subscription);
183 connectSubscriptionFilters(subscription); 195 connectSubscriptionFilters(subscription);
184 196
185 filterNotifier.emit("subscription.added", subscription); 197 filterNotifier.emit("subscription.added", subscription);
198
199 subscription.clearCaches();
186 } 200 }
187 201
188 /** 202 /**
189 * Removes a subscription from the storage. 203 * Removes a subscription from the storage.
190 * @param {Subscription} subscription The subscription to be removed. 204 * @param {Subscription} subscription The subscription to be removed.
191 */ 205 */
192 removeSubscription(subscription) 206 removeSubscription(subscription)
193 { 207 {
194 if (!this.knownSubscriptions.has(subscription.url)) 208 if (!this.knownSubscriptions.has(subscription.url))
195 return; 209 return;
196 210
197 disconnectSubscriptionFilters(subscription); 211 disconnectSubscriptionFilters(subscription);
198 212
199 this.knownSubscriptions.delete(subscription.url); 213 this.knownSubscriptions.delete(subscription.url);
200 214
201 // This should be the last remaining reference to the Subscription 215 // This should be the last remaining reference to the Subscription
202 // object. 216 // object.
203 Subscription.knownSubscriptions.delete(subscription.url); 217 Subscription.knownSubscriptions.delete(subscription.url);
204 218
205 filterNotifier.emit("subscription.removed", subscription); 219 filterNotifier.emit("subscription.removed", subscription);
206 } 220 }
207 221
208 /** 222 /**
209 * Replaces the list of filters in a subscription with a new list. 223 * Replaces the list of filters in a subscription with a new list.
210 * @param {Subscription} subscription The subscription to be updated. 224 * @param {Subscription} subscription The subscription to be updated.
211 * @param {Array.<Filter>} filters The new list of filters. 225 * @param {Array.<Filter>} filters The new list of filters.
212 */ 226 */
213 updateSubscriptionFilters(subscription, filters) 227 updateSubscriptionFilters(subscription, filters)
214 { 228 {
215 disconnectSubscriptionFilters(subscription); 229 let oldFilters = [...subscription.filters()];
216 let oldFilters = subscription.filters; 230 disconnectSubscriptionFilters(subscription, oldFilters);
217 subscription.filters = filters; 231 subscription.clearFilters();
218 connectSubscriptionFilters(subscription); 232
233 for (let filter of filters)
234 subscription.addFilter(filter);
235
236 connectSubscriptionFilters(subscription, filters);
237
219 filterNotifier.emit("subscription.updated", subscription, oldFilters); 238 filterNotifier.emit("subscription.updated", subscription, oldFilters);
239
240 subscription.clearCaches();
220 } 241 }
221 242
222 /** 243 /**
223 * Adds a user-defined filter to the storage. 244 * Adds a user-defined filter to the storage.
224 * @param {Filter} filter 245 * @param {Filter} filter
225 * @param {?SpecialSubscription} [subscription] The subscription that the 246 * @param {?SpecialSubscription} [subscription] The subscription that the
226 * filter should be added to. 247 * filter should be added to.
227 * @param {number} [position] The position within the subscription at which 248 * @param {number} [position] The position within the subscription at which
228 * the filter should be added. If not specified, the filter is added at the 249 * the filter should be added. If not specified, the filter is added at the
229 * end of the subscription. 250 * end of the subscription.
230 */ 251 */
231 addFilter(filter, subscription, position) 252 addFilter(filter, subscription, position)
232 { 253 {
233 if (!subscription) 254 if (!subscription)
234 { 255 {
235 for (let currentSubscription of filter.subscriptions()) 256 for (let currentSubscription of this.subscriptionsForFilter(filter))
236 { 257 {
237 if (currentSubscription instanceof SpecialSubscription && 258 if (currentSubscription instanceof SpecialSubscription &&
238 !currentSubscription.disabled) 259 !currentSubscription.disabled)
239 { 260 {
240 return; // No need to add 261 return; // No need to add
241 } 262 }
242 } 263 }
243 subscription = this.getGroupForFilter(filter); 264 subscription = this.getGroupForFilter(filter);
244 } 265 }
245 if (!subscription) 266 if (!subscription)
246 { 267 {
247 // No group for this filter exists, create one 268 // No group for this filter exists, create one
248 subscription = SpecialSubscription.createForFilter(filter); 269 subscription = SpecialSubscription.createForFilter(filter);
249 this.addSubscription(subscription); 270 this.addSubscription(subscription);
250 return; 271 return;
251 } 272 }
252 273
253 if (typeof position == "undefined") 274 if (typeof position == "undefined")
254 position = subscription.filters.length; 275 position = subscription.filterCount;
255 276
256 filter.addSubscription(subscription); 277 filter.addSubscription(subscription);
257 subscription.filters.splice(position, 0, filter); 278 subscription.insertFilterAt(filter, position);
258 filterNotifier.emit("filter.added", filter, subscription, position); 279 filterNotifier.emit("filter.added", filter, subscription, position);
259 } 280 }
260 281
261 /** 282 /**
262 * Removes a user-defined filter from the storage. 283 * Removes a user-defined filter from the storage.
263 * @param {Filter} filter 284 * @param {Filter} filter
264 * @param {?SpecialSubscription} [subscription] The subscription that the 285 * @param {?SpecialSubscription} [subscription] The subscription that the
265 * filter should be removed from. If not specified, the filter will be 286 * filter should be removed from. If not specified, the filter will be
266 * removed from all subscriptions. 287 * removed from all subscriptions.
267 * @param {number} [position] The position within the subscription at which 288 * @param {number} [position] The position within the subscription at which
268 * the filter should be removed. If not specified, all instances of the 289 * the filter should be removed. If not specified, all instances of the
269 * filter will be removed. 290 * filter will be removed.
270 */ 291 */
271 removeFilter(filter, subscription, position) 292 removeFilter(filter, subscription, position)
272 { 293 {
273 let subscriptions = ( 294 let subscriptions = (
274 subscription ? [subscription] : filter.subscriptions() 295 subscription ? [subscription] : this.subscriptionsForFilter(filter)
275 ); 296 );
276 for (let currentSubscription of subscriptions) 297 for (let currentSubscription of subscriptions)
277 { 298 {
278 if (currentSubscription instanceof SpecialSubscription) 299 if (currentSubscription instanceof SpecialSubscription)
279 { 300 {
280 let positions = []; 301 let positions = [];
281 if (typeof position == "undefined") 302 if (typeof position == "undefined")
282 { 303 {
283 let index = -1; 304 let index = -1;
284 do 305 do
285 { 306 {
286 index = currentSubscription.filters.indexOf(filter, index + 1); 307 index = currentSubscription.searchFilter(filter, index + 1);
287 if (index >= 0) 308 if (index >= 0)
288 positions.push(index); 309 positions.push(index);
289 } while (index >= 0); 310 } while (index >= 0);
290 } 311 }
291 else 312 else
292 positions.push(position); 313 positions.push(position);
293 314
294 for (let j = positions.length - 1; j >= 0; j--) 315 for (let j = positions.length - 1; j >= 0; j--)
295 { 316 {
296 let currentPosition = positions[j]; 317 let currentPosition = positions[j];
297 if (currentSubscription.filters[currentPosition] == filter) 318 let currentFilter = currentSubscription.filterAt(currentPosition);
319 if (currentFilter && currentFilter.text == filter.text)
298 { 320 {
299 currentSubscription.filters.splice(currentPosition, 1); 321 currentSubscription.deleteFilterAt(currentPosition);
300 if (currentSubscription.filters.indexOf(filter) < 0) 322 if (currentSubscription.searchFilter(filter) < 0)
301 filter.removeSubscription(currentSubscription); 323 filter.removeSubscription(currentSubscription);
302 filterNotifier.emit("filter.removed", filter, currentSubscription, 324 filterNotifier.emit("filter.removed", filter, currentSubscription,
303 currentPosition); 325 currentPosition);
304 } 326 }
305 } 327 }
306 } 328 }
307 } 329 }
308 } 330 }
309 331
310 /** 332 /**
311 * Moves a user-defined filter to a new position. 333 * Moves a user-defined filter to a new position.
312 * @param {Filter} filter 334 * @param {Filter} filter
313 * @param {SpecialSubscription} subscription The subscription where the 335 * @param {SpecialSubscription} subscription The subscription where the
314 * filter is located. 336 * filter is located.
315 * @param {number} oldPosition The current position of the filter. 337 * @param {number} oldPosition The current position of the filter.
316 * @param {number} newPosition The new position of the filter. 338 * @param {number} newPosition The new position of the filter.
317 */ 339 */
318 moveFilter(filter, subscription, oldPosition, newPosition) 340 moveFilter(filter, subscription, oldPosition, newPosition)
319 { 341 {
320 if (!(subscription instanceof SpecialSubscription) || 342 if (!(subscription instanceof SpecialSubscription))
321 subscription.filters[oldPosition] != filter)
322 {
323 return; 343 return;
324 } 344
345 let currentFilter = subscription.filterAt(oldPosition);
346 if (!currentFilter || currentFilter.text != filter.text)
347 return;
325 348
326 newPosition = Math.min(Math.max(newPosition, 0), 349 newPosition = Math.min(Math.max(newPosition, 0),
327 subscription.filters.length - 1); 350 subscription.filterCount - 1);
328 if (oldPosition == newPosition) 351 if (oldPosition == newPosition)
329 return; 352 return;
330 353
331 subscription.filters.splice(oldPosition, 1); 354 subscription.deleteFilterAt(oldPosition);
332 subscription.filters.splice(newPosition, 0, filter); 355 subscription.insertFilterAt(filter, newPosition);
333 filterNotifier.emit("filter.moved", filter, subscription, oldPosition, 356 filterNotifier.emit("filter.moved", filter, subscription, oldPosition,
334 newPosition); 357 newPosition);
335 } 358 }
336 359
337 /** 360 /**
338 * Increases the hit count for a filter by one. 361 * Increases the hit count for a filter by one.
339 * @param {Filter} filter 362 * @param {Filter} filter
340 */ 363 */
341 increaseHitCount(filter) 364 increaseHitCount(filter)
342 { 365 {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 let knownSubscriptions = new Map(); 411 let knownSubscriptions = new Map();
389 for (let subscription of parser.subscriptions) 412 for (let subscription of parser.subscriptions)
390 knownSubscriptions.set(subscription.url, subscription); 413 knownSubscriptions.set(subscription.url, subscription);
391 414
392 this.fileProperties = parser.fileProperties; 415 this.fileProperties = parser.fileProperties;
393 this.knownSubscriptions = knownSubscriptions; 416 this.knownSubscriptions = knownSubscriptions;
394 Filter.knownFilters = parser.knownFilters; 417 Filter.knownFilters = parser.knownFilters;
395 Subscription.knownSubscriptions = parser.knownSubscriptions; 418 Subscription.knownSubscriptions = parser.knownSubscriptions;
396 419
397 if (!silent) 420 if (!silent)
421 {
398 filterNotifier.emit("load"); 422 filterNotifier.emit("load");
423
424 // Clear any in-memory caches that may have been created during
425 // initialization.
426 clearSubscriptionCaches();
427 }
399 } 428 }
400 }; 429 };
401 } 430 }
402 431
403 /** 432 /**
404 * Loads all subscriptions from disk. 433 * Loads all subscriptions from disk.
405 * @returns {Promise} A promise resolved or rejected when loading is complete. 434 * @returns {Promise} A promise resolved or rejected when loading is complete.
406 */ 435 */
407 loadFromDisk() 436 loadFromDisk()
408 { 437 {
(...skipping 28 matching lines...) Expand all
437 } 466 }
438 }); 467 });
439 }).catch(error => 468 }).catch(error =>
440 { 469 {
441 Cu.reportError(error); 470 Cu.reportError(error);
442 return tryBackup(1); 471 return tryBackup(1);
443 }).then(() => 472 }).then(() =>
444 { 473 {
445 this.initialized = true; 474 this.initialized = true;
446 filterNotifier.emit("load"); 475 filterNotifier.emit("load");
476 clearSubscriptionCaches();
447 }); 477 });
448 } 478 }
449 479
450 /** 480 /**
451 * Constructs the file name for a <code>patterns.ini</code> backup. 481 * Constructs the file name for a <code>patterns.ini</code> backup.
452 * @param {number} backupIndex Number of the backup file (1 being the most 482 * @param {number} backupIndex Number of the backup file (1 being the most
453 * recent). 483 * recent).
454 * @returns {string} Backup file name. 484 * @returns {string} Backup file name.
455 */ 485 */
456 getBackupName(backupIndex) 486 getBackupName(backupIndex)
(...skipping 27 matching lines...) Expand all
484 * @yields {string} 514 * @yields {string}
485 */ 515 */
486 *exportData() 516 *exportData()
487 { 517 {
488 // Do not persist external subscriptions 518 // Do not persist external subscriptions
489 let subscriptions = []; 519 let subscriptions = [];
490 for (let subscription of this.subscriptions()) 520 for (let subscription of this.subscriptions())
491 { 521 {
492 if (!(subscription instanceof ExternalSubscription) && 522 if (!(subscription instanceof ExternalSubscription) &&
493 !(subscription instanceof SpecialSubscription && 523 !(subscription instanceof SpecialSubscription &&
494 subscription.filters.length == 0)) 524 subscription.filterCount == 0))
495 { 525 {
496 subscriptions.push(subscription); 526 subscriptions.push(subscription);
497 } 527 }
498 } 528 }
499 529
500 yield "# Adblock Plus preferences"; 530 yield "# Adblock Plus preferences";
501 yield "version=" + this.formatVersion; 531 yield "version=" + this.formatVersion;
502 532
503 let saved = new Set(); 533 let saved = new Set();
504 534
505 // Save subscriptions 535 // Save subscriptions
506 for (let subscription of subscriptions) 536 for (let subscription of subscriptions)
507 { 537 {
508 yield* subscription.serialize(); 538 yield* subscription.serialize();
509 yield* subscription.serializeFilters(); 539 yield* subscription.serializeFilters();
510 } 540 }
511 541
512 // Save filter data 542 // Save filter data
513 for (let subscription of subscriptions) 543 for (let subscription of subscriptions)
514 { 544 {
515 for (let filter of subscription.filters) 545 for (let filter of subscription.filters())
516 { 546 {
517 if (!saved.has(filter.text)) 547 if (!saved.has(filter.text))
518 { 548 {
519 yield* filter.serialize(); 549 yield* filter.serialize();
520 saved.add(filter.text); 550 saved.add(filter.text);
521 } 551 }
522 } 552 }
523 } 553 }
524 } 554 }
525 555
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 682
653 /** 683 /**
654 * Reads the user's filters from disk, manages them in memory, and writes them 684 * Reads the user's filters from disk, manages them in memory, and writes them
655 * back to disk. 685 * back to disk.
656 */ 686 */
657 let filterStorage = new FilterStorage(); 687 let filterStorage = new FilterStorage();
658 688
659 exports.filterStorage = filterStorage; 689 exports.filterStorage = filterStorage;
660 690
661 /** 691 /**
692 * Adds to a filter any subscriptions in the storage to which the filter
693 * belongs.
694 * @param {Filter} filter
695 */
696 function addSubscriptionsToFilter(filter)
697 {
698 for (let subscription of filterStorage.subscriptions())
699 {
700 if (subscription.hasFilter(filter))
701 filter.addSubscription(subscription);
702 }
703
704 filter.subscriptionsAdded = true;
705 }
706
707 /**
662 * Connects a subscription to its filters without any notifications. 708 * Connects a subscription to its filters without any notifications.
663 * @param {Subscription} subscription The subscription that should be 709 * @param {Subscription} subscription The subscription that should be
664 * connected to its filters. 710 * connected to its filters.
665 */ 711 * @param {?Array.<Filter>} [filters] A list of filters to which the
666 function connectSubscriptionFilters(subscription) 712 * subscription should be connected. If this is not given, the subscription
713 * is connected to its own filters.
714 */
715 function connectSubscriptionFilters(subscription, filters)
667 { 716 {
668 if (!filterStorage.knownSubscriptions.has(subscription.url)) 717 if (!filterStorage.knownSubscriptions.has(subscription.url))
669 return; 718 return;
670 719
671 for (let filter of subscription.filters) 720 for (let filter of filters || subscription.filters())
672 filter.addSubscription(subscription); 721 filter.addSubscription(subscription);
673 } 722 }
674 723
675 /** 724 /**
676 * Disconnects a subscription from its filters without any notifications. 725 * Disconnects a subscription from its filters without any notifications.
677 * @param {Subscription} subscription The subscription that should be 726 * @param {Subscription} subscription The subscription that should be
678 * disconnected from its filters. 727 * disconnected from its filters.
679 */ 728 * @param {?Array.<Filter>} [filters] A list of filters from which the
680 function disconnectSubscriptionFilters(subscription) 729 * subscription should be disconnected. If this is not given, the
730 * subscription is disconnected from its own filters.
731 */
732 function disconnectSubscriptionFilters(subscription, filters)
681 { 733 {
682 if (!filterStorage.knownSubscriptions.has(subscription.url)) 734 if (!filterStorage.knownSubscriptions.has(subscription.url))
683 return; 735 return;
684 736
685 for (let filter of subscription.filters) 737 for (let filter of filters || subscription.filters())
686 filter.removeSubscription(subscription); 738 filter.removeSubscription(subscription);
687 } 739 }
740
741 /**
742 * Clears any in-memory caches held by subscriptions in the storage.
743 */
744 function clearSubscriptionCaches()
745 {
746 for (let subscription of filterStorage.subscriptions())
747 subscription.clearCaches();
748 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld