[jboss-svn-commits] JBoss Common SVN: r3090 - jboss-logmanager/trunk/src/main/java/org/jboss/logmanager.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Fri Apr 3 16:28:54 EDT 2009
Author: david.lloyd at jboss.com
Date: 2009-04-03 16:28:54 -0400 (Fri, 03 Apr 2009)
New Revision: 3090
Added:
jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/AtomicArray.java
Modified:
jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java
Log:
Use atomicarray class to simplify handler array stuff
Added: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/AtomicArray.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/AtomicArray.java (rev 0)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/AtomicArray.java 2009-04-03 20:28:54 UTC (rev 3090)
@@ -0,0 +1,365 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.logmanager;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+/**
+ * Utility for snapshot/copy-on-write arrays. To use these methods, two things are required: an immutable array
+ * stored on a volatile field, and an instance of
+ * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater AtomicReferenceFieldUpdater}
+ * which corresponds to that field. Some of these methods perform multi-step operations; if the array field value is
+ * changed in the middle of such an operation, the operation is retried. To avoid spinning, in some situations it
+ * may be advisable to hold a write lock to prevent multiple concurrent updates.
+ *
+ * @param <T> the type which contains the target field
+ * @param <V> the array value type
+ */
+final class AtomicArray<T, V> {
+
+ private final AtomicReferenceFieldUpdater<T, V[]> updater;
+ private final Class<V> componentType;
+ private final V[] emptyArray;
+
+ /**
+ * Construct an instance.
+ *
+ * @param updater the field updater
+ * @param componentType the component class
+ */
+ public AtomicArray(AtomicReferenceFieldUpdater<T, V[]> updater, Class<V> componentType) {
+ this.updater = updater;
+ this.componentType = componentType;
+ emptyArray = newInstance(componentType, 0);
+ }
+
+ /**
+ * Convenience method to create an instance.
+ *
+ * @param updater the field updater
+ * @param componentType the component class
+ * @param <T> the type which contains the target field
+ * @param <V> the array value type
+ * @return the new instance
+ */
+ public static <T, V> AtomicArray<T, V> create(AtomicReferenceFieldUpdater<T, V[]> updater, Class<V> componentType) {
+ return new AtomicArray<T,V>(updater, componentType);
+ }
+
+ /**
+ * Convenience method to set the field value to the empty array. Empty array instances are shared.
+ *
+ * @param instance the instance holding the field
+ */
+ public void clear(T instance) {
+ updater.set(instance, emptyArray);
+ }
+
+ /**
+ * Update the value of this array.
+ *
+ * @param instance the instance holding the field
+ * @param value the new value
+ */
+ public void set(T instance, V[] value) {
+ updater.set(instance, value);
+ }
+
+ /**
+ * Atomically get and update the value of this array.
+ *
+ * @param instance the instance holding the field
+ * @param value the new value
+ */
+ public V[] getAndSet(T instance, V[] value) {
+ return updater.getAndSet(instance, value);
+ }
+
+ /**
+ * Atomically replace the array with a new array which is one element longer, and which includes the given value.
+ *
+ * @param instance the instance holding the field
+ * @param value the updated value
+ */
+ public void add(T instance, V value) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ final int oldLen = oldVal.length;
+ final V[] newVal = Arrays.copyOf(oldVal, oldLen + 1);
+ newVal[oldLen] = value;
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Atomically replace the array with a new array which is one element longer, and which includes the given value,
+ * if the value is not already present within the array. This method does a linear search for the target value.
+ *
+ * @param instance the instance holding the field
+ * @param value the updated value
+ * @param identity {@code true} if comparisons should be done using reference identity, or {@code false} to use the {@code equals()} method
+ * @return {@code true} if the value was added, or {@code false} if it was already present
+ */
+ public boolean addIfAbsent(T instance, V value, boolean identity) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ final int oldLen = oldVal.length;
+ if (identity || value == null) {
+ for (int i = 0; i < oldLen; i++) {
+ if (oldVal[i] == value) {
+ return false;
+ }
+ }
+ } else {
+ for (int i = 0; i < oldLen; i++) {
+ if (value.equals(oldVal[i])) {
+ return false;
+ }
+ }
+ }
+ final V[] newVal = Arrays.copyOf(oldVal, oldLen + 1);
+ newVal[oldLen] = value;
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Atomically replace the array with a new array which does not include the first occurrance of the given value, if
+ * the value is present in the array.
+ *
+ * @param instance the instance holding the field
+ * @param value the updated value
+ * @param identity {@code true} if comparisons should be done using reference identity, or {@code false} to use the {@code equals()} method
+ * @return {@code true} if the value was removed, or {@code false} if it was not present
+ */
+ public boolean remove(T instance, V value, boolean identity) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ final int oldLen = oldVal.length;
+ if (oldLen == 0) {
+ return false;
+ } else {
+ int index = -1;
+ if (identity || value == null) {
+ for (int i = 0; i < oldLen; i++) {
+ if (oldVal[i] == value) {
+ index = i;
+ break;
+ }
+ }
+ } else {
+ for (int i = 0; i < oldLen; i++) {
+ if (value.equals(oldVal[i])) {
+ index = i;
+ break;
+ }
+ }
+ }
+ if (index == -1) {
+ return false;
+ }
+ final V[] newVal = newInstance(componentType, oldLen - 1);
+ System.arraycopy(oldVal, 0, newVal, 0, index);
+ System.arraycopy(oldVal, index + 1, newVal, index, oldLen - index - 1);
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Atomically replace the array with a new array which does not include any occurrances of the given value, if
+ * the value is present in the array.
+ *
+ * @param instance the instance holding the field
+ * @param value the updated value
+ * @param identity {@code true} if comparisons should be done using reference identity, or {@code false} to use the {@code equals()} method
+ * @return the number of values removed
+ */
+ public int removeAll(T instance, V value, boolean identity) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ final int oldLen = oldVal.length;
+ if (oldLen == 0) {
+ return 0;
+ } else {
+ final boolean[] removeSlots = new boolean[oldLen];
+ int removeCount = 0;
+ if (identity || value == null) {
+ for (int i = 0; i < oldLen; i++) {
+ if (oldVal[i] == value) {
+ removeSlots[i] = true;
+ removeCount++;
+ }
+ }
+ } else {
+ for (int i = 0; i < oldLen; i++) {
+ if (value.equals(oldVal[i])) {
+ removeSlots[i] = true;
+ removeCount++;
+ }
+ }
+ }
+ if (removeCount == 0) {
+ return 0;
+ }
+ final int newLen = oldLen - removeCount;
+ final V[] newVal;
+ if (newLen == 0) {
+ newVal = emptyArray;
+ } else {
+ newVal = newInstance(componentType, newLen);
+ for (int i = 0, j = 0; i < oldLen; i ++) {
+ if (! removeSlots[i]) {
+ newVal[j++] = oldVal[i];
+ }
+ }
+ }
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return removeCount;
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a value to a sorted array. Does not check for duplicates.
+ *
+ * @param instance the instance holding the field
+ * @param value the value to add
+ * @param comparator a comparator, or {@code null} to use natural ordering
+ */
+ public void add(T instance, V value, Comparator<? super V> comparator) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ final int oldLen = oldVal.length;
+ final int pos = insertionPoint(Arrays.binarySearch(oldVal, value, comparator));
+ final V[] newVal = newInstance(componentType, oldLen + 1);
+ System.arraycopy(oldVal, 0, newVal, 0, pos);
+ newVal[pos] = value;
+ System.arraycopy(oldVal, pos, newVal, pos + 1, oldLen - pos);
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Add a value to a sorted array if it is not already present. Does not check for duplicates.
+ *
+ * @param instance the instance holding the field
+ * @param value the value to add
+ * @param comparator a comparator, or {@code null} to use natural ordering
+ */
+ public boolean addIfAbsent(T instance, V value, Comparator<? super V> comparator) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ final int oldLen = oldVal.length;
+ final int pos = Arrays.binarySearch(oldVal, value, comparator);
+ if (pos < 0) {
+ return false;
+ }
+ final V[] newVal = newInstance(componentType, oldLen + 1);
+ System.arraycopy(oldVal, 0, newVal, 0, pos);
+ newVal[pos] = value;
+ System.arraycopy(oldVal, pos, newVal, pos + 1, oldLen - pos);
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Remove a value to a sorted array. Does not check for duplicates. If there are multiple occurrances of a value,
+ * there is no guarantee as to which one is removed.
+ *
+ * @param instance the instance holding the field
+ * @param value the value to remove
+ * @param comparator a comparator, or {@code null} to use natural ordering
+ */
+ public boolean remove(T instance, V value, Comparator<? super V> comparator) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ final int oldLen = oldVal.length;
+ if (oldLen == 0) {
+ return false;
+ } else {
+ final int pos = Arrays.binarySearch(oldVal, value, comparator);
+ if (pos < 0) {
+ return false;
+ }
+ final V[] newVal = newInstance(componentType, oldLen - 1);
+ System.arraycopy(oldVal, 0, newVal, 0, pos);
+ System.arraycopy(oldVal, pos + 1, newVal, pos, oldLen - pos - 1);
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Sort an array.
+ *
+ * @param instance the instance holding the field
+ * @param comparator a comparator, or {@code null} to use natural ordering
+ */
+ public void sort(T instance, Comparator<? super V> comparator) {
+ final AtomicReferenceFieldUpdater<T, V[]> updater = this.updater;
+ for (;;) {
+ final V[] oldVal = updater.get(instance);
+ if (oldVal.length == 0) {
+ return;
+ }
+ final V[] newVal = oldVal.clone();
+ Arrays.sort(newVal, comparator);
+ if (updater.compareAndSet(instance, oldVal, newVal)) {
+ return;
+ }
+ }
+ }
+
+ private static int insertionPoint(int searchResult) {
+ return searchResult > 0 ? searchResult : - (searchResult + 1);
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ private static <V> V[] newInstance(Class<V> componentType, int length) {
+ return (V[]) Array.newInstance(componentType, length);
+ }
+}
Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java 2009-03-30 16:28:21 UTC (rev 3089)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/Logger.java 2009-04-03 20:28:54 UTC (rev 3090)
@@ -22,20 +22,17 @@
package org.jboss.logmanager;
+import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.Lock;
-import java.util.Comparator;
-import java.util.Arrays;
-import java.util.ResourceBundle;
+import org.slf4j.Marker;
+import org.slf4j.spi.LocationAwareLogger;
import java.util.logging.Filter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
-import org.slf4j.spi.LocationAwareLogger;
-import org.slf4j.Marker;
-
/**
* An actual logger instance. This is the end-user interface into the logging system.
*/
@@ -66,12 +63,8 @@
/**
* The atomic updater for the {@link #handlers} field.
*/
- private static final AtomicReferenceFieldUpdater<Logger, Handler[]> handlersUpdater = AtomicReferenceFieldUpdater.newUpdater(Logger.class, Handler[].class, "handlers");
+ private static final AtomicArray<Logger, Handler> handlersUpdater = AtomicArray.create(AtomicReferenceFieldUpdater.newUpdater(Logger.class, Handler[].class, "handlers"), Handler.class);
- /**
- * The empty handler list.
- */
- private static final Handler[] EMPTY_HANDLERS = new Handler[0];
private static final String LOGGER_CLASS_NAME = Logger.class.getName();
/**
@@ -96,6 +89,7 @@
// We maintain our own level
super.setLevel(Level.ALL);
this.loggerNode = loggerNode;
+ handlersUpdater.clear(this);
}
// Filter mgmt
@@ -186,35 +180,13 @@
// Handler mgmt
- private static final Comparator<Handler> IHC_COMPARATOR = new Comparator<Handler>() {
- public int compare(final Handler o1, final Handler o2) {
- return Integer.signum(System.identityHashCode(o1) - System.identityHashCode(o2));
- }
- };
-
/** {@inheritDoc} */
public void addHandler(Handler handler) throws SecurityException {
LogContext.checkAccess();
if (handler == null) {
throw new NullPointerException("handler is null");
}
- boolean ok;
- do {
- final Handler[] oldHandlers = handlers;
- final Handler[] newHandlers;
- if (oldHandlers != null) {
- final int len = oldHandlers.length;
- newHandlers = new Handler[len + 1];
- final int pos = Arrays.binarySearch(oldHandlers, handler, IHC_COMPARATOR);
- final int ip = pos < 0 ? -pos - 1 : pos;
- newHandlers[ip] = handler;
- System.arraycopy(oldHandlers, 0, newHandlers, 0, ip);
- System.arraycopy(oldHandlers, ip, newHandlers, ip + 1, len - ip);
- } else {
- newHandlers = new Handler[] { handler };
- }
- ok = handlersUpdater.compareAndSet(this, oldHandlers, newHandlers);
- } while (! ok);
+ handlersUpdater.add(this, handler);
}
/** {@inheritDoc} */
@@ -223,30 +195,13 @@
if (handler == null) {
return;
}
- boolean ok;
- do {
- final Handler[] oldHandlers = handlers;
- final Handler[] newHandlers;
- if (oldHandlers == null) {
- return;
- } else {
- final int len = oldHandlers.length;
- final int pos = Arrays.binarySearch(oldHandlers, handler, IHC_COMPARATOR);
- if (pos < 0) {
- return;
- }
- newHandlers = new Handler[len - 1];
- System.arraycopy(oldHandlers, 0, newHandlers, 0, pos);
- System.arraycopy(oldHandlers, pos + 1, newHandlers, pos, len - pos - 1);
- }
- ok = handlersUpdater.compareAndSet(this, oldHandlers, newHandlers);
- } while (! ok);
+ handlersUpdater.remove(this, handler, true);
}
/** {@inheritDoc} */
public Handler[] getHandlers() {
final Handler[] handlers = this.handlers;
- return handlers == null ? EMPTY_HANDLERS : handlers.clone();
+ return handlers.length > 0 ? handlers.clone() : handlers;
}
/**
@@ -256,8 +211,9 @@
*/
public Handler[] clearHandlers() throws SecurityException {
LogContext.checkAccess();
- final Handler[] handlers = handlersUpdater.getAndSet(this, null);
- return handlers == null ? EMPTY_HANDLERS : handlers;
+ final Handler[] handlers = this.handlers;
+ handlersUpdater.clear(this);
+ return handlers.length > 0 ? handlers.clone() : handlers;
}
/** {@inheritDoc} */
More information about the jboss-svn-commits
mailing list