diff --git a/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java b/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java index aeb7b06..58c8e1c 100644 --- a/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java +++ b/utils/src/main/java/datadog/instrument/utils/ClassNameTrie.java @@ -899,8 +899,8 @@ private char newJump(int jump) { if (longJumps == null) { longJumps = new int[16]; // create table on first use } else if (longJumpCount == longJumps.length) { - // expand the table by 50% to fit additional entries - longJumps = Arrays.copyOf(longJumps, longJumpCount + (longJumpCount >> 1)); + // expand the table by 50%, ensuring progress even after compaction to one entry + longJumps = Arrays.copyOf(longJumps, longJumpCount + Math.max(1, longJumpCount >> 1)); } longJumps[longJumpCount] = jump; return (char) (longJumpCount++ | LONG_JUMP_MARKER); diff --git a/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java b/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java index 3caa5ef..23655a2 100644 --- a/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java +++ b/utils/src/test/java/datadog/instrument/utils/ClassNameTrieTest.java @@ -42,6 +42,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; @SuppressFBWarnings("NP_NONNULL_PARAM_VIOLATION") class ClassNameTrieTest { @@ -262,6 +263,30 @@ void tooManyLongJumps() { IllegalArgumentException.class, () -> builder.put("" + ((char) 67) + ((char) 2), 1)); } + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void growsLongJumpTableAfterCompaction(boolean newBuilder) { + ClassNameTrie.Builder builder = new ClassNameTrie.Builder(); + String padding = padding(7700); + for (char branch = 'a'; branch <= 'h'; branch++) { + builder.put("aa" + branch + padding, 1); + } + builder.put("ab", 2); // first long jump skips the padded sub-trie + ClassNameTrie compacted = builder.buildTrie(); // compacts the long-jump table to one entry + if (newBuilder) { + builder = new ClassNameTrie.Builder(compacted); + } + + builder.put("ac", 3); // needs a second long jump + + ClassNameTrie trie = builder.buildTrie(); + for (char branch = 'a'; branch <= 'h'; branch++) { + assertEquals(1, trie.apply("aa" + branch + padding)); + } + assertEquals(2, trie.apply("ab")); + assertEquals(3, trie.apply("ac")); + } + @Test void failedInsertionPreservesExistingMappings() { String padding = padding(7700);