Skip to content

Conversation

@kevinrr888
Copy link
Member

@kevinrr888 kevinrr888 commented Dec 16, 2025

Enables the SharedVariableAtomicityDetector SpotBugs detector. Resolved all race conditions and all false-positives (with suppressions or NotThreadSafe annotation)

closes #5636

Enables the SharedVariableAtomicityDetector SpotBugs detector.
Resolved all race conditions and all false-positives (with suppressions or
NotThreadSafe annotation)
@kevinrr888 kevinrr888 added this to the 2.1.5 milestone Dec 16, 2025
@kevinrr888 kevinrr888 self-assigned this Dec 16, 2025
Copy link
Member Author

@kevinrr888 kevinrr888 left a 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

Comment on lines +81 to 82
@NotThreadSafe
class RFileScanner extends ScannerOptions implements Scanner {
Copy link
Member Author

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

Comment on lines +51 to 52
@NotThreadSafe
public class ScannerOptions implements ScannerBase {
Copy link
Member Author

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

Comment on lines +360 to 361
@NotThreadSafe
private class QueryTask implements Runnable {
Copy link
Member Author

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

Comment on lines +582 to 583
@NotThreadSafe
private static class CachedTTransport extends TTransport {
Copy link
Member Author

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

Comment on lines +32 to 33
@NotThreadSafe
public class BlockedInputStream extends InputStream {
Copy link
Member Author

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

Comment on lines +539 to 540
@NotThreadSafe
private static class NMSKVIter implements InterruptibleIterator {
Copy link
Member Author

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;
Copy link
Member Author

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

Comment on lines +483 to 484
@NotThreadSafe
static class TestFileManager extends CompactableImpl.FileManager {
Copy link
Member Author

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

Comment on lines +42 to 43
@NotThreadSafe
public class ErrorThrowingIterator extends WrappingIterator {
Copy link
Member Author

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

Comment on lines +253 to 254
@NotThreadSafe
private abstract static class Test implements Runnable {
Copy link
Member Author

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.

Comment on lines +31 to 32
@NotThreadSafe
public final class CountingInputStream extends FilterInputStream {
Copy link
Member Author

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

Copy link
Contributor

@keith-turner keith-turner left a 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;
Copy link
Contributor

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.

@kevinrr888
Copy link
Member Author

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?

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

@kevinrr888
Copy link
Member Author

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:

LoadFiles.Loader - not used as or expected to be thread safe
SystemInformation - is used as and expected to be thread safe - timestamp needs to be volatile

@kevinrr888 kevinrr888 linked an issue Dec 18, 2025 that may be closed by this pull request
if (this.nextTime.get() < time) {
this.nextTime.set(time);
}
this.nextTime.getAndUpdate(val -> Math.max(val, finalTime));
Copy link
Contributor

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.

Suggested change
this.nextTime.getAndUpdate(val -> Math.max(val, finalTime));
this.nextTime.getAndUpdate(val -> Math.max(val, time + 1));

Copy link
Member Author

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.

* changed `batchTimeout = scanner.getTimeout` to `batchTimeout =
  scanner.getBatchTimeout` in ClientSideIteratorScanner, appeared to be
calling incorrect method
* address review
Copy link
Contributor

@dlmarion dlmarion left a comment

Choose a reason for hiding this comment

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

Still reviewing....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable SharedVariableAtomicityDetector SpotBugs detector

3 participants