3636import software .amazon .jdbc .util .WrapperUtils ;
3737import software .amazon .jdbc .util .telemetry .TelemetryCounter ;
3838import software .amazon .jdbc .util .telemetry .TelemetryFactory ;
39+ import software .amazon .jdbc .util .telemetry .TelemetryContext ;
40+ import software .amazon .jdbc .util .telemetry .TelemetryTraceLevel ;
3941
4042public class DataRemoteCachePlugin extends AbstractConnectionPlugin {
4143 private static final Logger LOGGER = Logger .getLogger (DataRemoteCachePlugin .class .getName ());
44+ private static final int MAX_CACHEABLE_QUERY_SIZE = 16000 ;
4245 private static final String QUERY_HINT_START_PATTERN = "/*+" ;
4346 private static final String QUERY_HINT_END_PATTERN = "*/" ;
4447 private static final String CACHE_PARAM_PATTERN = "CACHE_PARAM(" ;
48+ private static final String TELEMETRY_CACHE_LOOKUP = "jdbc-cache-lookup" ;
49+ private static final String TELEMETRY_DATABASE_QUERY = "jdbc-database-query" ;
4550 private static final Set <String > subscribedMethods = Collections .unmodifiableSet (new HashSet <>(
4651 Arrays .asList (JdbcMethod .STATEMENT_EXECUTEQUERY .methodName ,
4752 JdbcMethod .STATEMENT_EXECUTE .methodName ,
@@ -52,10 +57,11 @@ public class DataRemoteCachePlugin extends AbstractConnectionPlugin {
5257
5358 private PluginService pluginService ;
5459 private TelemetryFactory telemetryFactory ;
55- private TelemetryCounter hitCounter ;
56- private TelemetryCounter missCounter ;
57- private TelemetryCounter totalCallsCounter ;
60+ private TelemetryCounter cacheHitCounter ;
61+ private TelemetryCounter cacheMissCounter ;
62+ private TelemetryCounter totalQueryCounter ;
5863 private TelemetryCounter malformedHintCounter ;
64+ private TelemetryCounter cacheBypassCounter ;
5965 private CacheConnection cacheConnection ;
6066
6167 public DataRemoteCachePlugin (final PluginService pluginService , final Properties properties ) {
@@ -67,10 +73,11 @@ public DataRemoteCachePlugin(final PluginService pluginService, final Properties
6773 }
6874 this .pluginService = pluginService ;
6975 this .telemetryFactory = pluginService .getTelemetryFactory ();
70- this .hitCounter = telemetryFactory .createCounter ("remoteCache.cache.hit " );
71- this .missCounter = telemetryFactory .createCounter ("remoteCache.cache.miss " );
72- this .totalCallsCounter = telemetryFactory .createCounter ("remoteCache.cache.totalCalls " );
76+ this .cacheHitCounter = telemetryFactory .createCounter ("JdbcCachedQueryCount " );
77+ this .cacheMissCounter = telemetryFactory .createCounter ("JdbcCacheMissCount " );
78+ this .totalQueryCounter = telemetryFactory .createCounter ("JdbcCacheTotalQueryCount " );
7379 this .malformedHintCounter = telemetryFactory .createCounter ("JdbcCacheMalformedQueryHint" );
80+ this .cacheBypassCounter = telemetryFactory .createCounter ("JdbcCacheBypassCount" );
7481 this .cacheConnection = new CacheConnection (properties );
7582 }
7683
@@ -223,45 +230,77 @@ public <T, E extends Exception> T execute(
223230 boolean needToCache = false ;
224231 final String sql = getQuery (jdbcMethodArgs );
225232
233+ TelemetryContext cacheContext = null ;
234+ TelemetryContext dbContext = null ;
226235 // If the query is cacheable, we try to fetch the query result from the cache.
227236 boolean isInTransaction = pluginService .isInTransaction ();
228237 // Get the query hint part in front of the query itself
229238 String mainQuery = sql ; // The main part of the query with the query hint prefix trimmed
230239 int endOfQueryHint = 0 ;
231240 Integer configuredQueryTtl = null ;
232241 // Queries longer than 16KB is not cacheable
233- if ((sql .length () < 16000 ) && sql .startsWith (QUERY_HINT_START_PATTERN )) {
242+ if ((sql .length () < MAX_CACHEABLE_QUERY_SIZE ) && sql .startsWith (QUERY_HINT_START_PATTERN )) {
234243 endOfQueryHint = sql .indexOf (QUERY_HINT_END_PATTERN );
235244 if (endOfQueryHint > 0 ) {
236245 configuredQueryTtl = getTtlForQuery (sql .substring (2 , endOfQueryHint ).trim ());
237246 mainQuery = sql .substring (endOfQueryHint + 2 ).trim ();
238247 }
239248 }
240249
250+ incrCounter (totalQueryCounter );
251+
241252 // Query result can be served from the cache if it has a configured TTL value, and it is
242253 // not executed in a transaction as a transaction typically need to return consistent results.
243254 if (!isInTransaction && (configuredQueryTtl != null )) {
244- incrCounter (totalCallsCounter );
245- result = fetchResultSetFromCache (mainQuery );
246- if (result == null ) {
247- // Cache miss. Need to fetch result from the database
248- needToCache = true ;
249- incrCounter (missCounter );
250- LOGGER .finest ("Got a cache miss for SQL: " + sql );
251- } else {
252- LOGGER .finest ("Got a cache hit for SQL: " + sql );
253- // Cache hit. Return the cached result
254- incrCounter (hitCounter );
255- try {
256- result .beforeFirst ();
257- } catch (final SQLException ex ) {
258- throw WrapperUtils .wrapExceptionIfNeeded (exceptionClass , ex );
255+ cacheContext = telemetryFactory .openTelemetryContext (
256+ TELEMETRY_CACHE_LOOKUP , TelemetryTraceLevel .TOP_LEVEL );
257+ Exception cacheException = null ;
258+ try {
259+ result = fetchResultSetFromCache (mainQuery );
260+ if (result == null ) {
261+ // Cache miss. Need to fetch result from the database
262+ needToCache = true ;
263+ incrCounter (cacheMissCounter );
264+ LOGGER .finest ("Got a cache miss for SQL: " + sql );
265+ } else {
266+ LOGGER .finest ("Got a cache hit for SQL: " + sql );
267+ // Cache hit. Return the cached result
268+ incrCounter (cacheHitCounter );
269+ try {
270+ result .beforeFirst ();
271+ } catch (final SQLException ex ) {
272+ cacheException = ex ;
273+ throw WrapperUtils .wrapExceptionIfNeeded (exceptionClass , ex );
274+ }
275+ return resultClass .cast (result );
276+ }
277+ } finally {
278+ if (cacheContext != null ) {
279+ if (cacheException != null ) {
280+ cacheContext .setSuccess (false );
281+ cacheContext .setException (cacheException );
282+ cacheContext .closeContext ();
283+ } else if (!needToCache ) { // Cache hit
284+ cacheContext .setSuccess (true );
285+ cacheContext .closeContext ();
286+ } else { // Cache miss - leave context open
287+ cacheContext .setSuccess (false );
288+ }
259289 }
260- return resultClass .cast (result );
261290 }
291+ } else {
292+ incrCounter (cacheBypassCounter );
262293 }
263294
264- result = (ResultSet ) jdbcMethodFunc .call ();
295+ dbContext = telemetryFactory .openTelemetryContext (
296+ TELEMETRY_DATABASE_QUERY , TelemetryTraceLevel .TOP_LEVEL );
297+
298+ try {
299+ result = (ResultSet ) jdbcMethodFunc .call ();
300+ } finally {
301+ if (dbContext != null ) dbContext .closeContext ();
302+ if (cacheContext != null ) cacheContext .closeContext ();
303+ }
265304
266305 // We need to cache the query result if we got a cache miss for the query result,
267306 // or the query is cacheable and executed inside a transaction.
0 commit comments