-
Notifications
You must be signed in to change notification settings - Fork 10
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
[break] Fix MetricName comparator for tags, MetricName#safeTags() returns SortedMap #272
Changes from 2 commits
8435797
28fba1b
6dfa869
a201e13
b1e527d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,9 +17,7 @@ | |
package com.palantir.tritium.metrics.registry; | ||
|
||
import com.palantir.logsafe.Safe; | ||
import java.util.Comparator; | ||
import java.util.Iterator; | ||
import java.util.Map; | ||
import java.util.NavigableMap; | ||
import org.immutables.value.Value; | ||
|
||
@Value.Immutable(prehash = true) | ||
|
@@ -30,25 +28,6 @@ | |
visibility = Value.Style.ImplementationVisibility.PACKAGE) | ||
public interface MetricName extends Comparable<MetricName> { | ||
|
||
Comparator<Map.Entry<String, String>> entryComparator = | ||
Map.Entry.<String, String>comparingByKey() | ||
.thenComparing(Map.Entry.comparingByValue()); | ||
Comparator<MetricName> metricNameComparator = | ||
Comparator.comparing(MetricName::safeName) | ||
.thenComparing(metricName -> metricName.safeTags().entrySet(), (set1, set2) -> { | ||
Iterator<Map.Entry<String, String>> i1 = set1.iterator(); | ||
Iterator<Map.Entry<String, String>> i2 = set2.iterator(); | ||
while (i1.hasNext() && i2.hasNext()) { | ||
Map.Entry<String, String> e1 = i1.next(); | ||
Map.Entry<String, String> e2 = i2.next(); | ||
int compare = entryComparator.compare(e1, e2); | ||
if (compare != 0) { | ||
return compare; | ||
} | ||
} | ||
return i1.hasNext() ? -1 : i2.hasNext() ? 1 : 0; | ||
}); | ||
|
||
/** | ||
* General/abstract measure (e.g. server.response-time). | ||
* <p> | ||
|
@@ -61,11 +40,12 @@ public interface MetricName extends Comparable<MetricName> { | |
* <p> | ||
* All tags and keys must be {@link Safe} to log. | ||
*/ | ||
Map<String, String> safeTags(); | ||
@Value.NaturalOrder | ||
NavigableMap<String, String> safeTags(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually should make this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would do the trick, if we're okay with exposing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does MetricName need to be comparable? Are we better off removing that piece? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mainly added it for convenience for the |
||
@Override | ||
default int compareTo(MetricName that) { | ||
return metricNameComparator.compare(this, that); | ||
return MetricNames.metricNameComparator.compare(this, that); | ||
} | ||
|
||
static Builder builder() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* (c) Copyright 2019 Palantir Technologies Inc. All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.palantir.tritium.metrics.registry; | ||
|
||
import com.google.common.annotations.VisibleForTesting; | ||
import java.util.Comparator; | ||
import java.util.Iterator; | ||
import java.util.Map; | ||
|
||
final class MetricNames { | ||
|
||
private MetricNames() {} | ||
|
||
private static final Comparator<Map.Entry<String, String>> entryComparator = | ||
Map.Entry.<String, String>comparingByKey() | ||
.thenComparing(Map.Entry.comparingByValue()); | ||
|
||
private static final Comparator<Map<String, String>> sizeComparator = Comparator.comparingInt(Map::size); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice touch |
||
|
||
private static final Comparator<Map<String, String>> mapComparator = (m1, m2) -> { | ||
Iterator<Map.Entry<String, String>> i1 = m1.entrySet().iterator(); | ||
Iterator<Map.Entry<String, String>> i2 = m2.entrySet().iterator(); | ||
while (i1.hasNext() && i2.hasNext()) { | ||
Map.Entry<String, String> e1 = i1.next(); | ||
Map.Entry<String, String> e2 = i2.next(); | ||
int compare = entryComparator.compare(e1, e2); | ||
if (compare != 0) { | ||
return compare; | ||
} | ||
} | ||
return i1.hasNext() ? -1 : i2.hasNext() ? 1 : 0; | ||
}; | ||
|
||
@VisibleForTesting | ||
static final Comparator<MetricName> metricNameComparator = | ||
Comparator.comparing(MetricName::safeName) | ||
.thenComparing(MetricName::safeTags, sizeComparator) | ||
.thenComparing(MetricName::safeTags, mapComparator); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we loosen this to SortedMap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to just leave this as a
NavigableMap
as the underlying impl generated by immutables is aTreeMap
either way withjdkOnly = true
(though we could remove that since we already rely on Guavaimplementation
dependency, created optional #273 for that).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer the guava approach. We heavily rely on guava immutable collections, and they will avoid collection re-allocations when we attempt to re-wrap them.
I'm not sure any of the functionality provided by
NavigableMap
will be helpful forsafeTags
, whereSortedMap
provides clear advantages. Using the less specific type allows more freedom to change the implementation in the future. That said, I'm not actually aware of aSortedMap
implementation which doesn't also implementNavigableMap
, so I defer to your judgement.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, you convinced me, went with
SortedMap
for now