Make Backoff class thread-safe#13993
Conversation
| this.mandatoryStopMade = false; | ||
| } | ||
|
|
||
| public synchronized boolean isMandatoryStopMade() { |
There was a problem hiding this comment.
This method looks like just getting the current value, should we synchronize it?
There was a problem hiding this comment.
We either need to synchronize it or make the variable volatile. Since it is only used in one place (and is possibly used incorrectly), I lean towards making it synchronized, for now.
|
|
||
| @VisibleForTesting | ||
| long getFirstBackoffTimeInMillis() { | ||
| synchronized long getFirstBackoffTimeInMillis() { |
There was a problem hiding this comment.
Same comment as above, except this is only used for a test.
| import lombok.Getter; | ||
|
|
||
| // All variables are in TimeUnit millis by default | ||
| @Data |
There was a problem hiding this comment.
I guess @Data should be replaced with @ToString @EqualsAndHashCode if the intention is to remove setters. @Value would be the correct solution if Backoff would be fully immutable.
There was a problem hiding this comment.
https://projectlombok.org/features/Data is the docs for @Data
There was a problem hiding this comment.
Great point. Do you think that I also need to make the mutable fields volatile then, since toString() and .equals won't be synchronized?
There was a problem hiding this comment.
Great point. Do you think that I also need to make the mutable fields
volatilethen, sincetoString()and.equalswon't be synchronized?
I think that it would be an overkill to use volatile in this case. In Java with 64 bit JVMs you cannot hit a "word tearing" issue where the observed field value would be corrupted. The worst that could happen in Java (on a 64 bit JVM) is a data race.
There was a problem hiding this comment.
I added in the annotations.
There was a problem hiding this comment.
Interestingly, it looks like spot bugs didn't like the change for the lack of synchronization introduced by the annotations:
Error: Medium: Inconsistent synchronization of org.apache.pulsar.client.impl.Backoff.next; locked 75% of time [org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff, org.apache.pulsar.client.impl.Backoff] Unsynchronized access at Backoff.java:[line 35]Unsynchronized access at Backoff.java:[line 35]Unsynchronized access at Backoff.java:[line 35]Synchronized access at Backoff.java:[line 96]Synchronized access at Backoff.java:[line 99]Synchronized access at Backoff.java:[line 97]Synchronized access at Backoff.java:[line 101]Synchronized access at Backoff.java:[line 101]Synchronized access at Backoff.java:[line 142]Synchronized access at Backoff.java:[line 133]Synchronized access at Backoff.java:[line 134]Synchronized access at Backoff.java:[line 134]Synchronized access at Backoff.java:[line 34] IS2_INCONSISTENT_SYNC
There was a problem hiding this comment.
I don't see any use for equality checking of Backoff objects outside of reference equality, and calling toString on the class is going to log a lot of information. I am leaning towards just removing these annotations. If we really want toString, I can write one in the class.
There was a problem hiding this comment.
@lhotari - are you able to take a look at this again?
|
The pr had no activity for 30 days, mark with Stale label. |
|
The pr had no activity for 30 days, mark with Stale label. |
|
Closing as stale... We later duplicate Maybe we should move this class to pulsar-common and do the refactor if it's still relevant. |
Another approach is we pass always the builder and initialize the instance per thread (call graph). It seems more reasonable. |
Motivation
In preparing #13951 (still a draft at this time), I noticed that the
Backoffclass is not thread safe, but it is accessed as if it were because we pass it to multiple threads and call.next()to get the next backoff delay.Modifications
initialandmaxvalues to constructor and remove them from theRetryUtilclass.@Dataannotation on theBackoffclass. It allowed for unsafe access to internal state.nextvariable. Here is my source showing that this initialization is unsafe: https://shipilev.net/blog/2014/safe-public-construction/.Verifying this change
There is already test coverage for this class. The primary changes just add
synchronizedkeywords to methods that get or update mutable state.Does this pull request potentially affect one of the following parts:
It's possible that removing the
@Dataannotation on the class will break client applications sinceBackoffis a public class in the java client. I'll need guidance on how we should proceed here.Documentation
docThis PR contains Javadocs for relevant documentation. There is no need to document this change elsewhere.