-
Notifications
You must be signed in to change notification settings - Fork 7.3k
ZOOKEEPER-3020: Review of SyncRequestProcessor #876
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
Conversation
| if (si == requestOfDeath) { | ||
| break; | ||
| } | ||
| if (si != 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.
This looks like a lot of code change, but I simply removed this check 'is null' check and subsequently had to fix the indentation of the large block of code beneath it.
anmolnar
left a comment
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.
+1
Great refactoring.
| this.join(); | ||
| this.flush(); | ||
| } catch (InterruptedException e) { | ||
| LOG.warn("Interrupted while wating for " + this + " to finish"); |
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.
Nit: LOG.warn("Interrupted while wating for {} to finish", this);
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.
@anmolnar Well, if you can believe it, lol, I am trying to touch less where I can in order to make a review easier. Also, using SLF4J parameter-ized logging is the fastest way to do logging when logging is disabled. It would be very unlikely that a WARN message is disabled so it's actually faster to just keep it as is. If I was writing this code from scratch, I would use a parameter logging message here for consistency, but there's no strong argument to change it now.
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.
Got you. You can leave it as is.
In my understanding parameterised logging is not slower than constructing message beforehand, but I agree that it only has performance gain when not logging the message.
|
@belugabehr Please update the comment and description of this PR. Thanks! |
| private final RequestProcessor nextProcessor; | ||
|
|
||
| private Thread snapInProcess = null; | ||
| private final Semaphore snapThreadMutex = new Semaphore(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.
So, just FYI. I wanted to make this change because of two reasons:
- It removes the special-case 'null' check (line 131) when the first iteration occurs.
- The last 'snapInProcess' variable is never cleared out so there is always a dangling pointer to the last instance that ran... i.e., it never gets GC'ed until the next time a snap process runs and kicks the previous reference out.
|
@belugabehr Jira doesn't indicate that, but I suppose this is going to be a master-only commit |
|
@anmolnar Yes. All of my work is for master, unless anyone has strong feelings that it should be committed elsewhere. That decision is above my pay grade here :) |
enixon
left a comment
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 @belugabehr , for breaking this in to pieces! Much easier to review. :)
Overall looks very sane to me, just a couple of points.
| continue; | ||
| } | ||
| toFlush.add(si); | ||
| if (toFlush.size() == FLUSH_SIZE) { |
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.
any danger from changing > to == here?
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.
The only things that adds an item to this collection is the thread itself, and the 'add' exists immediately before the check against FLUSH_SIZE. There is no risk of somehow jumping over the threshold. A 'greater than' check is confusing to the reader because it implies that there might be some way to jump the threshold.
| while (true) { | ||
| Request si = null; | ||
| if (toFlush.isEmpty()) { | ||
| Request si = queuedRequests.poll(); |
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.
Is behavior changing here? Your logic of tolling from a poll directly to a take instead of forcing a loop via continue looks right to me - is there a way that take can respond with a null value or otherwise break something in the new arrangement?
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.
Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html#take()
The only way a 'null' could become available here is if a 'null' value is inserted into the collection. However, that is prevented on line 212.
I believe this is a good improvement because previously it was always checking 'isEmpty' to make a decision about how to interact with the 'queuedRequests' queue. I have removed that condition and it will just go ahead and try to pull something from the queue.
|
lgtm +1 (non-committer) |
|
@anmolnar Any additional ideas for improvements? |
|
Committed to master branch. Thanks @belugabehr ! |
1. Use ArrayDeque instead of LinkedList 2. Use ThreadLocalRandom instead of Random 3. Remove the 'running' flag - use the Thread#join facility to detect if the thread has stopped running. Using a flag can cause race condition issues and is superfluous. 4. Make static final variable names in all caps 5. General cleanup > This class is likely to be faster than Stack when used as a stack, and faster than LinkedList when used as a queue. https://docs.oracle.com/javase/7/docs/api/java/util/ArrayDeque.html Author: Beluga Behr <dam6923@gmail.com> Reviewers: andor@apache.org Closes apache#876 from BELUGABEHR/ZOOKEEPER-3020-2 and squashes the following commits: 8f1df37 [Beluga Behr] General cleanup 83cab73 [Beluga Behr] Simplify and streamline access pattern of queuedRequests 5e0b801 [Beluga Behr] Use a semaphore to track status of snapshot thread d119ef7 [Beluga Behr] No need to keep a flag which states if the thread is alive e2059cf [Beluga Behr] Replace LinkedList with ArrayDeque 57a0449 [Beluga Behr] Replace Random with ThreadLocalRandom 17bd1fa [Beluga Behr] Require that the request not be 'null' b28ff94 [Beluga Behr] Refactor flush method
https://docs.oracle.com/javase/7/docs/api/java/util/ArrayDeque.html