From 79f3a07e29653ecde810d1a2819b25a91ef26d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 10 Apr 2025 13:09:46 +0200 Subject: [PATCH 1/2] perf: cache the key used for OTEL traces and metrics The HeaderInterceptor creates a key consisting of the database name and method name that is used for OpenTelemetry attributes and metrics. The number of unique keys is low. However, the key is constructed from the DatabaseName and method name every time, which leads to a lot of string creation: 1. The DatabaseName.toString() method is called every time. This constructs a new string. 2. The result of DatabaseName.toString() is concatenated with the methodName to create yet another string. Instead of creating the key every time, we can cache the key values without doing the string creation and concatenation every time. --- .../cloud/spanner/spi/v1/HeaderInterceptor.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java index dba3b38e92f..b972ecdcef4 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java @@ -87,6 +87,8 @@ class HeaderInterceptor implements ClientInterceptor { CacheBuilder.newBuilder().maximumSize(1000).build(); private final Cache> builtInAttributesCache = CacheBuilder.newBuilder().maximumSize(1000).build(); + private final Cache> keyCache = + CacheBuilder.newBuilder().maximumSize(1000).build(); // Get the global singleton Tagger object. private static final Tagger TAGGER = Tags.getTagger(); @@ -116,7 +118,7 @@ public void start(Listener responseListener, Metadata headers) { try { Span span = Span.current(); DatabaseName databaseName = extractDatabaseName(headers); - String key = databaseName + method.getFullMethodName(); + String key = extractKey(databaseName, method.getFullMethodName()); TagContext tagContext = getTagContext(key, method.getFullMethodName(), databaseName); Attributes attributes = getMetricAttributes(key, method.getFullMethodName(), databaseName); @@ -201,6 +203,13 @@ private Map parseServerTimingHeader(String serverTiming) { return serverTimingMetrics; } + private String extractKey(DatabaseName databaseName, String methodName) + throws ExecutionException { + Cache keys = + keyCache.get(databaseName, () -> CacheBuilder.newBuilder().maximumSize(1000).build()); + return keys.get(methodName, () -> databaseName + methodName); + } + private DatabaseName extractDatabaseName(Metadata headers) throws ExecutionException { String googleResourcePrefix = headers.get(GOOGLE_CLOUD_RESOURCE_PREFIX_KEY); if (googleResourcePrefix != null) { From 36b4b5b7ed7490e52cb6b4e3f995411d6a1baf22 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Thu, 10 Apr 2025 11:18:12 +0000 Subject: [PATCH 2/2] chore: generate libraries at Thu Apr 10 11:15:55 UTC 2025 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01c88f4f8cf..b3edd324c8e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file: com.google.cloud libraries-bom - 26.54.0 + 26.57.0 pom import