Skip to content

Commit 528cfc3

Browse files
authored
Merge pull request #2294 from newrelic/db-parser-optimization
Prevent cache lock for long DB statement parsing
2 parents 9be91b8 + dbf4a39 commit 528cfc3

File tree

2 files changed

+16
-8
lines changed

2 files changed

+16
-8
lines changed

newrelic-agent/src/main/java/com/newrelic/agent/database/CachingDatabaseStatementParser.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,14 @@ public ParsedDatabaseStatement getParsedDatabaseStatement(final DatabaseVendor d
5959
return UNPARSEABLE_STATEMENT;
6060
}
6161

62-
return getOrCreateCache().get(
63-
statement,
64-
s -> databaseStatementParser.getParsedDatabaseStatement(databaseVendor, statement, resultSetMetaData));
62+
Cache<String, ParsedDatabaseStatement> cache = getOrCreateCache();
63+
ParsedDatabaseStatement parsedStatement = cache.getIfPresent(statement);
64+
if (parsedStatement == null) {
65+
parsedStatement = databaseStatementParser.getParsedDatabaseStatement(databaseVendor, statement, resultSetMetaData);
66+
cache.put(statement, parsedStatement);
67+
}
68+
69+
return parsedStatement;
6570
} catch (RuntimeException ex) {
6671
toLog = ex;
6772
}

newrelic-agent/src/test/java/com/newrelic/agent/database/CachingDatabaseStatementParserTest.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,8 @@
55

66
import java.sql.ResultSetMetaData;
77

8-
import static org.junit.Assert.assertEquals;
9-
import static org.junit.Assert.assertNotNull;
108
import static org.junit.Assert.assertEquals;
119
import static org.mockito.ArgumentMatchers.any;
12-
import static org.mockito.ArgumentMatchers.anyInt;
13-
import static org.mockito.ArgumentMatchers.anyString;
1410
import static org.mockito.ArgumentMatchers.eq;
1511
import static org.mockito.Mockito.mock;
1612
import static org.mockito.Mockito.times;
@@ -24,8 +20,15 @@ public void getParsedDatabaseStatement_cachesSqlStatement() {
2420
DatabaseStatementParser mockParser = mock(DatabaseStatementParser.class);
2521
CachingDatabaseStatementParser cache = new CachingDatabaseStatementParser(mockParser);
2622

23+
when(mockParser.getParsedDatabaseStatement(any(), eq("sql"), any())).thenReturn(new ParsedDatabaseStatement("tablename", "select", true));
24+
25+
// Initial call will cache the result
2726
ParsedDatabaseStatement statement = cache.getParsedDatabaseStatement(mock(DatabaseVendor.class), "sql", mock(ResultSetMetaData.class));
2827
verify(mockParser, times(1)).getParsedDatabaseStatement(any(), eq("sql"), any());
28+
29+
// Subsequent calls will retrieve the value from the cache and not call the databaseStatementParser again
30+
assertEquals(statement, cache.getParsedDatabaseStatement(mock(DatabaseVendor.class), "sql", mock(ResultSetMetaData.class)));
31+
verify(mockParser, times(1)).getParsedDatabaseStatement(any(), eq("sql"), any());
2932
}
3033

3134
@Test
@@ -34,4 +37,4 @@ public void getParsedDatabaseStatement_withNullStatement_returnsUnparseableState
3437
CachingDatabaseStatementParser cache = new CachingDatabaseStatementParser(mockParser);
3538
assertEquals(DatabaseStatementParser.UNPARSEABLE_STATEMENT, cache.getParsedDatabaseStatement(mock(DatabaseVendor.class), null, null));
3639
}
37-
}
40+
}

0 commit comments

Comments
 (0)