-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Use nullIterable instead of new Set in RuleSets.ruleCache #12577
Conversation
| const nullIterable = Object.create(null, { | ||
| [Symbol.iterator]: { | ||
| value: function* () { | ||
| // do nothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done in a simpler way.
const nullIterator = {
next() {
return { done: true };
}
};
const nullIterable = {
[Symbol.iterator]: function () {
return nullIterator;
}
};Will also save memory since it will not create a new iterator each time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having just one name is nice. How about just:
const nullIterable = Object.create(null, {
[Symbol.iterator]: {
value: () => ({
next() {
return {done: true};
}
})
}
});There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cowlicks const nullIterable = (function* () {})() would be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cowlicks why use Object.create(null, { ...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cowlicks This will create a new instance of { next() { return { done: true } } } each time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently I have this code:
const nullIterator = {
next() {
return { done: true };
}
};
const nullIterable = {
size: 0,
[Symbol.iterator]: function () {
return nullIterator;
}
};There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@koops76 see #12577 (comment)
re: new instance of ... thing - that is fine, it should get GC'd immediately anyway
chromium/rules.js
Outdated
| }; | ||
|
|
||
| const nullIterable = { | ||
| [Symbol.iterator]: function *() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simply change it into () => nullIterator I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without * it does not work for me (it is a generator function).
See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the * after fixing this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the * now.
chromium/rules.js
Outdated
|
|
||
| // Empty iterable singleton to reduce memory usage (#12494). | ||
| const nullIterator = { | ||
| next : () => { done: true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next: () => ({ done: true })
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or next() { return { done: true } }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
|
|
chromium/rules.js
Outdated
| next : () => ({ done: true }) | ||
| }; | ||
|
|
||
| const nullIterable = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simply replace this entire code with const nullIterable = (function* () {})(). Calling a generator function will return a Generator instance which implements both Iterator and Iterable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I choose to create Object.creat(null, ... because the created object wouldn't have extra properties, so it would be harder to misuse. This seemed important because we are using it alongside real data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, using Object.create(... lets us specify other properties we might want, like size in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would simply doing { size: 0 } cause a conflict?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it makes it read only.
chromium/rules.js
Outdated
| log(DBUG, "Ruleset cache hit for " + host + " items:" + cached_item.length); | ||
| if (this.ruleCache.has(host)) { | ||
| let cached_item = this.ruleCache.get(host); | ||
| let len = cached_item && cached_item != nullIterable ? cached_item.size : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just add a size property to the nullIterable thing.
|
@cowlicks Look at this code: const nullIterator = Object.create(null, {
next: { value: function() { return { done: true }; } }
});
const nullIterable = Object.create(null, {
[Symbol.iterator]: { value: function() { return nullIterator; } }
});Is it okay to use in your opinion? |
chromium/rules.js
Outdated
| // Copy the host targets so we don't modify them. | ||
| results = results.concat(this.targets.get(host)); | ||
| let results = this.targets.get(host); | ||
| results.map(result => resultSet.add(result)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little confused by having both results and resultsSet variables. You can just do:
if (this.targets.has(host)) {
results = new Set([...results, this.targets.get(host)]);
}| if (host.indexOf("..") != -1 || host.length > 255) { | ||
| log(WARN,"Malformed host passed to potentiallyApplicableRulesets: " + host); | ||
| return null; | ||
| if (host.length > 255 || host.indexOf("..") != -1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense 👍
| } | ||
|
|
||
| // Replace each portion of the domain with a * in turn | ||
| var segmented = host.split("."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid renaming and changing this code unless its necessary to the PR. This algorithm is important, but isn't well tested unfortunately.
| for (let i=0; i < segmented.length; i++) { | ||
| let tmp = segmented[i]; | ||
| segmented[i] = "*"; | ||
| results = results.concat(this.targets.get(segmented.join("."))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be something like my above comment, (https://github.com/EFForg/https-everywhere/pull/12577/files#r139258106) or maybe a ternary expression like
results = (this.targets.has(segmented.join('.')) ?
(new Set([...results, ...this.targets.get(segmented.join('.')]) :
results);| // check *.z.google.com and *.google.com (we did *.y.z.google.com above) | ||
| for (var i = 2; i <= segmented.length - 2; ++i) { | ||
| var t = "*." + segmented.slice(i,segmented.length).join("."); | ||
| results = results.concat(this.targets.get(t)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this rename. Then just use one of the methods I suggested above to update the results
|
|
||
| // Clean the results list, which may contain duplicates or undefined entries | ||
| var resultSet = new Set(results); | ||
| resultSet.delete(undefined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep a results.delete(undefined) around to be safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what
|
@koops76 re: #12577 (comment) It depends on the context. I'd prefer to avoid using 2 names here. I don't think it creating an iterator when iterated matters. It should be garbage collected immediately, and js engines are pretty good at optimizing simple functions like this. @cschanaj with the size property it would look like: const nullIterable = Object.create(null, {
[Symbol.iterator]: {
value: () => ({
next() {
return {done: true};
}
})
},
size: {value: 0},
}); |
|
@cschanaj in the future, please try to keep revisions to PR's as the same PR. This makes reviewing easier for me. It is hard to track what changed and what didn't between two similar PR's so I end up re-reading a lot of code. (I'm referring to this and #12494). There is no need to worry about force pushes or anything. |
|
@cowlicks modified accordingly, please check. thanks!! |
|
@cowlicks Sorry for force pushing a few times. This PR is ready for review and merging now. thanks! |
|
@cschanaj I can rebase this if you'd like. |
|
thanks!! |
|
@cowlicks please merge this if it looks good for you. thank you!! |
| } else { | ||
| util.log(DBUG, "Ruleset cache miss for " + host); | ||
| } | ||
| util.log(util.DBUG, "Ruleset cache miss for " + host); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some issues with how this was merged, this line should have been kept (it should be util.DBUG).
|
@cowlicks Travis all passing now, please merge this if it looks good. (It has been sort of annoying to rebase a few time and keeping up with the incompatible changes). |
|
@cowlicks could you please merge this before the next release? |
|
@cschanaj sorry we won't have time! It will be in the next release. Totally my fault, I forgot to check back on this after you rebased :( Thank you for your work! |
|
@cowlicks Never mind. Please be sure to merge this PR before the next release. 😄 |
|
merged in #13208 thank you! |
@cowlicks this replaces and closes #12494. thanks!
P.S.
eslinterror is unexpected, but it should be fine to fix it here.