Skip to content

Rework subtypes populating code algorithm #7010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Rework subtypes populating code algorithm #7010

wants to merge 1 commit into from

Conversation

ghost
Copy link

@ghost ghost commented Sep 23, 2016

If I'm reading this correctly, subtypes contains mapping for exceptions that themselves doesn't have error-path mapped, but their super class has, therefore to skip checking inheritance chain each time, they have this shortcut mapping. But here, map is populated the other way around! This might be due to the naming glitch: local variable subtype should probably be named _super_type since it contains parent type. Then mapping would go like: map type to supertype - which is what is going on. Maybe map should also be named supertypes?

@pivotal-issuemaster
Copy link

@mwojterski Please sign the Contributor License Agreement!

Click here to manually synchronize the status of this Pull Request.

See the FAQ for frequently asked questions.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 23, 2016
@pivotal-issuemaster
Copy link

@mwojterski Thank you for signing the Contributor License Agreement!

while (supertype != Object.class) {
supertype = supertype.getSuperclass();
if (this.exceptions.containsKey(supertype)) {
this.subtypes.put(type, supertype);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like more than a typo correction. You've swapped the key and value in this call to put. Was that intentional?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Yes It was intentional as I've mentioned in the first comment to this PR. I also changed variable name from subtype to supertype because I suspect it was the reason for initial mistake (swapped put arguments) since it was suggesting different relation between arguments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then shouldn't the containsKey check have been updated too?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. The way I'm reading this code, we only want to save this particular supertype if we have an explicit exception mapping for it, if not, we should continue upwards till we find the one or there is no more types to check.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. It's a different map. Well, if nothing else, this discussion has shown that the code's confusing to me at least.

I also think that the PR has shown that we're missing some tests. You've changed the behaviour, but haven't had to change any tests. That's bad. I'd like to see some tests around this before we change anything.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class has a nice battery of tests, but what's more important I haven't changed the contract (behaviour visible from the outside is still the same), but rather fixed an internal optimization. I can't see how I may test this particular internal implementation detail without exposing it, which I think would be a bad thing. If you could shed some light on the way you'd wish such test to be implemented, I'd be most grateful.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be clear, I was saying that the current code and tests are bad, not your PR.

Given that it would appear that the optimisation is faulty in its current state, and no one has raised it as a performance problem, I'm very tempted to remove it and simplify the code. If the optimisation is worth having then it's worth testing. To do that, the filter will need to be refactored. I would create a separate package-private class that's sole responsibility is mapping from a status or exception to an error path and implement it in such a way that it can be spied on or whatever to verify that the optimisation is working as intended.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if I seemed offensive, I didn't mean to. I was thinking as well that if nobody noticed it wasn't working, than maybe it's redundant and it'd be better to just remove this piece to reduce complexity. But since I'm no expert on performance optimizations, please decide if you want to keep it and I should refactor & test it, or you wish it simply removed.

@philwebb philwebb removed the status: waiting-for-triage An issue we've not yet triaged label Sep 29, 2016
@philwebb philwebb added this to the 1.4.2 milestone Sep 29, 2016
@philwebb
Copy link
Member

Tagged to 1.4.2 but let's not merge this in it's current form. We'll look at Andy's suggestion above.

@snicoll snicoll changed the title Fix typo in subtypes populating code Rework subtypes populating code algorithm Oct 3, 2016
@wilkinsona wilkinsona self-assigned this Oct 19, 2016
@wilkinsona
Copy link
Member

I've removed the optimisation as JMH told me that it wasn't worth the effort due to the tiny amount of time that's taken looking up the mapping. Here's the benchmark that I used:

import java.util.HashMap;
import java.util.Map;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.springframework.beans.factory.UnsatisfiedDependencyException;

public class ErrorPathMappingBenchmark {

    @State(Scope.Benchmark)
    public static class BenchmarkState {

        private final Map<Class<?>, String> exceptions = new HashMap<Class<?>, String>();

        private final Map<Class<?>, Class<?>> superTypes = new HashMap<Class<?>, Class<?>>();

        public BenchmarkState() {
            this.exceptions.put(Exception.class, "/500");
            this.superTypes.put(UnsatisfiedDependencyException.class, Exception.class);
        }
    }

    @Benchmark
    public String deepException(BenchmarkState state) {
        Class<?> type = UnsatisfiedDependencyException.class;
        return getErrorPath(state, type);
    }

    @Benchmark
    public String deepExceptionUsingSuperTypes(BenchmarkState state) {
        Class<?> type = UnsatisfiedDependencyException.class;
        return getErrorPathUsingSuperTypes(state, type);
    }

    @Benchmark
    public String shallowException(BenchmarkState state) {
        Class<?> type = Exception.class;
        return getErrorPath(state, type);
    }

    private String getErrorPathUsingSuperTypes(BenchmarkState state, Class<?> type) {
        Class<?> superType = state.superTypes.get(type);
        if (superType != null) {
            return state.exceptions.get(superType);
        }
        while (type != Object.class) {
            String path = state.exceptions.get(type);
            if (path != null) {
                return path;
            }
            type = type.getSuperclass();
        }
        return "global";
    }

    private String getErrorPath(BenchmarkState state, Class<?> type) {
        while (type != Object.class) {
            String path = state.exceptions.get(type);
            if (path != null) {
                return path;
            }
            type = type.getSuperclass();
        }
        return "global";
    }

}

izeye added a commit to izeye/sample-jmh-maven that referenced this pull request Nov 1, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants