-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Fix thread safety issues within BasicStatusManager #851
base: master
Are you sure you want to change the base?
Conversation
d641b43
to
99a3726
Compare
99a3726
to
356a4e9
Compare
count.increment(); | ||
int newLevel = newStatus.getLevel(); | ||
int currentLevel; | ||
do { | ||
currentLevel = level.get(); | ||
if (newLevel <= currentLevel) { | ||
break; | ||
} | ||
} while (!level.compareAndSet(currentLevel, newLevel)); |
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 about
synchronized (statusListLock) {
count++;
if (newStatus.getLevel() > level) {
level = newStatus.getLevel();
}
if (statusList.size() < MAX_HEADER_COUNT) {
statusList.add(newStatus);
} else {
tailBuffer.add(newStatus);
}
}
The code might be more simple.
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.
Yes, we certainly could take advantage of the existing lock that's going to be taken out.
However, for correctness, the reads would also need to use the same lock:
public int getLevel() {
synchronized (statusListLock) {
return level;
}
}
public int getCount() {
synchronized (statusListLock) {
return count;
}
}
Otherwise the fields would need to be made volatile:
volatile int count = 0;
volatile int level = Status.INFO;
It also occurred to me that perhaps the level should be reset when the count is reset:
public void clear() {
synchronized (statusListLock) {
count = 0;
level = Level.INFO;
statusList.clear();
tailBuffer.clear();
}
}
356a4e9
to
cfd7df2
Compare
cfd7df2
to
05f70bf
Compare
Signed-off-by: Mark Chesney <mches@users.noreply.github.com>
count.increment(); | ||
int newLevel = newStatus.getLevel(); | ||
int currentLevel; | ||
do { | ||
currentLevel = level.get(); | ||
if (newLevel <= currentLevel) { | ||
break; | ||
} | ||
} while (!level.compareAndSet(currentLevel, newLevel)); | ||
|
||
synchronized (statusListLock) { |
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.
Here's an alternate approach to CAS
count.increment(); | |
int newLevel = newStatus.getLevel(); | |
int currentLevel; | |
do { | |
currentLevel = level.get(); | |
if (newLevel <= currentLevel) { | |
break; | |
} | |
} while (!level.compareAndSet(currentLevel, newLevel)); | |
synchronized (statusListLock) { | |
synchronized (statusListLock) { | |
count.increment(); | |
int newLevel = newStatus.getLevel(); | |
if (newLevel > level.get()) { | |
level.set(newLevel); | |
} | |
@@ -90,18 +97,18 @@ private void fireStatusAddEvent(Status status) { | |||
|
|||
public void clear() { | |||
synchronized (statusListLock) { | |||
count = 0; | |||
count.reset(); |
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.
Should level be reset as well?
count.reset(); | |
count.reset(); | |
level.set(Status.INFO); |
@@ -90,18 +97,18 @@ private void fireStatusAddEvent(Status status) { | |||
|
|||
public void clear() { | |||
synchronized (statusListLock) { | |||
count = 0; | |||
count.reset(); | |||
statusList.clear(); | |||
tailBuffer.clear(); | |||
} | |||
} | |||
|
|||
public int getLevel() { |
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.
Should StatusManager#getLevel()
be uncommented?
package ch.qos.logback.core.status;
…
public interface StatusManager {
…
/**
* Return the highest level of all the statii.
*
* @return
*/
// int getLevel();
…
}
Should @Override
be added to all implemented methods? (Available since Java 6)
See also #845
Fixes thread safety issues within
BasicStatusManager
, with respect tocount
andlevel
. As it stands, updates tocount
andlevel
could be temporarily or permanently invisible to other threads, or simply lost, due to lack of synchronization and non-atomic read-modify-write operations. Adopts the well-suitedLongAdder
forcount
andAtomicInteger
forlevel
. Without synchronization,level
needs to be set using CAS to avoid a race.