From: <pj...@us...> - 2010-04-10 20:50:52
|
Revision: 7015 http://jython.svn.sourceforge.net/jython/?rev=7015&view=rev Author: pjenvey Date: 2010-04-10 20:50:46 +0000 (Sat, 10 Apr 2010) Log Message: ----------- o bring in Java 6's Collections.newSetFromMap as Generic.newSetFromMap which makes our ConcurrentHashSet redundant o hold PyConnection cursors/statements in a weak Set so they can be GC'd easier. synchronize these sets too fixes #1582 Modified Paths: -------------- trunk/jython/NEWS trunk/jython/src/com/ziclix/python/sql/PyConnection.java trunk/jython/src/org/python/util/Generic.java Removed Paths: ------------- trunk/jython/src/org/python/core/util/ConcurrentHashSet.java Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2010-04-10 20:48:35 UTC (rev 7014) +++ trunk/jython/NEWS 2010-04-10 20:50:46 UTC (rev 7015) @@ -26,6 +26,7 @@ - [ 1502 ] string-escape codec incorrect - [ 1534 ] new style object __dict__[name] ignored - [ 1479 ] xml parser file lock + - [ 1582 ] com.ziclix.python.sql.PyConnection leaks memory - Fix runtime issues during exitfuncs triggered via SystemRestart (such as during Django or Pylons development mode reloading) - Fix pickling of collections.defaultdict objects Modified: trunk/jython/src/com/ziclix/python/sql/PyConnection.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/PyConnection.java 2010-04-10 20:48:35 UTC (rev 7014) +++ trunk/jython/src/com/ziclix/python/sql/PyConnection.java 2010-04-10 20:50:46 UTC (rev 7015) @@ -11,10 +11,11 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.Collections; -import java.util.HashSet; +import java.util.WeakHashMap; import java.util.Set; import org.python.core.ClassDictInit; +import org.python.core.ContextManager; import org.python.core.Py; import org.python.core.PyBuiltinMethodSet; import org.python.core.PyException; @@ -23,12 +24,11 @@ import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyUnicode; +import org.python.core.ThreadState; +import org.python.util.Generic; import com.ziclix.python.sql.util.PyArgParser; -import org.python.core.ContextManager; -import org.python.core.ThreadState; - /** * A connection to the database. * @@ -93,9 +93,11 @@ */ public PyConnection(Connection connection) throws SQLException { this.closed = false; - this.cursors = new HashSet<PyCursor>(); + cursors = Generic.newSetFromMap(new WeakHashMap<PyCursor, Boolean>()); + cursors = Collections.synchronizedSet(cursors); this.connection = connection; - this.statements = new HashSet<PyStatement>(); + statements = Generic.newSetFromMap(new WeakHashMap<PyStatement, Boolean>()); + statements = Collections.synchronizedSet(statements); this.supportsTransactions = this.connection.getMetaData().supportsTransactions(); this.supportsMultipleResultSets = this.connection.getMetaData().supportsMultipleResultSets(); Deleted: trunk/jython/src/org/python/core/util/ConcurrentHashSet.java =================================================================== --- trunk/jython/src/org/python/core/util/ConcurrentHashSet.java 2010-04-10 20:48:35 UTC (rev 7014) +++ trunk/jython/src/org/python/core/util/ConcurrentHashSet.java 2010-04-10 20:50:46 UTC (rev 7015) @@ -1,109 +0,0 @@ -/* Copyright (c) Jython Developers */ -package org.python.core.util; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * A Set backed by ConcurrentHashMap. - */ -public class ConcurrentHashSet<E> extends AbstractSet<E> implements Serializable { - - /** The backing Map. */ - private final ConcurrentMap<E, Boolean> map; - - /** Backing's KeySet. */ - private transient Set<E> keySet; - - public ConcurrentHashSet() { - map = new ConcurrentHashMap<E, Boolean>(); - keySet = map.keySet(); - } - - public ConcurrentHashSet(int initialCapacity) { - map = new ConcurrentHashMap<E, Boolean>(initialCapacity); - keySet = map.keySet(); - } - - public ConcurrentHashSet(int initialCapacity, float loadFactor, int concurrencyLevel) { - map = new ConcurrentHashMap<E, Boolean>(initialCapacity, loadFactor, concurrencyLevel); - keySet = map.keySet(); - } - - @Override - public int size() { - return map.size(); - } - - @Override - public boolean isEmpty() { - return map.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return map.containsKey(o); - } - - @Override - public Iterator<E> iterator() { - return keySet.iterator(); - } - - @Override - public Object[] toArray() { - return keySet.toArray(); - } - - @Override - public <T> T[] toArray(T[] a) { - return keySet.toArray(a); - } - - @Override - public boolean add(E e) { - return map.put(e, Boolean.TRUE) == null; - } - - @Override - public boolean remove(Object o) { - return map.remove(o) != null; - } - - @Override - public boolean removeAll(Collection<?> c) { - return keySet.removeAll(c); - } - - @Override - public boolean retainAll(Collection<?> c) { - return keySet.retainAll(c); - } - - @Override - public void clear() { - map.clear(); - } - - @Override - public boolean equals(Object o) { - return keySet.equals(o); - } - - @Override - public int hashCode() { - return keySet.hashCode(); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - keySet = map.keySet(); - } -} Modified: trunk/jython/src/org/python/util/Generic.java =================================================================== --- trunk/jython/src/org/python/util/Generic.java 2010-04-10 20:48:35 UTC (rev 7014) +++ trunk/jython/src/org/python/util/Generic.java 2010-04-10 20:50:46 UTC (rev 7015) @@ -1,16 +1,20 @@ package org.python.util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.util.AbstractSet; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.python.core.util.ConcurrentHashSet; - /** * Static methods to make instances of collections with their generic types inferred from what * they're being assigned to. The idea is stolen from <code>Sets</code>, <code>Lists</code> and @@ -64,8 +68,8 @@ /** * Makes a Set using the generic type inferred from whatever this is being assigned to. */ - public static <T> Set<T> set() { - return new HashSet<T>(); + public static <E> Set<E> set() { + return new HashSet<E>(); } /** @@ -84,8 +88,128 @@ * Makes a Set, ensuring safe concurrent operations, using generic types inferred from * whatever this is being assigned to. */ - public static <T> Set<T> concurrentSet() { - return new ConcurrentHashSet<T>(CHM_INITIAL_CAPACITY, CHM_LOAD_FACTOR, - CHM_CONCURRENCY_LEVEL); + public static <E> Set<E> concurrentSet() { + return newSetFromMap(new ConcurrentHashMap<E, Boolean>(CHM_INITIAL_CAPACITY, + CHM_LOAD_FACTOR, + CHM_CONCURRENCY_LEVEL)); } + + /** + * Return a Set backed by the specified Map with the same ordering, concurrency and + * performance characteristics. + * + * The specified Map must be empty at the time this method is invoked. + * + * Note that this method is based on Java 6's Collections.newSetFromMap, and will be + * removed in a future version of Jython (likely 2.6) that will rely on Java 6. + * + * @param map the backing Map + * @return a Set backed by the Map + * @throws IllegalArgumentException if Map is not empty + */ + public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) { + return new SetFromMap<E>(map); + } + + /** + * A Set backed by a generic Map. + */ + private static class SetFromMap<E> extends AbstractSet<E> + implements Serializable { + + /** The backing Map. */ + private final Map<E, Boolean> map; + + /** Backing's KeySet. */ + private transient Set<E> keySet; + + public SetFromMap(Map<E, Boolean> map) { + if (!map.isEmpty()) { + throw new IllegalArgumentException("Map is non-empty"); + } + this.map = map; + keySet = map.keySet(); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return map.containsKey(o); + } + + @Override + public boolean containsAll(Collection<?> c) { + return keySet.containsAll(c); + } + + @Override + public Iterator<E> iterator() { + return keySet.iterator(); + } + + @Override + public Object[] toArray() { + return keySet.toArray(); + } + + @Override + public <T> T[] toArray(T[] a) { + return keySet.toArray(a); + } + + @Override + public boolean add(E e) { + return map.put(e, Boolean.TRUE) == null; + } + + @Override + public boolean remove(Object o) { + return map.remove(o) != null; + } + + @Override + public boolean removeAll(Collection<?> c) { + return keySet.removeAll(c); + } + + @Override + public boolean retainAll(Collection<?> c) { + return keySet.retainAll(c); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public boolean equals(Object o) { + return o == this || keySet.equals(o); + } + + @Override + public int hashCode() { + return keySet.hashCode(); + } + + @Override + public String toString() { + return keySet.toString(); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + keySet = map.keySet(); + } + } + } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |