From d9c453d8fb11f27b5ddd3eaad5a63175ed90f019 Mon Sep 17 00:00:00 2001 From: "Andreas L. Delmelle" Date: Sun, 6 Feb 2011 22:02:13 +0000 Subject: [PATCH] Reverted previous commit; looks like it does require all related property classes to be committed... Better luck next week git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1067783 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fo/flow/Marker.java | 4 +- .../fop/fo/properties/PropertyCache.java | 254 +++++++++--------- 2 files changed, 136 insertions(+), 122 deletions(-) diff --git a/src/java/org/apache/fop/fo/flow/Marker.java b/src/java/org/apache/fop/fo/flow/Marker.java index 847c7a846..4588a9df3 100644 --- a/src/java/org/apache/fop/fo/flow/Marker.java +++ b/src/java/org/apache/fop/fo/flow/Marker.java @@ -357,8 +357,8 @@ public class Marker extends FObjMixed { /** Convenience inner class */ public static final class MarkerAttribute { - private static PropertyCache attributeCache - = new PropertyCache(); + private static PropertyCache attributeCache + = new PropertyCache(MarkerAttribute.class); /** namespace */ protected String namespace; diff --git a/src/java/org/apache/fop/fo/properties/PropertyCache.java b/src/java/org/apache/fop/fo/properties/PropertyCache.java index a75529971..920125796 100644 --- a/src/java/org/apache/fop/fo/properties/PropertyCache.java +++ b/src/java/org/apache/fop/fo/properties/PropertyCache.java @@ -19,31 +19,21 @@ package org.apache.fop.fo.properties; +import org.apache.fop.fo.flow.Marker; + import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; -import java.lang.reflect.Type; /** * Dedicated cache, meant for storing canonical instances * of property-related classes. - * The public access point is a generic fetch() method. - * Internally, the instances are wrapped in a java.lang.ref.WeakReference, - * so that the actual instance only remains in the cache until no reference - * to that instance exists anywhere else (i.e. as long as it is needed). - * Classes that want to use this cache to store canonical instances should - * override {@link Object#hashCode()} and {@link Object#equals(Object)} to - * make sure the cache exhibits the expected behavior. - * + * The public access points are overloaded fetch() methods + * that each correspond to a cached type. * It is designed especially to be used concurrently by multiple threads, - * drawing heavily upon the principles behind Java 5's - * ConcurrentHashMap, but then limited to store only keys. - * (a more proper comparison would be a ConcurrentWeakHashSet) - * - * @param the type of object that will be stored in the cache - * + * drawing heavily upon the principles behind Java 1.5's + * ConcurrentHashMap. */ -//TODO: With generics, this actually has the potential of a more general utility class?? -public final class PropertyCache { +public final class PropertyCache { private static final int SEGMENT_COUNT = 32; //0x20 private static final int INITIAL_BUCKET_COUNT = SEGMENT_COUNT; @@ -59,12 +49,11 @@ public final class PropertyCache { private final boolean useCache; /** the segments array (length = 32) */ - private final CacheSegment[] segments = new CacheSegment[SEGMENT_COUNT]; + private CacheSegment[] segments = new CacheSegment[SEGMENT_COUNT]; /** the table of hash-buckets */ - @SuppressWarnings(value = "unchecked") //guaranteed by design - private CacheEntry[] table = new CacheEntry[INITIAL_BUCKET_COUNT]; + private CacheEntry[] table = new CacheEntry[INITIAL_BUCKET_COUNT]; - private Type runtimeType; + private Class runtimeType; private final boolean[] votesForRehash = new boolean[SEGMENT_COUNT]; @@ -88,20 +77,19 @@ public final class PropertyCache { } /* Class modeling a cached entry */ - private static class CacheEntry extends WeakReference { - private volatile CacheEntry nextEntry; + private static class CacheEntry extends WeakReference { + private volatile CacheEntry nextEntry; private final int hash; /* main constructor */ - @SuppressWarnings(value = "unchecked") //see below - public CacheEntry(T p, CacheEntry nextEntry, ReferenceQueue refQueue) { - super(p, refQueue); //unchecked operation, but constructor unused? + public CacheEntry(Object p, CacheEntry nextEntry, ReferenceQueue refQueue) { + super(p, refQueue); this.nextEntry = nextEntry; this.hash = hash(p); } /* main constructor */ - public CacheEntry(T p, CacheEntry nextEntry) { + public CacheEntry(Object p, CacheEntry nextEntry) { super(p); this.nextEntry = nextEntry; this.hash = hash(p); @@ -128,8 +116,8 @@ public final class PropertyCache { for (int bucketIndex = segmentIndex; bucketIndex < table.length; bucketIndex += SEGMENT_COUNT) { - CacheEntry prev = null; - CacheEntry entry = table[bucketIndex]; + CacheEntry prev = null; + CacheEntry entry = table[bucketIndex]; if (entry == null) { continue; } @@ -170,6 +158,7 @@ public final class PropertyCache { for (int i = SEGMENT_MASK + 1; --i >= 0;) { votesForRehash[i] = false; } + } } } @@ -182,26 +171,26 @@ public final class PropertyCache { * cleanup will be performed to try and remove obsolete * entries. */ - private void put(T o) { + private void put(Object o) { int hash = hash(o); int segmentIndex = hash & SEGMENT_MASK; CacheSegment segment = segments[segmentIndex]; - synchronized (segments[segmentIndex]) { + synchronized (segment) { int index = hash & (table.length - 1); - CacheEntry entry = table[index]; + CacheEntry entry = table[index]; if (entry == null) { - entry = new CacheEntry(o, null); + entry = new CacheEntry(o, null); table[index] = entry; segment.count++; } else { - T p = entry.get(); + Object p = entry.get(); if (eq(p, o)) { return; } else { - CacheEntry newEntry = new CacheEntry(o, entry); + CacheEntry newEntry = new CacheEntry(o, entry); table[index] = newEntry; segment.count++; } @@ -215,19 +204,19 @@ public final class PropertyCache { /* Gets a cached instance. Returns null if not found */ - private T get(T o) { + private Object get(Object o) { int hash = hash(o); int index = hash & (table.length - 1); - CacheEntry entry = table[index]; - T q; + CacheEntry entry = table[index]; + Object q; /* try non-synched first */ - for (CacheEntry e = entry; e != null; e = e.nextEntry) { - if (e.hash == hash) { + for (CacheEntry e = entry; e != null; e = e.nextEntry) { + if ( e.hash == hash ) { q = e.get(); - if ((q != null) && eq(q, o)) { + if ( ( q != null ) && eq ( q, o ) ) { return q; } } @@ -236,12 +225,13 @@ public final class PropertyCache { /* retry synched, only if the above attempt did not succeed, * as another thread may, in the meantime, have added a * corresponding entry */ - synchronized (segments[hash & SEGMENT_MASK]) { + CacheSegment segment = segments[hash & SEGMENT_MASK]; + synchronized (segment) { entry = table[index]; - for (CacheEntry e = entry; e != null; e = e.nextEntry) { - if (e.hash == hash) { + for (CacheEntry e = entry; e != null; e = e.nextEntry) { + if ( e.hash == hash ) { q = e.get(); - if ((q != null) && eq(q, o)) { + if ( ( q != null ) && eq ( q, o ) ) { return q; } } @@ -257,7 +247,8 @@ public final class PropertyCache { */ private void rehash(int index) { - synchronized (segments[index]) { + CacheSegment seg = segments[index]; + synchronized (seg) { if (index > 0) { /* need to recursively acquire locks on all segments */ rehash(index - 1); @@ -270,19 +261,18 @@ public final class PropertyCache { segments[i].count = 0; } - @SuppressWarnings(value = "unchecked") //guaranteed by design - CacheEntry[] newTable = new CacheEntry[newLength]; + CacheEntry[] newTable = new CacheEntry[newLength]; int hash, idx; - T o; + Object o; newLength--; for (int i = table.length; --i >= 0;) { - for (CacheEntry c = table[i]; c != null; c = c.nextEntry) { + for (CacheEntry c = table[i]; c != null; c = c.nextEntry) { o = c.get(); if (o != null) { hash = c.hash; idx = hash & newLength; - newTable[idx] = new CacheEntry(o, newTable[idx]); + newTable[idx] = new CacheEntry(o, newTable[idx]); segments[hash & SEGMENT_MASK].count++; } } @@ -293,68 +283,15 @@ public final class PropertyCache { } } - /* - * Recursively acquires locks on all 32 segments, - * counts all the entries, and returns the total number - * of elements in the cache - */ - private int size(int index) { - synchronized (segments[index]) { - if (index > 0) { - /* need to recursively acquire locks on all segments */ - return size(index - 1); - } else { - int size = 0; - T o; - for (int i = table.length; --i >= 0;) { - for (CacheEntry c = table[i]; c != null; c = c.nextEntry) { - o = c.get(); - if (o != null) { - size++; - } - } - } - return size; - } - } - } - - /** - * Return the number of elements stored in this cache (approximation). - *
Note: only meant for use during debugging or unit/regression testing. - * As the cache only keeps weak references, it is not feasible to cache this - * number internally. This method will lock the entire cache and trigger - * a recount upon every call. - * While it is guaranteed that instances to which hard references still exist elsewhere, - * will be present in the cache, it is not guaranteed that all the instances in the cache - * are actually referenced. Hence, it is possible for this method to return different results - * for subsequent calls, even though the {@link #fetch(Object)} method has not been called - * in between, depending on the JVM (= implementation of WeakReference and GC) - * @return the number of elements stored in this cache (approx.) - */ - protected int size() { - return size(SEGMENT_MASK); - } - /** - * Default constructor - */ - public PropertyCache() { - this(null); - } - - /** - * Alternate constructor. Can be used to set the runtimeType, in - * order to facilitate tracking of specific caches. + * Default constructor. * - * @param c Runtime type of the objects that will be stored in the cache + * @param c Runtime type of the objects that will be stored in the cache */ - protected PropertyCache(Class c) { - //TODO Tie this in to the config in FopFactory? - // Should really avoid System.getProperty()... - // See also Bugzilla #50435 - this.useCache = Boolean.valueOf( - System.getProperty("org.apache.fop.fo.properties.use-cache", "true")); + public PropertyCache(Class c) { + this.useCache = Boolean.valueOf(System.getProperty( + "org.apache.fop.fo.properties.use-cache", "true") + ).booleanValue(); if (useCache) { for (int i = SEGMENT_MASK + 1; --i >= 0;) { segments[i] = new CacheSegment(); @@ -364,16 +301,15 @@ public final class PropertyCache { } /** - * Generic fetch() method. - * Checks if an equivalent for the given instance is present in the cache. - * If so, it returns a reference to the cached instance, and the object - * passed in is discarded. - * Otherwise the given object is added to the cache and returned. + * Generic fetch() method. + * Checks if the given Object is present in the cache - + * if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. * - * @param obj the object to check for - * @return the cached instance + * @param obj the Object to check for + * @return the cached instance */ - public T fetch(T obj) { + private Object fetch(Object obj) { if (!this.useCache) { return obj; } @@ -382,7 +318,7 @@ public final class PropertyCache { return null; } - T cacheEntry = get(obj); + Object cacheEntry = get(obj); if (cacheEntry != null) { return cacheEntry; } @@ -390,10 +326,88 @@ public final class PropertyCache { return obj; } + /** + * Checks if the given {@link Property} is present in the cache - + * if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. + * + * @param prop the Property instance to check for + * @return the cached instance + */ + public Property fetch(Property prop) { + + return (Property) fetch((Object) prop); + } + + /** + * Checks if the given {@link CommonHyphenation} is present in the cache - + * if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. + * + * @param chy the CommonHyphenation instance to check for + * @return the cached instance + */ + public CommonHyphenation fetch(CommonHyphenation chy) { + + return (CommonHyphenation) fetch((Object) chy); + } + + /** + * Checks if the given {@link CommonFont} is present in the cache - + * if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. + * + * @param cf the CommonFont instance to check for + * @return the cached instance + */ + public CommonFont fetch(CommonFont cf) { + + return (CommonFont) fetch((Object) cf); + } + + /** + * Checks if the given {@link CommonBorderPaddingBackground} is present in the cache - + * if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. + * + * @param cbpb the CommonBorderPaddingBackground instance to check for + * @return the cached instance + */ + public CommonBorderPaddingBackground fetch(CommonBorderPaddingBackground cbpb) { + + return (CommonBorderPaddingBackground) fetch((Object) cbpb); + } + + /** + * Checks if the given {@link CommonBorderPaddingBackground.BorderInfo} is present + * in the cache - if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. + * + * @param bi the BorderInfo instance to check for + * @return the cached instance + */ + public CommonBorderPaddingBackground.BorderInfo fetch( + CommonBorderPaddingBackground.BorderInfo bi) { + return (CommonBorderPaddingBackground.BorderInfo) fetch((Object) bi); + } + + /** + * Checks if the given {@link org.apache.fop.fo.flow.Marker.MarkerAttribute} is present + * in the cache - if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. + * + * @param ma the MarkerAttribute instance to check for + * @return the cached instance + */ + public Marker.MarkerAttribute fetch( + Marker.MarkerAttribute ma) { + return (Marker.MarkerAttribute) fetch((Object) ma); + } + /** {@inheritDoc} */ - @Override public String toString() { return super.toString() + "[runtimeType=" + this.runtimeType + "]"; } + } -- 2.39.5