Definitely the right track Oliver... it's called a blocking map (most
easily implemented in Java5 via Future).  I don't think you need two
maps though, right?  just stick a placeholder in the outer map.

-Yonik
http://incubator.apache.org/solr Solr, the open-source Lucene search server

On 8/9/06, Oliver Hutchison <[EMAIL PROTECTED]> wrote:
Otis, Doron, thanks for the feedback.

First up I'd just like to say that I totally agree with Doron on this - any
attempt to fix this issue needs to be done using as fine grain
synchronization as is possible or you'd just be introducing a new bottle
neck.

It terms of the level of granularity, the work around I posted in my
previous email and the approach suggested by Doron are basically the same
(though Doron's code is certainly preferable) and I can certainly say that
synchronizing the object creation against the field name does solve the
problem.

However I have another solution that I'm working on that may be cleaner - by
encapsulate the caching logic that is currently spread across FieldCacheImpl
and FieldSortedHitQueue it becomes quite easy to implement a more complex
but certainly more fine grained level of synchronization and we don't have
to worry about synchronizing against an interned String or using some other
trick to synchronize on the field name.

I currently have:

public abstract class Cache {

        private final Map readerCache = new WeakHashMap();

        protected Cache() {
        }

        protected abstract Object createValue(IndexReader reader, Object
key)
                        throws IOException;

        public Object get(IndexReader reader, Object key) throws IOException
{
                Map innerCache;
                Object value;
                synchronized (readerCache) {
                        innerCache = (Map) readerCache.get(reader);
                        // no inner cache create it
                        if (innerCache == null) {
                                innerCache = new HashMap();
                                readerCache.put(reader, innerCache);
                                value = null;
                        } else {
                                value = innerCache.get(key);
                        }
                        if (value == null) {
                                value = new CreationPlaceholder();
                                readerCache.put(reader, value);
                        }
                }
                if (value instanceof CreationPlaceholder) {
                        // must be one of the first threads to request this
value,
                        // synchronize on the CreationPlaceholder so we
don't block
                        // any other calls for different values
                        CreationPlaceholder ph = (CreationPlaceholder)
value;
                        synchronized (ph) {
                                // if this thread is the very first one to
reach this point
                                // then this test will be true and we should
do the creation
                                if (ph.value == null) {
                                        ph.value = createValue(reader, key);
                                        synchronized (readerCache) {
                                                innerCache.put(key,
ph.value);
                                        }
                                }
                                return ph.value;
                        }
                }
                return value;
        }

        static final class CreationPlaceholder {
                Object value;
        }
}


class FieldCacheImpl implements FieldCache {

...

        public String[] getStrings(IndexReader reader, String field)
                        throws IOException {
                return (String[]) stringsCache.get(reader, field);
        }

        Cache stringsCache = new Cache() {

                protected Object createValue(IndexReader reader, Object
fieldKey)
                                throws IOException {
                        String field = ((String) fieldKey).intern();

... create String[] ...

                        return retArray;
                }
        };

        public StringIndex getStringIndex(IndexReader reader, String field)
                        throws IOException {
                return (StringIndex) stringsIndexCache.get(reader, field);
        }

        Cache stringsIndexCache = new Cache() {

                protected Object createValue(IndexReader reader, Object
fieldKey)
                                throws IOException {
                        String field = ((String) fieldKey).intern();

... create StringIndex ...

                        return value;
                }
        };

... etc

}

Is this an avenue worth pursuing further? Or are you guys happy to simply
synchronizing on the field?

Thanks again,

Oliver

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to