You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2006/02/17 16:01:13 UTC
svn commit: r378539 - in /incubator/jackrabbit/trunk/jackrabbit: ./
src/main/java/org/apache/jackrabbit/core/state/
src/main/java/org/apache/jackrabbit/util/
Author: mreutegg
Date: Fri Feb 17 07:01:11 2006
New Revision: 378539
URL: http://svn.apache.org/viewcvs?rev=378539&view=rev
Log:
- Use custom collection implementation for item state listeners.
reduces memory consumption caused by those collections to about 1/3.
Performance of common operations on the WeakIdentityCollection scale linearly and outperforms the previously used ReferenceMap until it contains aprox. 100 listeners. Most item states only contain few listeners.
Added:
incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/WeakIdentityCollection.java (with props)
Modified:
incubator/jackrabbit/trunk/jackrabbit/project.properties
incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/ItemState.java
incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeState.java
Modified: incubator/jackrabbit/trunk/jackrabbit/project.properties
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/project.properties?rev=378539&r1=378538&r2=378539&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/project.properties (original)
+++ incubator/jackrabbit/trunk/jackrabbit/project.properties Fri Feb 17 07:01:11 2006
@@ -32,7 +32,7 @@
maven.junit.sysproperties=derby.system.durability
derby.system.durability=test
#java.security.auth.login.config=applications/test/jaas.config
-maven.junit.jvmargs=-Xmx128m
+maven.junit.jvmargs=-Xmx128m -enableassertions
#If you wish to skip tests when doing builds, uncomment
#maven.test.skip = true
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/ItemState.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/ItemState.java?rev=378539&r1=378538&r2=378539&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/ItemState.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/ItemState.java Fri Feb 17 07:01:11 2006
@@ -16,18 +16,16 @@
*/
package org.apache.jackrabbit.core.state;
-import org.apache.commons.collections.map.ReferenceMap;
import org.apache.jackrabbit.core.ItemId;
import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.util.WeakIdentityCollection;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.Collection;
/**
* <code>ItemState</code> represents the state of an <code>Item</code>.
@@ -89,9 +87,7 @@
/**
* Listeners (weak references)
*/
- private final transient Map listeners =
- Collections.synchronizedMap(
- new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK));
+ private final transient Collection listeners = new WeakIdentityCollection(5);
/**
* the backing persistent item state (may be null)
@@ -176,7 +172,9 @@
*/
void onDisposed() {
// prepare this instance so it can be gc'ed
- listeners.clear();
+ synchronized (listeners) {
+ listeners.clear();
+ }
disconnect();
overlayedState = null;
status = STATUS_UNDEFINED;
@@ -223,11 +221,9 @@
*/
protected void notifyStateDiscarded() {
// copy listeners to array to avoid ConcurrentModificationException
- ItemStateListener[] la = new ItemStateListener[listeners.size()];
- Iterator iter = listeners.values().iterator();
- int cnt = 0;
- while (iter.hasNext()) {
- la[cnt++] = (ItemStateListener) iter.next();
+ ItemStateListener[] la;
+ synchronized (listeners) {
+ la = (ItemStateListener[]) listeners.toArray(new ItemStateListener[listeners.size()]);
}
for (int i = 0; i < la.length; i++) {
if (la[i] != null) {
@@ -242,11 +238,9 @@
*/
protected void notifyStateCreated() {
// copy listeners to array to avoid ConcurrentModificationException
- ItemStateListener[] la = new ItemStateListener[listeners.size()];
- Iterator iter = listeners.values().iterator();
- int cnt = 0;
- while (iter.hasNext()) {
- la[cnt++] = (ItemStateListener) iter.next();
+ ItemStateListener[] la;
+ synchronized (listeners) {
+ la = (ItemStateListener[]) listeners.toArray(new ItemStateListener[listeners.size()]);
}
for (int i = 0; i < la.length; i++) {
if (la[i] != null) {
@@ -261,11 +255,9 @@
*/
public void notifyStateUpdated() {
// copy listeners to array to avoid ConcurrentModificationException
- ItemStateListener[] la = new ItemStateListener[listeners.size()];
- Iterator iter = listeners.values().iterator();
- int cnt = 0;
- while (iter.hasNext()) {
- la[cnt++] = (ItemStateListener) iter.next();
+ ItemStateListener[] la;
+ synchronized (listeners) {
+ la = (ItemStateListener[]) listeners.toArray(new ItemStateListener[listeners.size()]);
}
for (int i = 0; i < la.length; i++) {
if (la[i] != null) {
@@ -280,11 +272,9 @@
*/
protected void notifyStateDestroyed() {
// copy listeners to array to avoid ConcurrentModificationException
- ItemStateListener[] la = new ItemStateListener[listeners.size()];
- Iterator iter = listeners.values().iterator();
- int cnt = 0;
- while (iter.hasNext()) {
- la[cnt++] = (ItemStateListener) iter.next();
+ ItemStateListener[] la;
+ synchronized (listeners) {
+ la = (ItemStateListener[]) listeners.toArray(new ItemStateListener[listeners.size()]);
}
for (int i = 0; i < la.length; i++) {
if (la[i] != null) {
@@ -441,8 +431,9 @@
* @param listener the new listener to be informed on modifications
*/
public void addListener(ItemStateListener listener) {
- if (!listeners.containsKey(listener)) {
- listeners.put(listener, listener);
+ synchronized (listeners) {
+ assert (!listeners.contains(listener));
+ listeners.add(listener);
}
}
@@ -452,7 +443,9 @@
* @param listener an existing listener
*/
public void removeListener(ItemStateListener listener) {
- listeners.remove(listener);
+ synchronized (listeners) {
+ listeners.remove(listener);
+ }
}
//----------------------------------------------------< ItemStateListener >
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeState.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeState.java?rev=378539&r1=378538&r2=378539&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeState.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeState.java Fri Feb 17 07:01:11 2006
@@ -19,11 +19,12 @@
import org.apache.commons.collections.MapIterator;
import org.apache.commons.collections.OrderedMapIterator;
import org.apache.commons.collections.map.LinkedMap;
-import org.apache.commons.collections.map.ReferenceMap;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.ItemId;
import org.apache.jackrabbit.core.nodetype.NodeDefId;
import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.util.WeakIdentityCollection;
+import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -49,6 +50,8 @@
*/
static final long serialVersionUID = -4116945555530446652L;
+ private static Logger log = Logger.getLogger(NodeState.class);
+
/**
* the name of this node's primary type
*/
@@ -87,8 +90,7 @@
/**
* Listeners (weak references)
*/
- private final transient ReferenceMap listeners =
- new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
+ private final transient Collection listeners = new WeakIdentityCollection(3);
/**
* Constructs a new node state that is initially connected to an overlayed
@@ -675,8 +677,12 @@
public void addListener(ItemStateListener listener) {
if (listener instanceof NodeStateListener) {
synchronized (listeners) {
- if (!listeners.containsKey(listener)) {
- listeners.put(listener, listener);
+ if (listeners.contains(listener)) {
+ log.debug("listener already registered: " + listener);
+ // no need to add to call ItemState.addListener()
+ return;
+ } else {
+ listeners.add(listener);
}
}
}
@@ -704,7 +710,7 @@
*/
protected void notifyNodeAdded(ChildNodeEntry added) {
synchronized (listeners) {
- MapIterator iter = listeners.mapIterator();
+ Iterator iter = listeners.iterator();
while (iter.hasNext()) {
NodeStateListener l = (NodeStateListener) iter.next();
if (l != null) {
@@ -720,7 +726,7 @@
*/
protected void notifyNodesReplaced() {
synchronized (listeners) {
- MapIterator iter = listeners.mapIterator();
+ Iterator iter = listeners.iterator();
while (iter.hasNext()) {
NodeStateListener l = (NodeStateListener) iter.next();
if (l != null) {
@@ -735,7 +741,7 @@
*/
protected void notifyNodeRemoved(ChildNodeEntry removed) {
synchronized (listeners) {
- MapIterator iter = listeners.mapIterator();
+ Iterator iter = listeners.iterator();
while (iter.hasNext()) {
NodeStateListener l = (NodeStateListener) iter.next();
if (l != null) {
Added: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/WeakIdentityCollection.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/WeakIdentityCollection.java?rev=378539&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/WeakIdentityCollection.java (added)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/WeakIdentityCollection.java Fri Feb 17 07:01:11 2006
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.util;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.BitSet;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+
+/**
+ * <code>WeakIdentityCollection</code> implements a Collection with weak values.
+ * Equality of elements is tested using the == operator.
+ * <p/>
+ * This collection does not hide the fact that the garbage collector will remove
+ * a mapping at some point in time. Thus, the {@link java.util.Iterator} returned
+ * by this collection might return <code>null</code> values. The same applies
+ * to the method {@link #toArray()} in both its variants.
+ */
+public class WeakIdentityCollection implements Collection {
+
+ /**
+ * The weak references.
+ */
+ private transient WeakRef[] elementData;
+
+ /**
+ * The current number of elements in {@link #elementData}.
+ */
+ private int size;
+
+ /**
+ * The reference queue to poll for references that point to unreachable
+ * objects.
+ */
+ private final ReferenceQueue refQueue = new ReferenceQueue();
+
+ /**
+ * BitSet where a set bit indicates that the slot at this position in
+ * {@link #elementData} is empty and can be reused.
+ */
+ private final BitSet emptySlots = new BitSet();
+
+ /**
+ * Creates a new WeakIdentityCollection.
+ *
+ * @param initialCapacity the initial capacity.
+ */
+ public WeakIdentityCollection(int initialCapacity) {
+ if (initialCapacity < 0) {
+ throw new IllegalArgumentException("Illegal Capacity: " +
+ initialCapacity);
+ }
+ this.elementData = new WeakRef[initialCapacity];
+ }
+
+ /**
+ * Returns the current size of this collection.
+ *
+ * @return the current size of this collection.
+ */
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Returns <code>true</code> if this collection is empty.
+ *
+ * @return <code>true</code> if this collection is empty.
+ */
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ /**
+ * Releases all references held by this collection.
+ */
+ public void clear() {
+ for (int i = 0; i < size; i++) {
+ elementData[i] = null;
+ }
+ size = 0;
+ emptySlots.clear();
+ }
+
+ /**
+ * Adds object <code>o</code> to this collection.
+ *
+ * @param o the object to add.
+ * @return always <code>true</code> as this collection allows duplicates.
+ * @throws NullPointerException if <code>o</code> is <code>null</code>.
+ */
+ public boolean add(Object o) {
+ if (o == null) {
+ throw new NullPointerException("Object must not be null");
+ }
+ // poll refQueue for a slot we can reuse
+ WeakRef ref = (WeakRef) refQueue.poll();
+ if (ref != null) {
+ elementData[ref.index] = new WeakRef(o, ref.index);
+ cleanQueue();
+ } else if (!emptySlots.isEmpty()) {
+ int idx = emptySlots.nextSetBit(0);
+ elementData[idx] = new WeakRef(o, idx);
+ emptySlots.clear(idx);
+ } else {
+ ensureCapacity(size + 1);
+ elementData[size++] = new WeakRef(o, size - 1);
+ }
+ return true;
+ }
+
+ /**
+ * Returns <code>true</code> if this collection contains <code>o</code>.
+ *
+ * @param o element whose presence in this collection is to be tested.
+ * @return <code>true</code> if this collection contains the specified
+ * element
+ */
+ public boolean contains(Object o) {
+ for (int i = 0; i < size; i++) {
+ if (elementData[i].get() == o) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes the object <code>o</code> from this collection if it is present.
+ *
+ * @param o the object to remove.
+ * @return <code>true</code> if this collection changed as a result of the
+ * call.
+ */
+ public boolean remove(Object o) {
+ for (int i = 0; i < size; i++) {
+ if (elementData[i].get() == o) {
+ emptySlots.set(i);
+ // overwrite entry with dummy ref
+ elementData[i] = new WeakRef(null, i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @throws UnsupportedOperationException always.
+ */
+ public boolean addAll(Collection c) {
+ throw new UnsupportedOperationException("addAll");
+ }
+
+ /**
+ * @throws UnsupportedOperationException always.
+ */
+ public boolean containsAll(Collection c) {
+ throw new UnsupportedOperationException("containsAll");
+ }
+
+ /**
+ * @throws UnsupportedOperationException always.
+ */
+ public boolean removeAll(Collection c) {
+ throw new UnsupportedOperationException("removeAll");
+ }
+
+ /**
+ * @throws UnsupportedOperationException always.
+ */
+ public boolean retainAll(Collection c) {
+ throw new UnsupportedOperationException("retainAll");
+ }
+
+ /**
+ * Returns an {@link java.util.Iterator} over the elements of this
+ * collection. The returned iterator is not fail-fast. That is, it does
+ * not throw a {@link java.util.ConcurrentModificationException} if this
+ * collection is modified while iterating over the collection.
+ *
+ * @return an {@link java.util.Iterator} over the elements of this
+ * collection.
+ */
+ public Iterator iterator() {
+ return new Iter();
+ }
+
+ /**
+ * Returns an array containing all of the elements in this collection. The
+ * returned array may contain <code>null</code> elements!
+ *
+ * @return an array containing all of the elements in this collection.
+ */
+ public Object[] toArray() {
+ Object[] result = new Object[size];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = elementData[i].get();
+ }
+ return result;
+ }
+
+ /**
+ * The returned array may contain <code>null</code> elements!
+ * @inheritDoc
+ */
+ public Object[] toArray(Object a[]) {
+ if (a.length < size) {
+ a = (Object[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
+ }
+
+ for (int i = 0; i < size; i++) {
+ a[i] = elementData[i].get();
+ }
+
+ if (a.length > size) {
+ a[size] = null;
+ }
+
+ return a;
+ }
+
+ /**
+ * Ensures that the internal {@link #elementData} has
+ * <code>minCapacity</code>.
+ *
+ * @param minCapacity the minimal capacity to ensure.
+ */
+ private void ensureCapacity(int minCapacity) {
+ int oldCapacity = elementData.length;
+ if (minCapacity > oldCapacity) {
+ Object oldData[] = elementData;
+ int newCapacity = (oldCapacity * 3)/2 + 1;
+ if (newCapacity < minCapacity)
+ newCapacity = minCapacity;
+ elementData = new WeakRef[newCapacity];
+ System.arraycopy(oldData, 0, elementData, 0, size);
+ }
+ }
+
+ /**
+ * Polls the reference queue until no reference is available anymore.
+ */
+ private void cleanQueue() {
+ WeakRef ref;
+ while ((ref = (WeakRef) refQueue.poll()) != null) {
+ emptySlots.set(ref.index);
+ }
+ }
+
+ /**
+ * Iterator implementation for this collecation.
+ */
+ private final class Iter implements Iterator {
+
+ /**
+ * current index.
+ */
+ private int index;
+
+ /**
+ * The current element data.
+ */
+ private Reference[] elements = elementData;
+
+ /**
+ * The current size of this collection.
+ */
+ private int size = WeakIdentityCollection.this.size;
+
+ /**
+ * @throws UnsupportedOperationException always.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("remove");
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public boolean hasNext() {
+ return index < size;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public Object next() {
+ if (index >= size) {
+ throw new NoSuchElementException();
+ }
+ return elements[index++].get();
+ }
+ }
+
+ /**
+ * Weak reference with index value that points to the slot in {@link
+ * WeakIdentityCollection#elementData}.
+ */
+ private final class WeakRef extends WeakReference {
+
+ /**
+ * The index of this weak reference.
+ */
+ private final int index;
+
+ /**
+ * Creates a new WeakRef.
+ *
+ * @param referent object the new weak reference will refer to.
+ * @param index the index of this weak reference.
+ */
+ public WeakRef(Object referent, int index) {
+ super(referent, refQueue);
+ this.index = index;
+ }
+ }
+}
Propchange: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/WeakIdentityCollection.java
------------------------------------------------------------------------------
svn:eol-style = native