• Bug
  • Status: Resolved
  • 2 Major
  • Resolution: Fixed
  • ehcache
  • alexsnaps
  • Reporter: candrews
  • December 03, 2013
  • 0
  • Watchers: 4
  • December 23, 2013
  • December 23, 2013

Description

When using Automatic Resource Control, ehcache calculates object sizes using net.sf.ehcache.pool.SizeOfEngine, specifically net.sf.ehcache.pool.impl.DefaultSizeOfEngine. DefaultSizeOfEngine isn’t handling Groovy classes correctly; it doesn’t exclude classes/fields appropriately. The result is that Groovy classes have higher sizes than they should, and the “The configured limit of 1,500 object references was reached while attempting to calculate the size of the object graph” message occurs more often than it should.

I believe that excluding groovy.lang.MetaClass and it’s subclasses (and fields that have this class and its subclasses as a type) would fix this problem.

I think a decent solution would be to add new implementation of net.sf.ehcache.pool.sizeof.filter.SizeOfFilter that looks like this would work:

package net.sf.ehcache.pool.sizeof.filter;

import java.lang.reflect.Field;
import java.util.Collection;

/**
 * Filter for Groovy objects
 * @author Chris Dennis
 */
public class GroovySizeOfFilter implements SizeOfFilter {

    /**
     * {@inheritDoc}
     */
    public Collection<Field> filterFields(Class<?> klazz, Collection<Field> fields) {
        for (Iterator<Field> it = fields.iterator(); it.hasNext();) {
            Field f = it.next();
            if (groovy.lang.MetaClass.class.isAssignableFrom(f.geType())) {
                it.remove();
            }
        }
        return fields;
    }

    /**
     * {@inheritDoc}
     */
    public boolean filterClass(Class<?> klazz) {
        return !(groovy.lang.MetaClass.class.isAssignableFrom(klazz));
    }
}

The modify net.sf.ehcache.pool.impl.DefaultSizeOfEngine to use it by changing this:

    static {
        Collection<SizeOfFilter> filters = new ArrayList<SizeOfFilter>();
        filters.add(new AnnotationSizeOfFilter());
        try {
            filters.add(new ResourceSizeOfFilter(SizeOfEngine.class.getResource("builtin-sizeof.filter")));
        } catch (IOException e) {
            LOG.warn("Built-in sizeof filter could not be loaded: {}", e);
        }
        SizeOfFilter userFilter = getUserFilter();
        if (userFilter != null) {
            filters.add(userFilter);
        }
        DEFAULT_FILTER = new CombinationSizeOfFilter(filters.toArray(new SizeOfFilter[filters.size()]));

        USE_VERBOSE_DEBUG_LOGGING = getVerboseSizeOfDebugLogging();
    }

to this:

    static {
        Collection<SizeOfFilter> filters = new ArrayList<SizeOfFilter>();
        filters.add(new AnnotationSizeOfFilter());
        try {
            filters.add(new ResourceSizeOfFilter(SizeOfEngine.class.getResource("builtin-sizeof.filter")));
        } catch (IOException e) {
            LOG.warn("Built-in sizeof filter could not be loaded: {}", e);
        }
        try {
            Class.forName("groovy.lang.MetaClass");
        } catch(ClassNotFoundException e) {
        }
        filters.add(new GroovySizeOfFilter());
        SizeOfFilter userFilter = getUserFilter();
        if (userFilter != null) {
            filters.add(userFilter);
        }
        DEFAULT_FILTER = new CombinationSizeOfFilter(filters.toArray(new SizeOfFilter[filters.size()]));

        USE_VERBOSE_DEBUG_LOGGING = getVerboseSizeOfDebugLogging();
    }

Comments

Craig Andrews 2013-12-03

Please note that this is related to EHC-919 but not the same problem or solution.

Also, ResourceSizeOfFilter (and the file specified by the “net.sf.ehcache.sizeof.filter” system property) cannot solve this problem, as they look for exact matches, and in this case, we need to catch all subclasses of groovy.lang.MetaClass as well as groovy.lang.MetaClass.

Craig Andrews 2013-12-04

I asked for help on calculating the size of Groovy objects on the groovy-user mailing list at http://groovy.329449.n5.nabble.com/Calculate-size-of-Groovy-objects-td5717674.html

James House 2013-12-09

for review

Louis Jacomet Jacomet 2013-12-11

One more use case for the new filter support being worked on.

Alexander Snaps 2013-12-23

This as been solved by using the new pluggable sizeof engine module here: http://terracotta-oss.github.io/ehcache-sizeofengine/ There are links to the groovy module as well as both hibernate v3 & v4 ones.