Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: refactored cluster schedule_handlers #32485

Closed

Conversation

yashLadha
Copy link
Member

Scheduler handler for cluster were implemented in function prototype
form, which can be converted to newer syntax of classes. Also seperated
concern for attaching listener to one of the internal methods of class
in round_robin_handle. Used Map instead of Array when there are
cases for continous finding element. Also prefered destructuring over
sending large number of parameters because one of the parameters
addressType can only be used in shared_handle implementation and not
round_robin.

Fixes: #32480

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added the cluster Issues and PRs related to the cluster subsystem. label Mar 25, 2020
@jasnell jasnell requested a review from cjihrig March 25, 2020 17:00
class SharedHandle {
constructor(key, address, { port, addressType, fd, flags }) {
this.key = key;
this.workers = new Map();
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't a WeakSet (or SafeWeakSet) be a better fit than Map here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Since in map we are relying on a key, that is in our case is id. On if deep-clone an object itself and pass it then also the lookup will not be evaluated to true. Ref:

> a = {b: 'some key'};
{ b: 'some key' }
> st = new WeakSet()
WeakSet { <items unknown> }
> st.add(a)
WeakSet { <items unknown> }
> st
WeakSet { <items unknown> }
> m = Object.assign({}, a)
{ b: 'some key' }
> st.has(m)
false
> st.has(a)
true
>

this.workers = new Map();
this.handle = null;
this.errno = 0;
const rval = this.determineRval(addressType,
Copy link
Contributor

Choose a reason for hiding this comment

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

This method is only used here, I don't think it's worth moving to a separate function. I think keeping the original conditionals here is best.

Copy link
Member Author

Choose a reason for hiding this comment

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

The previous implement was using let and I think if we can restructure the logic to const that solidifies the meaning of that variable. Let's say if one goes from top to bottom reading this file, then reaching this rvalue variable one can infer that it will be a fixed rval determined by the function.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see the use of let being a problem, especially given the size of the function and that the assignments happen immediately after the declaration.

Copy link
Member Author

Choose a reason for hiding this comment

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

let send a wrong signal on the meaning of variable as it can be changed, but const signifies that the value will not be changed and thus can be believed to be the same throughout the scope of the class.

this.handles = [];
this.handle = null;
this.server = net.createServer(assert.fail);
this.attachListener(fd, port, address, flags); // UNIX socket path.
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this method is only used here, I think it's best to just keep the original code here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Isn't now it is giving it much more meaning to what the block is actually doing, and also if there are more case logic in some block, better to abstract it in some other place. This is done because in the future also there might be some more conditionals around that code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think if the logic gets that complicated then we can revisit it at that point. Separating out 10 lines of code does not seem worthwhile.

Copy link
Member Author

Choose a reason for hiding this comment

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

I still think that decreasing the vertical complexity gives the code a nice look and meaningfulness. I am still not clear about why moving it to previous implementation gives it verbosity and meaningfulness.

return; // Worker is closing (or has closed) the server.
distribute(err, handle) {
this.handles.push(handle);
const worker = this.free.values().next().value;
Copy link
Contributor

Choose a reason for hiding this comment

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

The previous implementation actually removed the worker from .free(), this will keep the worker in place.

Copy link
Member Author

Choose a reason for hiding this comment

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

Can get the key and remove it from the map instead.

constructor(key, address, { port, fd, flags }) {
this.key = key;
this.all = new Map();
this.free = new Map();
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's best to keep this as an array since an array is most likely designed better for the purposes of a queue than a Map is. The only real benefit of the Map is faster lookups, but we shouldn't really optimize that over faster/easier shift()/push() because workers are not likely to be added/removed as often as workers being selected for requests.

Copy link
Member Author

Choose a reason for hiding this comment

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

True, but shifting logic is at the time of distributing the load and that is a single operation that can be implemented using keys iterator on map is still an O(1) operation and getting the element and deleting that from the Hash is same on average. Reimplemented to delete the worker from free pool.

@yashLadha yashLadha force-pushed the refactor/worker_scheduling_handlers branch from 20c71b8 to 2b6b006 Compare March 26, 2020 02:37
Scheduler handler for cluster were implemented in function prototype
form, which can be converted to newer syntax of classes. Also seperated
concern for attaching listener to one of the internal methods of class
in round_robin_handle. Used `Map` instead of `Array` when there are
cases for continous finding element.

Fixes: nodejs#32480
@yashLadha yashLadha force-pushed the refactor/worker_scheduling_handlers branch from 2b6b006 to e6c9a26 Compare March 26, 2020 04:23
@bnoordhuis
Copy link
Member

This PR contains a single commit that does two unrelated things:

  1. Make stylistic changes (switch to ES6 classes)
  2. Make functional changes (switch from arrays to maps)

Don't do that - it makes review and back-porting difficult. Start with (1) and open a new PR for (2) after (1) lands.

Aside: I see a couple of long lines in there. I'm not sure why the linter isn't complaining but lines should stay <= 80 columns.

My personal opinion: (1) is a lot of code churn for little to no benefit. It doesn't make a material difference for readability or maintainability and the current code is working just fine. Leave well enough alone.

@yashLadha
Copy link
Member Author

@bnoordhuis I can split the functional changes into a new PR.

@yashLadha
Copy link
Member Author

Closing this cosmetic and functional changes are mixed into one commit.

@yashLadha yashLadha closed this Mar 26, 2020
@yashLadha yashLadha deleted the refactor/worker_scheduling_handlers branch March 26, 2020 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cluster Issues and PRs related to the cluster subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

class implementation for files
5 participants