Skip to content
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

LastModifiedComparator file comparator is not transitive #516

Closed
kboyarshinov opened this issue Sep 28, 2016 · 8 comments
Closed

LastModifiedComparator file comparator is not transitive #516

kboyarshinov opened this issue Sep 28, 2016 · 8 comments

Comments

@kboyarshinov
Copy link
Contributor

kboyarshinov commented Sep 28, 2016

Hello, we are receiving the following error:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:743)
at java.util.TimSort.mergeAt(TimSort.java:479)
at java.util.TimSort.mergeCollapse(TimSort.java:406)
at java.util.TimSort.sort(TimSort.java:210)
at java.util.TimSort.sort(TimSort.java:169)
at java.util.Arrays.sort(Arrays.java:2010)
at org.acra.file.ReportLocator.getApprovedReports(ReportLocator.java:55)
at org.acra.util.ApplicationStartupProcessor.sendApprovedReports(ApplicationStartupProcessor.java:70)
at org.acra.ACRA.init(ACRA.java:272)
at org.acra.ACRA.init(ACRA.java:200)

It seems that LastModifiedComparator is not transitive:

final class LastModifiedComparator implements Comparator<File> {
    @Override
    public int compare(@NonNull File lhs, @NonNull File rhs) {
        return (int) (lhs.lastModified() - rhs.lastModified());
    }
}

It should be like this:

final class LastModifiedComparator implements Comparator<File> {
    @Override
    public int compare(@NonNull File lhs, @NonNull File rhs) {
        return Long.compare(lhs.lastModified(), rhs.lastModified());
    }
}

ACRA version: 4.9.0

@william-ferguson-au
Copy link
Member

Its only non-transitive if there is more than 1600 years between your 2 outliers.
Do you really have files that are more than 1600 years old?

@kboyarshinov
Copy link
Contributor Author

I suppose not. Will check and try provide more details. Thanks.

@kboyarshinov
Copy link
Contributor Author

I have checked the reports on affected device and the earliest report was dated 2010. It can happen after hardware reset or when battery completely ran out, when time is reset to manufacturing time and the application is launcher (starts at boot).

I do not know the reason but changing Comparator to the one I suggested solved the problem and reports were sent.

@F43nd1r
Copy link
Member

F43nd1r commented Oct 11, 2016

Long.compare was introduced in API 19. So, we cannot use it.

@kboyarshinov
Copy link
Contributor Author

Implementation can be used:

public static int compare(long lhs, long rhs) {
        return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1);
}

@william-ferguson-au
Copy link
Member

So provide a pull request.

@kboyarshinov
Copy link
Contributor Author

Thank you. Opened #521

@gregoiredx
Copy link

gregoiredx commented Jun 29, 2017

Ran into this bug. I can confirm the comparator fix solved it.
By the way, it's not 1600 years. You can have problems as soon as the cast from long to int is unsafe (so when there is more than Integer.MAX_VALUE milliseconds between two reports, that is less than 25 days)

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

No branches or pull requests

4 participants