[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