-
-
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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,6 @@ | ||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||
* Logback: the reliable, generic, fast and flexible logging framework. | ||||||||||||||||||||||||||||||||||||||
* Copyright (C) 1999-2015, QOS.ch. All rights reserved. | ||||||||||||||||||||||||||||||||||||||
* Copyright (C) 1999-2024, QOS.ch. All rights reserved. | ||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||
* This program and the accompanying materials are dual-licensed under | ||||||||||||||||||||||||||||||||||||||
* either the terms of the Eclipse Public License v1.0 as published by | ||||||||||||||||||||||||||||||||||||||
|
@@ -15,6 +15,8 @@ | |||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
import java.util.ArrayList; | ||||||||||||||||||||||||||||||||||||||
import java.util.List; | ||||||||||||||||||||||||||||||||||||||
import java.util.concurrent.atomic.AtomicInteger; | ||||||||||||||||||||||||||||||||||||||
import java.util.concurrent.atomic.LongAdder; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
import ch.qos.logback.core.helpers.CyclicBuffer; | ||||||||||||||||||||||||||||||||||||||
import ch.qos.logback.core.spi.LogbackLock; | ||||||||||||||||||||||||||||||||||||||
|
@@ -28,14 +30,14 @@ public class BasicStatusManager implements StatusManager { | |||||||||||||||||||||||||||||||||||||
public static final int MAX_HEADER_COUNT = 150; | ||||||||||||||||||||||||||||||||||||||
public static final int TAIL_SIZE = 150; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
int count = 0; | ||||||||||||||||||||||||||||||||||||||
final LongAdder count = new LongAdder(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
// protected access was requested in http://jira.qos.ch/browse/LBCORE-36 | ||||||||||||||||||||||||||||||||||||||
final protected List<Status> statusList = new ArrayList<Status>(); | ||||||||||||||||||||||||||||||||||||||
final protected CyclicBuffer<Status> tailBuffer = new CyclicBuffer<Status>(TAIL_SIZE); | ||||||||||||||||||||||||||||||||||||||
final protected LogbackLock statusListLock = new LogbackLock(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
int level = Status.INFO; | ||||||||||||||||||||||||||||||||||||||
final AtomicInteger level = new AtomicInteger(Status.INFO); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
// protected access was requested in http://jira.qos.ch/browse/LBCORE-36 | ||||||||||||||||||||||||||||||||||||||
final protected List<StatusListener> statusListenerList = new ArrayList<StatusListener>(); | ||||||||||||||||||||||||||||||||||||||
|
@@ -57,10 +59,15 @@ public void add(Status newStatus) { | |||||||||||||||||||||||||||||||||||||
// LBCORE-72: fire event before the count check | ||||||||||||||||||||||||||||||||||||||
fireStatusAddEvent(newStatus); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
count++; | ||||||||||||||||||||||||||||||||||||||
if (newStatus.getLevel() > level) { | ||||||||||||||||||||||||||||||||||||||
level = newStatus.getLevel(); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
count.increment(); | ||||||||||||||||||||||||||||||||||||||
int newLevel = newStatus.getLevel(); | ||||||||||||||||||||||||||||||||||||||
int currentLevel; | ||||||||||||||||||||||||||||||||||||||
do { | ||||||||||||||||||||||||||||||||||||||
currentLevel = level.get(); | ||||||||||||||||||||||||||||||||||||||
if (newLevel <= currentLevel) { | ||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} while (!level.compareAndSet(currentLevel, newLevel)); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
synchronized (statusListLock) { | ||||||||||||||||||||||||||||||||||||||
Comment on lines
+62
to
72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's an alternate approach to CAS
Suggested change
|
||||||||||||||||||||||||||||||||||||||
if (statusList.size() < MAX_HEADER_COUNT) { | ||||||||||||||||||||||||||||||||||||||
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. Should level be reset as well?
Suggested change
|
||||||||||||||||||||||||||||||||||||||
statusList.clear(); | ||||||||||||||||||||||||||||||||||||||
tailBuffer.clear(); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
public int getLevel() { | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should package ch.qos.logback.core.status;
…
public interface StatusManager {
…
/**
* Return the highest level of all the statii.
*
* @return
*/
// int getLevel();
…
} Should See also #845 |
||||||||||||||||||||||||||||||||||||||
return level; | ||||||||||||||||||||||||||||||||||||||
return level.get(); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
public int getCount() { | ||||||||||||||||||||||||||||||||||||||
return count; | ||||||||||||||||||||||||||||||||||||||
return count.intValue(); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||
|
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
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:
Otherwise the fields would need to be made volatile:
It also occurred to me that perhaps the level should be reset when the count is reset: