-
Notifications
You must be signed in to change notification settings - Fork 471
Enables SharedVariableAtomicityDetector #6025
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
base: 2.1
Are you sure you want to change the base?
Conversation
Enables the SharedVariableAtomicityDetector SpotBugs detector. Resolved all race conditions and all false-positives (with suppressions or NotThreadSafe annotation)
kevinrr888
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.
Provided my reasoning in case it's helpful in review
| @NotThreadSafe | ||
| class RFileScanner extends ScannerOptions implements Scanner { |
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.
Scanners are not thread safe objects
| @NotThreadSafe | ||
| public class ScannerOptions implements ScannerBase { |
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.
Scanners are not thread safe
| @NotThreadSafe | ||
| private class QueryTask implements Runnable { |
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.
QueryTask is not used as/expected to be a thread-safe object
| @NotThreadSafe | ||
| private static class CachedTTransport extends TTransport { |
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.
CachedTTransport is only modified by a single thread at a time (must be reserved()/unreserved())
| @NotThreadSafe | ||
| public class BlockedInputStream extends InputStream { |
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.
BlockedInputStream is a wrapper for DataInputStream, which is not thread safe
| @NotThreadSafe | ||
| private static class NMSKVIter implements InterruptibleIterator { |
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.
Iterators are not thread safe
| private static final Logger log = LoggerFactory.getLogger(AssignmentWatcher.class); | ||
|
|
||
| private static long longAssignments = 0; | ||
| private static volatile long longAssignments = 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.
Set in a thread, but get in another thread, needs to be volatile
| @NotThreadSafe | ||
| static class TestFileManager extends CompactableImpl.FileManager { |
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.
Test class used in single threaded test
| @NotThreadSafe | ||
| public class ErrorThrowingIterator extends WrappingIterator { |
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.
accumulo iterators are not thread safe
| @NotThreadSafe | ||
| private abstract static class Test implements Runnable { |
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.
These are updated in this "Test" thread and checked in main thread, but they aren't checked until execution has completed, so fine not to use volatile or sync.
| @NotThreadSafe | ||
| public final class CountingInputStream extends FilterInputStream { |
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 is a stream and the impl shows this is not intended to be thread safe
keith-turner
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.
How does this static analysis pick which classes to inspect? Does every class that has non volatile and mutable fields have to be marked as not thread safe?
| QueueLock qlock; | ||
| byte[] userData; | ||
| long entry = -1; | ||
| AtomicLong entry; |
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.
Changes may not be needed to this class. I think it is only used by a single thread, but not 100% sure. Did some sampling and found this usually created as a local var in a function to try to obtain a lock in zookeeper, but the local var is not shared among threads.
core/src/main/java/org/apache/accumulo/core/fate/zookeeper/DistributedReadWriteLock.java
Outdated
Show resolved
Hide resolved
I believe it looks at every class, but not entirely sure how it chooses what to flag. I think it looks for common non-thread safe patterns and flags those (e.g., getting and then setting an atomic var in two operations, modifying a non-volatile/non-atomic var in a run(), but also having a getter in that same class, etc.). The documentation is pretty vague. https://spotbugs.readthedocs.io/en/latest/detectors.html It does not seem that every class needs to be marked/considered, I only had to change ~40 for 2.1 |
|
Looked into what the merge for main would look like, thankfully very few changes needed. This is what I'll be fixing in the merge to main:
|
core/src/main/java/org/apache/accumulo/core/client/ClientSideIteratorScanner.java
Outdated
Show resolved
Hide resolved
server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Scanner.java
Outdated
Show resolved
Hide resolved
| if (this.nextTime.get() < time) { | ||
| this.nextTime.set(time); | ||
| } | ||
| this.nextTime.getAndUpdate(val -> Math.max(val, finalTime)); |
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.
Maybe do not need finalTime.
| this.nextTime.getAndUpdate(val -> Math.max(val, finalTime)); | |
| this.nextTime.getAndUpdate(val -> Math.max(val, time + 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.
Yeah, fixed in f827d1a. When looking at this again, realized this method is only called in the constructor of Tablet before TabletTime is available to multiple threads, so technically no changes were needed at all here and there was no bug. But only using one atomic op here is still probably better.
server/base/src/main/java/org/apache/accumulo/server/tablets/TabletTime.java
Outdated
Show resolved
Hide resolved
dlmarion
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.
Still reviewing....
Enables the SharedVariableAtomicityDetector SpotBugs detector. Resolved all race conditions and all false-positives (with suppressions or NotThreadSafe annotation)
closes #5636