Skip to content
This repository was archived by the owner on Nov 6, 2023. It is now read-only.

Use nullIterable instead of new Set in RuleSets.ruleCache - #12577

Closed
cschanaj wants to merge 4 commits into
EFForg:masterfrom
cschanaj:user-nullIterable
Closed

Use nullIterable instead of new Set in RuleSets.ruleCache#12577
cschanaj wants to merge 4 commits into
EFForg:masterfrom
cschanaj:user-nullIterable

Conversation

@cschanaj

@cschanaj cschanaj commented Sep 15, 2017

Copy link
Copy Markdown
Collaborator

@cowlicks this replaces and closes #12494. thanks!

P.S. eslint error is unexpected, but it should be fine to fix it here.

Comment thread chromium/rules.js
const nullIterable = Object.create(null, {
[Symbol.iterator]: {
value: function* () {
// do nothing

@ghost ghost Sep 15, 2017

Copy link
Copy Markdown

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.

Copy link
Copy Markdown
Contributor

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};
      }
    })
  }
});

Copy link
Copy Markdown

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.

Copy link
Copy Markdown

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, { ...?

@ghost ghost Sep 15, 2017

Copy link
Copy Markdown

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.

@ghost ghost Sep 15, 2017

Copy link
Copy Markdown

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;
  }
};

Copy link
Copy Markdown
Contributor

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

Comment thread chromium/rules.js Outdated
};

const nullIterable = {
[Symbol.iterator]: function *() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*

Copy link
Copy Markdown

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.

@cschanaj cschanaj Sep 15, 2017

Copy link
Copy Markdown
Collaborator Author

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

@ghost ghost Sep 15, 2017

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the * now.

Comment thread chromium/rules.js Outdated

// Empty iterable singleton to reduce memory usage (#12494).
const nullIterator = {
next : () => { done: true }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next: () => ({ done: true })

Copy link
Copy Markdown

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 } }

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

@ghost

ghost commented Sep 15, 2017

Copy link
Copy Markdown

(function* () {})() is the shortest code for empty Iterable. Use it.

Comment thread chromium/rules.js Outdated
next : () => ({ done: true })
};

const nullIterable = {

@ghost ghost Sep 15, 2017

Copy link
Copy Markdown

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.

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown

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?

Copy link
Copy Markdown

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.

Comment thread 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;

Copy link
Copy Markdown
Contributor

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.

@ghost

ghost commented Sep 15, 2017

Copy link
Copy Markdown

@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?

Comment thread 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));

@cowlicks cowlicks Sep 15, 2017

Copy link
Copy Markdown
Contributor

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)]);
}

Comment thread chromium/rules.js
if (host.indexOf("..") != -1 || host.length > 255) {
log(WARN,"Malformed host passed to potentiallyApplicableRulesets: " + host);
return null;
if (host.length > 255 || host.indexOf("..") != -1) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense 👍

Comment thread chromium/rules.js
}

// Replace each portion of the domain with a * in turn
var segmented = host.split(".");

Copy link
Copy Markdown
Contributor

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.

Comment thread chromium/rules.js
for (let i=0; i < segmented.length; i++) {
let tmp = segmented[i];
segmented[i] = "*";
results = results.concat(this.targets.get(segmented.join(".")));

Copy link
Copy Markdown
Contributor

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);

Comment thread chromium/rules.js
// 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));

Copy link
Copy Markdown
Contributor

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

Comment thread chromium/rules.js

// Clean the results list, which may contain duplicates or undefined entries
var resultSet = new Set(results);
resultSet.delete(undefined);

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what

@cowlicks

Copy link
Copy Markdown
Contributor

@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},
});

@cowlicks

Copy link
Copy Markdown
Contributor

@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.

@cschanaj

cschanaj commented Sep 16, 2017

Copy link
Copy Markdown
Collaborator Author

@cowlicks modified accordingly, please check. thanks!!

@cschanaj

Copy link
Copy Markdown
Collaborator Author

@cowlicks Sorry for force pushing a few times. This PR is ready for review and merging now. thanks!

@cschanaj

cschanaj commented Sep 18, 2017

Copy link
Copy Markdown
Collaborator Author

@cowlicks @Hainish I did not realize that you are modifying rules.js as well. I will rebase this branch in the weekend...

P.S. I have made a mistake in rebasing this. Please do not merge the current branch.

@cowlicks

Copy link
Copy Markdown
Contributor

@cschanaj I can rebase this if you'd like.

@cschanaj

Copy link
Copy Markdown
Collaborator Author

thanks!!

@cschanaj

Copy link
Copy Markdown
Collaborator Author

@cowlicks please merge this if it looks good for you. thank you!!

Comment thread chromium/rules.js
} else {
util.log(DBUG, "Ruleset cache miss for " + host);
}
util.log(util.DBUG, "Ruleset cache miss for " + host);

Copy link
Copy Markdown
Contributor

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).

@cschanaj

cschanaj commented Sep 23, 2017

Copy link
Copy Markdown
Collaborator Author

@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).

@cschanaj

Copy link
Copy Markdown
Collaborator Author

@cowlicks could you please merge this before the next release?

@cowlicks

cowlicks commented Oct 3, 2017

Copy link
Copy Markdown
Contributor

@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!

@cschanaj

cschanaj commented Oct 6, 2017

Copy link
Copy Markdown
Collaborator Author

@cowlicks Never mind. Please be sure to merge this PR before the next release. 😄

@cowlicks

Copy link
Copy Markdown
Contributor

merged in #13208 thank you!

@cowlicks cowlicks closed this Oct 17, 2017
@cschanaj
cschanaj deleted the user-nullIterable branch October 24, 2017 11:03
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants