Skip to content

Commit 03fcfc0

Browse files
authored
Merge pull request #231 from dmlloyd/attach
[LOGMGR-238] Lightweight attachments
2 parents a63b10d + 8412565 commit 03fcfc0

File tree

3 files changed

+178
-69
lines changed

3 files changed

+178
-69
lines changed

core/src/main/java/org/jboss/logmanager/LogContext.java

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.jboss.logmanager;
2121

22+
import org.wildfly.common.Assert;
2223
import org.wildfly.common.ref.Reference;
2324
import org.wildfly.common.ref.References;
2425

@@ -35,6 +36,8 @@
3536
import java.util.logging.LoggingMXBean;
3637
import java.util.logging.LoggingPermission;
3738

39+
import static org.jboss.logmanager.LoggerNode.attachmentsFull;
40+
3841
/**
3942
* A logging context, for producing isolated logging environments.
4043
*/
@@ -51,6 +54,26 @@ public final class LogContext implements AutoCloseable {
5154
private final LoggingMXBean mxBean = new LoggingMXBeanImpl(this);
5255
private final boolean strong;
5356

57+
/**
58+
* The first attachment key.
59+
*/
60+
private Logger.AttachmentKey<?> attachmentKey1;
61+
62+
/**
63+
* The first attachment value.
64+
*/
65+
private Object attachmentValue1;
66+
67+
/**
68+
* The second attachment key.
69+
*/
70+
private Logger.AttachmentKey<?> attachmentKey2;
71+
72+
/**
73+
* The second attachment value.
74+
*/
75+
private Object attachmentValue2;
76+
5477
/**
5578
* This lazy holder class is required to prevent a problem due to a LogContext instance being constructed
5679
* before the class init is complete.
@@ -140,9 +163,14 @@ public static LogContext create() {
140163
* @param <V> the attachment value type
141164
* @return the attachment, or {@code null} if there is none for this key
142165
*/
143-
@SuppressWarnings({ "unchecked" })
166+
@SuppressWarnings("unchecked")
144167
public <V> V getAttachment(Logger.AttachmentKey<V> key) {
145-
return rootLogger.getAttachment(key);
168+
Assert.checkNotNullParam("key", key);
169+
synchronized (this) {
170+
if (key == attachmentKey1) return (V) attachmentValue1;
171+
if (key == attachmentKey2) return (V) attachmentValue2;
172+
}
173+
return null;
146174
}
147175

148176
/**
@@ -155,10 +183,34 @@ public <V> V getAttachment(Logger.AttachmentKey<V> key) {
155183
* @param <V> the attachment value type
156184
* @return the old attachment, if there was one
157185
* @throws SecurityException if a security manager exists and if the caller does not have {@code LoggingPermission(control)}
186+
* @throws IllegalArgumentException if the attachment cannot be added because the maximum has been reached
158187
*/
188+
@SuppressWarnings("unchecked")
159189
public <V> V attach(Logger.AttachmentKey<V> key, V value) throws SecurityException {
160190
checkAccess();
161-
return rootLogger.attach(key, value);
191+
Assert.checkNotNullParam("key", key);
192+
Assert.checkNotNullParam("value", value);
193+
V old;
194+
synchronized (this) {
195+
if (key == attachmentKey1) {
196+
old = (V) attachmentValue1;
197+
attachmentValue1 = value;
198+
} else if (key == attachmentKey2) {
199+
old = (V) attachmentValue2;
200+
attachmentValue2 = value;
201+
} else if (attachmentKey1 == null) {
202+
old = null;
203+
attachmentKey1 = key;
204+
attachmentValue1 = value;
205+
} else if (attachmentKey2 == null) {
206+
old = null;
207+
attachmentKey2 = key;
208+
attachmentValue2 = value;
209+
} else {
210+
throw attachmentsFull();
211+
}
212+
}
213+
return old;
162214
}
163215

164216
/**
@@ -171,11 +223,32 @@ public <V> V attach(Logger.AttachmentKey<V> key, V value) throws SecurityExcepti
171223
* @param <V> the attachment value type
172224
* @return the current attachment, if there is one, or {@code null} if the value was successfully attached
173225
* @throws SecurityException if a security manager exists and if the caller does not have {@code LoggingPermission(control)}
226+
* @throws IllegalArgumentException if the attachment cannot be added because the maximum has been reached
174227
*/
175-
@SuppressWarnings({ "unchecked" })
228+
@SuppressWarnings("unchecked")
176229
public <V> V attachIfAbsent(Logger.AttachmentKey<V> key, V value) throws SecurityException {
177230
checkAccess();
178-
return rootLogger.attachIfAbsent(key, value);
231+
Assert.checkNotNullParam("key", key);
232+
Assert.checkNotNullParam("value", value);
233+
V old;
234+
synchronized (this) {
235+
if (key == attachmentKey1) {
236+
old = (V) attachmentValue1;
237+
} else if (key == attachmentKey2) {
238+
old = (V) attachmentValue2;
239+
} else if (attachmentKey1 == null) {
240+
old = null;
241+
attachmentKey1 = key;
242+
attachmentValue1 = value;
243+
} else if (attachmentKey2 == null) {
244+
old = null;
245+
attachmentKey2 = key;
246+
attachmentValue2 = value;
247+
} else {
248+
throw attachmentsFull();
249+
}
250+
}
251+
return old;
179252
}
180253

181254
/**
@@ -187,10 +260,23 @@ public <V> V attachIfAbsent(Logger.AttachmentKey<V> key, V value) throws Securit
187260
* @return the old value, or {@code null} if there was none
188261
* @throws SecurityException if a security manager exists and if the caller does not have {@code LoggingPermission(control)}
189262
*/
190-
@SuppressWarnings({ "unchecked" })
263+
@SuppressWarnings("unchecked")
191264
public <V> V detach(Logger.AttachmentKey<V> key) throws SecurityException {
192265
checkAccess();
193-
return rootLogger.detach(key);
266+
Assert.checkNotNullParam("key", key);
267+
V old;
268+
synchronized (this) {
269+
if (key == attachmentKey1) {
270+
old = (V) attachmentValue1;
271+
attachmentValue1 = null;
272+
} else if (key == attachmentKey2) {
273+
old = (V) attachmentValue2;
274+
attachmentValue2 = null;
275+
} else {
276+
old = null;
277+
}
278+
}
279+
return old;
194280
}
195281

196282
/**

core/src/main/java/org/jboss/logmanager/Logger.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ public <V> V getAttachment(AttachmentKey<V> key) {
182182
* @param <V> the attachment value type
183183
* @return the old attachment, if there was one
184184
* @throws SecurityException if a security manager exists and if the caller does not have {@code LoggingPermission(control)}
185+
* @throws IllegalArgumentException if the attachment cannot be added because the maximum has been reached
185186
*/
186187
public <V> V attach(AttachmentKey<V> key, V value) throws SecurityException {
187188
LogContext.checkAccess();
@@ -197,6 +198,7 @@ public <V> V attach(AttachmentKey<V> key, V value) throws SecurityException {
197198
* @param <V> the attachment value type
198199
* @return the current attachment, if there is one, or {@code null} if the value was successfully attached
199200
* @throws SecurityException if a security manager exists and if the caller does not have {@code LoggingPermission(control)}
201+
* @throws IllegalArgumentException if the attachment cannot be added because the maximum has been reached
200202
*/
201203
@SuppressWarnings({ "unchecked" })
202204
public <V> V attachIfAbsent(AttachmentKey<V> key, V value) throws SecurityException {

core/src/main/java/org/jboss/logmanager/LoggerNode.java

Lines changed: 83 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,14 @@
1919

2020
package org.jboss.logmanager;
2121

22+
import org.wildfly.common.Assert;
2223
import org.wildfly.common.ref.PhantomReference;
2324
import org.wildfly.common.ref.Reaper;
2425
import org.wildfly.common.ref.Reference;
2526

2627
import java.util.Collection;
27-
import java.util.Collections;
2828
import java.util.Enumeration;
29-
import java.util.HashMap;
3029
import java.util.Iterator;
31-
import java.util.Map;
3230
import java.util.Set;
3331
import java.util.concurrent.ConcurrentHashMap;
3432
import java.util.concurrent.ConcurrentMap;
@@ -95,19 +93,29 @@ public void reap(Reference<Logger, LoggerNode> reference) {
9593
private final Set<Reference<Logger, LoggerNode>> activeLoggers = ConcurrentHashMap.newKeySet();
9694

9795
/**
98-
* The attachments map.
96+
* The first attachment key.
9997
*/
100-
private volatile Map<Logger.AttachmentKey, Object> attachments = Collections.emptyMap();
98+
private Logger.AttachmentKey<?> attachmentKey1;
10199

102100
/**
103-
* The atomic updater for the {@link #handlers} field.
101+
* The first attachment value.
104102
*/
105-
private static final AtomicArray<LoggerNode, Handler> handlersUpdater = AtomicArray.create(AtomicReferenceFieldUpdater.newUpdater(LoggerNode.class, Handler[].class, "handlers"), Handler.class);
103+
private Object attachmentValue1;
104+
105+
/**
106+
* The second attachment key.
107+
*/
108+
private Logger.AttachmentKey<?> attachmentKey2;
109+
110+
/**
111+
* The second attachment value.
112+
*/
113+
private Object attachmentValue2;
106114

107115
/**
108-
* The atomic updater for the {@link #attachments} field.
116+
* The atomic updater for the {@link #handlers} field.
109117
*/
110-
private static final AtomicReferenceFieldUpdater<LoggerNode, Map> attachmentsUpdater = AtomicReferenceFieldUpdater.newUpdater(LoggerNode.class, Map.class, "attachments");
118+
private static final AtomicArray<LoggerNode, Handler> handlersUpdater = AtomicArray.create(AtomicReferenceFieldUpdater.newUpdater(LoggerNode.class, Handler[].class, "handlers"), Handler.class);
111119

112120
/**
113121
* The actual level. May only be modified when the context's level change lock is held; in addition, changing
@@ -176,7 +184,10 @@ public void close() {
176184
handlersUpdater.clear(this);
177185
useParentFilter = false;
178186
useParentHandlers = true;
179-
attachmentsUpdater.get(this).clear();
187+
attachmentKey1 = null;
188+
attachmentValue1 = null;
189+
attachmentKey2 = null;
190+
attachmentValue2 = null;
180191
children.clear();
181192
}
182193
}
@@ -379,76 +390,82 @@ Level getLevel() {
379390

380391
@SuppressWarnings({ "unchecked" })
381392
<V> V getAttachment(final Logger.AttachmentKey<V> key) {
382-
if (key == null) {
383-
throw new NullPointerException("key is null");
393+
Assert.checkNotNullParam("key", key);
394+
synchronized (this) {
395+
if (key == attachmentKey1) return (V) attachmentValue1;
396+
if (key == attachmentKey2) return (V) attachmentValue2;
384397
}
385-
final Map<Logger.AttachmentKey, Object> attachments = this.attachments;
386-
return (V) attachments.get(key);
398+
return null;
387399
}
388400

389401
@SuppressWarnings({ "unchecked" })
390402
<V> V attach(final Logger.AttachmentKey<V> key, final V value) {
391-
if (key == null) {
392-
throw new NullPointerException("key is null");
393-
}
394-
if (value == null) {
395-
throw new NullPointerException("value is null");
396-
}
397-
Map<Logger.AttachmentKey, Object> oldAttachments;
398-
Map<Logger.AttachmentKey, Object> newAttachments;
403+
Assert.checkNotNullParam("key", key);
404+
Assert.checkNotNullParam("value", value);
399405
V old;
400-
do {
401-
oldAttachments = attachments;
402-
newAttachments = new HashMap<>(oldAttachments);
403-
old = (V) newAttachments.put(key, value);
404-
} while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments));
406+
synchronized (this) {
407+
if (key == attachmentKey1) {
408+
old = (V) attachmentValue1;
409+
attachmentValue1 = value;
410+
} else if (key == attachmentKey2) {
411+
old = (V) attachmentValue2;
412+
attachmentValue2 = value;
413+
} else if (attachmentKey1 == null) {
414+
old = null;
415+
attachmentKey1 = key;
416+
attachmentValue1 = value;
417+
} else if (attachmentKey2 == null) {
418+
old = null;
419+
attachmentKey2 = key;
420+
attachmentValue2 = value;
421+
} else {
422+
throw attachmentsFull();
423+
}
424+
}
405425
return old;
406426
}
407427

408428
@SuppressWarnings({ "unchecked" })
409429
<V> V attachIfAbsent(final Logger.AttachmentKey<V> key, final V value) {
410-
if (key == null) {
411-
throw new NullPointerException("key is null");
412-
}
413-
if (value == null) {
414-
throw new NullPointerException("value is null");
415-
}
416-
Map<Logger.AttachmentKey, Object> oldAttachments;
417-
Map<Logger.AttachmentKey, Object> newAttachments;
418-
do {
419-
oldAttachments = attachments;
420-
if (oldAttachments.containsKey(key)) {
421-
return (V) oldAttachments.get(key);
430+
Assert.checkNotNullParam("key", key);
431+
Assert.checkNotNullParam("value", value);
432+
V old;
433+
synchronized (this) {
434+
if (key == attachmentKey1) {
435+
old = (V) attachmentValue1;
436+
} else if (key == attachmentKey2) {
437+
old = (V) attachmentValue2;
438+
} else if (attachmentKey1 == null) {
439+
old = null;
440+
attachmentKey1 = key;
441+
attachmentValue1 = value;
442+
} else if (attachmentKey2 == null) {
443+
old = null;
444+
attachmentKey2 = key;
445+
attachmentValue2 = value;
446+
} else {
447+
throw attachmentsFull();
422448
}
423-
newAttachments = new HashMap<>(oldAttachments);
424-
newAttachments.put(key, value);
425-
} while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments));
426-
return null;
449+
}
450+
return old;
427451
}
428452

429453
@SuppressWarnings({ "unchecked" })
430454
public <V> V detach(final Logger.AttachmentKey<V> key) {
431-
if (key == null) {
432-
throw new NullPointerException("key is null");
433-
}
434-
Map<Logger.AttachmentKey, Object> oldAttachments;
435-
Map<Logger.AttachmentKey, Object> newAttachments;
436-
V result;
437-
do {
438-
oldAttachments = attachments;
439-
result = (V) oldAttachments.get(key);
440-
if (result == null) {
441-
return null;
442-
}
443-
final int size = oldAttachments.size();
444-
if (size == 1) {
445-
// special case - the new map is empty
446-
newAttachments = Collections.emptyMap();
455+
Assert.checkNotNullParam("key", key);
456+
V old;
457+
synchronized (this) {
458+
if (key == attachmentKey1) {
459+
old = (V) attachmentValue1;
460+
attachmentValue1 = null;
461+
} else if (key == attachmentKey2) {
462+
old = (V) attachmentValue2;
463+
attachmentValue2 = null;
447464
} else {
448-
newAttachments = new HashMap<Logger.AttachmentKey, Object>(oldAttachments);
465+
old = null;
449466
}
450-
} while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments));
451-
return result;
467+
}
468+
return old;
452469
}
453470

454471
String getFullName() {
@@ -524,4 +541,8 @@ public String nextElement() {
524541
}
525542
};
526543
}
544+
545+
static IllegalArgumentException attachmentsFull() {
546+
return new IllegalArgumentException("Attachments map is full");
547+
}
527548
}

0 commit comments

Comments
 (0)