Skip to content

Commit

Permalink
atlas: add method to find hotspots in index
Browse files Browse the repository at this point in the history
Add helper method to QueryIndex to help find hot spots
in the index.
  • Loading branch information
brharrington committed Dec 2, 2023
1 parent 278395b commit a9804e7
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import com.netflix.spectator.api.Registry;
import com.netflix.spectator.impl.Cache;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
Expand Down Expand Up @@ -533,6 +536,69 @@ public void forEachMatch(Function<String, String> tags, Consumer<T> consumer) {
}
}

/**
* Find hot spots in the index where there is a large set of linear matches, e.g. a bunch
* of regex queries for a given key.
*
* @param threshold
* Threshold for the number of entries in the other checks sub-tree to be considered
* a hot spot.
* @param consumer
* Function that will be invoked with a path and set of queries for the hot spot.
*/
public void findHotSpots(int threshold, BiConsumer<List<String>, List<Query.KeyQuery>> consumer) {
Deque<String> path = new ArrayDeque<>();
findHotSpots(threshold, path, consumer);
}

private void findHotSpots(
int threshold,
Deque<String> path,
BiConsumer<List<String>, List<Query.KeyQuery>> consumer
) {
if (key != null) {
path.addLast("K=" + key);

equalChecks.forEach((v, idx) -> {
path.addLast(key + "," + v + ",:eq");
idx.findHotSpots(threshold, path, consumer);
path.removeLast();
});

path.addLast("other-checks");
if (otherChecks.size() > threshold) {
List<Query.KeyQuery> queries = new ArrayList<>(otherChecks.keySet());
consumer.accept(new ArrayList<>(path), queries);
}
otherChecks.forEach((q, idx) -> {
path.addLast(q.toString());
idx.findHotSpots(threshold, path, consumer);
path.removeLast();
});
path.removeLast();

if (hasKeyIdx != null) {
path.addLast("has");
hasKeyIdx.findHotSpots(threshold, path, consumer);
path.removeLast();
}

path.removeLast();
}

if (otherKeysIdx != null) {
path.addLast("other-keys");
otherKeysIdx.findHotSpots(threshold, path, consumer);
path.removeLast();
}

if (missingKeysIdx != null) {
path.addLast("missing-keys");
missingKeysIdx.findHotSpots(threshold, path, consumer);
path.removeLast();
}
}

@Override public String toString() {
StringBuilder builder = new StringBuilder();
buildString(builder, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,4 +533,22 @@ public void addRemoveFuzz() {
Assertions.assertTrue(idx.isEmpty());
}
}

@Test
public void findHotSpots() {
Registry registry = new NoopRegistry();
QueryIndex<Integer> idx = QueryIndex.newInstance(registry);
for (int i = 0; i < 5; ++i) {
Query q = Parser.parseQuery("name,foo,:re,i," + i + ",:re,:and");
idx.add(q, i);
}

idx.findHotSpots(4, (path, queries) -> {
Assertions.assertEquals(
"K=name > other-checks > name,foo,:re > K=i > other-checks",
String.join(" > ", path)
);
Assertions.assertEquals(5, queries.size());
});
}
}

0 comments on commit a9804e7

Please sign in to comment.