This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-graalvm-distro.git


The following commit(s) were added to refs/heads/main by this push:
     new e438f0f  Sync with upstream submodule: VirtualThreads, 
ExporterSetting, oap.yaml, warm/cold config
e438f0f is described below

commit e438f0fd7514fc45b8e648777ffdd6a4a623007f
Author: Wu Sheng <[email protected]>
AuthorDate: Wed Feb 25 20:13:11 2026 +0800

    Sync with upstream submodule: VirtualThreads, ExporterSetting, oap.yaml, 
warm/cold config
    
    - Update skywalking submodule to a0cec0c
    - Add VirtualThreads replacement (direct JDK 25 API, no reflection)
    - Update HierarchyService to use VirtualThreads.createScheduledExecutor()
    - Fix ExporterSetting: bufferChannelSize/bufferChannelNum -> bufferSize
    - Handle BanyanDB warm/cold Stage config in YamlConfigLoaderUtils
      (extract shared copyToGroupResource with deferred stage processing)
    - Update oap.yaml metric label change (kind+metricName -> slot)
    - Update SHA-256 hashes for changed upstream files
---
 .../server/library/util/YamlConfigLoaderUtils.java | 483 +++------------------
 .../skywalking/oap/server/graalvm/mal/OapTest.java |   5 +-
 .../resources/precompiled-yaml-sha256.properties   |   2 +-
 .../resources/replacement-source-sha256.properties |   4 +-
 oap-libs-for-graalvm/CLAUDE.md                     |  12 +-
 .../library-util-for-graalvm/pom.xml               |   1 +
 .../oap/server/library/util/VirtualThreads.java    |  97 +++++
 .../server/core/hierarchy/HierarchyService.java    |  15 +-
 skywalking                                         |   2 +-
 9 files changed, 191 insertions(+), 430 deletions(-)

diff --git 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
index 649f154..077128a 100644
--- 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
+++ 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
@@ -1438,11 +1438,8 @@ public class YamlConfigLoaderUtils {
                 case "gRPCTargetPort":
                     cfg.setGRPCTargetPort((int) value);
                     break;
-                case "bufferChannelSize":
-                    cfg.setBufferChannelSize((int) value);
-                    break;
-                case "bufferChannelNum":
-                    cfg.setBufferChannelNum((int) value);
+                case "bufferSize":
+                    cfg.setBufferSize((int) value);
                     break;
                 case "enableKafkaTrace":
                     cfg.setEnableKafkaTrace((boolean) value);
@@ -1596,10 +1593,18 @@ public class YamlConfigLoaderUtils {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    private static void copyToRecordsNormal(
-            final BanyanDBStorageConfig.RecordsNormal cfg, final Properties 
src,
-            final String moduleName, final String providerName) {
+    /**
+     * Copies GroupResource fields (shardNum, segmentInterval, ttl, replicas, 
enableWarmStage,
+     * enableColdStage) and processes nested warm/cold Stage sections.
+     * Mirrors upstream BanyanDBConfigLoader.copyStages() logic: warm/cold are 
deferred
+     * until after all simple fields are set, so 
enableWarmStage/enableColdStage flags
+     * are available regardless of Properties iteration order.
+     */
+    private static void copyToGroupResource(
+            final BanyanDBStorageConfig.GroupResource cfg, final Properties 
src,
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        Properties warmProps = null;
+        Properties coldProps = null;
         final Enumeration<?> propertyNames = src.propertyNames();
         while (propertyNames.hasMoreElements()) {
             final String key = (String) propertyNames.nextElement();
@@ -1630,474 +1635,120 @@ public class YamlConfigLoaderUtils {
                 case "additionalLifecycleStages":
                     cfg.setAdditionalLifecycleStages((List) value);
                     break;
+                case "warm":
+                    if (value instanceof Properties) {
+                        warmProps = (Properties) value;
+                    }
+                    break;
+                case "cold":
+                    if (value instanceof Properties) {
+                        coldProps = (Properties) value;
+                    }
+                    break;
                 default:
                     log.warn("{} setting is not supported in {} provider of {} 
module",
                         key, providerName, moduleName);
                     break;
             }
         }
+        if (cfg.isEnableWarmStage() && warmProps != null) {
+            BanyanDBStorageConfig.Stage warm = new 
BanyanDBStorageConfig.Stage();
+            warm.setName(BanyanDBStorageConfig.StageName.warm);
+            copyProperties(warm, warmProps, moduleName, providerName);
+            cfg.getAdditionalLifecycleStages().add(warm);
+            
cfg.getDefaultQueryStages().add(BanyanDBStorageConfig.StageName.warm.name());
+        }
+        if (cfg.isEnableColdStage() && coldProps != null) {
+            BanyanDBStorageConfig.Stage cold = new 
BanyanDBStorageConfig.Stage();
+            cold.setName(BanyanDBStorageConfig.StageName.cold);
+            cold.setClose(true);
+            copyProperties(cold, coldProps, moduleName, providerName);
+            cfg.getAdditionalLifecycleStages().add(cold);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void copyToRecordsNormal(
+            final BanyanDBStorageConfig.RecordsNormal cfg, final Properties 
src,
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToRecordsLog(
             final BanyanDBStorageConfig.RecordsLog cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToTrace(
             final BanyanDBStorageConfig.Trace cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToZipkinTrace(
             final BanyanDBStorageConfig.ZipkinTrace cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToRecordsTrace(
             final BanyanDBStorageConfig.RecordsTrace cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToRecordsZipkinTrace(
             final BanyanDBStorageConfig.RecordsZipkinTrace cfg, final 
Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToRecordsBrowserErrorLog(
             final BanyanDBStorageConfig.RecordsBrowserErrorLog cfg, final 
Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToMetricsMin(
             final BanyanDBStorageConfig.MetricsMin cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToMetricsHour(
             final BanyanDBStorageConfig.MetricsHour cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToMetricsDay(
             final BanyanDBStorageConfig.MetricsDay cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToMetadata(
             final BanyanDBStorageConfig.Metadata cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
     private static void copyToProperty(
             final BanyanDBStorageConfig.Property cfg, final Properties src,
-            final String moduleName, final String providerName) {
-        final Enumeration<?> propertyNames = src.propertyNames();
-        while (propertyNames.hasMoreElements()) {
-            final String key = (String) propertyNames.nextElement();
-            final Object value = src.get(key);
-            log.debug("{}.{} config: {} = {}", moduleName, providerName, key, 
value);
-            switch (key) {
-                case "shardNum":
-                    cfg.setShardNum((int) value);
-                    break;
-                case "segmentInterval":
-                    cfg.setSegmentInterval((int) value);
-                    break;
-                case "ttl":
-                    cfg.setTtl((int) value);
-                    break;
-                case "replicas":
-                    cfg.setReplicas((int) value);
-                    break;
-                case "enableWarmStage":
-                    cfg.setEnableWarmStage((boolean) value);
-                    break;
-                case "enableColdStage":
-                    cfg.setEnableColdStage((boolean) value);
-                    break;
-                case "defaultQueryStages":
-                    cfg.setDefaultQueryStages((List) value);
-                    break;
-                case "additionalLifecycleStages":
-                    cfg.setAdditionalLifecycleStages((List) value);
-                    break;
-                default:
-                    log.warn("{} setting is not supported in {} provider of {} 
module",
-                        key, providerName, moduleName);
-                    break;
-            }
-        }
+            final String moduleName, final String providerName) throws 
IllegalAccessException {
+        copyToGroupResource(cfg, src, moduleName, providerName);
     }
 
     @SuppressWarnings("unchecked")
diff --git 
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/OapTest.java
 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/OapTest.java
index 906b64d..bb9534c 100644
--- 
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/OapTest.java
+++ 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/OapTest.java
@@ -88,7 +88,7 @@ class OapTest extends MALScriptComparisonBase {
      * # --- Metrics Aggregation (tagEqual + conditional rewrite) ---
      * metrics_aggregation{...,dimensionality="minute",level="1"} 100.0
      * metrics_aggregation{...,dimensionality="minute",level="2"} 50.0
-     * 
metrics_aggregation_queue_used_percentage{...,level="1",kind="metrics",metricName="test_metric"}
 75.0
+     * metrics_aggregation_queue_used_percentage{...,level="1",slot="0"} 75.0
      *
      * # --- Persistence ---
      * persistence_timer_bulk_execute_latency{...le buckets...} histogram
@@ -244,8 +244,7 @@ class OapTest extends MALScriptComparisonBase {
                         .labels(ImmutableMap.<String, String>builder()
                             .putAll(scope)
                             .put("level", "1")
-                            .put("kind", "metrics")
-                            .put("metricName", "test_metric")
+                            .put("slot", "0")
                             .build())
                         .value(75.0 * scale).timestamp(timestamp).build()
                 ).build())
diff --git 
a/oap-graalvm-server/src/test/resources/precompiled-yaml-sha256.properties 
b/oap-graalvm-server/src/test/resources/precompiled-yaml-sha256.properties
index 5b92f60..d36eae5 100644
--- a/oap-graalvm-server/src/test/resources/precompiled-yaml-sha256.properties
+++ b/oap-graalvm-server/src/test/resources/precompiled-yaml-sha256.properties
@@ -77,7 +77,7 @@ 
otel-rules/mysql/mysql-service.yaml=8d912d600c27073a5b4cb14ab4e99869157c1e230274
 
otel-rules/nginx/nginx-endpoint.yaml=5c8ff99f9324faa8451f32cadd9d14c247e3fffc72cb717295eae7e428a907f9
 
otel-rules/nginx/nginx-instance.yaml=999269ade04346cc22dbcd1a761128f09afc51c1e44ea0a01ba333caee19190c
 
otel-rules/nginx/nginx-service.yaml=fdacf1236821635763a601e5146d042c3aa10db69c631e115b8d08a68e9ba896
-otel-rules/oap.yaml=69499222f5897af16d3d42c082420403d053d19b38888006786f59cbfd65f216
+otel-rules/oap.yaml=6a61b77b0200ac35fac18d9cd3cfca425c6009461e58a8b9d5040ff6c0410d08
 
otel-rules/postgresql/postgresql-instance.yaml=6e060619d9f9c0fff5607cc59207e9bafd8f1767cd3dcdee48fe4561644388d3
 
otel-rules/postgresql/postgresql-service.yaml=8c19e9b218241c0c4deb2affd863a2a36950be90b93867002deef427a417a412
 
otel-rules/pulsar/pulsar-broker.yaml=eec34a2a75efdbd59830743c8b8e2584bfcb2ab769dac3b4506534b758fecb16
diff --git 
a/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties 
b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
index 17cee20..70d746e 100644
--- a/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
+++ b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
@@ -35,7 +35,7 @@ 
skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server
 
skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleConfig.java
 = f17b294a952670c00ef0b26059cc7fdf458ced0861c5c00210594ba4953edf30
 # Java-backed closures instead of GroovyShell
 
skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
 = ffadc2cb0a3cfe85b53b3d7fbd74505c7e528f187fd6dc615ede523642bb6c26
-skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
 = 600eaa0c5f5d873792997ece22fb4560e422b987d374d0ea0667e855b4f28d96
+skywalking/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
 = f4fc740467b43741e6813ad8cb94bdc42e63965455627bb147faafaf97a76e77
 
 # --- meter-analyzer-for-graalvm ---
 # MAL DSL: loads transpiled MalExpression from manifest
@@ -78,6 +78,8 @@ 
skywalking/oap-server/server-library/library-module/src/main/java/org/apache/sky
 # --- library-util-for-graalvm ---
 # Config loading: type-dispatch with Lombok setters instead of reflection
 
skywalking/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
 = 041a64c32e0296cc799e12d192d4f15bdec83ac5660cc01dc00fd57734a64768
+# Virtual threads: direct JDK 25 API calls instead of reflection
+skywalking/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/VirtualThreads.java
 = 79c6a30a0843893bb68f45592f7fde21f3ccfe3e726c3ef8413e397023b766b4
 
 # --- Config-only replacements (added @Setter at class level) ---
 
skywalking/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/EnvoyMetricReceiverConfig.java
 = 2113f0e0c214ec002ba94d8dd06d1ba929c7f54f111266982d1da77c6574c485
diff --git a/oap-libs-for-graalvm/CLAUDE.md b/oap-libs-for-graalvm/CLAUDE.md
index b49bbc7..8de4821 100644
--- a/oap-libs-for-graalvm/CLAUDE.md
+++ b/oap-libs-for-graalvm/CLAUDE.md
@@ -95,11 +95,15 @@ JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal 
make build-distro
 |---|---|---|---|
 | `ModuleDefine` | `library-module/.../module/ModuleDefine.java` | Added 
`prepare()` overload for direct provider wiring | **Yes** |
 
-### library-util-for-graalvm (0 classes, shade-only)
+### library-util-for-graalvm (1 class)
 
-No replacement Java sources. Uses shade plugin to exclude 
`YamlConfigLoaderUtils`,
-`ResourceUtils`, `FieldsHelper` from upstream JAR. The replacements for these 
live
-in `oap-graalvm-server/` (due to 30+ cross-module imports).
+| Replacement Class | Upstream Source | Change | Staleness Tracked |
+|---|---|---|---|
+| `VirtualThreads` | `library-util/.../util/VirtualThreads.java` | Direct JDK 
25 API calls instead of reflection | **Yes** |
+
+Also uses shade plugin to exclude `YamlConfigLoaderUtils`, `ResourceUtils`,
+`FieldsHelper` from upstream JAR. The replacements for those live in
+`oap-graalvm-server/` (due to 30+ cross-module imports).
 
 ### Config-only replacements (added `@Setter` at class level)
 
diff --git a/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
index ab03e5b..38ee55e 100644
--- a/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
@@ -61,6 +61,7 @@
                                 
<exclude>org/apache/skywalking/oap/server/library/util/ResourceUtils.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/server/library/util/FieldsHelper.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/server/library/util/FieldsHelper$*.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/server/library/util/VirtualThreads.class</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git 
a/oap-libs-for-graalvm/library-util-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/util/VirtualThreads.java
 
b/oap-libs-for-graalvm/library-util-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/util/VirtualThreads.java
new file mode 100644
index 0000000..c51e005
--- /dev/null
+++ 
b/oap-libs-for-graalvm/library-util-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/util/VirtualThreads.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.server.library.util;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.function.Supplier;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * GraalVM replacement for upstream VirtualThreads.
+ * Original: 
skywalking/oap-server/server-library/library-util/src/main/java/.../util/VirtualThreads.java
+ *
+ * <p>Change: Calls JDK 25 virtual thread APIs directly instead of reflection.
+ * This distro targets JDK 25 exclusively, so no reflection needed.
+ * <p>Why: Reflection-based method handles are not needed when the target JDK 
is fixed,
+ * and direct calls are GraalVM native-image friendly.
+ */
+@Slf4j
+public final class VirtualThreads {
+
+    static final int MINIMUM_JDK_VERSION = 25;
+    static final String ENV_VIRTUAL_THREADS_ENABLED = 
"SW_VIRTUAL_THREADS_ENABLED";
+
+    private static final boolean SUPPORTED;
+
+    static {
+        final String envValue = System.getenv(ENV_VIRTUAL_THREADS_ENABLED);
+        final boolean disabledByEnv = "false".equalsIgnoreCase(envValue);
+
+        if (disabledByEnv) {
+            log.info("Virtual threads disabled by environment variable {}={}",
+                     ENV_VIRTUAL_THREADS_ENABLED, envValue);
+            SUPPORTED = false;
+        } else {
+            SUPPORTED = true;
+            log.info("Virtual threads available (JDK {})", 
Runtime.version().feature());
+        }
+    }
+
+    private VirtualThreads() {
+    }
+
+    public static boolean isSupported() {
+        return SUPPORTED;
+    }
+
+    public static ExecutorService createExecutor(final String namePrefix,
+                                                 final 
Supplier<ExecutorService> platformExecutorSupplier) {
+        return createExecutor(namePrefix, true, platformExecutorSupplier);
+    }
+
+    public static ExecutorService createExecutor(final String namePrefix,
+                                                 final boolean 
enableVirtualThreads,
+                                                 final 
Supplier<ExecutorService> platformExecutorSupplier) {
+        if (enableVirtualThreads && SUPPORTED) {
+            return createVirtualThreadExecutor(namePrefix);
+        }
+        return platformExecutorSupplier.get();
+    }
+
+    public static ScheduledExecutorService createScheduledExecutor(
+            final String namePrefix,
+            final Supplier<ScheduledExecutorService> platformExecutorSupplier) 
{
+        if (SUPPORTED) {
+            final ExecutorService vtExecutor = 
createVirtualThreadExecutor(namePrefix);
+            return new VirtualThreadScheduledExecutor(vtExecutor);
+        }
+        return platformExecutorSupplier.get();
+    }
+
+    private static ExecutorService createVirtualThreadExecutor(final String 
namePrefix) {
+        final ThreadFactory factory = Thread.ofVirtual()
+            .name("vt:" + namePrefix + "-", 0)
+            .factory();
+        final ExecutorService executor = 
Executors.newThreadPerTaskExecutor(factory);
+        log.info("Created virtual-thread-per-task executor [{}]", namePrefix);
+        return executor;
+    }
+}
diff --git 
a/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
 
b/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
index a2c0b16..5d881f9 100644
--- 
a/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
+++ 
b/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
+import org.apache.skywalking.oap.server.library.util.VirtualThreads;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.CoreModule;
@@ -122,10 +123,16 @@ public class HierarchyService implements 
org.apache.skywalking.oap.server.librar
         if (!this.isEnableHierarchy) {
             return;
         }
-        Executors.newSingleThreadScheduledExecutor()
-                 .scheduleWithFixedDelay(
-                     new 
RunnableWithExceptionProtection(this::autoMatchingServiceRelation, t -> 
log.error(
-                         "Scheduled auto matching service hierarchy from 
service traffic failure.", t)), 30, 20, TimeUnit.SECONDS);
+        VirtualThreads.createScheduledExecutor(
+                          "HierarchyAutoMatching",
+                          () -> Executors.newSingleThreadScheduledExecutor(r 
-> {
+                              final Thread t = new Thread(r, 
"HierarchyAutoMatching");
+                              t.setDaemon(true);
+                              return t;
+                          }))
+                      .scheduleWithFixedDelay(
+                          new 
RunnableWithExceptionProtection(this::autoMatchingServiceRelation, t -> 
log.error(
+                              "Scheduled auto matching service hierarchy from 
service traffic failure.", t)), 30, 20, TimeUnit.SECONDS);
     }
 
     private void autoMatchingServiceRelation(String upperServiceName,
diff --git a/skywalking b/skywalking
index b537891..a0cec0c 160000
--- a/skywalking
+++ b/skywalking
@@ -1 +1 @@
-Subproject commit b5378919288e4e7992a0a794fa0126ff29a42702
+Subproject commit a0cec0ca237792497d2da0b65757d11f58c3f342


Reply via email to