in spectator-reg-atlas/src/main/java/com/netflix/spectator/atlas/impl/QueryIndex.java [394:470]
private void forEachMatch(Id tags, int i, Consumer<T> consumer) {
// Matches for this level
matches.forEach(consumer);
final String keyRef = key;
if (keyRef != null) {
boolean keyPresent = false;
final int tagsSize = tags.size();
for (int j = i; j < tagsSize; ++j) {
String k = tags.getKey(j);
String v = tags.getValue(j);
int cmp = compare(k, keyRef);
if (cmp == 0) {
final int nextPos = j + 1;
keyPresent = true;
// Find exact matches
QueryIndex<T> eqIdx = equalChecks.get(v);
if (eqIdx != null) {
eqIdx.forEachMatch(tags, nextPos, consumer);
}
// Scan for matches with other conditions
List<QueryIndex<T>> otherMatches = otherChecksCache.get(v);
if (otherMatches == null) {
// Avoid the list and cache allocations if there are no other checks at
// this level
if (!otherChecks.isEmpty()) {
List<QueryIndex<T>> tmp = new ArrayList<>();
otherChecksTree.forEach(v, kq -> {
if (kq instanceof Query.In || kq.matches(v)) {
QueryIndex<T> idx = otherChecks.get(kq);
if (idx != null) {
tmp.add(idx);
idx.forEachMatch(tags, nextPos, consumer);
}
}
});
otherChecksCache.put(v, tmp);
}
} else {
// Enhanced for loop typically results in iterator being allocated. Using
// size/get avoids the allocation and has better throughput.
final int n = otherMatches.size();
for (int p = 0; p < n; ++p) {
otherMatches.get(p).forEachMatch(tags, nextPos, consumer);
}
}
// Check matches for has key
final QueryIndex<T> hasKeyIdxRef = hasKeyIdx;
if (hasKeyIdxRef != null) {
hasKeyIdxRef.forEachMatch(tags, j, consumer);
}
}
// Quit loop if the key was found or not present
if (cmp >= 0) {
break;
}
}
// Check matches with other keys
final QueryIndex<T> otherKeysIdxRef = otherKeysIdx;
if (otherKeysIdxRef != null) {
otherKeysIdxRef.forEachMatch(tags, i, consumer);
}
// Check matches with missing keys
final QueryIndex<T> missingKeysIdxRef = missingKeysIdx;
if (missingKeysIdxRef != null && !keyPresent) {
missingKeysIdxRef.forEachMatch(tags, i, consumer);
}
}
}