You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by jw...@apache.org on 2009/10/13 05:06:55 UTC
svn commit: r824575 - in /myfaces/trinidad/branches/1.2.12.2-branch:
trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
Author: jwaldman
Date: Tue Oct 13 03:06:54 2009
New Revision: 824575
URL: http://svn.apache.org/viewvc?rev=824575&view=rev
Log:
TRINIDAD-1594 FileSystemStyleCache doesn't scale due to over-synchronization
Mostly changed Hashtable to ConcurrentMap in FileSystemStyleCache
thanks to Blake Sullivan for the patch
1.2.12.2-branch
Modified:
myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java?rev=824575&r1=824574&r2=824575&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java Tue Oct 13 03:06:54 2009
@@ -69,6 +69,28 @@
}
/**
+ * Returns an array containing all of the elements of the
+ * Iterator
+ * @param iterator Iterator to copy the contexts of
+ * @return an array containing a copy of the iterator contents
+ */
+ public static <T> T[] toArray(Iterator<? extends T> iterator, Class<T> type)
+ {
+ if (iterator.hasNext())
+ {
+ Collection arrayList = arrayList(iterator);
+ T[] outArray = (T[])Array.newInstance(type, arrayList.size());
+
+ return (T[])arrayList.toArray(outArray);
+ }
+ else
+ {
+ // optimize empty iterator case
+ return (T[])Array.newInstance(type, 0);
+ }
+ }
+
+ /**
* Returns an empty, unmodifiable, Serializable Queue.
* @return an empty, unmodifiable, Serializable Queue.
*/
Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java?rev=824575&r1=824574&r2=824575&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java Tue Oct 13 03:06:54 2009
@@ -32,14 +32,12 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -52,6 +50,7 @@
import org.apache.myfaces.trinidad.style.Selector;
import org.apache.myfaces.trinidad.style.Style;
import org.apache.myfaces.trinidad.style.Styles;
+import org.apache.myfaces.trinidad.util.CollectionUtils;
import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent;
import org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderingContext;
import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.SkinSelectors;
@@ -92,14 +91,6 @@
*
* @version $Name: $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/style/cache/FileSystemStyleCache.java#0 $) $Date: 10-nov-2005.18:58:54 $
*/
-// -= Simon Lessard =-
-// TODO: Synchronization does not seem to be needed since there's
-// synchronized blocks in the code, using HashMap hence
-// looks like a better choice than Hashtable.
-// -= Blake Sullivan =-
-// rebuttal - _createEntry() which assigns values to _cache and _entryCache is called
-// without a lock and these Maps are read without a lock.
-// _cache and _entryCache should probably be ConcurrentHashMaps.
public class FileSystemStyleCache implements StyleProvider
{
/**
@@ -143,6 +134,27 @@
if (dotIndex != -1)
baseName = baseName.substring(0, dotIndex);
_baseName = baseName;
+
+ NameResolver resolver = new DefaultNameResolver(sourceFile, null);
+
+ // We explicitly wrap the NameResolver in a CachingNameResolver
+ // since that conveniently handles checking for modifications to
+ // dependent (imported) files.
+ // The default storage for cached files is a bit large,
+ // so we use a smaller hash table. Also, always enable
+ // modification checking.
+ resolver = new CachingNameResolver(resolver,
+ new ConcurrentHashMap<Object, InputStreamProvider>(17),
+ true);
+
+ _resolver = resolver;
+ }
+ else
+ {
+ // make sure final fields are initialized
+ _sourceFile = null;
+ _baseName = null;
+ _resolver = null;
}
// If the target directory does not exist, create it now.
@@ -168,8 +180,10 @@
{
return Collections.emptyList();
}
-
- return entry.uris;
+ else
+ {
+ return entry.uris;
+ }
}
/**
@@ -182,8 +196,8 @@
if (entry == null)
return null;
-
- return entry.styles;
+ else
+ return entry.styles;
}
/**
@@ -196,8 +210,8 @@
if (entry == null)
return null;
-
- return entry.skinProperties;
+ else
+ return entry.skinProperties;
}
/**
@@ -210,8 +224,8 @@
if (entry == null)
return null;
-
- return entry.icons;
+ else
+ return entry.icons;
}
/**
@@ -364,8 +378,8 @@
// And Entry contains the style sheet URI.
private Entry _getEntry(StyleContext context)
{
- Hashtable<Key, Entry> cache = null;
- Hashtable<Object, Entry> entryCache = null;
+ ConcurrentMap<Key, Entry> cache = null;
+ ConcurrentMap<Object, Entry> entryCache = null;
StyleSheetDocument document = null;
Map<String, String> shortStyleClassMap = null;
String[] namespacePrefixes = null;
@@ -375,13 +389,6 @@
// Synchronize while set up the _cache, _entryCache, _document, etc...
synchronized (this)
{
- // Before we do anything, set up the NameResolver and
- // InputStreamProvider. _getEntry() is the single entry point
- // through which all calls into the FileSystemStyleCache flow.
- // So, by initializing the NameResolver/InputStreamProvider
- // here, we know they will always be available to other code.
- _initResolver();
-
// If checking for modified files, then check to see if the XSS or CSS
// document has been modified. If so, we dump our in-memory style cache.
if (checkModified && hasSourceDocumentChanged(context))
@@ -400,17 +407,10 @@
// modified.) We need to use a consistent set of caches
// throughout the entire request, to avoid adding bogus entries
// to a new re-allocated cache.
- // Note: It would probably make sense to use Map for the
- // cache type in our vars and method prototypes. We explicitly
- // use Hashtable, because our implementation relies on the
- // synchronization provided by Hashtable. If we change the
- // cache data structure, we might need to re-code to add
- // synchronization. Thus the somewhat ugly explicit references
- // to Hashtable everywhere.
if (_cache == null)
- _cache = new Hashtable<Key, Entry>();
+ _cache = new ConcurrentHashMap<Key, Entry>();
if (_entryCache == null)
- _entryCache = new Hashtable<Object, Entry>(19);
+ _entryCache = new ConcurrentHashMap<Object, Entry>(19);
cache = _cache;
entryCache = _entryCache;
@@ -453,9 +453,9 @@
}
private Entry _getEntry(
- Map<?, Entry> cache,
- Object key,
- boolean checkModified
+ ConcurrentMap<?, Entry> cache,
+ Object key,
+ boolean checkModified
)
{
Entry entry = cache.get(key);
@@ -489,14 +489,9 @@
if (!valid)
{
_deleteAll(existing);
-
- synchronized (cache)
- {
- if (cache.get(key) == entry)
- {
- cache.remove(key);
- }
- }
+
+ // atomically remove the key from the cache if it currently points to the entry
+ cache.remove(key, entry);
return null;
}
@@ -513,15 +508,14 @@
* and the entry cache (the one that is based on the StyleSheetNodes)
*/
private Entry _createEntry(
- StyleContext context,
- StyleSheetDocument document,
- Hashtable<Key, Entry> cache,
- Key key,
- Hashtable<Object, Entry> entryCache,
- Map<String, String> shortStyleClassMap,
- String[] namespacePrefixes,
- boolean checkModified
- )
+ StyleContext context,
+ StyleSheetDocument document,
+ ConcurrentMap<Key, Entry> cache,
+ Key key,
+ ConcurrentMap<Object, Entry> entryCache,
+ Map<String, String> shortStyleClassMap,
+ String[] namespacePrefixes,
+ boolean checkModified)
{
// Next, get the fully resolved styles for this context. This will be
// those StyleNodes that match the locale, direction, browser, portlet mode
@@ -578,12 +572,12 @@
* same StyleSheetNodes.
*/
private Entry _getCompatibleEntry(
- StyleContext context,
- StyleSheetDocument document,
- Map<Key, Entry> cache,
- Key key,
- Map<Object, Entry> entryCache,
- boolean checkModified
+ StyleContext context,
+ StyleSheetDocument document,
+ ConcurrentMap<Key, Entry> cache,
+ Key key,
+ ConcurrentMap<Object, Entry> entryCache,
+ boolean checkModified
)
{
DerivationKey derivationKey = _getDerivationKey(context, document);
@@ -608,18 +602,16 @@
// Entries with the same style sheet derivation are compatible.
// Get the style sheet derivation list.
Iterator<StyleSheetNode> e = document.getStyleSheets(context);
- // -= Simon Lessard =-
- // TODO: Check if synchronization is truly required
- Vector<StyleSheetNode> v = _copyIterator(e);
- StyleSheetNode[] styleSheets;
- if (v == null)
+
+ StyleSheetNode[] styleSheets;
+
+ if (e.hasNext())
{
- styleSheets = new StyleSheetNode[0];
+ styleSheets = CollectionUtils.toArray(e, StyleSheetNode.class);
}
else
{
- styleSheets= new StyleSheetNode[v.size()];
- v.copyInto(styleSheets);
+ styleSheets = _EMPTY_STYLE_SHEET_NODE_ARRAY;
}
// Create a key out of the style sheet derivation list
@@ -985,47 +977,6 @@
}
/**
- * Initiializes the NameResolver. Does not need to be synchronized only because it is
- * synchronized in the calling code.
- */
- private void _initResolver()
- {
-
- if (_resolver == null)
- {
- NameResolver resolver = new DefaultNameResolver(_sourceFile, null);
-
- // We explicitly wrap the NameResolver in a CachingNameResolver
- // since that conveniently handles checking for modifications to
- // dependent (imported) files.
- // The default storage for cached files is a bit large,
- // so we use a smaller hash table. Also, always enable
- // modification checking.
- // FIXME: Should probably be a ConcurrentHashMap
- resolver = new CachingNameResolver(resolver,
- new Hashtable<Object, InputStreamProvider>(17),
- true);
-
- _resolver = resolver;
- }
- }
-
- /**
- * Copies an enumeration into a Vector
- */
- private <T> Vector<T> _copyIterator(Iterator<T> e)
- {
- if (e == null)
- return null;
-
- Vector<T> v = new Vector<T>();
- while (e.hasNext())
- v.addElement(e.next());
-
- return v;
- }
-
- /**
* Create an array of all the namespace prefixes in the xss/css file. E.g., "af|" or "tr|"
*/
private static String[] _getNamespacePrefixes(
@@ -1621,28 +1572,28 @@
}
}
- private File _sourceFile; // The source XSS file
+ private final File _sourceFile; // The source XSS file
private final String _targetPath; // The location of the cache
- private String _baseName; // The base file name for generated CSS files
+ private final String _baseName; // The base file name for generated CSS files
/**
* The NameResolver and InputStreamProvider we use to
* resolve/load all files. We also use the InputStreamProvider
* to check for modifications to any dependent files.
*/
- private volatile NameResolver _resolver;
+ private final NameResolver _resolver;
/** The parsed StyleSheetDocument */
private StyleSheetDocument _document;
/** The cache of style sheet URIs */
- private Hashtable<Key, Entry> _cache;
+ private ConcurrentMap<Key, Entry> _cache;
/**
* We cache Entry objects, hashed by DerivationKey (ie.
* hashed based on the StyleSheetNode derivation list).
*/
- private Hashtable<Object, Entry> _entryCache;
+ private ConcurrentMap<Object, Entry> _entryCache;
/** Map which maps from full style class names to our compressed names. */
private Map<String, String> _shortStyleClassMap;
@@ -1791,6 +1742,6 @@
}
+ private static final StyleSheetNode[] _EMPTY_STYLE_SHEET_NODE_ARRAY = new StyleSheetNode[0];
private static final String[] _EMPTY_STRING_ARRAY = new String[0];
-
}