Skip to content

Commit

Permalink
Use a map for the attachments.
Browse files Browse the repository at this point in the history
Signed-off-by: James R. Perkins <jperkins@redhat.com>
  • Loading branch information
jamezp committed Jun 27, 2023
1 parent 9387782 commit ae4c349
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 171 deletions.
131 changes: 42 additions & 89 deletions src/main/java/org/jboss/logmanager/LogContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@

package org.jboss.logmanager;

import static org.jboss.logmanager.LoggerNode.attachmentsFull;

import java.lang.invoke.ConstantBootstraps;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
Expand Down Expand Up @@ -75,25 +76,10 @@ private static LogContextInitializer discoverDefaultInitializer0() {
private final boolean strong;
private final LogContextInitializer initializer;

/**
* The first attachment key.
*/
private Logger.AttachmentKey<?> attachmentKey1;

/**
* The first attachment value.
*/
private Object attachmentValue1;

/**
* The second attachment key.
*/
private Logger.AttachmentKey<?> attachmentKey2;
private volatile Map<Logger.AttachmentKey<?>, Object> attachments;

/**
* The second attachment value.
*/
private Object attachmentValue2;
private static final VarHandle attachmentHandle = ConstantBootstraps.fieldVarHandle(MethodHandles.lookup(), "attachments",
VarHandle.class, LogContext.class, Map.class);

/**
* This lazy holder class is required to prevent a problem due to a LogContext instance being constructed
Expand Down Expand Up @@ -147,6 +133,7 @@ private static void addStrong(Map<String, Reference<Level, Void>> map, Level lev
levelMapReference = new AtomicReference<Map<String, Reference<Level, Void>>>(LazyHolder.INITIAL_LEVEL_MAP);
rootLogger = new LoggerNode(this);
closeHandlers = new LinkedHashSet<>();
attachments = Map.of();
}

/**
Expand Down Expand Up @@ -213,13 +200,7 @@ public static LogContext create(LogContextInitializer initializer) {
@SuppressWarnings("unchecked")
public <V> V getAttachment(Logger.AttachmentKey<V> key) {
Assert.checkNotNullParam("key", key);
synchronized (this) {
if (key == attachmentKey1)
return (V) attachmentValue1;
if (key == attachmentKey2)
return (V) attachmentValue2;
}
return null;
return (V) attachments.get(key);
}

/**
Expand All @@ -240,26 +221,14 @@ public <V> V attach(Logger.AttachmentKey<V> key, V value) throws SecurityExcepti
checkAccess();
Assert.checkNotNullParam("key", key);
Assert.checkNotNullParam("value", value);
Map<Logger.AttachmentKey<?>, Object> oldAttachments;
Map<Logger.AttachmentKey<?>, Object> newAttachments;
V old;
synchronized (this) {
if (key == attachmentKey1) {
old = (V) attachmentValue1;
attachmentValue1 = value;
} else if (key == attachmentKey2) {
old = (V) attachmentValue2;
attachmentValue2 = value;
} else if (attachmentKey1 == null) {
old = null;
attachmentKey1 = key;
attachmentValue1 = value;
} else if (attachmentKey2 == null) {
old = null;
attachmentKey2 = key;
attachmentValue2 = value;
} else {
throw attachmentsFull();
}
}
do {
oldAttachments = attachments;
newAttachments = new HashMap<>(oldAttachments);
old = (V) newAttachments.put(key, value);
} while (!attachmentHandle.compareAndSet(this, oldAttachments, Map.copyOf(newAttachments)));
return old;
}

Expand All @@ -281,25 +250,17 @@ public <V> V attachIfAbsent(Logger.AttachmentKey<V> key, V value) throws Securit
checkAccess();
Assert.checkNotNullParam("key", key);
Assert.checkNotNullParam("value", value);
V old;
synchronized (this) {
if (key == attachmentKey1) {
old = (V) attachmentValue1;
} else if (key == attachmentKey2) {
old = (V) attachmentValue2;
} else if (attachmentKey1 == null) {
old = null;
attachmentKey1 = key;
attachmentValue1 = value;
} else if (attachmentKey2 == null) {
old = null;
attachmentKey2 = key;
attachmentValue2 = value;
} else {
throw attachmentsFull();
Map<Logger.AttachmentKey<?>, Object> oldAttachments;
Map<Logger.AttachmentKey<?>, Object> newAttachments;
do {
oldAttachments = attachments;
if (oldAttachments.containsKey(key)) {
return (V) oldAttachments.get(key);
}
}
return old;
newAttachments = new HashMap<>(oldAttachments);
newAttachments.put(key, value);
} while (!attachmentHandle.compareAndSet(this, oldAttachments, Map.copyOf(newAttachments)));
return null;
}

/**
Expand All @@ -315,19 +276,24 @@ public <V> V attachIfAbsent(Logger.AttachmentKey<V> key, V value) throws Securit
public <V> V detach(Logger.AttachmentKey<V> key) throws SecurityException {
checkAccess();
Assert.checkNotNullParam("key", key);
V old;
synchronized (this) {
if (key == attachmentKey1) {
old = (V) attachmentValue1;
attachmentValue1 = null;
} else if (key == attachmentKey2) {
old = (V) attachmentValue2;
attachmentValue2 = null;
Map<Logger.AttachmentKey<?>, Object> oldAttachments;
Map<Logger.AttachmentKey<?>, Object> newAttachments;
V result;
do {
oldAttachments = attachments;
result = (V) oldAttachments.get(key);
if (result == null) {
return null;
}
final int size = oldAttachments.size();
if (size == 1) {
// special case - the new map is empty
newAttachments = Map.of();
} else {
old = null;
newAttachments = new HashMap<>(oldAttachments);
}
}
return old;
} while (!attachmentHandle.compareAndSet(this, oldAttachments, Map.copyOf(newAttachments)));
return result;
}

/**
Expand Down Expand Up @@ -529,20 +495,7 @@ public void close() throws Exception {
for (AutoCloseable handler : closeHandlers) {
handler.close();
}
synchronized (this) {
attachmentKey1 = null;
attachmentKey2 = null;
final var value1 = attachmentValue1;
attachmentValue1 = null;
if (value1 instanceof AutoCloseable) {
((AutoCloseable) value1).close();
}
final var value2 = attachmentValue2;
attachmentValue2 = null;
if (value2 instanceof AutoCloseable) {
((AutoCloseable) value2).close();
}
}
attachmentHandle.setVolatile(this, Map.of());
} finally {
treeLock.unlock();
}
Expand Down
127 changes: 45 additions & 82 deletions src/main/java/org/jboss/logmanager/LoggerNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@

package org.jboss.logmanager;

import java.lang.invoke.ConstantBootstraps;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -98,26 +103,10 @@ public void reap(Reference<Logger, LoggerNode> reference) {
* The set of phantom references to active loggers.
*/
private final Set<Reference<Logger, LoggerNode>> activeLoggers = ConcurrentHashMap.newKeySet();
private volatile Map<Logger.AttachmentKey<?>, Object> attachments;

/**
* The first attachment key.
*/
private Logger.AttachmentKey<?> attachmentKey1;

/**
* The first attachment value.
*/
private Object attachmentValue1;

/**
* The second attachment key.
*/
private Logger.AttachmentKey<?> attachmentKey2;

/**
* The second attachment value.
*/
private Object attachmentValue2;
private static final VarHandle attachmentHandle = ConstantBootstraps.fieldVarHandle(MethodHandles.lookup(), "attachments",
VarHandle.class, LoggerNode.class, Map.class);

/**
* The atomic updater for the {@link #handlers} field.
Expand Down Expand Up @@ -162,6 +151,7 @@ public void reap(Reference<Logger, LoggerNode> reference) {
}
handlers = safeCloneHandlers(initializer.getInitialHandlers(fullName));
children = context.createChildMap();
attachments = Map.of();
}

/**
Expand Down Expand Up @@ -199,6 +189,7 @@ private LoggerNode(LogContext context, LoggerNode parent, String nodeName) {
}
handlers = safeCloneHandlers(initializer.getInitialHandlers(fullName));
children = context.createChildMap();
attachments = Map.of();
}

static Handler[] safeCloneHandlers(Handler... initialHandlers) {
Expand Down Expand Up @@ -248,10 +239,7 @@ public void close() {
handlersUpdater.clear(this);
useParentFilter = false;
useParentHandlers = true;
attachmentKey1 = null;
attachmentValue1 = null;
attachmentKey2 = null;
attachmentValue2 = null;
attachmentHandle.setVolatile(this, Map.of());
children.clear();
} finally {
treeLock.unlock();
Expand Down Expand Up @@ -486,83 +474,62 @@ Level getLevel() {
@SuppressWarnings({ "unchecked" })
<V> V getAttachment(final Logger.AttachmentKey<V> key) {
Assert.checkNotNullParam("key", key);
synchronized (this) {
if (key == attachmentKey1)
return (V) attachmentValue1;
if (key == attachmentKey2)
return (V) attachmentValue2;
}
return null;
return (V) attachments.get(key);
}

@SuppressWarnings({ "unchecked" })
<V> V attach(final Logger.AttachmentKey<V> key, final V value) {
Assert.checkNotNullParam("key", key);
Assert.checkNotNullParam("value", value);
Map<Logger.AttachmentKey<?>, Object> oldAttachments;
Map<Logger.AttachmentKey<?>, Object> newAttachments;
V old;
synchronized (this) {
if (key == attachmentKey1) {
old = (V) attachmentValue1;
attachmentValue1 = value;
} else if (key == attachmentKey2) {
old = (V) attachmentValue2;
attachmentValue2 = value;
} else if (attachmentKey1 == null) {
old = null;
attachmentKey1 = key;
attachmentValue1 = value;
} else if (attachmentKey2 == null) {
old = null;
attachmentKey2 = key;
attachmentValue2 = value;
} else {
throw attachmentsFull();
}
}
do {
oldAttachments = attachments;
newAttachments = new HashMap<>(oldAttachments);
old = (V) newAttachments.put(key, value);
} while (!attachmentHandle.compareAndSet(this, oldAttachments, Map.copyOf(newAttachments)));
return old;
}

@SuppressWarnings({ "unchecked" })
<V> V attachIfAbsent(final Logger.AttachmentKey<V> key, final V value) {
Assert.checkNotNullParam("key", key);
Assert.checkNotNullParam("value", value);
V old;
synchronized (this) {
if (key == attachmentKey1) {
old = (V) attachmentValue1;
} else if (key == attachmentKey2) {
old = (V) attachmentValue2;
} else if (attachmentKey1 == null) {
old = null;
attachmentKey1 = key;
attachmentValue1 = value;
} else if (attachmentKey2 == null) {
old = null;
attachmentKey2 = key;
attachmentValue2 = value;
} else {
throw attachmentsFull();
Map<Logger.AttachmentKey<?>, Object> oldAttachments;
Map<Logger.AttachmentKey<?>, Object> newAttachments;
do {
oldAttachments = attachments;
if (oldAttachments.containsKey(key)) {
return (V) oldAttachments.get(key);
}
}
return old;
newAttachments = new HashMap<>(oldAttachments);
newAttachments.put(key, value);
} while (!attachmentHandle.compareAndSet(this, oldAttachments, Map.copyOf(newAttachments)));
return null;
}

@SuppressWarnings({ "unchecked" })
public <V> V detach(final Logger.AttachmentKey<V> key) {
Assert.checkNotNullParam("key", key);
V old;
synchronized (this) {
if (key == attachmentKey1) {
old = (V) attachmentValue1;
attachmentValue1 = null;
} else if (key == attachmentKey2) {
old = (V) attachmentValue2;
attachmentValue2 = null;
Map<Logger.AttachmentKey<?>, Object> oldAttachments;
Map<Logger.AttachmentKey<?>, Object> newAttachments;
V result;
do {
oldAttachments = attachments;
result = (V) oldAttachments.get(key);
if (result == null) {
return null;
}
final int size = oldAttachments.size();
if (size == 1) {
// special case - the new map is empty
newAttachments = Map.of();
} else {
old = null;
newAttachments = new HashMap<>(oldAttachments);
}
}
return old;
} while (!attachmentHandle.compareAndSet(this, oldAttachments, Map.copyOf(newAttachments)));
return result;
}

String getFullName() {
Expand Down Expand Up @@ -641,8 +608,4 @@ public String nextElement() {
}
};
}

static IllegalArgumentException attachmentsFull() {
return new IllegalArgumentException("Attachments map is full");
}
}

0 comments on commit ae4c349

Please sign in to comment.