Skip to content

Commit 21a47ac

Browse files
committed
Speed-up isEnabled() by caching the least specific listener level
1 parent fd67e38 commit 21a47ac

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ private static Properties readPropertiesFile() {
300300

301301
private final Collection<StatusListener> listeners;
302302

303+
/**
304+
* Cache of the least-specific level available among {@link #listeners} to speed-up {@link #isEnabled(Level, Marker)}.
305+
*/
306+
private volatile Level leastSpecificListenerLevel;
307+
303308
private final transient ReadWriteLock listenerLock = new ReentrantReadWriteLock();
304309

305310
private final transient Lock listenerReadLock = listenerLock.readLock();
@@ -342,6 +347,7 @@ public StatusLogger(
342347
this.config = requireNonNull(config, "config");
343348
this.defaultListener = requireNonNull(defaultListener, "defaultListener");
344349
this.listeners = new ArrayList<>(Collections.singleton(defaultListener));
350+
this.leastSpecificListenerLevel = defaultListener.getStatusLevel();
345351
}
346352

347353
/**
@@ -409,6 +415,7 @@ public void registerListener(final StatusListener listener) {
409415
listenerWriteLock.lock();
410416
try {
411417
listeners.add(listener);
418+
updateLeastSpecificListenerLevel();
412419
} finally {
413420
listenerWriteLock.unlock();
414421
}
@@ -425,11 +432,25 @@ public void removeListener(final StatusListener listener) {
425432
try {
426433
closeListenerSafely(listener);
427434
listeners.remove(listener);
435+
updateLeastSpecificListenerLevel();
428436
} finally {
429437
listenerWriteLock.unlock();
430438
}
431439
}
432440

441+
private void updateLeastSpecificListenerLevel() {
442+
Level localLeastSpecificListenerLevel = leastSpecificListenerLevel;
443+
for (final StatusListener listener : listeners) {
444+
final Level listenerLevel = listener.getStatusLevel();
445+
if (listenerLevel.isLessSpecificThan(localLeastSpecificListenerLevel)) {
446+
localLeastSpecificListenerLevel = listener.getStatusLevel();
447+
}
448+
}
449+
// We must update `leastSpecificListenerLevel` in a single instruction!
450+
// It is `volatile` and accessed by `getLevel()` and `isEnabled()` without listener locks for efficiency.
451+
leastSpecificListenerLevel = localLeastSpecificListenerLevel;
452+
}
453+
433454
/**
434455
*
435456
* Sets the level of the default listener.
@@ -458,16 +479,18 @@ public Iterable<StatusListener> getListeners() {
458479
}
459480

460481
/**
461-
* Clears the event buffer and listeners.
482+
* Clears the event buffer and removes the <em>registered</em> (not the default one!) listeners.
462483
*/
463484
public void reset() {
464485
listenerWriteLock.lock();
465486
try {
466-
Iterator<StatusListener> listenerIterator = listeners.iterator();
487+
final Iterator<StatusListener> listenerIterator = listeners.iterator();
467488
while (listenerIterator.hasNext()) {
468-
StatusListener listener = listenerIterator.next();
469-
closeListenerSafely(listener);
470-
listenerIterator.remove();
489+
final StatusListener listener = listenerIterator.next();
490+
if (listener != defaultListener) {
491+
closeListenerSafely(listener);
492+
listenerIterator.remove();
493+
}
471494
}
472495
} finally {
473496
listenerWriteLock.unlock();
@@ -501,13 +524,13 @@ public void clear() {
501524
}
502525

503526
/**
504-
* Returns the level of the default listener.
527+
* Returns the least specific level among listeners.
505528
*
506-
* @return the default listener level
529+
* @return the least specific listener level
507530
*/
508531
@Override
509532
public Level getLevel() {
510-
return defaultListener.getStatusLevel();
533+
return leastSpecificListenerLevel;
511534
}
512535

513536
@Override
@@ -736,12 +759,6 @@ public boolean isEnabled(final Level level, final Marker marker, final Message m
736759
@Override
737760
public boolean isEnabled(final Level level, final Marker marker) {
738761
requireNonNull(level, "level");
739-
listenerReadLock.lock();
740-
try {
741-
return listeners.stream()
742-
.anyMatch(listener -> listener.getStatusLevel().isLessSpecificThan(level));
743-
} finally {
744-
listenerReadLock.unlock();
745-
}
762+
return leastSpecificListenerLevel.isLessSpecificThan(level);
746763
}
747764
}

0 commit comments

Comments
 (0)