Adam, all,

I am resurrecting this part of the thread: is it ok if we fix the 10.04 with 
the patch below (Adam's commit with rev. 948333 that adds the putIfAbsent 
method and then the same fix I committed to 11.04, 12.04 and trunk)?

Thanks,

Jacopo

On May 12, 2012, at 9:17 AM, Jacopo Cappellato wrote:

> As regards the 10.04, what if we backport the putIfAbsent method there and 
> then apply a similar fix? Here is the patch I would like to backport:
> 
> Index: framework/base/src/org/ofbiz/base/util/cache/test/UtilCacheTests.java
> ===================================================================
> --- framework/base/src/org/ofbiz/base/util/cache/test/UtilCacheTests.java     
> (revision 1337449)
> +++ framework/base/src/org/ofbiz/base/util/cache/test/UtilCacheTests.java     
> (working copy)
> @@ -323,6 +323,19 @@
>         basicTest(cache);
>     }
> 
> +    public void testPutIfAbsent() throws Exception {
> +        UtilCache<String, String> cache = createUtilCache(5, 5, 2000, false, 
> false);
> +        Listener<String, String> gotListener = createListener(cache);
> +        Listener<String, String> wantedListener = new Listener<String, 
> String>();
> +        wantedListener.noteKeyAddition(cache, "two", "dos");
> +        assertNull("putIfAbsent", cache.putIfAbsent("two", "dos"));
> +        assertHasSingleKey(cache, "two", "dos");
> +        assertEquals("putIfAbsent", "dos", cache.putIfAbsent("two", 
> "double"));
> +        assertHasSingleKey(cache, "two", "dos");
> +        cache.removeListener(gotListener);
> +        assertEquals("listener", wantedListener, gotListener);
> +    }
> +
>     public void testChangeMemSize() throws Exception {
>         int size = 5;
>         long ttl = 2000;
> Index: framework/base/src/org/ofbiz/base/util/cache/UtilCache.java
> ===================================================================
> --- framework/base/src/org/ofbiz/base/util/cache/UtilCache.java       
> (revision 1337449)
> +++ framework/base/src/org/ofbiz/base/util/cache/UtilCache.java       
> (working copy)
> @@ -289,6 +289,10 @@
>         return putInternal(key, value, expireTimeNanos);
>     }
> 
> +    public V putIfAbsent(K key, V value) {
> +        return putIfAbsentInternal(key, value, expireTimeNanos);
> +    }
> +
>     CacheLine<V> createSoftRefCacheLine(final Object key, V value, long 
> loadTimeNanos, long expireTimeNanos) {
>         return tryRegister(loadTimeNanos, new SoftRefCacheLine<V>(value, 
> loadTimeNanos, expireTimeNanos) {
>             @Override
> @@ -366,6 +370,10 @@
>         return putInternal(key, value, 
> TimeUnit.NANOSECONDS.convert(expireTimeMillis, TimeUnit.MILLISECONDS));
>     }
> 
> +    public V putIfAbsent(K key, V value, long expireTimeMillis) {
> +        return putIfAbsentInternal(key, value, 
> TimeUnit.NANOSECONDS.convert(expireTimeMillis, TimeUnit.MILLISECONDS));
> +    }
> +
>     V putInternal(K key, V value, long expireTimeNanos) {
>         Object nulledKey = fromKey(key);
>         CacheLine<V> oldCacheLine = memoryTable.put(nulledKey, 
> createCacheLine(key, value, expireTimeNanos));
> @@ -388,6 +396,41 @@
>         }
>     }
> 
> +    V putIfAbsentInternal(K key, V value, long expireTimeNanos) {
> +        Object nulledKey = fromKey(key);
> +        V oldValue;
> +        if (fileTable != null) {
> +            try {
> +                synchronized (this) {
> +                    oldValue = fileTable.get(nulledKey);
> +                    if (oldValue == null) {
> +                        memoryTable.put(nulledKey, createCacheLine(key, 
> value, expireTimeNanos));
> +                        fileTable.put(nulledKey, value);
> +                        jdbmMgr.commit();
> +                    }
> +                }
> +            } catch (IOException e) {
> +                Debug.logError(e, module);
> +                oldValue = null;
> +            }
> +        } else {
> +            CacheLine<V> newCacheLine = createCacheLine(key, value, 
> expireTimeNanos);
> +            CacheLine<V> oldCacheLine = memoryTable.putIfAbsent(nulledKey, 
> newCacheLine);
> +            if (oldCacheLine == null) {
> +                oldValue = null;
> +            } else {
> +                oldValue = oldCacheLine.getValue();
> +                cancel(newCacheLine);
> +            }
> +        }
> +        if (oldValue == null) {
> +            noteAddition(key, value);
> +            return null;
> +        } else {
> +            return oldValue;
> +        }
> +    }
> +
>     /** Gets an element from the cache according to the specified key.
>      * @param key The key for the element, used to reference it in the 
> hastables and LRU linked list
>      * @return The value of the element specified by the key
> Index: framework/base/src/org/ofbiz/base/util/GroovyUtil.java
> ===================================================================
> --- framework/base/src/org/ofbiz/base/util/GroovyUtil.java    (revision 
> 1337449)
> +++ framework/base/src/org/ofbiz/base/util/GroovyUtil.java    (working copy)
> @@ -102,26 +102,20 @@
> 
>     public static Class<?> getScriptClassFromLocation(String location) throws 
> GeneralException {
>         try {
> -            Class<?> scriptClass = null;
> -            synchronized (parsedScripts) {
> -                scriptClass = parsedScripts.get(location);
> -            }
> +            Class<?> scriptClass = parsedScripts.get(location);
>             if (scriptClass == null) {
>                 URL scriptUrl = FlexibleLocation.resolveLocation(location);
>                 if (scriptUrl == null) {
>                     throw new GeneralException("Script not found at location 
> [" + location + "]");
>                 }
>                 scriptClass = parseClass(scriptUrl.openStream(), location);
> -                synchronized (parsedScripts) {
> -                    Class<?> scriptClassCached = parsedScripts.get(location);
> -                    if (scriptClassCached == null) {
> -                        if (Debug.verboseOn()) {
> -                            Debug.logVerbose("Caching Groovy script at: " + 
> location, module);
> -                        }
> -                        parsedScripts.put(location, scriptClass);
> -                    } else {
> -                        scriptClass = scriptClassCached;
> +                Class<?> scriptClassCached = 
> parsedScripts.putIfAbsent(location, scriptClass);
> +                if (scriptClassCached == null) { // putIfAbsent returns null 
> if the class is added
> +                    if (Debug.verboseOn()) {
> +                        Debug.logVerbose("Cached Groovy script at: " + 
> location, module);
>                     }
> +                } else {
> +                    scriptClass = scriptClassCached;
>                 }
>             }
>             return scriptClass;
> @@ -152,22 +146,16 @@
> 
>     public static Object runScriptFromClasspath(String script, 
> Map<String,Object> context) throws GeneralException {
>         try {
> -            Class<?> scriptClass = null;
> -            synchronized (parsedScripts) {
> -                parsedScripts.get(script);
> -            }
> +            Class<?> scriptClass = parsedScripts.get(script);
>             if (scriptClass == null) {
>                 scriptClass = loadClass(script);
> -                synchronized (parsedScripts) {
> -                    Class<?> scriptClassCached = parsedScripts.get(script);
> -                    if (scriptClassCached == null) {
> -                        if (Debug.verboseOn()) {
> -                            Debug.logVerbose("Caching Groovy script: " + 
> script, module);
> -                        }
> -                        parsedScripts.put(script, scriptClass);
> -                    } else {
> -                        scriptClass = scriptClassCached;
> +                Class<?> cachedScriptClass = 
> parsedScripts.putIfAbsent(script, scriptClass);
> +                if (cachedScriptClass == null) { // putIfAbsent returns null 
> if the class is added
> +                    if (Debug.verboseOn()) {
> +                        Debug.logVerbose("Cached Groovy script at: " + 
> script, module);
>                     }
> +                } else {
> +                    scriptClass = cachedScriptClass;
>                 }
>             }
>             return InvokerHelper.createScript(scriptClass, 
> getBinding(context)).run();

Reply via email to