From c40ab3e9c88233f365f1f0b825597944e2b8a2f6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 06:50:21 +0000 Subject: [PATCH 01/40] Add performance results for commit e6ca15a18f62837564202a548f294c32aa3ca28f --- ...f62837564202a548f294c32aa3ca28f-jdk17.json | 1279 +++++++++++++++++ 1 file changed, 1279 insertions(+) create mode 100644 performance-results/2025-09-22T06:49:47Z-e6ca15a18f62837564202a548f294c32aa3ca28f-jdk17.json diff --git a/performance-results/2025-09-22T06:49:47Z-e6ca15a18f62837564202a548f294c32aa3ca28f-jdk17.json b/performance-results/2025-09-22T06:49:47Z-e6ca15a18f62837564202a548f294c32aa3ca28f-jdk17.json new file mode 100644 index 000000000..cc943175a --- /dev/null +++ b/performance-results/2025-09-22T06:49:47Z-e6ca15a18f62837564202a548f294c32aa3ca28f-jdk17.json @@ -0,0 +1,1279 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "5" + }, + "primaryMetric" : { + "score" : 3.3496359760769683, + "scoreError" : 0.029788854925604347, + "scoreConfidence" : [ + 3.319847121151364, + 3.3794248310025727 + ], + "scorePercentiles" : { + "0.0" : 3.343058943697042, + "50.0" : 3.35086586116409, + "90.0" : 3.353753238282651, + "95.0" : 3.353753238282651, + "99.0" : 3.353753238282651, + "99.9" : 3.353753238282651, + "99.99" : 3.353753238282651, + "99.999" : 3.353753238282651, + "99.9999" : 3.353753238282651, + "100.0" : 3.353753238282651 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.343058943697042, + 3.351374753228679 + ], + [ + 3.3503569690995008, + 3.353753238282651 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "10" + }, + "primaryMetric" : { + "score" : 1.697293564229039, + "scoreError" : 0.01614358808624621, + "scoreConfidence" : [ + 1.6811499761427928, + 1.7134371523152852 + ], + "scorePercentiles" : { + "0.0" : 1.6938488115852268, + "50.0" : 1.6977982046674653, + "90.0" : 1.6997290359959976, + "95.0" : 1.6997290359959976, + "99.0" : 1.6997290359959976, + "99.9" : 1.6997290359959976, + "99.99" : 1.6997290359959976, + "99.999" : 1.6997290359959976, + "99.9999" : 1.6997290359959976, + "100.0" : 1.6997290359959976 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.6938488115852268, + 1.6982545015866084 + ], + [ + 1.6973419077483225, + 1.6997290359959976 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "20" + }, + "primaryMetric" : { + "score" : 0.8520049747056817, + "scoreError" : 0.030893589196560628, + "scoreConfidence" : [ + 0.8211113855091211, + 0.8828985639022423 + ], + "scorePercentiles" : { + "0.0" : 0.8474798972464561, + "50.0" : 0.8511394310643619, + "90.0" : 0.8582611394475472, + "95.0" : 0.8582611394475472, + "99.0" : 0.8582611394475472, + "99.9" : 0.8582611394475472, + "99.99" : 0.8582611394475472, + "99.999" : 0.8582611394475472, + "99.9999" : 0.8582611394475472, + "100.0" : 0.8582611394475472 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.8530700245322967, + 0.8582611394475472 + ], + [ + 0.8474798972464561, + 0.8492088375964268 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 16.485860471979176, + "scoreError" : 0.03824936393164474, + "scoreConfidence" : [ + 16.447611108047532, + 16.52410983591082 + ], + "scorePercentiles" : { + "0.0" : 16.470186216833234, + "50.0" : 16.48226527396083, + "90.0" : 16.502570084543326, + "95.0" : 16.502570084543326, + "99.0" : 16.502570084543326, + "99.9" : 16.502570084543326, + "99.99" : 16.502570084543326, + "99.999" : 16.502570084543326, + "99.9999" : 16.502570084543326, + "100.0" : 16.502570084543326 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 16.475557891676782, + 16.502570084543326, + 16.502318090900054 + ], + [ + 16.470186216833234, + 16.48114282263713, + 16.483387725284533 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput_getImmediateFields", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2708.268536915973, + "scoreError" : 36.22216052793814, + "scoreConfidence" : [ + 2672.046376388035, + 2744.4906974439114 + ], + "scorePercentiles" : { + "0.0" : 2694.8842638461924, + "50.0" : 2708.0160123297355, + "90.0" : 2721.595279935854, + "95.0" : 2721.595279935854, + "99.0" : 2721.595279935854, + "99.9" : 2721.595279935854, + "99.99" : 2721.595279935854, + "99.999" : 2721.595279935854, + "99.9999" : 2721.595279935854, + "100.0" : 2721.595279935854 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 2694.8842638461924, + 2696.2368011489557, + 2698.688130371997 + ], + [ + 2717.3438942874736, + 2721.595279935854, + 2720.8628519053696 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 75945.7787225041, + "scoreError" : 1641.990158273962, + "scoreConfidence" : [ + 74303.78856423014, + 77587.76888077805 + ], + "scorePercentiles" : { + "0.0" : 75367.44129599974, + "50.0" : 75953.8848213015, + "90.0" : 76492.38929076183, + "95.0" : 76492.38929076183, + "99.0" : 76492.38929076183, + "99.9" : 76492.38929076183, + "99.99" : 76492.38929076183, + "99.999" : 76492.38929076183, + "99.9999" : 76492.38929076183, + "100.0" : 76492.38929076183 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 76492.38929076183, + 76474.04136730185, + 76473.00932650767 + ], + [ + 75367.44129599974, + 75433.03073835814, + 75434.76031609531 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 343.77591293827754, + "scoreError" : 2.8901245861991076, + "scoreConfidence" : [ + 340.8857883520784, + 346.6660375244767 + ], + "scorePercentiles" : { + "0.0" : 342.56633371119176, + "50.0" : 343.6449839679681, + "90.0" : 345.59208372253556, + "95.0" : 345.59208372253556, + "99.0" : 345.59208372253556, + "99.9" : 345.59208372253556, + "99.99" : 345.59208372253556, + "99.999" : 345.59208372253556, + "99.9999" : 345.59208372253556, + "100.0" : 345.59208372253556 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 345.59208372253556, + 343.1261078956025, + 344.0809843643991 + ], + [ + 342.56633371119176, + 343.64546775983484, + 343.64450017610136 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 114.32659320091456, + "scoreError" : 2.960395654273195, + "scoreConfidence" : [ + 111.36619754664136, + 117.28698885518776 + ], + "scorePercentiles" : { + "0.0" : 112.65183532479064, + "50.0" : 114.83129812160851, + "90.0" : 115.29110592527894, + "95.0" : 115.29110592527894, + "99.0" : 115.29110592527894, + "99.9" : 115.29110592527894, + "99.99" : 115.29110592527894, + "99.999" : 115.29110592527894, + "99.9999" : 115.29110592527894, + "100.0" : 115.29110592527894 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 113.37669102214478, + 112.65183532479064, + 115.29110592527894 + ], + [ + 114.7977916119232, + 114.86480463129382, + 114.97733069005595 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.06159744638230849, + "scoreError" : 0.001637280741300189, + "scoreConfidence" : [ + 0.059960165641008305, + 0.06323472712360868 + ], + "scorePercentiles" : { + "0.0" : 0.06102665141427394, + "50.0" : 0.061625093759965575, + "90.0" : 0.062142634860367134, + "95.0" : 0.062142634860367134, + "99.0" : 0.062142634860367134, + "99.9" : 0.062142634860367134, + "99.99" : 0.062142634860367134, + "99.999" : 0.062142634860367134, + "99.9999" : 0.062142634860367134, + "100.0" : 0.062142634860367134 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.06213141885779611, + 0.06211351735425285, + 0.062142634860367134 + ], + [ + 0.0610337856414826, + 0.0611366701656783, + 0.06102665141427394 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime_getImmediateFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3.739469346231514E-4, + "scoreError" : 1.4079256770433099E-5, + "scoreConfidence" : [ + 3.598676778527183E-4, + 3.880261913935845E-4 + ], + "scorePercentiles" : { + "0.0" : 3.684522013233481E-4, + "50.0" : 3.741899766392553E-4, + "90.0" : 3.785810440056022E-4, + "95.0" : 3.785810440056022E-4, + "99.0" : 3.785810440056022E-4, + "99.9" : 3.785810440056022E-4, + "99.99" : 3.785810440056022E-4, + "99.999" : 3.785810440056022E-4, + "99.9999" : 3.785810440056022E-4, + "100.0" : 3.785810440056022E-4 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.7843791332732303E-4, + 3.785810440056022E-4, + 3.784986528433399E-4 + ], + [ + 3.6994203995118754E-4, + 3.697697562881073E-4, + 3.684522013233481E-4 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DataLoaderPerformance.executeRequestWithDataLoaders", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.521398443060576, + "scoreError" : 0.08910038705621467, + "scoreConfidence" : [ + 2.432298056004361, + 2.6104988301167906 + ], + "scorePercentiles" : { + "0.0" : 2.4864232282446546, + "50.0" : 2.51697658935123, + "90.0" : 2.5723473112139916, + "95.0" : 2.5723473112139916, + "99.0" : 2.5723473112139916, + "99.9" : 2.5723473112139916, + "99.99" : 2.5723473112139916, + "99.999" : 2.5723473112139916, + "99.9999" : 2.5723473112139916, + "100.0" : 2.5723473112139916 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.5398777447943117, + 2.495789195408036, + 2.4864232282446546 + ], + [ + 2.5723473112139916, + 2.5267867046488126, + 2.5071664740536477 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.013080461824156937, + "scoreError" : 8.680639739726075E-5, + "scoreConfidence" : [ + 0.012993655426759676, + 0.013167268221554198 + ], + "scorePercentiles" : { + "0.0" : 0.013051508657604688, + "50.0" : 0.013078615058292987, + "90.0" : 0.013114501506180124, + "95.0" : 0.013114501506180124, + "99.0" : 0.013114501506180124, + "99.9" : 0.013114501506180124, + "99.99" : 0.013114501506180124, + "99.999" : 0.013114501506180124, + "99.9999" : 0.013114501506180124, + "100.0" : 0.013114501506180124 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.013103365944549925, + 0.013114501506180124, + 0.01310770615436641 + ], + [ + 0.013053864172036049, + 0.013051508657604688, + 0.013051824510204427 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF2Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.1120725154260704, + "scoreError" : 0.2997884248803559, + "scoreConfidence" : [ + 0.8122840905457145, + 1.4118609403064264 + ], + "scorePercentiles" : { + "0.0" : 1.0134889811511958, + "50.0" : 1.1122757973107193, + "90.0" : 1.2105479820844933, + "95.0" : 1.2105479820844933, + "99.0" : 1.2105479820844933, + "99.9" : 1.2105479820844933, + "99.99" : 1.2105479820844933, + "99.999" : 1.2105479820844933, + "99.9999" : 1.2105479820844933, + "100.0" : 1.2105479820844933 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 1.2092566726723095, + 1.2091833881030105, + 1.2105479820844933 + ], + [ + 1.0134889811511958, + 1.0153682065184282, + 1.014589862026986 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "2" + }, + "primaryMetric" : { + "score" : 0.010576567943549407, + "scoreError" : 8.01183711594851E-4, + "scoreConfidence" : [ + 0.009775384231954556, + 0.011377751655144258 + ], + "scorePercentiles" : { + "0.0" : 0.010312777170942587, + "50.0" : 0.01057730979818363, + "90.0" : 0.010839297513960667, + "95.0" : 0.010839297513960667, + "99.0" : 0.010839297513960667, + "99.9" : 0.010839297513960667, + "99.99" : 0.010839297513960667, + "99.999" : 0.010839297513960667, + "99.9999" : 0.010839297513960667, + "100.0" : 0.010839297513960667 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.010833619389952724, + 0.010839175763382773, + 0.010839297513960667 + ], + [ + 0.010313537616643153, + 0.010321000206414539, + 0.010312777170942587 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "10" + }, + "primaryMetric" : { + "score" : 3.1242275525570045, + "scoreError" : 0.09976646116987556, + "scoreConfidence" : [ + 3.024461091387129, + 3.22399401372688 + ], + "scorePercentiles" : { + "0.0" : 3.0899167770228537, + "50.0" : 3.117203892057417, + "90.0" : 3.1720970196575777, + "95.0" : 3.1720970196575777, + "99.0" : 3.1720970196575777, + "99.9" : 3.1720970196575777, + "99.99" : 3.1720970196575777, + "99.999" : 3.1720970196575777, + "99.9999" : 3.1720970196575777, + "100.0" : 3.1720970196575777 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.0899167770228537, + 3.102748251240695, + 3.09024156145769 + ], + [ + 3.131659532874139, + 3.1720970196575777, + 3.1587021730890714 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.8942256093892915, + "scoreError" : 0.1132928813899829, + "scoreConfidence" : [ + 2.780932727999309, + 3.0075184907792742 + ], + "scorePercentiles" : { + "0.0" : 2.8483187761321562, + "50.0" : 2.891599411155812, + "90.0" : 2.9406392446339313, + "95.0" : 2.9406392446339313, + "99.0" : 2.9406392446339313, + "99.9" : 2.9406392446339313, + "99.99" : 2.9406392446339313, + "99.999" : 2.9406392446339313, + "99.9999" : 2.9406392446339313, + "100.0" : 2.9406392446339313 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.862741448769319, + 2.8634743844832524, + 2.8483187761321562 + ], + [ + 2.9406392446339313, + 2.9304553644887195, + 2.9197244378283713 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkDeepAbstractConcrete", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.18359464893897617, + "scoreError" : 0.026735088381444335, + "scoreConfidence" : [ + 0.15685956055753184, + 0.2103297373204205 + ], + "scorePercentiles" : { + "0.0" : 0.17404164472058337, + "50.0" : 0.1838341954352512, + "90.0" : 0.192449687739353, + "95.0" : 0.192449687739353, + "99.0" : 0.192449687739353, + "99.9" : 0.192449687739353, + "99.99" : 0.192449687739353, + "99.999" : 0.192449687739353, + "99.9999" : 0.192449687739353, + "100.0" : 0.192449687739353 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.17554534597222954, + 0.17404164472058337, + 0.1751231626506024 + ], + [ + 0.192449687739353, + 0.19228500765281598, + 0.19212304489827284 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.3291284158749855, + "scoreError" : 0.02890070010517245, + "scoreConfidence" : [ + 0.30022771576981305, + 0.3580291159801579 + ], + "scorePercentiles" : { + "0.0" : 0.3196283847284815, + "50.0" : 0.32861018854278434, + "90.0" : 0.33912732657352146, + "95.0" : 0.33912732657352146, + "99.0" : 0.33912732657352146, + "99.9" : 0.33912732657352146, + "99.99" : 0.33912732657352146, + "99.999" : 0.33912732657352146, + "99.9999" : 0.33912732657352146, + "100.0" : 0.33912732657352146 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.3373141362026512, + 0.33910977202441506, + 0.33912732657352146 + ], + [ + 0.3196283847284815, + 0.319684634837926, + 0.31990624088291747 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.1479364146788637, + "scoreError" : 0.009020044394819867, + "scoreConfidence" : [ + 0.13891637028404383, + 0.15695645907368358 + ], + "scorePercentiles" : { + "0.0" : 0.14518249499128918, + "50.0" : 0.14735536607677147, + "90.0" : 0.15293019727485435, + "95.0" : 0.15293019727485435, + "99.0" : 0.15293019727485435, + "99.9" : 0.15293019727485435, + "99.99" : 0.15293019727485435, + "99.999" : 0.15293019727485435, + "99.9999" : 0.15293019727485435, + "100.0" : 0.15293019727485435 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.15293019727485435, + 0.14958367144823048, + 0.14940442916903218 + ], + [ + 0.14521139220526522, + 0.14518249499128918, + 0.14530630298451078 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.39726246744718513, + "scoreError" : 0.009123819141630388, + "scoreConfidence" : [ + 0.3881386483055547, + 0.40638628658881554 + ], + "scorePercentiles" : { + "0.0" : 0.3947651694694458, + "50.0" : 0.3953507804131454, + "90.0" : 0.40206225666385237, + "95.0" : 0.40206225666385237, + "99.0" : 0.40206225666385237, + "99.9" : 0.40206225666385237, + "99.99" : 0.40206225666385237, + "99.999" : 0.40206225666385237, + "99.9999" : 0.40206225666385237, + "100.0" : 0.40206225666385237 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.39526718150197626, + 0.39531371629046924, + 0.3947651694694458 + ], + [ + 0.40206225666385237, + 0.40077863622154536, + 0.3953878445358216 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.15360524371981474, + "scoreError" : 0.002750173499502835, + "scoreConfidence" : [ + 0.15085507022031192, + 0.15635541721931756 + ], + "scorePercentiles" : { + "0.0" : 0.1516243314734512, + "50.0" : 0.15395947178698044, + "90.0" : 0.15416787229056825, + "95.0" : 0.15416787229056825, + "99.0" : 0.15416787229056825, + "99.9" : 0.15416787229056825, + "99.99" : 0.15416787229056825, + "99.999" : 0.15416787229056825, + "99.9999" : 0.15416787229056825, + "100.0" : 0.15416787229056825 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.15416787229056825, + 0.1538382793981909, + 0.1538252192893401 + ], + [ + 0.15408066417577, + 0.15409509569156804, + 0.1516243314734512 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkRepeatedFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.04662359449964403, + "scoreError" : 0.0017915052564357013, + "scoreConfidence" : [ + 0.044832089243208334, + 0.04841509975607973 + ], + "scorePercentiles" : { + "0.0" : 0.0460147077878753, + "50.0" : 0.04660958504281068, + "90.0" : 0.04731384416960796, + "95.0" : 0.04731384416960796, + "99.0" : 0.04731384416960796, + "99.9" : 0.04731384416960796, + "99.99" : 0.04731384416960796, + "99.999" : 0.04731384416960796, + "99.9999" : 0.04731384416960796, + "100.0" : 0.04731384416960796 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.04731384416960796, + 0.04715483416796341, + 0.0471430772853486 + ], + [ + 0.04603901078679619, + 0.0460147077878753, + 0.046076092800272764 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 8751847.78459636, + "scoreError" : 215597.68497896375, + "scoreConfidence" : [ + 8536250.099617396, + 8967445.469575323 + ], + "scorePercentiles" : { + "0.0" : 8678622.612315698, + "50.0" : 8750421.270949967, + "90.0" : 8833320.883495146, + "95.0" : 8833320.883495146, + "99.0" : 8833320.883495146, + "99.9" : 8833320.883495146, + "99.99" : 8833320.883495146, + "99.999" : 8833320.883495146, + "99.9999" : 8833320.883495146, + "100.0" : 8833320.883495146 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 8686107.290798612, + 8678622.612315698, + 8681088.158854166 + ], + [ + 8833320.883495146, + 8814735.251101322, + 8817212.511013215 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + From cb6f0e262f5f518a0be11f0a45581a974c4f8ae5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 16:04:04 +0000 Subject: [PATCH 02/40] Bump com.uber.nullaway:nullaway from 0.12.9 to 0.12.10 Bumps [com.uber.nullaway:nullaway](https://github.com/uber/NullAway) from 0.12.9 to 0.12.10. - [Release notes](https://github.com/uber/NullAway/releases) - [Changelog](https://github.com/uber/NullAway/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber/NullAway/compare/v0.12.9...v0.12.10) --- updated-dependencies: - dependency-name: com.uber.nullaway:nullaway dependency-version: 0.12.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8cc48c3a7..2dfa1ef12 100644 --- a/build.gradle +++ b/build.gradle @@ -155,7 +155,7 @@ dependencies { // comment this in if you want to run JMH benchmarks from idea // jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.37' - errorprone 'com.uber.nullaway:nullaway:0.12.9' + errorprone 'com.uber.nullaway:nullaway:0.12.10' errorprone 'com.google.errorprone:error_prone_core:2.41.0' // just tests - no Kotlin otherwise From 929ac69a9bf0dc2b5948776d18131b20767b2d4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 16:04:07 +0000 Subject: [PATCH 03/40] Bump com.google.errorprone:error_prone_core from 2.41.0 to 2.42.0 Bumps [com.google.errorprone:error_prone_core](https://github.com/google/error-prone) from 2.41.0 to 2.42.0. - [Release notes](https://github.com/google/error-prone/releases) - [Commits](https://github.com/google/error-prone/compare/v2.41.0...v2.42.0) --- updated-dependencies: - dependency-name: com.google.errorprone:error_prone_core dependency-version: 2.42.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8cc48c3a7..a4fa87ab5 100644 --- a/build.gradle +++ b/build.gradle @@ -156,7 +156,7 @@ dependencies { // jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.37' errorprone 'com.uber.nullaway:nullaway:0.12.9' - errorprone 'com.google.errorprone:error_prone_core:2.41.0' + errorprone 'com.google.errorprone:error_prone_core:2.42.0' // just tests - no Kotlin otherwise testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' From e862e23e271549ce0b247a2924b1cdf73ddb5131 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 21:17:48 +0000 Subject: [PATCH 04/40] Add performance results for commit 8e4f4596733814ad92020cfcc5171448a0be2e1a --- ...33814ad92020cfcc5171448a0be2e1a-jdk17.json | 1279 +++++++++++++++++ 1 file changed, 1279 insertions(+) create mode 100644 performance-results/2025-09-22T21:17:24Z-8e4f4596733814ad92020cfcc5171448a0be2e1a-jdk17.json diff --git a/performance-results/2025-09-22T21:17:24Z-8e4f4596733814ad92020cfcc5171448a0be2e1a-jdk17.json b/performance-results/2025-09-22T21:17:24Z-8e4f4596733814ad92020cfcc5171448a0be2e1a-jdk17.json new file mode 100644 index 000000000..d28d86635 --- /dev/null +++ b/performance-results/2025-09-22T21:17:24Z-8e4f4596733814ad92020cfcc5171448a0be2e1a-jdk17.json @@ -0,0 +1,1279 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "5" + }, + "primaryMetric" : { + "score" : 3.314022811691902, + "scoreError" : 0.0541966896066759, + "scoreConfidence" : [ + 3.2598261220852263, + 3.368219501298578 + ], + "scorePercentiles" : { + "0.0" : 3.304194048355106, + "50.0" : 3.313707183089784, + "90.0" : 3.324482832232933, + "95.0" : 3.324482832232933, + "99.0" : 3.324482832232933, + "99.9" : 3.324482832232933, + "99.99" : 3.324482832232933, + "99.999" : 3.324482832232933, + "99.9999" : 3.324482832232933, + "100.0" : 3.324482832232933 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.304194048355106, + 3.3152578813872067 + ], + [ + 3.312156484792362, + 3.324482832232933 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "10" + }, + "primaryMetric" : { + "score" : 1.6712603261970465, + "scoreError" : 0.018142346406554506, + "scoreConfidence" : [ + 1.653117979790492, + 1.6894026726036009 + ], + "scorePercentiles" : { + "0.0" : 1.668586385117959, + "50.0" : 1.6708547696159761, + "90.0" : 1.6747453804382741, + "95.0" : 1.6747453804382741, + "99.0" : 1.6747453804382741, + "99.9" : 1.6747453804382741, + "99.99" : 1.6747453804382741, + "99.999" : 1.6747453804382741, + "99.9999" : 1.6747453804382741, + "100.0" : 1.6747453804382741 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.6694365904564337, + 1.6747453804382741 + ], + [ + 1.668586385117959, + 1.6722729487755186 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "20" + }, + "primaryMetric" : { + "score" : 0.8394464879842283, + "scoreError" : 0.02129677653453746, + "scoreConfidence" : [ + 0.8181497114496908, + 0.8607432645187657 + ], + "scorePercentiles" : { + "0.0" : 0.8354426843180475, + "50.0" : 0.8397314013517216, + "90.0" : 0.8428804649154225, + "95.0" : 0.8428804649154225, + "99.0" : 0.8428804649154225, + "99.9" : 0.8428804649154225, + "99.99" : 0.8428804649154225, + "99.999" : 0.8428804649154225, + "99.9999" : 0.8428804649154225, + "100.0" : 0.8428804649154225 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.8354426843180475, + 0.8428804649154225 + ], + [ + 0.841247962885109, + 0.8382148398183343 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 16.011288148980004, + "scoreError" : 0.5018285430660081, + "scoreConfidence" : [ + 15.509459605913996, + 16.51311669204601 + ], + "scorePercentiles" : { + "0.0" : 15.777353748640426, + "50.0" : 16.025052167576717, + "90.0" : 16.20868747168987, + "95.0" : 16.20868747168987, + "99.0" : 16.20868747168987, + "99.9" : 16.20868747168987, + "99.99" : 16.20868747168987, + "99.999" : 16.20868747168987, + "99.9999" : 16.20868747168987, + "100.0" : 16.20868747168987 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 16.20868747168987, + 16.179384309471292, + 16.104082184327684 + ], + [ + 15.777353748640426, + 15.852199028925018, + 15.946022150825748 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput_getImmediateFields", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2733.465575211411, + "scoreError" : 151.73841292032816, + "scoreConfidence" : [ + 2581.7271622910825, + 2885.203988131739 + ], + "scorePercentiles" : { + "0.0" : 2674.5303194476496, + "50.0" : 2737.309498514745, + "90.0" : 2790.6696012687553, + "95.0" : 2790.6696012687553, + "99.0" : 2790.6696012687553, + "99.9" : 2790.6696012687553, + "99.99" : 2790.6696012687553, + "99.999" : 2790.6696012687553, + "99.9999" : 2790.6696012687553, + "100.0" : 2790.6696012687553 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 2790.6696012687553, + 2785.7195478920985, + 2766.8564123439705 + ], + [ + 2707.7625846855194, + 2674.5303194476496, + 2675.2549856304727 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 76531.1384609008, + "scoreError" : 515.4412416679229, + "scoreConfidence" : [ + 76015.69721923287, + 77046.57970256872 + ], + "scorePercentiles" : { + "0.0" : 76376.08383147985, + "50.0" : 76465.40591084602, + "90.0" : 76871.28084055861, + "95.0" : 76871.28084055861, + "99.0" : 76871.28084055861, + "99.9" : 76871.28084055861, + "99.99" : 76871.28084055861, + "99.999" : 76871.28084055861, + "99.9999" : 76871.28084055861, + "100.0" : 76871.28084055861 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 76473.19417101903, + 76601.77884466675, + 76871.28084055861 + ], + [ + 76457.61765067301, + 76376.08383147985, + 76406.87542700753 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 337.7922444590617, + "scoreError" : 4.036389849878064, + "scoreConfidence" : [ + 333.75585460918364, + 341.82863430893974 + ], + "scorePercentiles" : { + "0.0" : 335.7420165479613, + "50.0" : 337.7801406204766, + "90.0" : 339.61496363944684, + "95.0" : 339.61496363944684, + "99.0" : 339.61496363944684, + "99.9" : 339.61496363944684, + "99.99" : 339.61496363944684, + "99.999" : 339.61496363944684, + "99.9999" : 339.61496363944684, + "100.0" : 339.61496363944684 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 335.7420165479613, + 337.3824893427294, + 336.80328909107857 + ], + [ + 339.03291623493044, + 338.1777918982238, + 339.61496363944684 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 107.73988583126498, + "scoreError" : 7.837746310010851, + "scoreConfidence" : [ + 99.90213952125413, + 115.57763214127584 + ], + "scorePercentiles" : { + "0.0" : 104.42290378696231, + "50.0" : 108.02725454189343, + "90.0" : 111.64004355831095, + "95.0" : 111.64004355831095, + "99.0" : 111.64004355831095, + "99.9" : 111.64004355831095, + "99.99" : 111.64004355831095, + "99.999" : 111.64004355831095, + "99.9999" : 111.64004355831095, + "100.0" : 111.64004355831095 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 104.42290378696231, + 109.56750571822366, + 108.4899662186823 + ], + [ + 104.75435284030613, + 107.56454286510457, + 111.64004355831095 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.06224595222351487, + "scoreError" : 6.995150499724861E-4, + "scoreConfidence" : [ + 0.06154643717354238, + 0.06294546727348735 + ], + "scorePercentiles" : { + "0.0" : 0.0618431342098428, + "50.0" : 0.06223886530851824, + "90.0" : 0.06260241496547536, + "95.0" : 0.06260241496547536, + "99.0" : 0.06260241496547536, + "99.9" : 0.06260241496547536, + "99.99" : 0.06260241496547536, + "99.999" : 0.06260241496547536, + "99.9999" : 0.06260241496547536, + "100.0" : 0.06260241496547536 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.06237238086446704, + 0.06226513855646738, + 0.06260241496547536 + ], + [ + 0.0618431342098428, + 0.06218005268426747, + 0.06221259206056911 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime_getImmediateFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3.7179579434428334E-4, + "scoreError" : 8.041842088100423E-6, + "scoreConfidence" : [ + 3.637539522561829E-4, + 3.798376364323838E-4 + ], + "scorePercentiles" : { + "0.0" : 3.667811652424725E-4, + "50.0" : 3.720500442273067E-4, + "90.0" : 3.7544620580236553E-4, + "95.0" : 3.7544620580236553E-4, + "99.0" : 3.7544620580236553E-4, + "99.9" : 3.7544620580236553E-4, + "99.99" : 3.7544620580236553E-4, + "99.999" : 3.7544620580236553E-4, + "99.9999" : 3.7544620580236553E-4, + "100.0" : 3.7544620580236553E-4 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.7544620580236553E-4, + 3.71340739322794E-4, + 3.667811652424725E-4 + ], + [ + 3.7150468125177785E-4, + 3.731065672434549E-4, + 3.7259540720283556E-4 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DataLoaderPerformance.executeRequestWithDataLoaders", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.6065140423547306, + "scoreError" : 0.0878324362403623, + "scoreConfidence" : [ + 2.5186816061143684, + 2.694346478595093 + ], + "scorePercentiles" : { + "0.0" : 2.5654608116983066, + "50.0" : 2.600502211316018, + "90.0" : 2.6559617652681893, + "95.0" : 2.6559617652681893, + "99.0" : 2.6559617652681893, + "99.9" : 2.6559617652681893, + "99.99" : 2.6559617652681893, + "99.999" : 2.6559617652681893, + "99.9999" : 2.6559617652681893, + "100.0" : 2.6559617652681893 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.5951435586403737, + 2.6058608639916625, + 2.62619703282563 + ], + [ + 2.6559617652681893, + 2.590460221704222, + 2.5654608116983066 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.013068189520707547, + "scoreError" : 4.758208011554296E-5, + "scoreConfidence" : [ + 0.013020607440592004, + 0.013115771600823091 + ], + "scorePercentiles" : { + "0.0" : 0.013047852657811644, + "50.0" : 0.013066306973347515, + "90.0" : 0.013089392061414417, + "95.0" : 0.013089392061414417, + "99.0" : 0.013089392061414417, + "99.9" : 0.013089392061414417, + "99.99" : 0.013089392061414417, + "99.999" : 0.013089392061414417, + "99.9999" : 0.013089392061414417, + "100.0" : 0.013089392061414417 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.013047852657811644, + 0.013069138335855636, + 0.013053069020969437 + ], + [ + 0.013063475610839394, + 0.013089392061414417, + 0.013086209437354746 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF2Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.0458713106870163, + "scoreError" : 0.2555485889654377, + "scoreConfidence" : [ + 0.7903227217215787, + 1.301419899652454 + ], + "scorePercentiles" : { + "0.0" : 0.961285840430645, + "50.0" : 1.0453254822709421, + "90.0" : 1.1320143119764545, + "95.0" : 1.1320143119764545, + "99.0" : 1.1320143119764545, + "99.9" : 1.1320143119764545, + "99.99" : 1.1320143119764545, + "99.999" : 1.1320143119764545, + "99.9999" : 1.1320143119764545, + "100.0" : 1.1320143119764545 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 1.1320143119764545, + 1.1263734874422795, + 1.1287370961625283 + ], + [ + 0.9625396510105871, + 0.9642774770996047, + 0.961285840430645 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "2" + }, + "primaryMetric" : { + "score" : 0.010504882869921947, + "scoreError" : 1.4108359247088276E-4, + "scoreConfidence" : [ + 0.010363799277451064, + 0.01064596646239283 + ], + "scorePercentiles" : { + "0.0" : 0.010447678010476674, + "50.0" : 0.010497536453350269, + "90.0" : 0.0105750908623698, + "95.0" : 0.0105750908623698, + "99.0" : 0.0105750908623698, + "99.9" : 0.0105750908623698, + "99.99" : 0.0105750908623698, + "99.999" : 0.0105750908623698, + "99.9999" : 0.0105750908623698, + "100.0" : 0.0105750908623698 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.010525354146362, + 0.010543129568988965, + 0.0105750908623698 + ], + [ + 0.010468325870995701, + 0.010469718760338538, + 0.010447678010476674 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "10" + }, + "primaryMetric" : { + "score" : 3.159283885424873, + "scoreError" : 0.25586271124217214, + "scoreConfidence" : [ + 2.9034211741827005, + 3.415146596667045 + ], + "scorePercentiles" : { + "0.0" : 3.0489593652439027, + "50.0" : 3.165829379693399, + "90.0" : 3.2517827880364107, + "95.0" : 3.2517827880364107, + "99.0" : 3.2517827880364107, + "99.9" : 3.2517827880364107, + "99.99" : 3.2517827880364107, + "99.999" : 3.2517827880364107, + "99.9999" : 3.2517827880364107, + "100.0" : 3.2517827880364107 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.0489593652439027, + 3.0843352638717634, + 3.0993215855018588 + ], + [ + 3.2389671360103627, + 3.2323371738849387, + 3.2517827880364107 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.9637489833842348, + "scoreError" : 0.05950943704115313, + "scoreConfidence" : [ + 2.9042395463430815, + 3.023258420425388 + ], + "scorePercentiles" : { + "0.0" : 2.9441374901383575, + "50.0" : 2.9602015223628886, + "90.0" : 2.9914487071492672, + "95.0" : 2.9914487071492672, + "99.0" : 2.9914487071492672, + "99.9" : 2.9914487071492672, + "99.99" : 2.9914487071492672, + "99.999" : 2.9914487071492672, + "99.9999" : 2.9914487071492672, + "100.0" : 2.9914487071492672 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.9914487071492672, + 2.981926377161598, + 2.9739274451382696 + ], + [ + 2.946475599587507, + 2.9441374901383575, + 2.944578281130409 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkDeepAbstractConcrete", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.17877283202507357, + "scoreError" : 0.008750092929814521, + "scoreConfidence" : [ + 0.17002273909525906, + 0.1875229249548881 + ], + "scorePercentiles" : { + "0.0" : 0.17687838380175813, + "50.0" : 0.17771275120783386, + "90.0" : 0.1851039395279963, + "95.0" : 0.1851039395279963, + "99.0" : 0.1851039395279963, + "99.9" : 0.1851039395279963, + "99.99" : 0.1851039395279963, + "99.999" : 0.1851039395279963, + "99.9999" : 0.1851039395279963, + "100.0" : 0.1851039395279963 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.1851039395279963, + 0.17779775649391058, + 0.17779605763965436 + ], + [ + 0.17762944477601336, + 0.17743140991110876, + 0.17687838380175813 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.3263847193121482, + "scoreError" : 0.012345491264338093, + "scoreConfidence" : [ + 0.3140392280478101, + 0.3387302105764863 + ], + "scorePercentiles" : { + "0.0" : 0.3217403550929799, + "50.0" : 0.32647665116039054, + "90.0" : 0.3322582626752608, + "95.0" : 0.3322582626752608, + "99.0" : 0.3322582626752608, + "99.9" : 0.3322582626752608, + "99.99" : 0.3322582626752608, + "99.999" : 0.3322582626752608, + "99.9999" : 0.3322582626752608, + "100.0" : 0.3322582626752608 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.3242301800408521, + 0.3218224348651606, + 0.3217403550929799 + ], + [ + 0.3322582626752608, + 0.328723122279929, + 0.32953396091870696 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.145944147393136, + "scoreError" : 0.007036163387471947, + "scoreConfidence" : [ + 0.13890798400566404, + 0.15298031078060795 + ], + "scorePercentiles" : { + "0.0" : 0.14348563015998278, + "50.0" : 0.1459663244243061, + "90.0" : 0.14841178771463764, + "95.0" : 0.14841178771463764, + "99.0" : 0.14841178771463764, + "99.9" : 0.14841178771463764, + "99.99" : 0.14841178771463764, + "99.999" : 0.14841178771463764, + "99.9999" : 0.14841178771463764, + "100.0" : 0.14841178771463764 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.14806305275314255, + 0.1482142547316625, + 0.14841178771463764 + ], + [ + 0.14362056290392072, + 0.14348563015998278, + 0.14386959609546965 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.40635855948103955, + "scoreError" : 0.013269123442330714, + "scoreConfidence" : [ + 0.39308943603870883, + 0.41962768292337027 + ], + "scorePercentiles" : { + "0.0" : 0.39969741011191046, + "50.0" : 0.4078320754049398, + "90.0" : 0.4105838537116111, + "95.0" : 0.4105838537116111, + "99.0" : 0.4105838537116111, + "99.9" : 0.4105838537116111, + "99.99" : 0.4105838537116111, + "99.999" : 0.4105838537116111, + "99.9999" : 0.4105838537116111, + "100.0" : 0.4105838537116111 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.41034722905211324, + 0.4105838537116111, + 0.4099802880862578 + ], + [ + 0.4056838627236218, + 0.4018587132007233, + 0.39969741011191046 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.15945744478336296, + "scoreError" : 0.004099220421924381, + "scoreConfidence" : [ + 0.1553582243614386, + 0.16355666520528733 + ], + "scorePercentiles" : { + "0.0" : 0.15828925202209665, + "50.0" : 0.15894693119756265, + "90.0" : 0.1620532286339329, + "95.0" : 0.1620532286339329, + "99.0" : 0.1620532286339329, + "99.9" : 0.1620532286339329, + "99.99" : 0.1620532286339329, + "99.999" : 0.1620532286339329, + "99.9999" : 0.1620532286339329, + "100.0" : 0.1620532286339329 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.1620532286339329, + 0.16012251917441916, + 0.15943162768637203 + ], + [ + 0.15838580647460365, + 0.15846223470875326, + 0.15828925202209665 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkRepeatedFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.04675981633134168, + "scoreError" : 0.00194891175221639, + "scoreConfidence" : [ + 0.04481090457912529, + 0.04870872808355807 + ], + "scorePercentiles" : { + "0.0" : 0.046050023664688085, + "50.0" : 0.046769634315124944, + "90.0" : 0.047424308945017216, + "95.0" : 0.047424308945017216, + "99.0" : 0.047424308945017216, + "99.9" : 0.047424308945017216, + "99.99" : 0.047424308945017216, + "99.999" : 0.047424308945017216, + "99.9999" : 0.047424308945017216, + "100.0" : 0.047424308945017216 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.04734259124457343, + 0.047424308945017216, + 0.04741010129048775 + ], + [ + 0.0461351954576071, + 0.046050023664688085, + 0.04619667738567647 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 9071387.26860865, + "scoreError" : 861671.6769094984, + "scoreConfidence" : [ + 8209715.591699151, + 9933058.945518149 + ], + "scorePercentiles" : { + "0.0" : 8665944.31629116, + "50.0" : 9088677.52329212, + "90.0" : 9449535.86496695, + "95.0" : 9449535.86496695, + "99.0" : 9449535.86496695, + "99.9" : 9449535.86496695, + "99.99" : 9449535.86496695, + "99.999" : 9449535.86496695, + "99.9999" : 9449535.86496695, + "100.0" : 9449535.86496695 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 8949361.397137746, + 8817460.832599118, + 8665944.31629116 + ], + [ + 9449535.86496695, + 9318027.551210428, + 9227993.649446495 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + From 15953bfca855591faa2f6c701ba575b0f34a1bcb Mon Sep 17 00:00:00 2001 From: bbaker Date: Tue, 23 Sep 2025 11:10:54 +1000 Subject: [PATCH 05/40] 5.0.3 version of dataloader --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a4fa87ab5..f6a17aae6 100644 --- a/build.gradle +++ b/build.gradle @@ -119,7 +119,7 @@ jar { } dependencies { - api 'com.graphql-java:java-dataloader:5.0.2' + api 'com.graphql-java:java-dataloader:5.0.3' api 'org.reactivestreams:reactive-streams:' + reactiveStreamsVersion api "org.jspecify:jspecify:1.0.0" From 1f2021a4622a77fb68746c628b71ef0c7377060d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 02:19:23 +0000 Subject: [PATCH 06/40] Add performance results for commit 2a24cd7606ed6da9e38ab7799ba91643a48235b4 --- ...6ed6da9e38ab7799ba91643a48235b4-jdk17.json | 1279 +++++++++++++++++ 1 file changed, 1279 insertions(+) create mode 100644 performance-results/2025-09-23T02:19:02Z-2a24cd7606ed6da9e38ab7799ba91643a48235b4-jdk17.json diff --git a/performance-results/2025-09-23T02:19:02Z-2a24cd7606ed6da9e38ab7799ba91643a48235b4-jdk17.json b/performance-results/2025-09-23T02:19:02Z-2a24cd7606ed6da9e38ab7799ba91643a48235b4-jdk17.json new file mode 100644 index 000000000..43ae7b889 --- /dev/null +++ b/performance-results/2025-09-23T02:19:02Z-2a24cd7606ed6da9e38ab7799ba91643a48235b4-jdk17.json @@ -0,0 +1,1279 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "5" + }, + "primaryMetric" : { + "score" : 3.3095789782897893, + "scoreError" : 0.04801273377918843, + "scoreConfidence" : [ + 3.261566244510601, + 3.3575917120689778 + ], + "scorePercentiles" : { + "0.0" : 3.299009383359393, + "50.0" : 3.3119763758360063, + "90.0" : 3.315353778127752, + "95.0" : 3.315353778127752, + "99.0" : 3.315353778127752, + "99.9" : 3.315353778127752, + "99.99" : 3.315353778127752, + "99.999" : 3.315353778127752, + "99.9999" : 3.315353778127752, + "100.0" : 3.315353778127752 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.299009383359393, + 3.3141042945798667 + ], + [ + 3.309848457092146, + 3.315353778127752 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "10" + }, + "primaryMetric" : { + "score" : 1.6660827371626785, + "scoreError" : 0.032886787999731326, + "scoreConfidence" : [ + 1.633195949162947, + 1.69896952516241 + ], + "scorePercentiles" : { + "0.0" : 1.661395463297402, + "50.0" : 1.6661021651352073, + "90.0" : 1.6707311550828976, + "95.0" : 1.6707311550828976, + "99.0" : 1.6707311550828976, + "99.9" : 1.6707311550828976, + "99.99" : 1.6707311550828976, + "99.999" : 1.6707311550828976, + "99.9999" : 1.6707311550828976, + "100.0" : 1.6707311550828976 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.6707311550828976, + 1.6702327117552471 + ], + [ + 1.661395463297402, + 1.6619716185151676 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "20" + }, + "primaryMetric" : { + "score" : 0.8356100491743486, + "scoreError" : 0.014578931263266277, + "scoreConfidence" : [ + 0.8210311179110823, + 0.8501889804376148 + ], + "scorePercentiles" : { + "0.0" : 0.8322866494118423, + "50.0" : 0.8364279076296748, + "90.0" : 0.8372977320262023, + "95.0" : 0.8372977320262023, + "99.0" : 0.8372977320262023, + "99.9" : 0.8372977320262023, + "99.99" : 0.8372977320262023, + "99.999" : 0.8372977320262023, + "99.9999" : 0.8372977320262023, + "100.0" : 0.8372977320262023 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.8322866494118423, + 0.8365675414037795 + ], + [ + 0.8372977320262023, + 0.83628827385557 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 15.969170181416553, + "scoreError" : 0.28317620649087805, + "scoreConfidence" : [ + 15.685993974925674, + 16.25234638790743 + ], + "scorePercentiles" : { + "0.0" : 15.814964681233025, + "50.0" : 16.000453808931024, + "90.0" : 16.07259690184377, + "95.0" : 16.07259690184377, + "99.0" : 16.07259690184377, + "99.9" : 16.07259690184377, + "99.99" : 16.07259690184377, + "99.999" : 16.07259690184377, + "99.9999" : 16.07259690184377, + "100.0" : 16.07259690184377 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 15.985024269520867, + 16.0469682946154, + 16.07259690184377 + ], + [ + 15.814964681233025, + 15.879583592945076, + 16.01588334834118 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput_getImmediateFields", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2573.7185257361284, + "scoreError" : 155.4941527711142, + "scoreConfidence" : [ + 2418.224372965014, + 2729.212678507243 + ], + "scorePercentiles" : { + "0.0" : 2515.989393106845, + "50.0" : 2575.658216426219, + "90.0" : 2628.2329781854205, + "95.0" : 2628.2329781854205, + "99.0" : 2628.2329781854205, + "99.9" : 2628.2329781854205, + "99.99" : 2628.2329781854205, + "99.999" : 2628.2329781854205, + "99.9999" : 2628.2329781854205, + "100.0" : 2628.2329781854205 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 2515.989393106845, + 2520.1619941941312, + 2534.4510758798106 + ], + [ + 2616.865356972628, + 2626.6103560779343, + 2628.2329781854205 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 76957.23559403383, + "scoreError" : 758.3029841918509, + "scoreConfidence" : [ + 76198.93260984198, + 77715.53857822568 + ], + "scorePercentiles" : { + "0.0" : 76615.1895682339, + "50.0" : 76975.5722330914, + "90.0" : 77232.2252515146, + "95.0" : 77232.2252515146, + "99.0" : 77232.2252515146, + "99.9" : 77232.2252515146, + "99.99" : 77232.2252515146, + "99.999" : 77232.2252515146, + "99.9999" : 77232.2252515146, + "100.0" : 77232.2252515146 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 76615.1895682339, + 76753.11863462513, + 76781.03610547178 + ], + [ + 77191.7356436466, + 77232.2252515146, + 77170.10836071102 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 339.3236232360392, + "scoreError" : 8.606615040571501, + "scoreConfidence" : [ + 330.7170081954677, + 347.93023827661074 + ], + "scorePercentiles" : { + "0.0" : 334.5973548333436, + "50.0" : 339.1572116456855, + "90.0" : 343.00540044827744, + "95.0" : 343.00540044827744, + "99.0" : 343.00540044827744, + "99.9" : 343.00540044827744, + "99.99" : 343.00540044827744, + "99.999" : 343.00540044827744, + "99.9999" : 343.00540044827744, + "100.0" : 343.00540044827744 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 343.00540044827744, + 342.05211479044726, + 340.12704961842326 + ], + [ + 334.5973548333436, + 338.18737367294773, + 337.97244605279616 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 107.48432849157484, + "scoreError" : 2.5347782155776972, + "scoreConfidence" : [ + 104.94955027599714, + 110.01910670715255 + ], + "scorePercentiles" : { + "0.0" : 106.52150762450255, + "50.0" : 107.12267671091882, + "90.0" : 108.64698423730712, + "95.0" : 108.64698423730712, + "99.0" : 108.64698423730712, + "99.9" : 108.64698423730712, + "99.99" : 108.64698423730712, + "99.999" : 108.64698423730712, + "99.9999" : 108.64698423730712, + "100.0" : 108.64698423730712 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 108.57019407262297, + 106.96512784941628, + 108.64698423730712 + ], + [ + 106.52150762450255, + 107.28022557242136, + 106.92193159317883 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.06211041797514658, + "scoreError" : 9.250884679121894E-4, + "scoreConfidence" : [ + 0.06118532950723439, + 0.06303550644305878 + ], + "scorePercentiles" : { + "0.0" : 0.06164008986346966, + "50.0" : 0.06208369845160775, + "90.0" : 0.0626596128826091, + "95.0" : 0.0626596128826091, + "99.0" : 0.0626596128826091, + "99.9" : 0.0626596128826091, + "99.99" : 0.0626596128826091, + "99.999" : 0.0626596128826091, + "99.9999" : 0.0626596128826091, + "100.0" : 0.0626596128826091 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.06164008986346966, + 0.0620058137997743, + 0.062189594401810926 + ], + [ + 0.0626596128826091, + 0.06212039099024108, + 0.06204700591297442 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime_getImmediateFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3.739201694529456E-4, + "scoreError" : 2.0438533564249867E-5, + "scoreConfidence" : [ + 3.5348163588869576E-4, + 3.943587030171955E-4 + ], + "scorePercentiles" : { + "0.0" : 3.6694989062872446E-4, + "50.0" : 3.7334034521908216E-4, + "90.0" : 3.8152067934462986E-4, + "95.0" : 3.8152067934462986E-4, + "99.0" : 3.8152067934462986E-4, + "99.9" : 3.8152067934462986E-4, + "99.99" : 3.8152067934462986E-4, + "99.999" : 3.8152067934462986E-4, + "99.9999" : 3.8152067934462986E-4, + "100.0" : 3.8152067934462986E-4 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.6708994313204075E-4, + 3.6694989062872446E-4, + 3.679656095995706E-4 + ], + [ + 3.787150808385938E-4, + 3.8127981317411425E-4, + 3.8152067934462986E-4 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DataLoaderPerformance.executeRequestWithDataLoaders", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.708733128936368, + "scoreError" : 0.09480710099463438, + "scoreConfidence" : [ + 2.6139260279417336, + 2.803540229931002 + ], + "scorePercentiles" : { + "0.0" : 2.6735564448008553, + "50.0" : 2.706927408088565, + "90.0" : 2.7574730093741384, + "95.0" : 2.7574730093741384, + "99.0" : 2.7574730093741384, + "99.9" : 2.7574730093741384, + "99.99" : 2.7574730093741384, + "99.999" : 2.7574730093741384, + "99.9999" : 2.7574730093741384, + "100.0" : 2.7574730093741384 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.7574730093741384, + 2.723458327342048, + 2.6735564448008553 + ], + [ + 2.690396488835082, + 2.731140889404697, + 2.676373613861386 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.013082249642555692, + "scoreError" : 6.953747280457144E-5, + "scoreConfidence" : [ + 0.01301271216975112, + 0.013151787115360263 + ], + "scorePercentiles" : { + "0.0" : 0.013056661024539597, + "50.0" : 0.013075846872048269, + "90.0" : 0.013123045050778907, + "95.0" : 0.013123045050778907, + "99.0" : 0.013123045050778907, + "99.9" : 0.013123045050778907, + "99.99" : 0.013123045050778907, + "99.999" : 0.013123045050778907, + "99.9999" : 0.013123045050778907, + "100.0" : 0.013123045050778907 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.013123045050778907, + 0.013098040561426303, + 0.013056661024539597 + ], + [ + 0.013069016938520268, + 0.013064057474492794, + 0.01308267680557627 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF2Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.969529345158123, + "scoreError" : 0.023726873881165934, + "scoreConfidence" : [ + 0.945802471276957, + 0.9932562190392888 + ], + "scorePercentiles" : { + "0.0" : 0.9602343382621219, + "50.0" : 0.9690918609681216, + "90.0" : 0.9787368435114504, + "95.0" : 0.9787368435114504, + "99.0" : 0.9787368435114504, + "99.9" : 0.9787368435114504, + "99.99" : 0.9787368435114504, + "99.999" : 0.9787368435114504, + "99.9999" : 0.9787368435114504, + "100.0" : 0.9787368435114504 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.9602343382621219, + 0.964078407500241, + 0.961774333237161 + ], + [ + 0.9787368435114504, + 0.9782468340017607, + 0.9741053144360023 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "2" + }, + "primaryMetric" : { + "score" : 0.0102813420188602, + "scoreError" : 2.641824339899928E-4, + "scoreConfidence" : [ + 0.010017159584870207, + 0.010545524452850194 + ], + "scorePercentiles" : { + "0.0" : 0.010175120492298675, + "50.0" : 0.010282188849950719, + "90.0" : 0.01037699533046797, + "95.0" : 0.01037699533046797, + "99.0" : 0.01037699533046797, + "99.9" : 0.01037699533046797, + "99.99" : 0.01037699533046797, + "99.999" : 0.01037699533046797, + "99.9999" : 0.01037699533046797, + "100.0" : 0.01037699533046797 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.010204343369387756, + 0.01020924839668004, + 0.010175120492298675 + ], + [ + 0.01037699533046797, + 0.01036721522110536, + 0.010355129303221397 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "10" + }, + "primaryMetric" : { + "score" : 3.265837577738878, + "scoreError" : 0.034587894230118855, + "scoreConfidence" : [ + 3.231249683508759, + 3.300425471968997 + ], + "scorePercentiles" : { + "0.0" : 3.2433177924773022, + "50.0" : 3.268676114782512, + "90.0" : 3.2775043931847967, + "95.0" : 3.2775043931847967, + "99.0" : 3.2775043931847967, + "99.9" : 3.2775043931847967, + "99.99" : 3.2775043931847967, + "99.999" : 3.2775043931847967, + "99.9999" : 3.2775043931847967, + "100.0" : 3.2775043931847967 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.2619459680365295, + 3.274905083169614, + 3.2700814640522875 + ], + [ + 3.2433177924773022, + 3.2775043931847967, + 3.2672707655127367 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.9003792886728363, + "scoreError" : 0.14957413971308717, + "scoreConfidence" : [ + 2.750805148959749, + 3.0499534283859235 + ], + "scorePercentiles" : { + "0.0" : 2.845782786344239, + "50.0" : 2.900799230805492, + "90.0" : 2.9549145610044314, + "95.0" : 2.9549145610044314, + "99.0" : 2.9549145610044314, + "99.9" : 2.9549145610044314, + "99.99" : 2.9549145610044314, + "99.999" : 2.9549145610044314, + "99.9999" : 2.9549145610044314, + "100.0" : 2.9549145610044314 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.9549145610044314, + 2.952189377804014, + 2.9383522967097533 + ], + [ + 2.845782786344239, + 2.8477905452733485, + 2.863246164901231 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkDeepAbstractConcrete", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.17740550423110923, + "scoreError" : 8.012613890564514E-4, + "scoreConfidence" : [ + 0.17660424284205278, + 0.17820676562016569 + ], + "scorePercentiles" : { + "0.0" : 0.17697164089404852, + "50.0" : 0.17741756005622028, + "90.0" : 0.17776747002044263, + "95.0" : 0.17776747002044263, + "99.0" : 0.17776747002044263, + "99.9" : 0.17776747002044263, + "99.99" : 0.17776747002044263, + "99.999" : 0.17776747002044263, + "99.9999" : 0.17776747002044263, + "100.0" : 0.17776747002044263 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.17755434968573558, + 0.17776747002044263, + 0.17728077042670495 + ], + [ + 0.17758769723499848, + 0.17727109712472525, + 0.17697164089404852 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.337242834382161, + "scoreError" : 0.018107217783755545, + "scoreConfidence" : [ + 0.31913561659840545, + 0.3553500521659166 + ], + "scorePercentiles" : { + "0.0" : 0.3308738535269984, + "50.0" : 0.336070955409201, + "90.0" : 0.34481690473070825, + "95.0" : 0.34481690473070825, + "99.0" : 0.34481690473070825, + "99.9" : 0.34481690473070825, + "99.99" : 0.34481690473070825, + "99.999" : 0.34481690473070825, + "99.9999" : 0.34481690473070825, + "100.0" : 0.34481690473070825 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.33195921108713694, + 0.33175661457054706, + 0.3308738535269984 + ], + [ + 0.3401826997312651, + 0.34386772264631044, + 0.34481690473070825 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.14962478777569557, + "scoreError" : 0.013296020759109756, + "scoreConfidence" : [ + 0.1363287670165858, + 0.16292080853480534 + ], + "scorePercentiles" : { + "0.0" : 0.145046001334397, + "50.0" : 0.14964429165303766, + "90.0" : 0.1546479741436635, + "95.0" : 0.1546479741436635, + "99.0" : 0.1546479741436635, + "99.9" : 0.1546479741436635, + "99.99" : 0.1546479741436635, + "99.999" : 0.1546479741436635, + "99.9999" : 0.1546479741436635, + "100.0" : 0.1546479741436635 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.1546479741436635, + 0.1534419615638378, + 0.15369867840895118 + ], + [ + 0.145046001334397, + 0.14584662174223753, + 0.14506748946108652 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.4000424865094383, + "scoreError" : 0.007436356398219337, + "scoreConfidence" : [ + 0.392606130111219, + 0.4074788429076576 + ], + "scorePercentiles" : { + "0.0" : 0.39681826352128885, + "50.0" : 0.399696655135814, + "90.0" : 0.4049147449487792, + "95.0" : 0.4049147449487792, + "99.0" : 0.4049147449487792, + "99.9" : 0.4049147449487792, + "99.99" : 0.4049147449487792, + "99.999" : 0.4049147449487792, + "99.9999" : 0.4049147449487792, + "100.0" : 0.4049147449487792 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.4049147449487792, + 0.3991696065141899, + 0.39681826352128885 + ], + [ + 0.39959757212499003, + 0.3997957381466379, + 0.3999589938007439 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.15433508632479864, + "scoreError" : 0.013892588588388346, + "scoreConfidence" : [ + 0.1404424977364103, + 0.168227674913187 + ], + "scorePercentiles" : { + "0.0" : 0.14961103918195146, + "50.0" : 0.1543933164859873, + "90.0" : 0.15904309307059816, + "95.0" : 0.15904309307059816, + "99.0" : 0.15904309307059816, + "99.9" : 0.15904309307059816, + "99.99" : 0.15904309307059816, + "99.999" : 0.15904309307059816, + "99.9999" : 0.15904309307059816, + "100.0" : 0.15904309307059816 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.15883331398802433, + 0.15904309307059816, + 0.15868584941049524 + ], + [ + 0.14961103918195146, + 0.15010078356147935, + 0.14973643873624318 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkRepeatedFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.048113976404333035, + "scoreError" : 0.0010519157533025996, + "scoreConfidence" : [ + 0.047062060651030434, + 0.049165892157635636 + ], + "scorePercentiles" : { + "0.0" : 0.04757733251342852, + "50.0" : 0.04822778876981573, + "90.0" : 0.04857862111680552, + "95.0" : 0.04857862111680552, + "99.0" : 0.04857862111680552, + "99.9" : 0.04857862111680552, + "99.99" : 0.04857862111680552, + "99.999" : 0.04857862111680552, + "99.9999" : 0.04857862111680552, + "100.0" : 0.04857862111680552 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.04857862111680552, + 0.048192631236024366, + 0.048262946303607106 + ], + [ + 0.04757733251342852, + 0.047754013160785064, + 0.04831831409534761 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 9339927.80242196, + "scoreError" : 646079.2773135401, + "scoreConfidence" : [ + 8693848.52510842, + 9986007.079735499 + ], + "scorePercentiles" : { + "0.0" : 9024597.714156898, + "50.0" : 9353948.21616831, + "90.0" : 9594757.45637584, + "95.0" : 9594757.45637584, + "99.0" : 9594757.45637584, + "99.9" : 9594757.45637584, + "99.99" : 9594757.45637584, + "99.999" : 9594757.45637584, + "99.9999" : 9594757.45637584, + "100.0" : 9594757.45637584 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 9133683.376255708, + 9024597.714156898, + 9330118.939365672 + ], + [ + 9578631.835406698, + 9594757.45637584, + 9377777.492970947 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + From 956632656de69efc55b69b181529f067bc7ca53c Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Tue, 23 Sep 2025 14:27:43 +1000 Subject: [PATCH 07/40] nearly works --- .../execution/DataLoaderDispatchStrategy.java | 4 + .../graphql/execution/ExecutionStrategy.java | 1 + .../PerLevelDataLoaderDispatchStrategy.java | 376 ++++++++++-------- 3 files changed, 221 insertions(+), 160 deletions(-) diff --git a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java index b3f837cd5..a169b1cb9 100644 --- a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java @@ -40,6 +40,10 @@ default void executeObjectOnFieldValuesInfo(List fieldValueInfoL } + default void fieldCompleted(FieldValueInfo fieldValueInfo, ExecutionStrategyParameters executionStrategyParameters) { + + } + default void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable throwable, ExecutionStrategyParameters parameters) { } diff --git a/src/main/java/graphql/execution/ExecutionStrategy.java b/src/main/java/graphql/execution/ExecutionStrategy.java index c1272df44..e15d27616 100644 --- a/src/main/java/graphql/execution/ExecutionStrategy.java +++ b/src/main/java/graphql/execution/ExecutionStrategy.java @@ -638,6 +638,7 @@ private FieldValueInfo completeField(GraphQLFieldDefinition fieldDef, ExecutionC ); FieldValueInfo fieldValueInfo = completeValue(executionContext, newParameters); + executionContext.getDataLoaderDispatcherStrategy().fieldCompleted(fieldValueInfo, parameters); ctxCompleteField.onDispatched(); if (fieldValueInfo.isFutureValue()) { CompletableFuture executionResultFuture = fieldValueInfo.getFieldValueFuture(); diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index bd971f656..0ca4a50c3 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -36,7 +36,7 @@ public class PerLevelDataLoaderDispatchStrategy implements DataLoaderDispatchStr private final Profiler profiler; - private final Map deferredCallStackMap = new ConcurrentHashMap<>(); + private final Map alternativeCallContextMap = new ConcurrentHashMap<>(); private static class ChainedDLStack { @@ -138,30 +138,41 @@ private static class CallStack { /** * A general overview of teh tracked data: * There are three aspects tracked per level: - * - number of execute object calls (executeObject) - * - number of fetches - * - number of sub selections finished fetching + * - number of expected and happened execute object calls (executeObject) + * - number of expected and happened fetches + * - number of happened sub selections finished fetching *

- * The level for an execute object call is the level of the field in the query: for - * { a {b {c}}} the level of a is 1, b is 2 and c is not an object + * The level for an execute object call is the level of sub selection of the object: for + * { a {b {c}}} the level of "execute object a" is 2 *

* For fetches the level is the level of the field fetched *

* For sub selections finished it is the level of the fields inside the sub selection: * {a1 { b c} a2 } the level of {a1 a2} is 1, the level of {b c} is 2 *

+ * The main aspect for when a level is ready is when all expected fetch call happened, meaning + * we can dispatch this level as all data loaders in this level have been called + * (if the number of expected fetches is correct). *

- * A finished subselection means we can predict the number of execute object calls in the same level as the subselection: + * The number of expected fetches is increased with every executeObject (based on the number of subselection + * fields for the execute object). + * Execute Object a (on level 2) with { a {f1 f2 f3} } means we expect 3 fetches on level 2. + *

+ * A finished subselection means we can predict the number of execute object calls in the next level as the subselection: * { a {x} b {y} } - * If a is a list of 3 objects and b is a list of 2 objects we expect 3 + 2 = 5 execute object calls on the level 1 to be happening + * If a is a list of 3 objects and b is a list of 2 objects we expect 3 + 2 = 5 execute object calls on the level 2 to be happening + *

+ * The finished sub selection is the only "cross level" event: a finished sub selections impacts the expected execute + * object calls on the next level. *

- * An executed object call again means we can predict the number of fetches in the next level: - * Execute Object a with { a {f1 f2 f3} } means we expect 3 fetches on level 2. *

* This means we know a level is ready to be dispatched if: - * - all subselections done in the parent level - * - all execute objects calls in the parent level are done * - all expected fetched happened in the current level + * - all expected execute objects calls happened in the current level (because they inform the expected fetches) + * - all expected sub selections happened in the parent level (because they inform the expected execute object in the current level). + * The expected sub selections are equal to the expected object calls (in the parent level) + * - All expected sub selections happened in the parent parent level (again: meaning #happenedSubSelections == #expectedExecuteObjectCalls) + * - And so until the first level */ private final LevelMap expectedFetchCountPerLevel = new LevelMap(); @@ -169,17 +180,17 @@ private static class CallStack { // an object call means a sub selection of a field of type object/interface/union // the number of fields for sub selections increases the expected fetch count for this level - private final LevelMap expectedExecuteObjectCallsPerLevel = new LevelMap(); - private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); +// private final LevelMap expectedExecuteObjectCallsPerLevel = new LevelMap(); +// private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); + + private final LevelMap happenedCompleteFieldPerLevel = new LevelMap(); // this means one sub selection has been fully fetched // and the expected execute objects calls for the next level have been calculated - private final LevelMap happenedOnFieldValueCallsPerLevel = new LevelMap(); +// private final LevelMap happenedOnFieldValueCallsPerLevel = new LevelMap(); private final Set dispatchedLevels = ConcurrentHashMap.newKeySet(); - // all levels that are ready to be dispatched - private int highestReadyLevel; public ChainedDLStack chainedDLStack = new ChainedDLStack(); @@ -188,7 +199,7 @@ private static class CallStack { public CallStack() { // in the first level there is only one sub selection, // so we only expect one execute object call (which is actually an executionStrategy call) - expectedExecuteObjectCallsPerLevel.set(0, 1); +// expectedExecuteObjectCallsPerLevel.set(1, 1); } @@ -200,7 +211,7 @@ void clearExpectedFetchCount() { expectedFetchCountPerLevel.clear(); } - void increaseFetchCount(int level) { + void increaseHappenedFetchCount(int level) { fetchCountPerLevel.increment(level, 1); } @@ -210,35 +221,40 @@ void clearFetchCount() { } void increaseExpectedExecuteObjectCalls(int level, int count) { - expectedExecuteObjectCallsPerLevel.increment(level, count); - } - - void clearExpectedObjectCalls() { - expectedExecuteObjectCallsPerLevel.clear(); +// expectedExecuteObjectCallsPerLevel.increment(level, count); } - void increaseHappenedExecuteObjectCalls(int level) { - happenedExecuteObjectCallsPerLevel.increment(level, 1); - } - - void clearHappenedExecuteObjectCalls() { - happenedExecuteObjectCallsPerLevel.clear(); - } +// void clearExpectedObjectCalls() { +// expectedExecuteObjectCallsPerLevel.clear(); +// } +// +// void increaseHappenedExecuteObjectCalls(int level) { +// happenedExecuteObjectCallsPerLevel.increment(level, 1); +// } +// +// void clearHappenedExecuteObjectCalls() { +// happenedExecuteObjectCallsPerLevel.clear(); +// } - void increaseHappenedOnFieldValueCalls(int level) { - happenedOnFieldValueCallsPerLevel.increment(level, 1); - } +// void increaseHappenedOnFieldValueCalls(int level) { +// happenedOnFieldValueCallsPerLevel.increment(level, 1); +// } +// +// void clearHappenedOnFieldValueCalls() { +// happenedOnFieldValueCallsPerLevel.clear(); +// } - void clearHappenedOnFieldValueCalls() { - happenedOnFieldValueCallsPerLevel.clear(); - } +// boolean allExecuteObjectCallsHappened(int level) { +// return happenedExecuteObjectCallsPerLevel.get(level) == expectedExecuteObjectCallsPerLevel.get(level); +// } - boolean allExecuteObjectCallsHappened(int level) { - return happenedExecuteObjectCallsPerLevel.get(level) == expectedExecuteObjectCallsPerLevel.get(level); - } +// boolean allSubSelectionsFetchingHappened(int level) { +// return happenedOnFieldValueCallsPerLevel.get(level) == expectedExecuteObjectCallsPerLevel.get(level); +// } +// - boolean allSubSelectionsFetchingHappened(int subSelectionLevel) { - return happenedOnFieldValueCallsPerLevel.get(subSelectionLevel) == expectedExecuteObjectCallsPerLevel.get(subSelectionLevel - 1); + boolean allFieldsCompleted(int level) { + return fetchCountPerLevel.get(level) == happenedCompleteFieldPerLevel.get(level); } boolean allFetchesHappened(int level) { @@ -254,9 +270,9 @@ public String toString() { return "CallStack{" + "expectedFetchCountPerLevel=" + expectedFetchCountPerLevel + ", fetchCountPerLevel=" + fetchCountPerLevel + - ", expectedExecuteObjectCallsPerLevel=" + expectedExecuteObjectCallsPerLevel + - ", happenedExecuteObjectCallsPerLevel=" + happenedExecuteObjectCallsPerLevel + - ", happenedOnFieldValueCallsPerLevel=" + happenedOnFieldValueCallsPerLevel + +// ", expectedExecuteObjectCallsPerLevel=" + expectedExecuteObjectCallsPerLevel + +// ", happenedExecuteObjectCallsPerLevel=" + happenedExecuteObjectCallsPerLevel + +// ", happenedOnFieldValueCallsPerLevel=" + happenedOnFieldValueCallsPerLevel + ", dispatchedLevels" + dispatchedLevels + '}'; } @@ -267,6 +283,11 @@ public void setDispatchedLevel(int level) { Assert.assertShouldNeverHappen("level " + level + " already dispatched"); } } + + public void clearHappenedCompleteFields() { + this.happenedCompleteFieldPerLevel.clear(); + + } } public PerLevelDataLoaderDispatchStrategy(ExecutionContext executionContext) { @@ -283,30 +304,30 @@ public PerLevelDataLoaderDispatchStrategy(ExecutionContext executionContext) { @Override public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); - increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(0, fieldCount, initialCallStack); + increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(1, fieldCount, initialCallStack); } @Override public void executionSerialStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); resetCallStack(callStack); - increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(0, 1, callStack); + // field count is always 1 for serial execution + increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(1, 1, callStack); } - @Override - public void executionStrategyOnFieldValuesInfo(List fieldValueInfoList, ExecutionStrategyParameters parameters) { - CallStack callStack = getCallStack(parameters); - // the root fields are the root sub selection on level 1 - onFieldValuesInfoDispatchIfNeeded(fieldValueInfoList, 1, callStack); - } +// @Override +// public void executionStrategyOnFieldValuesInfo(List fieldValueInfoList, ExecutionStrategyParameters parameters) { +// CallStack callStack = getCallStack(parameters); +// onFieldValuesInfoDispatchIfNeeded(fieldValueInfoList, 1, callStack); +// } - @Override - public void executionStrategyOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { - CallStack callStack = getCallStack(parameters); - synchronized (callStack) { - callStack.increaseHappenedOnFieldValueCalls(1); - } - } +// @Override +// public void executionStrategyOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { +// CallStack callStack = getCallStack(parameters); +// synchronized (callStack) { +// callStack.increaseHappenedOnFieldValueCalls(1); +// } +// } private CallStack getCallStack(ExecutionStrategyParameters parameters) { return getCallStack(parameters.getDeferredCallContext()); @@ -316,16 +337,19 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC if (alternativeCallContext == null) { return this.initialCallStack; } else { - return deferredCallStackMap.computeIfAbsent(alternativeCallContext, k -> { + return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { CallStack callStack = new CallStack(); int startLevel = alternativeCallContext.getStartLevel(); int fields = alternativeCallContext.getFields(); - // we make sure that startLevel-1 is considered done - callStack.expectedExecuteObjectCallsPerLevel.set(0, 0); // set to 1 in the constructor of CallStack - callStack.expectedExecuteObjectCallsPerLevel.set(startLevel - 1, 1); - callStack.happenedExecuteObjectCallsPerLevel.set(startLevel - 1, 1); - callStack.highestReadyLevel = startLevel - 1; - callStack.increaseExpectedFetchCount(startLevel, fields); + System.out.println("startLevel for new callstack " + startLevel); + // we make sure that startLevel is considered done + for (int i = 1; i <= startLevel; i++) { + callStack.increaseExpectedFetchCount(startLevel, 1); + callStack.increaseHappenedFetchCount(1); + if (i < startLevel) { + callStack.happenedCompleteFieldPerLevel.set(startLevel, 1); + } + } return callStack; }); } @@ -335,25 +359,25 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { CallStack callStack = getCallStack(parameters); int curLevel = parameters.getPath().getLevel(); - increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(curLevel, fieldCount, callStack); + increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(curLevel + 1, fieldCount, callStack); } - @Override - public void executeObjectOnFieldValuesInfo - (List fieldValueInfoList, ExecutionStrategyParameters parameters) { - // the level of the sub selection that is fully fetched is one level more than parameters level - int curLevel = parameters.getPath().getLevel() + 1; - CallStack callStack = getCallStack(parameters); - onFieldValuesInfoDispatchIfNeeded(fieldValueInfoList, curLevel, callStack); - } +// @Override +// public void executeObjectOnFieldValuesInfo +// (List fieldValueInfoList, ExecutionStrategyParameters parameters) { +// // the level of the sub selection that is fully fetched is one level more than parameters level +// int curLevel = parameters.getPath().getLevel() + 1; +// CallStack callStack = getCallStack(parameters); +// onFieldValuesInfoDispatchIfNeeded(fieldValueInfoList, curLevel, callStack); +// } @Override public void newSubscriptionExecution(FieldValueInfo fieldValueInfo, AlternativeCallContext alternativeCallContext) { CallStack callStack = getCallStack(alternativeCallContext); - callStack.increaseFetchCount(1); + callStack.increaseHappenedFetchCount(1); callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo); - onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, 1, callStack); +// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, 1, callStack); } @Override @@ -366,79 +390,106 @@ public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo Assert.assertNotNull(parameters.getDeferredCallContext()); ready = callStack.deferredFragmentRootFieldsFetched.size() == parameters.getDeferredCallContext().getFields(); } - if (ready) { - int curLevel = parameters.getPath().getLevel(); - onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, curLevel, callStack); - } - } - - @Override - public void executeObjectOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { - CallStack callStack = getCallStack(parameters); - // the level of the sub selection that is errored is one level more than parameters level - int curLevel = parameters.getPath().getLevel() + 1; - synchronized (callStack) { - callStack.increaseHappenedOnFieldValueCalls(curLevel); - } +// if (ready) { +// int curLevel = parameters.getPath().getLevel(); +// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, curLevel, callStack); +// } } +// @Override +// public void executeObjectOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { +// CallStack callStack = getCallStack(parameters); +// // the level of the sub selection that is errored is one level more than parameters level +// int curLevel = parameters.getPath().getLevel() + 1; +// synchronized (callStack) { +// callStack.increaseHappenedOnFieldValueCalls(curLevel); +// } +// } +// private void increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(int curLevel, int fieldCount, CallStack callStack) { synchronized (callStack) { - callStack.increaseHappenedExecuteObjectCalls(curLevel); - callStack.increaseExpectedFetchCount(curLevel + 1, fieldCount); + callStack.increaseExpectedFetchCount(curLevel, fieldCount); } } private void resetCallStack(CallStack callStack) { synchronized (callStack) { callStack.clearDispatchLevels(); - callStack.clearExpectedObjectCalls(); +// callStack.clearExpectedObjectCalls(); + callStack.clearHappenedCompleteFields(); callStack.clearExpectedFetchCount(); callStack.clearFetchCount(); - callStack.clearHappenedExecuteObjectCalls(); - callStack.clearHappenedOnFieldValueCalls(); - callStack.expectedExecuteObjectCallsPerLevel.set(0, 1); - callStack.highestReadyLevel = 0; +// callStack.clearHappenedExecuteObjectCalls(); +// callStack.clearHappenedOnFieldValueCalls(); +// callStack.expectedExecuteObjectCallsPerLevel.set(1, 1); callStack.chainedDLStack.clear(); } } - private void onFieldValuesInfoDispatchIfNeeded(List fieldValueInfoList, - int subSelectionLevel, - CallStack callStack) { - Integer dispatchLevel; +// private void onFieldValuesInfoDispatchIfNeeded(List fieldValueInfoList, +// int subSelectionLevel, +// CallStack callStack) { +// Integer dispatchLevel; +// synchronized (callStack) { +// dispatchLevel = handleSubSelectionFetched(fieldValueInfoList, subSelectionLevel, callStack); +// } +// // the handle on field values check for the next level if it is ready +// if (dispatchLevel != null) { +// dispatch(dispatchLevel, callStack); +// } +// } + + @Override + public void fieldCompleted(FieldValueInfo fieldValueInfo, ExecutionStrategyParameters parameters) { + int level = parameters.getPath().getLevel(); +// System.out.println("field completed at level: " + level + " at: " + parameters.getPath()); + CallStack callStack = getCallStack(parameters); + int currentLevel = parameters.getPath().getLevel() + 1; synchronized (callStack) { - dispatchLevel = handleSubSelectionFetched(fieldValueInfoList, subSelectionLevel, callStack); + callStack.happenedCompleteFieldPerLevel.increment(level, 1); } - // the handle on field values check for the next level if it is ready - if (dispatchLevel != null) { - dispatch(dispatchLevel, callStack); + while (true) { + boolean levelReady; + synchronized (callStack) { + if (callStack.dispatchedLevels.contains(currentLevel)) { + break; + } + levelReady = dispatchIfNeeded(currentLevel, callStack); + } + if (levelReady) { + dispatch(currentLevel, callStack); + } else { + break; + } + currentLevel++; } } // // thread safety: called with callStack.lock // - private @Nullable Integer handleSubSelectionFetched(List fieldValueInfos, int subSelectionLevel, CallStack - callStack) { - callStack.increaseHappenedOnFieldValueCalls(subSelectionLevel); - int expectedOnObjectCalls = getObjectCountForList(fieldValueInfos); - // we expect on the level of the current sub selection #expectedOnObjectCalls execute object calls - callStack.increaseExpectedExecuteObjectCalls(subSelectionLevel, expectedOnObjectCalls); - // maybe the object calls happened already (because the DataFetcher return directly values synchronously) - // therefore we check the next levels if they are ready - // this means we could skip some level because the higher level is also already ready, - // which means there is nothing to dispatch on these levels: if x and x+1 is ready, it means there are no - // data loaders used on x - // - // if data loader chaining is disabled (the old algo) the level we dispatch is not really relevant as - // we dispatch the whole registry anyway - - return getHighestReadyLevel(subSelectionLevel + 1, callStack); - } +// private @Nullable Integer handleSubSelectionFetched(List fieldValueInfos, int subSelectionLevel, CallStack +// callStack) { +// System.out.println("sub selection fetched at level :" + subSelectionLevel); +// callStack.increaseHappenedOnFieldValueCalls(subSelectionLevel); +// int expectedOnObjectCalls = getObjectCountForList(fieldValueInfos); +// // we expect on the next level of the current sub selection #expectedOnObjectCalls execute object calls +// callStack.increaseExpectedExecuteObjectCalls(subSelectionLevel + 1, expectedOnObjectCalls); +// +// // maybe the object calls happened already (because the DataFetcher return directly values synchronously) +// // therefore we check the next levels if they are ready +// // if data loader chaining is disabled (the old algo) the level we dispatch is not really relevant as +// // we dispatch the whole registry anyway +// +// if (checkLevelImpl(subSelectionLevel + 1, callStack)) { +// return subSelectionLevel + 1; +// } else { +// return null; +// } +// } /** * the amount of (non nullable) objects that will require an execute object call @@ -466,7 +517,8 @@ public void fieldFetched(ExecutionContext executionContext, int level = executionStrategyParameters.getPath().getLevel(); boolean dispatchNeeded; synchronized (callStack) { - callStack.increaseFetchCount(level); + System.out.println("field fetched at level " + level); + callStack.increaseHappenedFetchCount(level); dispatchNeeded = dispatchIfNeeded(level, callStack); } if (dispatchNeeded) { @@ -480,7 +532,7 @@ public void fieldFetched(ExecutionContext executionContext, // thread safety : called with callStack.lock // private boolean dispatchIfNeeded(int level, CallStack callStack) { - boolean ready = checkLevelBeingReady(level, callStack); + boolean ready = checkLevelImpl(level, callStack); if (ready) { callStack.setDispatchedLevel(level); return true; @@ -491,50 +543,53 @@ private boolean dispatchIfNeeded(int level, CallStack callStack) { // // thread safety: called with callStack.lock // - private @Nullable Integer getHighestReadyLevel(int startFrom, CallStack callStack) { - int curLevel = callStack.highestReadyLevel; - while (true) { - if (!checkLevelImpl(curLevel + 1, callStack)) { - callStack.highestReadyLevel = curLevel; - return curLevel >= startFrom ? curLevel : null; - } - curLevel++; - } - } - - private boolean checkLevelBeingReady(int level, CallStack callStack) { - Assert.assertTrue(level > 0); - if (level <= callStack.highestReadyLevel) { - return true; - } - - for (int i = callStack.highestReadyLevel + 1; i <= level; i++) { - if (!checkLevelImpl(i, callStack)) { - return false; - } - } - callStack.highestReadyLevel = level; - return true; - } +// private @Nullable Integer getHighestReadyLevel(int startFrom, CallStack callStack) { +// while (true) { +// if (!checkLevelImpl(curLevel + 1, callStack)) { +// callStack.highestReadyLevel = curLevel; +// return curLevel >= startFrom ? curLevel : null; +// } +// curLevel++; +// } +// } + +// private boolean checkLevelBeingReady(int level, CallStack callStack) { +// Assert.assertTrue(level > 0); +// +// for (int i = callStack.highestReadyLevel + 1; i <= level; i++) { +// if (!checkLevelImpl(i, callStack)) { +// return false; +// } +// } +// callStack.highestReadyLevel = level; +// return true; +// } private boolean checkLevelImpl(int level, CallStack callStack) { + System.out.println("checkLevelImpl " + level); // a level with zero expectations can't be ready if (callStack.expectedFetchCountPerLevel.get(level) == 0) { return false; } - // first we make sure that the expected fetch count is correct - // by verifying that the parent level all execute object + sub selection were fetched - if (!callStack.allExecuteObjectCallsHappened(level - 1)) { - return false; - } - if (level > 1 && !callStack.allSubSelectionsFetchingHappened(level - 1)) { - return false; - } - // the main check: all fetches must have happened + // all fetches happened if (!callStack.allFetchesHappened(level)) { return false; } +// // the fetch count is actually correct because all execute object happened +// if (!callStack.allFieldsCompleted(level-1)) { +// return false; +// } + // the expected execute object call is correct because all sub selections got fetched on the parent + // and their parent and their parent etc + int levelTmp = level - 1; + while (levelTmp >= 1) { + if (!callStack.allFieldsCompleted(levelTmp)) { + return false; + } + levelTmp--; + } + System.out.println("check ready " + level); return true; } @@ -545,6 +600,7 @@ void dispatch(int level, CallStack callStack) { dispatchAll(dataLoaderRegistry, level); return; } +// System.out.println("dispatching " + level); dispatchDLCFImpl(level, callStack, true, false); } From 07b160083f32bcd2191cbeda654b69108be73e4f Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Tue, 23 Sep 2025 21:22:57 +1000 Subject: [PATCH 08/40] works except dataloader in defer --- .../instrumentation/dataloader/LevelMap.java | 2 +- .../PerLevelDataLoaderDispatchStrategy.java | 30 +++++++------------ ...eferExecutionSupportIntegrationTest.groovy | 2 ++ .../dataloader/DeferWithDataLoaderTest.groovy | 7 +++++ .../dataloader/LevelMapTest.groovy | 5 ++-- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java b/src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java index ddf46f643..45fdca37b 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java @@ -57,7 +57,7 @@ public String toString() { StringBuilder result = new StringBuilder(); result.append("IntMap["); for (int i = 0; i < countsByLevel.length; i++) { - result.append("level=").append(i).append(",count=").append(countsByLevel[i]).append(" "); + result.append("[level=").append(i).append(",count=").append(countsByLevel[i]).append("] "); } result.append("]"); return result.toString(); diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 0ca4a50c3..311843eaf 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -175,15 +175,18 @@ private static class CallStack { * - And so until the first level */ + private final LevelMap expectedFetchCountPerLevel = new LevelMap(); private final LevelMap fetchCountPerLevel = new LevelMap(); + // happened complete field implies that the expected fetch field is correct + // because completion triggers all needed executeObject, which determines the expected fetch field count + private final LevelMap happenedCompleteFieldPerLevel = new LevelMap(); // an object call means a sub selection of a field of type object/interface/union // the number of fields for sub selections increases the expected fetch count for this level // private final LevelMap expectedExecuteObjectCallsPerLevel = new LevelMap(); // private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); - private final LevelMap happenedCompleteFieldPerLevel = new LevelMap(); // this means one sub selection has been fully fetched // and the expected execute objects calls for the next level have been calculated @@ -339,17 +342,11 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC } else { return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { CallStack callStack = new CallStack(); + System.out.println("new callstack: " + callStack); int startLevel = alternativeCallContext.getStartLevel(); int fields = alternativeCallContext.getFields(); - System.out.println("startLevel for new callstack " + startLevel); - // we make sure that startLevel is considered done - for (int i = 1; i <= startLevel; i++) { - callStack.increaseExpectedFetchCount(startLevel, 1); - callStack.increaseHappenedFetchCount(1); - if (i < startLevel) { - callStack.happenedCompleteFieldPerLevel.set(startLevel, 1); - } - } + callStack.expectedFetchCountPerLevel.set(1, 1); + callStack.fetchCountPerLevel.set(1, 1); return callStack; }); } @@ -445,12 +442,12 @@ private void resetCallStack(CallStack callStack) { @Override public void fieldCompleted(FieldValueInfo fieldValueInfo, ExecutionStrategyParameters parameters) { int level = parameters.getPath().getLevel(); -// System.out.println("field completed at level: " + level + " at: " + parameters.getPath()); + System.out.println("field completed at level: " + level + " at: " + parameters.getPath()); CallStack callStack = getCallStack(parameters); - int currentLevel = parameters.getPath().getLevel() + 1; synchronized (callStack) { callStack.happenedCompleteFieldPerLevel.increment(level, 1); } + int currentLevel = parameters.getPath().getLevel() + 1; while (true) { boolean levelReady; synchronized (callStack) { @@ -517,7 +514,7 @@ public void fieldFetched(ExecutionContext executionContext, int level = executionStrategyParameters.getPath().getLevel(); boolean dispatchNeeded; synchronized (callStack) { - System.out.println("field fetched at level " + level); + System.out.println("field fetched at level " + level + " - " + executionStrategyParameters.getPath()); callStack.increaseHappenedFetchCount(level); dispatchNeeded = dispatchIfNeeded(level, callStack); } @@ -576,12 +573,7 @@ private boolean checkLevelImpl(int level, CallStack callStack) { if (!callStack.allFetchesHappened(level)) { return false; } -// // the fetch count is actually correct because all execute object happened -// if (!callStack.allFieldsCompleted(level-1)) { -// return false; -// } - // the expected execute object call is correct because all sub selections got fetched on the parent - // and their parent and their parent etc + int levelTmp = level - 1; while (levelTmp >= 1) { if (!callStack.allFieldsCompleted(levelTmp)) { diff --git a/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy b/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy index b3b522d90..8afa04300 100644 --- a/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy +++ b/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy @@ -23,6 +23,7 @@ import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderRegistry import org.reactivestreams.Publisher +import spock.lang.Ignore import spock.lang.Specification import spock.lang.Unroll @@ -1690,6 +1691,7 @@ class DeferExecutionSupportIntegrationTest extends Specification { } + @Ignore("tmp not working") def "dataloader used inside defer"() { given: def query = ''' diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy index 362206f64..5df5837bf 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy @@ -11,6 +11,7 @@ import org.awaitility.Awaitility import org.dataloader.BatchLoader import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderRegistry +import spock.lang.Ignore import spock.lang.RepeatUntilFailure import spock.lang.Specification @@ -60,6 +61,7 @@ class DeferWithDataLoaderTest extends Specification { } } + @Ignore def "query with single deferred field"() { given: def query = getQuery(true, false) @@ -104,6 +106,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 3 } + @Ignore def "multiple fields on same defer block"() { given: def query = """ @@ -177,6 +180,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 } + @Ignore def "query with nested deferred fields"() { given: def query = getQuery(true, true) @@ -228,6 +232,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 9 } + @Ignore def "query with top-level deferred field"() { given: def query = """ @@ -291,6 +296,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 } + @Ignore def "query with multiple deferred fields"() { given: def query = getExpensiveQuery(true) @@ -348,6 +354,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 } + @Ignore @RepeatUntilFailure(maxAttempts = 50, ignoreRest = false) def "dataloader in initial result and chained dataloader inside nested defer block"() { given: diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy index 8ff6bece5..1f0069fb1 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy @@ -1,7 +1,6 @@ package graphql.execution.instrumentation.dataloader import spock.lang.Specification -import graphql.AssertException class LevelMapTest extends Specification { @@ -92,13 +91,13 @@ class LevelMapTest extends Specification { sut.increment(0, 42) then: - sut.toString() == "IntMap[level=0,count=42 ]" + sut.toString() == "IntMap[[level=0,count=42] ]" when: sut.increment(1, 1) then: - sut.toString() == "IntMap[level=0,count=42 level=1,count=1 ]" + sut.toString() == "IntMap[[level=0,count=42] [level=1,count=1] ]" } def "can get outside of its size"() { From 56a39dfbe8a1ec08a5dfaa1e87d0c3fdd1e87623 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 11:32:22 +1000 Subject: [PATCH 09/40] working with simpler mode except batching, defer, subscription --- .../graphql/execution/ExecutionStrategy.java | 4 +- .../PerLevelDataLoaderDispatchStrategy.java | 398 ++++++------------ 2 files changed, 126 insertions(+), 276 deletions(-) diff --git a/src/main/java/graphql/execution/ExecutionStrategy.java b/src/main/java/graphql/execution/ExecutionStrategy.java index e15d27616..8d29152b4 100644 --- a/src/main/java/graphql/execution/ExecutionStrategy.java +++ b/src/main/java/graphql/execution/ExecutionStrategy.java @@ -207,11 +207,11 @@ protected Object executeObject(ExecutionContext executionContext, ExecutionStrat List fieldNames = parameters.getFields().getKeys(); DeferredExecutionSupport deferredExecutionSupport = createDeferredExecutionSupport(executionContext, parameters); + List fieldsExecutedOnInitialResult = deferredExecutionSupport.getNonDeferredFieldNames(fieldNames); + dataLoaderDispatcherStrategy.executeObject(executionContext, parameters, fieldsExecutedOnInitialResult.size()); Async.CombinedBuilder resolvedFieldFutures = getAsyncFieldValueInfo(executionContext, parameters, deferredExecutionSupport); CompletableFuture> overallResult = new CompletableFuture<>(); - List fieldsExecutedOnInitialResult = deferredExecutionSupport.getNonDeferredFieldNames(fieldNames); - dataLoaderDispatcherStrategy.executeObject(executionContext, parameters, fieldsExecutedOnInitialResult.size()); BiConsumer, Throwable> handleResultsConsumer = buildFieldValueMap(fieldsExecutedOnInitialResult, overallResult, executionContext); resolveObjectCtx.onDispatched(); diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 311843eaf..4a7dde97f 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -177,20 +177,9 @@ private static class CallStack { private final LevelMap expectedFetchCountPerLevel = new LevelMap(); - private final LevelMap fetchCountPerLevel = new LevelMap(); - // happened complete field implies that the expected fetch field is correct - // because completion triggers all needed executeObject, which determines the expected fetch field count - private final LevelMap happenedCompleteFieldPerLevel = new LevelMap(); - - // an object call means a sub selection of a field of type object/interface/union - // the number of fields for sub selections increases the expected fetch count for this level -// private final LevelMap expectedExecuteObjectCallsPerLevel = new LevelMap(); -// private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); - - - // this means one sub selection has been fully fetched - // and the expected execute objects calls for the next level have been calculated -// private final LevelMap happenedOnFieldValueCallsPerLevel = new LevelMap(); + private final LevelMap happenedFetchCountPerLevel = new LevelMap(); + private final LevelMap happenedCompletionFinishedCountPerLevel = new LevelMap(); + private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); private final Set dispatchedLevels = ConcurrentHashMap.newKeySet(); @@ -200,69 +189,8 @@ private static class CallStack { private final List deferredFragmentRootFieldsFetched = new ArrayList<>(); public CallStack() { - // in the first level there is only one sub selection, - // so we only expect one execute object call (which is actually an executionStrategy call) -// expectedExecuteObjectCallsPerLevel.set(1, 1); - } - - - void increaseExpectedFetchCount(int level, int count) { - expectedFetchCountPerLevel.increment(level, count); - } - - void clearExpectedFetchCount() { - expectedFetchCountPerLevel.clear(); - } - - void increaseHappenedFetchCount(int level) { - fetchCountPerLevel.increment(level, 1); - } - - - void clearFetchCount() { - fetchCountPerLevel.clear(); - } - - void increaseExpectedExecuteObjectCalls(int level, int count) { -// expectedExecuteObjectCallsPerLevel.increment(level, count); - } - -// void clearExpectedObjectCalls() { -// expectedExecuteObjectCallsPerLevel.clear(); -// } -// -// void increaseHappenedExecuteObjectCalls(int level) { -// happenedExecuteObjectCallsPerLevel.increment(level, 1); -// } -// -// void clearHappenedExecuteObjectCalls() { -// happenedExecuteObjectCallsPerLevel.clear(); -// } - -// void increaseHappenedOnFieldValueCalls(int level) { -// happenedOnFieldValueCallsPerLevel.increment(level, 1); -// } -// -// void clearHappenedOnFieldValueCalls() { -// happenedOnFieldValueCallsPerLevel.clear(); -// } - -// boolean allExecuteObjectCallsHappened(int level) { -// return happenedExecuteObjectCallsPerLevel.get(level) == expectedExecuteObjectCallsPerLevel.get(level); -// } - -// boolean allSubSelectionsFetchingHappened(int level) { -// return happenedOnFieldValueCallsPerLevel.get(level) == expectedExecuteObjectCallsPerLevel.get(level); -// } -// - - boolean allFieldsCompleted(int level) { - return fetchCountPerLevel.get(level) == happenedCompleteFieldPerLevel.get(level); } - boolean allFetchesHappened(int level) { - return fetchCountPerLevel.get(level) == expectedFetchCountPerLevel.get(level); - } void clearDispatchLevels() { dispatchedLevels.clear(); @@ -272,7 +200,7 @@ void clearDispatchLevels() { public String toString() { return "CallStack{" + "expectedFetchCountPerLevel=" + expectedFetchCountPerLevel + - ", fetchCountPerLevel=" + fetchCountPerLevel + + ", fetchCountPerLevel=" + happenedFetchCountPerLevel + // ", expectedExecuteObjectCallsPerLevel=" + expectedExecuteObjectCallsPerLevel + // ", happenedExecuteObjectCallsPerLevel=" + happenedExecuteObjectCallsPerLevel + // ", happenedOnFieldValueCallsPerLevel=" + happenedOnFieldValueCallsPerLevel + @@ -287,8 +215,13 @@ public void setDispatchedLevel(int level) { } } - public void clearHappenedCompleteFields() { - this.happenedCompleteFieldPerLevel.clear(); + public void clear() { + dispatchedLevels.clear(); + happenedExecuteObjectCallsPerLevel.clear(); + expectedFetchCountPerLevel.clear(); + happenedFetchCountPerLevel.clear(); + happenedCompletionFinishedCountPerLevel.clear(); + } } @@ -307,7 +240,11 @@ public PerLevelDataLoaderDispatchStrategy(ExecutionContext executionContext) { @Override public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); - increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(1, fieldCount, initialCallStack); +// System.out.println("execution strategy started"); + synchronized (initialCallStack) { + initialCallStack.happenedExecuteObjectCallsPerLevel.set(0, 1); + initialCallStack.expectedFetchCountPerLevel.set(1, fieldCount); + } } @Override @@ -315,146 +252,67 @@ public void executionSerialStrategy(ExecutionContext executionContext, Execution CallStack callStack = getCallStack(parameters); resetCallStack(callStack); // field count is always 1 for serial execution - increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(1, 1, callStack); - } - -// @Override -// public void executionStrategyOnFieldValuesInfo(List fieldValueInfoList, ExecutionStrategyParameters parameters) { -// CallStack callStack = getCallStack(parameters); -// onFieldValuesInfoDispatchIfNeeded(fieldValueInfoList, 1, callStack); -// } - -// @Override -// public void executionStrategyOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { -// CallStack callStack = getCallStack(parameters); -// synchronized (callStack) { -// callStack.increaseHappenedOnFieldValueCalls(1); -// } -// } - - private CallStack getCallStack(ExecutionStrategyParameters parameters) { - return getCallStack(parameters.getDeferredCallContext()); - } - - private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallContext) { - if (alternativeCallContext == null) { - return this.initialCallStack; - } else { - return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { - CallStack callStack = new CallStack(); - System.out.println("new callstack: " + callStack); - int startLevel = alternativeCallContext.getStartLevel(); - int fields = alternativeCallContext.getFields(); - callStack.expectedFetchCountPerLevel.set(1, 1); - callStack.fetchCountPerLevel.set(1, 1); - return callStack; - }); + synchronized (callStack) { + callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); + callStack.expectedFetchCountPerLevel.set(1, 1); } } @Override - public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { + public void executionStrategyOnFieldValuesInfo(List fieldValueInfoList, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); - int curLevel = parameters.getPath().getLevel(); - increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(curLevel + 1, fieldCount, callStack); - } - -// @Override -// public void executeObjectOnFieldValuesInfo -// (List fieldValueInfoList, ExecutionStrategyParameters parameters) { -// // the level of the sub selection that is fully fetched is one level more than parameters level -// int curLevel = parameters.getPath().getLevel() + 1; -// CallStack callStack = getCallStack(parameters); -// onFieldValuesInfoDispatchIfNeeded(fieldValueInfoList, curLevel, callStack); -// } - +// System.out.println("1st level fields completed"); + onCompletionFinished(0, callStack); - @Override - public void newSubscriptionExecution(FieldValueInfo fieldValueInfo, AlternativeCallContext alternativeCallContext) { - CallStack callStack = getCallStack(alternativeCallContext); - callStack.increaseHappenedFetchCount(1); - callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo); -// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, 1, callStack); } @Override - public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable - throwable, ExecutionStrategyParameters parameters) { + public void executionStrategyOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); - boolean ready; - synchronized (callStack) { - callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo); - Assert.assertNotNull(parameters.getDeferredCallContext()); - ready = callStack.deferredFragmentRootFieldsFetched.size() == parameters.getDeferredCallContext().getFields(); - } -// if (ready) { -// int curLevel = parameters.getPath().getLevel(); -// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, curLevel, callStack); -// } + onCompletionFinished(0, callStack); } -// @Override -// public void executeObjectOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { -// CallStack callStack = getCallStack(parameters); -// // the level of the sub selection that is errored is one level more than parameters level -// int curLevel = parameters.getPath().getLevel() + 1; -// synchronized (callStack) { -// callStack.increaseHappenedOnFieldValueCalls(curLevel); -// } -// } -// - private void increaseHappenedExecuteObjectAndIncreaseExpectedFetchCount(int curLevel, - int fieldCount, - CallStack callStack) { + @Override + public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { + CallStack callStack = getCallStack(parameters); + int curLevel = parameters.getPath().getLevel(); +// System.out.println("execute object " + curLevel + " at " + parameters.getPath() ); synchronized (callStack) { - callStack.increaseExpectedFetchCount(curLevel, fieldCount); + callStack.happenedExecuteObjectCallsPerLevel.increment(curLevel, 1); + callStack.expectedFetchCountPerLevel.increment(curLevel + 1, fieldCount); } } - private void resetCallStack(CallStack callStack) { - synchronized (callStack) { - callStack.clearDispatchLevels(); -// callStack.clearExpectedObjectCalls(); - callStack.clearHappenedCompleteFields(); - callStack.clearExpectedFetchCount(); - callStack.clearFetchCount(); -// callStack.clearHappenedExecuteObjectCalls(); -// callStack.clearHappenedOnFieldValueCalls(); -// callStack.expectedExecuteObjectCallsPerLevel.set(1, 1); - callStack.chainedDLStack.clear(); - } + @Override + public void executeObjectOnFieldValuesInfo + (List fieldValueInfoList, ExecutionStrategyParameters parameters) { + int curLevel = parameters.getPath().getLevel(); + CallStack callStack = getCallStack(parameters); +// System.out.println("completion finished at " + curLevel + " at " + parameters.getPath() ); + onCompletionFinished(curLevel, callStack); } -// private void onFieldValuesInfoDispatchIfNeeded(List fieldValueInfoList, -// int subSelectionLevel, -// CallStack callStack) { -// Integer dispatchLevel; -// synchronized (callStack) { -// dispatchLevel = handleSubSelectionFetched(fieldValueInfoList, subSelectionLevel, callStack); -// } -// // the handle on field values check for the next level if it is ready -// if (dispatchLevel != null) { -// dispatch(dispatchLevel, callStack); -// } -// } - @Override - public void fieldCompleted(FieldValueInfo fieldValueInfo, ExecutionStrategyParameters parameters) { - int level = parameters.getPath().getLevel(); - System.out.println("field completed at level: " + level + " at: " + parameters.getPath()); + public void executeObjectOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); + int curLevel = parameters.getPath().getLevel(); + onCompletionFinished(curLevel, callStack); + } + + private void onCompletionFinished(int level, CallStack callStack) { synchronized (callStack) { - callStack.happenedCompleteFieldPerLevel.increment(level, 1); + callStack.happenedCompletionFinishedCountPerLevel.increment(level, 1); } - int currentLevel = parameters.getPath().getLevel() + 1; + // on completion might mark multiple higher levels as ready + int currentLevel = level + 2; while (true) { boolean levelReady; synchronized (callStack) { if (callStack.dispatchedLevels.contains(currentLevel)) { break; } - levelReady = dispatchIfNeeded(currentLevel, callStack); + levelReady = markLevelAsDispatchedIfReady(currentLevel, callStack); } if (levelReady) { dispatch(currentLevel, callStack); @@ -463,47 +321,9 @@ public void fieldCompleted(FieldValueInfo fieldValueInfo, ExecutionStrategyParam } currentLevel++; } - } - // -// thread safety: called with callStack.lock -// -// private @Nullable Integer handleSubSelectionFetched(List fieldValueInfos, int subSelectionLevel, CallStack -// callStack) { -// System.out.println("sub selection fetched at level :" + subSelectionLevel); -// callStack.increaseHappenedOnFieldValueCalls(subSelectionLevel); -// int expectedOnObjectCalls = getObjectCountForList(fieldValueInfos); -// // we expect on the next level of the current sub selection #expectedOnObjectCalls execute object calls -// callStack.increaseExpectedExecuteObjectCalls(subSelectionLevel + 1, expectedOnObjectCalls); -// -// // maybe the object calls happened already (because the DataFetcher return directly values synchronously) -// // therefore we check the next levels if they are ready -// // if data loader chaining is disabled (the old algo) the level we dispatch is not really relevant as -// // we dispatch the whole registry anyway -// -// if (checkLevelImpl(subSelectionLevel + 1, callStack)) { -// return subSelectionLevel + 1; -// } else { -// return null; -// } -// } - - /** - * the amount of (non nullable) objects that will require an execute object call - */ - private int getObjectCountForList(List fieldValueInfos) { - int result = 0; - for (FieldValueInfo fieldValueInfo : fieldValueInfos) { - if (fieldValueInfo.getCompleteValueType() == FieldValueInfo.CompleteValueType.OBJECT) { - result += 1; - } else if (fieldValueInfo.getCompleteValueType() == FieldValueInfo.CompleteValueType.LIST) { - result += getObjectCountForList(fieldValueInfo.getFieldValueInfos()); - } - } - return result; } - @Override public void fieldFetched(ExecutionContext executionContext, ExecutionStrategyParameters executionStrategyParameters, @@ -514,9 +334,8 @@ public void fieldFetched(ExecutionContext executionContext, int level = executionStrategyParameters.getPath().getLevel(); boolean dispatchNeeded; synchronized (callStack) { - System.out.println("field fetched at level " + level + " - " + executionStrategyParameters.getPath()); - callStack.increaseHappenedFetchCount(level); - dispatchNeeded = dispatchIfNeeded(level, callStack); + callStack.happenedFetchCountPerLevel.increment(level, 1); + dispatchNeeded = markLevelAsDispatchedIfReady(level, callStack); } if (dispatchNeeded) { dispatch(level, callStack); @@ -525,11 +344,67 @@ public void fieldFetched(ExecutionContext executionContext, } - // -// thread safety : called with callStack.lock + @Override + public void newSubscriptionExecution(FieldValueInfo fieldValueInfo, AlternativeCallContext alternativeCallContext) { + CallStack callStack = getCallStack(alternativeCallContext); + synchronized (callStack) { + callStack.happenedFetchCountPerLevel.increment(1, 1); + } + callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo); +// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, 1, callStack); + } + + @Override + public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable + throwable, ExecutionStrategyParameters parameters) { + CallStack callStack = getCallStack(parameters); + boolean ready; + synchronized (callStack) { + callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo); + Assert.assertNotNull(parameters.getDeferredCallContext()); + ready = callStack.deferredFragmentRootFieldsFetched.size() == parameters.getDeferredCallContext().getFields(); + } +// if (ready) { +// int curLevel = parameters.getPath().getLevel(); +// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, curLevel, callStack); +// } + } + // - private boolean dispatchIfNeeded(int level, CallStack callStack) { - boolean ready = checkLevelImpl(level, callStack); + + private CallStack getCallStack(ExecutionStrategyParameters parameters) { + return getCallStack(parameters.getDeferredCallContext()); + } + + private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallContext) { + if (alternativeCallContext == null) { + return this.initialCallStack; + } else { + return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { + CallStack callStack = new CallStack(); +// System.out.println("new callstack: " + callStack); + int startLevel = alternativeCallContext.getStartLevel(); + int fields = alternativeCallContext.getFields(); + callStack.expectedFetchCountPerLevel.set(1, 1); + callStack.happenedFetchCountPerLevel.set(1, 1); + return callStack; + }); + } + } + + + private void resetCallStack(CallStack callStack) { + synchronized (callStack) { + callStack.clear(); + callStack.chainedDLStack.clear(); + } + } + +// + + private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { + boolean ready = isLevelReady(level, callStack); +// System.out.println("markLevelAsDispatchedIfReady level: " + level + " ready: " + ready); if (ready) { callStack.setDispatchedLevel(level); return true; @@ -537,62 +412,37 @@ private boolean dispatchIfNeeded(int level, CallStack callStack) { return false; } - // -// thread safety: called with callStack.lock -// -// private @Nullable Integer getHighestReadyLevel(int startFrom, CallStack callStack) { -// while (true) { -// if (!checkLevelImpl(curLevel + 1, callStack)) { -// callStack.highestReadyLevel = curLevel; -// return curLevel >= startFrom ? curLevel : null; -// } -// curLevel++; -// } -// } - -// private boolean checkLevelBeingReady(int level, CallStack callStack) { -// Assert.assertTrue(level > 0); -// -// for (int i = callStack.highestReadyLevel + 1; i <= level; i++) { -// if (!checkLevelImpl(i, callStack)) { -// return false; -// } -// } -// callStack.highestReadyLevel = level; -// return true; -// } - private boolean checkLevelImpl(int level, CallStack callStack) { - System.out.println("checkLevelImpl " + level); + private boolean isLevelReady(int level, CallStack callStack) { // a level with zero expectations can't be ready - if (callStack.expectedFetchCountPerLevel.get(level) == 0) { + int expectedFetchCount = callStack.expectedFetchCountPerLevel.get(level); + if (expectedFetchCount == 0) { return false; } - // all fetches happened - if (!callStack.allFetchesHappened(level)) { + if (expectedFetchCount != callStack.happenedFetchCountPerLevel.get(level)) { return false; } - - int levelTmp = level - 1; - while (levelTmp >= 1) { - if (!callStack.allFieldsCompleted(levelTmp)) { - return false; - } - levelTmp--; + if (level == 1) { + // for the root fields we just expect that they were all fetched + return true; } - System.out.println("check ready " + level); - return true; + + // we expect that parent has been dispatched and that all parents fields are completed + // all parent fields completed means all parent parent on completions finished calls must have happened + return callStack.dispatchedLevels.contains(level - 1) && + callStack.happenedExecuteObjectCallsPerLevel.get(level - 2) == callStack.happenedCompletionFinishedCountPerLevel.get(level - 2); + } void dispatch(int level, CallStack callStack) { +// System.out.println("dispatching at " + level); if (!enableDataLoaderChaining) { profiler.oldStrategyDispatchingAll(level); DataLoaderRegistry dataLoaderRegistry = executionContext.getDataLoaderRegistry(); dispatchAll(dataLoaderRegistry, level); return; } -// System.out.println("dispatching " + level); dispatchDLCFImpl(level, callStack, true, false); } From 0436e5d9155acc5548089e7b9f99939b287c0f93 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 12:15:55 +1000 Subject: [PATCH 10/40] subscription works --- .../execution/DataLoaderDispatchStrategy.java | 5 ++- .../SubscriptionExecutionStrategy.java | 4 +- .../PerLevelDataLoaderDispatchStrategy.java | 37 +++++++++++++------ 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java index a169b1cb9..88ec0270e 100644 --- a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java @@ -61,8 +61,11 @@ default void fieldFetched(ExecutionContext executionContext, } + default void newSubscriptionExecution(AlternativeCallContext alternativeCallContext) { - default void newSubscriptionExecution(FieldValueInfo fieldValueInfo, AlternativeCallContext alternativeCallContext) { + } + + default void subscriptionEventCompletionDone(AlternativeCallContext alternativeCallContext) { } } diff --git a/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java b/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java index d2da97847..50cfcb4bc 100644 --- a/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java +++ b/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java @@ -168,9 +168,11 @@ private CompletableFuture executeSubscriptionEvent(ExecutionCon i13nFieldParameters, executionContext.getInstrumentationState() )); + + executionContext.getDataLoaderDispatcherStrategy().newSubscriptionExecution(newParameters.getDeferredCallContext()); Object fetchedValue = unboxPossibleDataFetcherResult(newExecutionContext, newParameters, eventPayload); FieldValueInfo fieldValueInfo = completeField(newExecutionContext, newParameters, fetchedValue); - executionContext.getDataLoaderDispatcherStrategy().newSubscriptionExecution(fieldValueInfo, newParameters.getDeferredCallContext()); + executionContext.getDataLoaderDispatcherStrategy().subscriptionEventCompletionDone(newParameters.getDeferredCallContext()); CompletableFuture overallResult = fieldValueInfo .getFieldValueFuture() .thenApply(val -> new ExecutionResultImpl(val, newParameters.getDeferredCallContext().getErrors())) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 4a7dde97f..cefd0fa0d 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -277,7 +277,7 @@ public void executionStrategyOnFieldValuesException(Throwable t, ExecutionStrate public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { CallStack callStack = getCallStack(parameters); int curLevel = parameters.getPath().getLevel(); -// System.out.println("execute object " + curLevel + " at " + parameters.getPath() ); +// System.out.println("execute object " + curLevel + " at " + parameters.getPath() + " with callstack " + callStack.hashCode()); synchronized (callStack) { callStack.happenedExecuteObjectCallsPerLevel.increment(curLevel, 1); callStack.expectedFetchCountPerLevel.increment(curLevel + 1, fieldCount); @@ -332,6 +332,7 @@ public void fieldFetched(ExecutionContext executionContext, Supplier dataFetchingEnvironment) { CallStack callStack = getCallStack(executionStrategyParameters); int level = executionStrategyParameters.getPath().getLevel(); +// System.out.println("field fetched at: " + level + " path: " + executionStrategyParameters.getPath() + " callStack: " + callStack.hashCode()); boolean dispatchNeeded; synchronized (callStack) { callStack.happenedFetchCountPerLevel.increment(level, 1); @@ -345,13 +346,22 @@ public void fieldFetched(ExecutionContext executionContext, @Override - public void newSubscriptionExecution(FieldValueInfo fieldValueInfo, AlternativeCallContext alternativeCallContext) { + public void newSubscriptionExecution(AlternativeCallContext alternativeCallContext) { + CallStack callStack = new CallStack(); + alternativeCallContextMap.put(alternativeCallContext, callStack); + + } + + @Override + public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCallContext) { CallStack callStack = getCallStack(alternativeCallContext); + // this means the single root field is completed (it was never "fetched" because it is + // the event payload) and we can mark level 1 (root fields) as dispatched and level 0 as completed synchronized (callStack) { - callStack.happenedFetchCountPerLevel.increment(1, 1); + callStack.dispatchedLevels.add(1); + callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); } - callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo); -// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, 1, callStack); + onCompletionFinished(0, callStack); } @Override @@ -382,11 +392,17 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC } else { return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { CallStack callStack = new CallStack(); -// System.out.println("new callstack: " + callStack); - int startLevel = alternativeCallContext.getStartLevel(); - int fields = alternativeCallContext.getFields(); - callStack.expectedFetchCountPerLevel.set(1, 1); - callStack.happenedFetchCountPerLevel.set(1, 1); +// System.out.println("new callstack : " + callStack.hashCode()); + // for subscriptions there is only root field which is already fetched +// callStack.expectedFetchCountPerLevel.set(1, 1); +// callStack.happenedFetchCountPerLevel.set(1, 1); +// // the level 0 is done +// callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); +// callStack.happenedCompletionFinishedCountPerLevel.set(0, 1); +// // level is 1 already dispatched +// callStack.setDispatchedLevel(1); +// int startLevel = alternativeCallContext.getStartLevel(); +// int fields = alternativeCallContext.getFields(); return callStack; }); } @@ -400,7 +416,6 @@ private void resetCallStack(CallStack callStack) { } } -// private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { boolean ready = isLevelReady(level, callStack); From b25724b28582c893d612c8ee6f00b06a22abc037 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 13:37:58 +1000 Subject: [PATCH 11/40] fix defer support --- .../PerLevelDataLoaderDispatchStrategy.java | 41 +++++++++++-------- ...eferExecutionSupportIntegrationTest.groovy | 2 - .../dataloader/DeferWithDataLoaderTest.groovy | 7 ---- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index cefd0fa0d..b1ef445de 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -186,7 +186,7 @@ private static class CallStack { public ChainedDLStack chainedDLStack = new ChainedDLStack(); - private final List deferredFragmentRootFieldsFetched = new ArrayList<>(); + private int deferredFragmentRootFieldsCompleted; public CallStack() { } @@ -370,14 +370,14 @@ public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo CallStack callStack = getCallStack(parameters); boolean ready; synchronized (callStack) { - callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo); + callStack.deferredFragmentRootFieldsCompleted++; Assert.assertNotNull(parameters.getDeferredCallContext()); - ready = callStack.deferredFragmentRootFieldsFetched.size() == parameters.getDeferredCallContext().getFields(); + ready = callStack.deferredFragmentRootFieldsCompleted == parameters.getDeferredCallContext().getFields(); } -// if (ready) { -// int curLevel = parameters.getPath().getLevel(); -// onFieldValuesInfoDispatchIfNeeded(callStack.deferredFragmentRootFieldsFetched, curLevel, callStack); -// } + if (ready) { + onCompletionFinished(parameters.getDeferredCallContext().getStartLevel() - 1, callStack); + } + } // @@ -393,16 +393,21 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { CallStack callStack = new CallStack(); // System.out.println("new callstack : " + callStack.hashCode()); - // for subscriptions there is only root field which is already fetched -// callStack.expectedFetchCountPerLevel.set(1, 1); -// callStack.happenedFetchCountPerLevel.set(1, 1); -// // the level 0 is done -// callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); -// callStack.happenedCompletionFinishedCountPerLevel.set(0, 1); -// // level is 1 already dispatched -// callStack.setDispatchedLevel(1); -// int startLevel = alternativeCallContext.getStartLevel(); -// int fields = alternativeCallContext.getFields(); + // on which level the fields are + int startLevel = k.getStartLevel(); + // how many fields are deferred on this level + int fields = k.getFields(); + if (startLevel > 1) { + // parent level is considered dispatched all fields completed + callStack.dispatchedLevels.add(startLevel - 1); + callStack.happenedExecuteObjectCallsPerLevel.set(startLevel - 2, 1); + callStack.happenedCompletionFinishedCountPerLevel.set(startLevel - 2, 1); + } + // the parent will have one completion therefore we set the expectation to 1 + callStack.happenedExecuteObjectCallsPerLevel.set(startLevel - 1, 1); + + // for the current level we set the fetch expectations + callStack.expectedFetchCountPerLevel.set(startLevel, fields); return callStack; }); } @@ -419,7 +424,7 @@ private void resetCallStack(CallStack callStack) { private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { boolean ready = isLevelReady(level, callStack); -// System.out.println("markLevelAsDispatchedIfReady level: " + level + " ready: " + ready); +// System.out.println("markLevelAsDispatchedIfReady level: " + level + " ready: " + ready + " callstack: " + callStack.hashCode()); if (ready) { callStack.setDispatchedLevel(level); return true; diff --git a/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy b/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy index 8afa04300..b3b522d90 100644 --- a/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy +++ b/src/test/groovy/graphql/execution/incremental/DeferExecutionSupportIntegrationTest.groovy @@ -23,7 +23,6 @@ import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderRegistry import org.reactivestreams.Publisher -import spock.lang.Ignore import spock.lang.Specification import spock.lang.Unroll @@ -1691,7 +1690,6 @@ class DeferExecutionSupportIntegrationTest extends Specification { } - @Ignore("tmp not working") def "dataloader used inside defer"() { given: def query = ''' diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy index 5df5837bf..362206f64 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy @@ -11,7 +11,6 @@ import org.awaitility.Awaitility import org.dataloader.BatchLoader import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderRegistry -import spock.lang.Ignore import spock.lang.RepeatUntilFailure import spock.lang.Specification @@ -61,7 +60,6 @@ class DeferWithDataLoaderTest extends Specification { } } - @Ignore def "query with single deferred field"() { given: def query = getQuery(true, false) @@ -106,7 +104,6 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 3 } - @Ignore def "multiple fields on same defer block"() { given: def query = """ @@ -180,7 +177,6 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 } - @Ignore def "query with nested deferred fields"() { given: def query = getQuery(true, true) @@ -232,7 +228,6 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 9 } - @Ignore def "query with top-level deferred field"() { given: def query = """ @@ -296,7 +291,6 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 } - @Ignore def "query with multiple deferred fields"() { given: def query = getExpensiveQuery(true) @@ -354,7 +348,6 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 } - @Ignore @RepeatUntilFailure(maxAttempts = 50, ignoreRest = false) def "dataloader in initial result and chained dataloader inside nested defer block"() { given: From 117ebe180ac1a5e10c1f03bf8f80b3703c45e10b Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 13:58:14 +1000 Subject: [PATCH 12/40] cleanup --- .../PerLevelDataLoaderDispatchStrategy.java | 101 +++--------------- 1 file changed, 13 insertions(+), 88 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index b1ef445de..de253cc9e 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -134,48 +134,6 @@ public void clear() { private static class CallStack { - - /** - * A general overview of teh tracked data: - * There are three aspects tracked per level: - * - number of expected and happened execute object calls (executeObject) - * - number of expected and happened fetches - * - number of happened sub selections finished fetching - *

- * The level for an execute object call is the level of sub selection of the object: for - * { a {b {c}}} the level of "execute object a" is 2 - *

- * For fetches the level is the level of the field fetched - *

- * For sub selections finished it is the level of the fields inside the sub selection: - * {a1 { b c} a2 } the level of {a1 a2} is 1, the level of {b c} is 2 - *

- * The main aspect for when a level is ready is when all expected fetch call happened, meaning - * we can dispatch this level as all data loaders in this level have been called - * (if the number of expected fetches is correct). - *

- * The number of expected fetches is increased with every executeObject (based on the number of subselection - * fields for the execute object). - * Execute Object a (on level 2) with { a {f1 f2 f3} } means we expect 3 fetches on level 2. - *

- * A finished subselection means we can predict the number of execute object calls in the next level as the subselection: - * { a {x} b {y} } - * If a is a list of 3 objects and b is a list of 2 objects we expect 3 + 2 = 5 execute object calls on the level 2 to be happening - *

- * The finished sub selection is the only "cross level" event: a finished sub selections impacts the expected execute - * object calls on the next level. - *

- *

- * This means we know a level is ready to be dispatched if: - * - all expected fetched happened in the current level - * - all expected execute objects calls happened in the current level (because they inform the expected fetches) - * - all expected sub selections happened in the parent level (because they inform the expected execute object in the current level). - * The expected sub selections are equal to the expected object calls (in the parent level) - * - All expected sub selections happened in the parent parent level (again: meaning #happenedSubSelections == #expectedExecuteObjectCalls) - * - And so until the first level - */ - - private final LevelMap expectedFetchCountPerLevel = new LevelMap(); private final LevelMap happenedFetchCountPerLevel = new LevelMap(); private final LevelMap happenedCompletionFinishedCountPerLevel = new LevelMap(); @@ -192,37 +150,14 @@ public CallStack() { } - void clearDispatchLevels() { - dispatchedLevels.clear(); - } - - @Override - public String toString() { - return "CallStack{" + - "expectedFetchCountPerLevel=" + expectedFetchCountPerLevel + - ", fetchCountPerLevel=" + happenedFetchCountPerLevel + -// ", expectedExecuteObjectCallsPerLevel=" + expectedExecuteObjectCallsPerLevel + -// ", happenedExecuteObjectCallsPerLevel=" + happenedExecuteObjectCallsPerLevel + -// ", happenedOnFieldValueCallsPerLevel=" + happenedOnFieldValueCallsPerLevel + - ", dispatchedLevels" + dispatchedLevels + - '}'; - } - - - public void setDispatchedLevel(int level) { - if (!dispatchedLevels.add(level)) { - Assert.assertShouldNeverHappen("level " + level + " already dispatched"); - } - } - public void clear() { dispatchedLevels.clear(); happenedExecuteObjectCallsPerLevel.clear(); expectedFetchCountPerLevel.clear(); happenedFetchCountPerLevel.clear(); happenedCompletionFinishedCountPerLevel.clear(); - - + deferredFragmentRootFieldsCompleted = 0; + chainedDLStack.clear(); } } @@ -240,7 +175,6 @@ public PerLevelDataLoaderDispatchStrategy(ExecutionContext executionContext) { @Override public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); -// System.out.println("execution strategy started"); synchronized (initialCallStack) { initialCallStack.happenedExecuteObjectCallsPerLevel.set(0, 1); initialCallStack.expectedFetchCountPerLevel.set(1, fieldCount); @@ -250,10 +184,10 @@ public void executionStrategy(ExecutionContext executionContext, ExecutionStrate @Override public void executionSerialStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); - resetCallStack(callStack); - // field count is always 1 for serial execution + callStack.clear(); synchronized (callStack) { callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); + // field count is always 1 for serial execution callStack.expectedFetchCountPerLevel.set(1, 1); } } @@ -261,7 +195,6 @@ public void executionSerialStrategy(ExecutionContext executionContext, Execution @Override public void executionStrategyOnFieldValuesInfo(List fieldValueInfoList, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); -// System.out.println("1st level fields completed"); onCompletionFinished(0, callStack); } @@ -277,7 +210,6 @@ public void executionStrategyOnFieldValuesException(Throwable t, ExecutionStrate public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { CallStack callStack = getCallStack(parameters); int curLevel = parameters.getPath().getLevel(); -// System.out.println("execute object " + curLevel + " at " + parameters.getPath() + " with callstack " + callStack.hashCode()); synchronized (callStack) { callStack.happenedExecuteObjectCallsPerLevel.increment(curLevel, 1); callStack.expectedFetchCountPerLevel.increment(curLevel + 1, fieldCount); @@ -289,7 +221,6 @@ public void executeObject(ExecutionContext executionContext, ExecutionStrategyPa (List fieldValueInfoList, ExecutionStrategyParameters parameters) { int curLevel = parameters.getPath().getLevel(); CallStack callStack = getCallStack(parameters); -// System.out.println("completion finished at " + curLevel + " at " + parameters.getPath() ); onCompletionFinished(curLevel, callStack); } @@ -332,7 +263,6 @@ public void fieldFetched(ExecutionContext executionContext, Supplier dataFetchingEnvironment) { CallStack callStack = getCallStack(executionStrategyParameters); int level = executionStrategyParameters.getPath().getLevel(); -// System.out.println("field fetched at: " + level + " path: " + executionStrategyParameters.getPath() + " callStack: " + callStack.hashCode()); boolean dispatchNeeded; synchronized (callStack) { callStack.happenedFetchCountPerLevel.increment(level, 1); @@ -380,7 +310,6 @@ public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo } -// private CallStack getCallStack(ExecutionStrategyParameters parameters) { return getCallStack(parameters.getDeferredCallContext()); @@ -391,14 +320,18 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC return this.initialCallStack; } else { return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { + /* + This is only for handling deferred cases. Subscription cases will also get a new callStack, but + it is explicitly created in `newSubscriptionExecution`. + The reason we are doing this lazily is, because we don't have explicit startDeferred callback. + */ CallStack callStack = new CallStack(); -// System.out.println("new callstack : " + callStack.hashCode()); // on which level the fields are int startLevel = k.getStartLevel(); // how many fields are deferred on this level int fields = k.getFields(); if (startLevel > 1) { - // parent level is considered dispatched all fields completed + // parent level is considered dispatched and all fields completed callStack.dispatchedLevels.add(startLevel - 1); callStack.happenedExecuteObjectCallsPerLevel.set(startLevel - 2, 1); callStack.happenedCompletionFinishedCountPerLevel.set(startLevel - 2, 1); @@ -414,19 +347,12 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC } - private void resetCallStack(CallStack callStack) { - synchronized (callStack) { - callStack.clear(); - callStack.chainedDLStack.clear(); - } - } - - private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { boolean ready = isLevelReady(level, callStack); -// System.out.println("markLevelAsDispatchedIfReady level: " + level + " ready: " + ready + " callstack: " + callStack.hashCode()); if (ready) { - callStack.setDispatchedLevel(level); + if (!callStack.dispatchedLevels.add(level)) { + Assert.assertShouldNeverHappen("level " + level + " already dispatched"); + } return true; } return false; @@ -456,7 +382,6 @@ private boolean isLevelReady(int level, CallStack callStack) { } void dispatch(int level, CallStack callStack) { -// System.out.println("dispatching at " + level); if (!enableDataLoaderChaining) { profiler.oldStrategyDispatchingAll(level); DataLoaderRegistry dataLoaderRegistry = executionContext.getDataLoaderRegistry(); From a5d29a6a4f5d68fb2ab43f1d9fecf45b293ce336 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 14:01:12 +1000 Subject: [PATCH 13/40] cleanup --- .../java/graphql/execution/DataLoaderDispatchStrategy.java | 4 ---- src/main/java/graphql/execution/ExecutionStrategy.java | 1 - 2 files changed, 5 deletions(-) diff --git a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java index 88ec0270e..8763d650f 100644 --- a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java @@ -40,10 +40,6 @@ default void executeObjectOnFieldValuesInfo(List fieldValueInfoL } - default void fieldCompleted(FieldValueInfo fieldValueInfo, ExecutionStrategyParameters executionStrategyParameters) { - - } - default void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable throwable, ExecutionStrategyParameters parameters) { } diff --git a/src/main/java/graphql/execution/ExecutionStrategy.java b/src/main/java/graphql/execution/ExecutionStrategy.java index 8d29152b4..a6061a15c 100644 --- a/src/main/java/graphql/execution/ExecutionStrategy.java +++ b/src/main/java/graphql/execution/ExecutionStrategy.java @@ -638,7 +638,6 @@ private FieldValueInfo completeField(GraphQLFieldDefinition fieldDef, ExecutionC ); FieldValueInfo fieldValueInfo = completeValue(executionContext, newParameters); - executionContext.getDataLoaderDispatcherStrategy().fieldCompleted(fieldValueInfo, parameters); ctxCompleteField.onDispatched(); if (fieldValueInfo.isFutureValue()) { CompletableFuture executionResultFuture = fieldValueInfo.getFieldValueFuture(); From 2686c32e64cbd240b63ef7e7e345e19daec9e654 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 19:32:43 +1000 Subject: [PATCH 14/40] no per level tracking anymore --- .../performance/DataLoaderPerformance.java | 36 +++++++------- .../PerLevelDataLoaderDispatchStrategy.java | 48 ++++++++++++------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/jmh/java/performance/DataLoaderPerformance.java b/src/jmh/java/performance/DataLoaderPerformance.java index d81636771..20e144abd 100644 --- a/src/jmh/java/performance/DataLoaderPerformance.java +++ b/src/jmh/java/performance/DataLoaderPerformance.java @@ -4,7 +4,6 @@ import graphql.ExecutionInput; import graphql.ExecutionResult; import graphql.GraphQL; -import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys; import graphql.schema.DataFetcher; import graphql.schema.GraphQLSchema; import graphql.schema.idl.RuntimeWiring; @@ -15,28 +14,16 @@ import org.dataloader.DataLoader; import org.dataloader.DataLoaderFactory; import org.dataloader.DataLoaderRegistry; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -@State(Scope.Benchmark) -@Warmup(iterations = 2, time = 5) -@Measurement(iterations = 3) -@Fork(2) public class DataLoaderPerformance { static Owner o1 = new Owner("O-1", "Andi", List.of("P-1", "P-2", "P-3")); @@ -573,9 +560,6 @@ public void setup() { } - @Benchmark - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.MILLISECONDS) public void executeRequestWithDataLoaders(MyState myState, Blackhole blackhole) { DataLoader ownerDL = DataLoaderFactory.newDataLoader(ownerBatchLoader); DataLoader petDL = DataLoaderFactory.newDataLoader(petBatchLoader); @@ -587,14 +571,30 @@ public void executeRequestWithDataLoaders(MyState myState, Blackhole blackhole) .dataLoaderRegistry(registry) // .profileExecution(true) .build(); - executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, true); +// executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, true); ExecutionResult execute = myState.graphQL.execute(executionInput); // ProfilerResult profilerResult = executionInput.getGraphQLContext().get(ProfilerResult.PROFILER_CONTEXT_KEY); -// System.out.println(profilerResult.shortSummaryMap()); +// System.out.println("execute: " + execute); Assert.assertTrue(execute.isDataPresent()); Assert.assertTrue(execute.getErrors().isEmpty()); blackhole.consume(execute); } + public static void main(String[] args) { + DataLoaderPerformance dataLoaderPerformance = new DataLoaderPerformance(); + MyState myState = new MyState(); + myState.setup(); + Blackhole blackhole = new Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous."); + for (int i = 0; i < 1; i++) { + dataLoaderPerformance.executeRequestWithDataLoaders(myState, blackhole); + } +// System.out.println(PerLevelDataLoaderDispatchStrategy.fieldFetchedCount); +// System.out.println(PerLevelDataLoaderDispatchStrategy.onCompletionFinishedCount); +// System.out.println(PerLevelDataLoaderDispatchStrategy.isReadyCounter); +// System.out.println(Duration.ofNanos(PerLevelDataLoaderDispatchStrategy.isReadyCounterNS.get()).toMillis()); + + + } + } diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index de253cc9e..89af3014f 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -17,6 +17,7 @@ import org.jspecify.annotations.Nullable; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -139,7 +140,7 @@ private static class CallStack { private final LevelMap happenedCompletionFinishedCountPerLevel = new LevelMap(); private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); - private final Set dispatchedLevels = ConcurrentHashMap.newKeySet(); + private final Set dispatchedLevels = new LinkedHashSet<>(); public ChainedDLStack chainedDLStack = new ChainedDLStack(); @@ -228,9 +229,11 @@ public void executeObject(ExecutionContext executionContext, ExecutionStrategyPa public void executeObjectOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); int curLevel = parameters.getPath().getLevel(); +// System.out.println("completion finished for level " + curLevel); onCompletionFinished(curLevel, callStack); } + private void onCompletionFinished(int level, CallStack callStack) { synchronized (callStack) { callStack.happenedCompletionFinishedCountPerLevel.increment(level, 1); @@ -241,6 +244,7 @@ private void onCompletionFinished(int level, CallStack callStack) { boolean levelReady; synchronized (callStack) { if (callStack.dispatchedLevels.contains(currentLevel)) { +// System.out.println("failed because already dispatched"); break; } levelReady = markLevelAsDispatchedIfReady(currentLevel, callStack); @@ -248,6 +252,7 @@ private void onCompletionFinished(int level, CallStack callStack) { if (levelReady) { dispatch(currentLevel, callStack); } else { +// System.out.println("failed because level not ready"); break; } currentLevel++; @@ -255,6 +260,7 @@ private void onCompletionFinished(int level, CallStack callStack) { } + @Override public void fieldFetched(ExecutionContext executionContext, ExecutionStrategyParameters executionStrategyParameters, @@ -263,12 +269,20 @@ public void fieldFetched(ExecutionContext executionContext, Supplier dataFetchingEnvironment) { CallStack callStack = getCallStack(executionStrategyParameters); int level = executionStrategyParameters.getPath().getLevel(); - boolean dispatchNeeded; - synchronized (callStack) { - callStack.happenedFetchCountPerLevel.increment(level, 1); - dispatchNeeded = markLevelAsDispatchedIfReady(level, callStack); + boolean dispatchNeeded = false; +// System.out.println("field fetched for level " + level + " path: " + executionStrategyParameters.getPath()); + AlternativeCallContext deferredCallContext = executionStrategyParameters.getDeferredCallContext(); + if (level == 1 || (deferredCallContext != null && level == deferredCallContext.getStartLevel())) { + synchronized (callStack) { + callStack.happenedFetchCountPerLevel.increment(level, 1); + dispatchNeeded = callStack.expectedFetchCountPerLevel.get(level) == callStack.happenedFetchCountPerLevel.get(level); + if (dispatchNeeded) { + callStack.dispatchedLevels.add(level); + } + } } if (dispatchNeeded) { +// System.out.println("Success field fetch"); dispatch(level, callStack); } @@ -361,27 +375,25 @@ private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { private boolean isLevelReady(int level, CallStack callStack) { // a level with zero expectations can't be ready - int expectedFetchCount = callStack.expectedFetchCountPerLevel.get(level); - if (expectedFetchCount == 0) { - return false; - } +// int expectedFetchCount = callStack.expectedFetchCountPerLevel.get(level); +// if (expectedFetchCount == 0) { +// return false; +// } - if (expectedFetchCount != callStack.happenedFetchCountPerLevel.get(level)) { - return false; - } - if (level == 1) { - // for the root fields we just expect that they were all fetched - return true; - } +// if (expectedFetchCount != callStack.happenedFetchCountPerLevel.get(level)) { +// return false; +// } // we expect that parent has been dispatched and that all parents fields are completed // all parent fields completed means all parent parent on completions finished calls must have happened + int happenedExecuteObjectCalls = callStack.happenedExecuteObjectCallsPerLevel.get(level - 2); return callStack.dispatchedLevels.contains(level - 1) && - callStack.happenedExecuteObjectCallsPerLevel.get(level - 2) == callStack.happenedCompletionFinishedCountPerLevel.get(level - 2); + happenedExecuteObjectCalls > 0 && happenedExecuteObjectCalls == callStack.happenedCompletionFinishedCountPerLevel.get(level - 2); } void dispatch(int level, CallStack callStack) { +// System.out.println("dispatching " + level); if (!enableDataLoaderChaining) { profiler.oldStrategyDispatchingAll(level); DataLoaderRegistry dataLoaderRegistry = executionContext.getDataLoaderRegistry(); @@ -392,9 +404,11 @@ void dispatch(int level, CallStack callStack) { } private void dispatchAll(DataLoaderRegistry dataLoaderRegistry, int level) { +// System.out.println("dispatch level " + level); for (DataLoader dataLoader : dataLoaderRegistry.getDataLoaders()) { dataLoader.dispatch().whenComplete((objects, throwable) -> { if (objects != null && objects.size() > 0) { +// System.out.println("dispatching " + objects.size() + " objects for level " + level); Assert.assertNotNull(dataLoader.getName()); profiler.batchLoadedOldStrategy(dataLoader.getName(), level, objects.size()); } From a67e56bf9560538f39a45b3ce9bff728f37622fb Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 19:43:10 +1000 Subject: [PATCH 15/40] cleanup --- .../PerLevelDataLoaderDispatchStrategy.java | 41 +++++-------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 89af3014f..4f0b8c081 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -135,8 +135,8 @@ public void clear() { private static class CallStack { - private final LevelMap expectedFetchCountPerLevel = new LevelMap(); - private final LevelMap happenedFetchCountPerLevel = new LevelMap(); + private int expectedFirstLevelFetchCount; + private int happenedFirstLevelFetchCount; private final LevelMap happenedCompletionFinishedCountPerLevel = new LevelMap(); private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); @@ -154,8 +154,8 @@ public CallStack() { public void clear() { dispatchedLevels.clear(); happenedExecuteObjectCallsPerLevel.clear(); - expectedFetchCountPerLevel.clear(); - happenedFetchCountPerLevel.clear(); + expectedFirstLevelFetchCount = 0; + happenedFirstLevelFetchCount = 0; happenedCompletionFinishedCountPerLevel.clear(); deferredFragmentRootFieldsCompleted = 0; chainedDLStack.clear(); @@ -178,7 +178,7 @@ public void executionStrategy(ExecutionContext executionContext, ExecutionStrate Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); synchronized (initialCallStack) { initialCallStack.happenedExecuteObjectCallsPerLevel.set(0, 1); - initialCallStack.expectedFetchCountPerLevel.set(1, fieldCount); + initialCallStack.expectedFirstLevelFetchCount = fieldCount; } } @@ -189,7 +189,7 @@ public void executionSerialStrategy(ExecutionContext executionContext, Execution synchronized (callStack) { callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); // field count is always 1 for serial execution - callStack.expectedFetchCountPerLevel.set(1, 1); + initialCallStack.expectedFirstLevelFetchCount = 1; } } @@ -213,13 +213,11 @@ public void executeObject(ExecutionContext executionContext, ExecutionStrategyPa int curLevel = parameters.getPath().getLevel(); synchronized (callStack) { callStack.happenedExecuteObjectCallsPerLevel.increment(curLevel, 1); - callStack.expectedFetchCountPerLevel.increment(curLevel + 1, fieldCount); } } @Override - public void executeObjectOnFieldValuesInfo - (List fieldValueInfoList, ExecutionStrategyParameters parameters) { + public void executeObjectOnFieldValuesInfo(List fieldValueInfoList, ExecutionStrategyParameters parameters) { int curLevel = parameters.getPath().getLevel(); CallStack callStack = getCallStack(parameters); onCompletionFinished(curLevel, callStack); @@ -229,7 +227,6 @@ public void executeObject(ExecutionContext executionContext, ExecutionStrategyPa public void executeObjectOnFieldValuesException(Throwable t, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); int curLevel = parameters.getPath().getLevel(); -// System.out.println("completion finished for level " + curLevel); onCompletionFinished(curLevel, callStack); } @@ -238,13 +235,11 @@ private void onCompletionFinished(int level, CallStack callStack) { synchronized (callStack) { callStack.happenedCompletionFinishedCountPerLevel.increment(level, 1); } - // on completion might mark multiple higher levels as ready int currentLevel = level + 2; while (true) { boolean levelReady; synchronized (callStack) { if (callStack.dispatchedLevels.contains(currentLevel)) { -// System.out.println("failed because already dispatched"); break; } levelReady = markLevelAsDispatchedIfReady(currentLevel, callStack); @@ -252,7 +247,6 @@ private void onCompletionFinished(int level, CallStack callStack) { if (levelReady) { dispatch(currentLevel, callStack); } else { -// System.out.println("failed because level not ready"); break; } currentLevel++; @@ -270,19 +264,17 @@ public void fieldFetched(ExecutionContext executionContext, CallStack callStack = getCallStack(executionStrategyParameters); int level = executionStrategyParameters.getPath().getLevel(); boolean dispatchNeeded = false; -// System.out.println("field fetched for level " + level + " path: " + executionStrategyParameters.getPath()); AlternativeCallContext deferredCallContext = executionStrategyParameters.getDeferredCallContext(); if (level == 1 || (deferredCallContext != null && level == deferredCallContext.getStartLevel())) { synchronized (callStack) { - callStack.happenedFetchCountPerLevel.increment(level, 1); - dispatchNeeded = callStack.expectedFetchCountPerLevel.get(level) == callStack.happenedFetchCountPerLevel.get(level); + callStack.happenedFirstLevelFetchCount++; + dispatchNeeded = callStack.expectedFirstLevelFetchCount == callStack.happenedFirstLevelFetchCount; if (dispatchNeeded) { callStack.dispatchedLevels.add(level); } } } if (dispatchNeeded) { -// System.out.println("Success field fetch"); dispatch(level, callStack); } @@ -354,7 +346,7 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC callStack.happenedExecuteObjectCallsPerLevel.set(startLevel - 1, 1); // for the current level we set the fetch expectations - callStack.expectedFetchCountPerLevel.set(startLevel, fields); + callStack.expectedFirstLevelFetchCount = fields; return callStack; }); } @@ -374,16 +366,6 @@ private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { private boolean isLevelReady(int level, CallStack callStack) { - // a level with zero expectations can't be ready -// int expectedFetchCount = callStack.expectedFetchCountPerLevel.get(level); -// if (expectedFetchCount == 0) { -// return false; -// } - -// if (expectedFetchCount != callStack.happenedFetchCountPerLevel.get(level)) { -// return false; -// } - // we expect that parent has been dispatched and that all parents fields are completed // all parent fields completed means all parent parent on completions finished calls must have happened int happenedExecuteObjectCalls = callStack.happenedExecuteObjectCallsPerLevel.get(level - 2); @@ -393,7 +375,6 @@ private boolean isLevelReady(int level, CallStack callStack) { } void dispatch(int level, CallStack callStack) { -// System.out.println("dispatching " + level); if (!enableDataLoaderChaining) { profiler.oldStrategyDispatchingAll(level); DataLoaderRegistry dataLoaderRegistry = executionContext.getDataLoaderRegistry(); @@ -404,11 +385,9 @@ void dispatch(int level, CallStack callStack) { } private void dispatchAll(DataLoaderRegistry dataLoaderRegistry, int level) { -// System.out.println("dispatch level " + level); for (DataLoader dataLoader : dataLoaderRegistry.getDataLoaders()) { dataLoader.dispatch().whenComplete((objects, throwable) -> { if (objects != null && objects.size() > 0) { -// System.out.println("dispatching " + objects.size() + " objects for level " + level); Assert.assertNotNull(dataLoader.getName()); profiler.batchLoadedOldStrategy(dataLoader.getName(), level, objects.size()); } From 2da8fef1aac9b313b09cb6b3d86932592bfbb1ee Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 20:56:51 +1000 Subject: [PATCH 16/40] no synchronized/locking anymore --- .../PerLevelDataLoaderDispatchStrategy.java | 158 +++++++++++------- 1 file changed, 102 insertions(+), 56 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 4f0b8c081..2cafbaa09 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -17,12 +17,12 @@ import org.jspecify.annotations.Nullable; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; @@ -135,29 +135,75 @@ public void clear() { private static class CallStack { - private int expectedFirstLevelFetchCount; - private int happenedFirstLevelFetchCount; - private final LevelMap happenedCompletionFinishedCountPerLevel = new LevelMap(); - private final LevelMap happenedExecuteObjectCallsPerLevel = new LevelMap(); + static class StateForLevel { + private final int happenedCompletionFinishedCount; + private final int happenedExecuteObjectCalls; - private final Set dispatchedLevels = new LinkedHashSet<>(); + public StateForLevel() { + this.happenedCompletionFinishedCount = 0; + this.happenedExecuteObjectCalls = 0; + } + + public StateForLevel(int happenedCompletionFinishedCount, int happenedExecuteObjectCalls) { + this.happenedCompletionFinishedCount = happenedCompletionFinishedCount; + this.happenedExecuteObjectCalls = happenedExecuteObjectCalls; + } + + public StateForLevel(StateForLevel other) { + this.happenedCompletionFinishedCount = other.happenedCompletionFinishedCount; + this.happenedExecuteObjectCalls = other.happenedExecuteObjectCalls; + } + + public StateForLevel copy() { + return new StateForLevel(this); + } + + public StateForLevel increaseHappenedCompletionFinishedCount() { + return new StateForLevel(happenedCompletionFinishedCount + 1, happenedExecuteObjectCalls); + } + + public StateForLevel increaseHappenedExecuteObjectCalls() { + return new StateForLevel(happenedCompletionFinishedCount, happenedExecuteObjectCalls + 1); + } + + } + + private final Object firstLevelDataLock = new Object() { + }; + private volatile int expectedFirstLevelFetchCount; + private final AtomicInteger happenedFirstLevelFetchCount = new AtomicInteger(); + + + private final Map> stateForLevelMap = new ConcurrentHashMap<>(); + + private final Set dispatchedLevels = ConcurrentHashMap.newKeySet(); public ChainedDLStack chainedDLStack = new ChainedDLStack(); - private int deferredFragmentRootFieldsCompleted; + private final AtomicInteger deferredFragmentRootFieldsCompleted = new AtomicInteger(); public CallStack() { } + public StateForLevel get(int level) { + AtomicReference dataPerLevelAtomicReference = stateForLevelMap.computeIfAbsent(level, __ -> new AtomicReference<>(new StateForLevel())); + return Assert.assertNotNull(dataPerLevelAtomicReference.get()); + } + + public boolean tryUpdateLevel(int level, StateForLevel oldData, StateForLevel newData) { + AtomicReference dataPerLevelAtomicReference = Assert.assertNotNull(stateForLevelMap.get(level)); + return dataPerLevelAtomicReference.compareAndSet(oldData, newData); + } + + public void clear() { dispatchedLevels.clear(); - happenedExecuteObjectCallsPerLevel.clear(); + stateForLevelMap.clear(); expectedFirstLevelFetchCount = 0; - happenedFirstLevelFetchCount = 0; - happenedCompletionFinishedCountPerLevel.clear(); - deferredFragmentRootFieldsCompleted = 0; + happenedFirstLevelFetchCount.set(0); + deferredFragmentRootFieldsCompleted.set(0); chainedDLStack.clear(); } } @@ -176,21 +222,20 @@ public PerLevelDataLoaderDispatchStrategy(ExecutionContext executionContext) { @Override public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); - synchronized (initialCallStack) { - initialCallStack.happenedExecuteObjectCallsPerLevel.set(0, 1); - initialCallStack.expectedFirstLevelFetchCount = fieldCount; - } + // no concurrency access happening + CallStack.StateForLevel currentState = initialCallStack.get(0); + initialCallStack.tryUpdateLevel(0, currentState, new CallStack.StateForLevel(0, 1)); + initialCallStack.expectedFirstLevelFetchCount = fieldCount; } @Override public void executionSerialStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); callStack.clear(); - synchronized (callStack) { - callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); - // field count is always 1 for serial execution - initialCallStack.expectedFirstLevelFetchCount = 1; - } + CallStack.StateForLevel currentState = initialCallStack.get(0); + initialCallStack.tryUpdateLevel(0, currentState, new CallStack.StateForLevel(0, 1)); + // field count is always 1 for serial execution + initialCallStack.expectedFirstLevelFetchCount = 1; } @Override @@ -211,8 +256,12 @@ public void executionStrategyOnFieldValuesException(Throwable t, ExecutionStrate public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { CallStack callStack = getCallStack(parameters); int curLevel = parameters.getPath().getLevel(); - synchronized (callStack) { - callStack.happenedExecuteObjectCallsPerLevel.increment(curLevel, 1); + while (true) { + CallStack.StateForLevel currentState = callStack.get(curLevel); + if (callStack.tryUpdateLevel(curLevel, currentState, currentState.increaseHappenedExecuteObjectCalls())) { + return; + } + } } @@ -232,18 +281,20 @@ public void executeObjectOnFieldValuesException(Throwable t, ExecutionStrategyPa private void onCompletionFinished(int level, CallStack callStack) { - synchronized (callStack) { - callStack.happenedCompletionFinishedCountPerLevel.increment(level, 1); + while (true) { + CallStack.StateForLevel currentState = callStack.get(level); + if (callStack.tryUpdateLevel(level, currentState, currentState.increaseHappenedCompletionFinishedCount())) { + break; + } } + int currentLevel = level + 2; while (true) { boolean levelReady; - synchronized (callStack) { - if (callStack.dispatchedLevels.contains(currentLevel)) { - break; - } - levelReady = markLevelAsDispatchedIfReady(currentLevel, callStack); + if (callStack.dispatchedLevels.contains(currentLevel)) { + break; } + levelReady = markLevelAsDispatchedIfReady(currentLevel, callStack); if (levelReady) { dispatch(currentLevel, callStack); } else { @@ -263,21 +314,14 @@ public void fieldFetched(ExecutionContext executionContext, Supplier dataFetchingEnvironment) { CallStack callStack = getCallStack(executionStrategyParameters); int level = executionStrategyParameters.getPath().getLevel(); - boolean dispatchNeeded = false; AlternativeCallContext deferredCallContext = executionStrategyParameters.getDeferredCallContext(); if (level == 1 || (deferredCallContext != null && level == deferredCallContext.getStartLevel())) { - synchronized (callStack) { - callStack.happenedFirstLevelFetchCount++; - dispatchNeeded = callStack.expectedFirstLevelFetchCount == callStack.happenedFirstLevelFetchCount; - if (dispatchNeeded) { - callStack.dispatchedLevels.add(level); - } + int happenedFirstLevelFetchCount = callStack.happenedFirstLevelFetchCount.incrementAndGet(); + if (happenedFirstLevelFetchCount == callStack.expectedFirstLevelFetchCount) { + callStack.dispatchedLevels.add(level); + dispatch(level, callStack); } } - if (dispatchNeeded) { - dispatch(level, callStack); - } - } @@ -293,9 +337,12 @@ public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCa CallStack callStack = getCallStack(alternativeCallContext); // this means the single root field is completed (it was never "fetched" because it is // the event payload) and we can mark level 1 (root fields) as dispatched and level 0 as completed - synchronized (callStack) { - callStack.dispatchedLevels.add(1); - callStack.happenedExecuteObjectCallsPerLevel.set(0, 1); + callStack.dispatchedLevels.add(1); + while (true) { + CallStack.StateForLevel currentState = callStack.get(0); + if (callStack.tryUpdateLevel(0, currentState, currentState.increaseHappenedExecuteObjectCalls())) { + break; + } } onCompletionFinished(0, callStack); } @@ -304,13 +351,9 @@ public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCa public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable throwable, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); - boolean ready; - synchronized (callStack) { - callStack.deferredFragmentRootFieldsCompleted++; - Assert.assertNotNull(parameters.getDeferredCallContext()); - ready = callStack.deferredFragmentRootFieldsCompleted == parameters.getDeferredCallContext().getFields(); - } - if (ready) { + int deferredFragmentRootFieldsCompleted = callStack.deferredFragmentRootFieldsCompleted.incrementAndGet(); + Assert.assertNotNull(parameters.getDeferredCallContext()); + if (deferredFragmentRootFieldsCompleted == parameters.getDeferredCallContext().getFields()) { onCompletionFinished(parameters.getDeferredCallContext().getStartLevel() - 1, callStack); } @@ -339,11 +382,13 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC if (startLevel > 1) { // parent level is considered dispatched and all fields completed callStack.dispatchedLevels.add(startLevel - 1); - callStack.happenedExecuteObjectCallsPerLevel.set(startLevel - 2, 1); - callStack.happenedCompletionFinishedCountPerLevel.set(startLevel - 2, 1); + CallStack.StateForLevel stateForLevel = callStack.get(startLevel - 2); + CallStack.StateForLevel newStateForLevel = stateForLevel.increaseHappenedExecuteObjectCalls().increaseHappenedCompletionFinishedCount(); + callStack.tryUpdateLevel(startLevel - 2, stateForLevel, newStateForLevel); } // the parent will have one completion therefore we set the expectation to 1 - callStack.happenedExecuteObjectCallsPerLevel.set(startLevel - 1, 1); + CallStack.StateForLevel stateForLevel = callStack.get(startLevel - 1); + callStack.tryUpdateLevel(startLevel - 1, stateForLevel, stateForLevel.increaseHappenedExecuteObjectCalls()); // for the current level we set the fetch expectations callStack.expectedFirstLevelFetchCount = fields; @@ -357,7 +402,8 @@ private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { boolean ready = isLevelReady(level, callStack); if (ready) { if (!callStack.dispatchedLevels.add(level)) { - Assert.assertShouldNeverHappen("level " + level + " already dispatched"); + // meaning another thread came before here + return false; } return true; } @@ -368,9 +414,9 @@ private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { private boolean isLevelReady(int level, CallStack callStack) { // we expect that parent has been dispatched and that all parents fields are completed // all parent fields completed means all parent parent on completions finished calls must have happened - int happenedExecuteObjectCalls = callStack.happenedExecuteObjectCallsPerLevel.get(level - 2); + int happenedExecuteObjectCalls = callStack.get(level - 2).happenedExecuteObjectCalls; return callStack.dispatchedLevels.contains(level - 1) && - happenedExecuteObjectCalls > 0 && happenedExecuteObjectCalls == callStack.happenedCompletionFinishedCountPerLevel.get(level - 2); + happenedExecuteObjectCalls > 0 && happenedExecuteObjectCalls == callStack.get(level - 2).happenedCompletionFinishedCount; } From 009fcb8434b9f6ed4d3912fb87cb861566c9429e Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Wed, 24 Sep 2025 22:14:11 +1000 Subject: [PATCH 17/40] cleanup and comment --- .../dataloader/PerLevelDataLoaderDispatchStrategy.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 2cafbaa09..a1b32bcd6 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -169,8 +169,6 @@ public StateForLevel increaseHappenedExecuteObjectCalls() { } - private final Object firstLevelDataLock = new Object() { - }; private volatile int expectedFirstLevelFetchCount; private final AtomicInteger happenedFirstLevelFetchCount = new AtomicInteger(); @@ -288,6 +286,10 @@ private void onCompletionFinished(int level, CallStack callStack) { } } + // due to synchronous DataFetcher the completion calls on higher levels + // can happen before the completion calls on lower level + // this means sometimes a lower level completion means multiple levels are ready + // hence this loop here until a level is not ready or already dispatched int currentLevel = level + 2; while (true) { boolean levelReady; From ab06e3032b18bf92f9829f9e0ece870b45196de0 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Thu, 25 Sep 2025 06:54:19 +1000 Subject: [PATCH 18/40] add Thread.onSpinWait to indicate active waiting Add assertion --- .../dataloader/PerLevelDataLoaderDispatchStrategy.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index a1b32bcd6..adedf3c11 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -97,6 +97,7 @@ public StateForLevel(@Nullable DataLoaderInvocation dataLoaderInvocation, if (currentStateRef.compareAndSet(currentState, newState)) { return currentState; } + Thread.onSpinWait(); } } @@ -124,6 +125,7 @@ public boolean newDataLoaderInvocation(DataLoaderInvocation dataLoaderInvocation if (currentStateRef.compareAndSet(currentState, newState)) { return newDelayedInvocation; } + Thread.onSpinWait(); } } @@ -259,7 +261,7 @@ public void executeObject(ExecutionContext executionContext, ExecutionStrategyPa if (callStack.tryUpdateLevel(curLevel, currentState, currentState.increaseHappenedExecuteObjectCalls())) { return; } - + Thread.onSpinWait(); } } @@ -284,6 +286,7 @@ private void onCompletionFinished(int level, CallStack callStack) { if (callStack.tryUpdateLevel(level, currentState, currentState.increaseHappenedCompletionFinishedCount())) { break; } + Thread.onSpinWait(); } // due to synchronous DataFetcher the completion calls on higher levels @@ -345,6 +348,7 @@ public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCa if (callStack.tryUpdateLevel(0, currentState, currentState.increaseHappenedExecuteObjectCalls())) { break; } + Thread.onSpinWait(); } onCompletionFinished(0, callStack); } @@ -404,7 +408,7 @@ private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { boolean ready = isLevelReady(level, callStack); if (ready) { if (!callStack.dispatchedLevels.add(level)) { - // meaning another thread came before here + // meaning another thread came before us, so they will take care of dispatching return false; } return true; @@ -414,6 +418,7 @@ private boolean markLevelAsDispatchedIfReady(int level, CallStack callStack) { private boolean isLevelReady(int level, CallStack callStack) { + Assert.assertTrue(level > 1); // we expect that parent has been dispatched and that all parents fields are completed // all parent fields completed means all parent parent on completions finished calls must have happened int happenedExecuteObjectCalls = callStack.get(level - 2).happenedExecuteObjectCalls; From 2eecad7ba6305d0d7ad02214de5154d9ac55f4ce Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Thu, 25 Sep 2025 06:59:14 +1000 Subject: [PATCH 19/40] remove Thread.onSpinWait again as not clear this is needed or has maybe negative effects --- .../dataloader/PerLevelDataLoaderDispatchStrategy.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index adedf3c11..943bae4ff 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -97,7 +97,6 @@ public StateForLevel(@Nullable DataLoaderInvocation dataLoaderInvocation, if (currentStateRef.compareAndSet(currentState, newState)) { return currentState; } - Thread.onSpinWait(); } } @@ -125,7 +124,6 @@ public boolean newDataLoaderInvocation(DataLoaderInvocation dataLoaderInvocation if (currentStateRef.compareAndSet(currentState, newState)) { return newDelayedInvocation; } - Thread.onSpinWait(); } } @@ -261,7 +259,6 @@ public void executeObject(ExecutionContext executionContext, ExecutionStrategyPa if (callStack.tryUpdateLevel(curLevel, currentState, currentState.increaseHappenedExecuteObjectCalls())) { return; } - Thread.onSpinWait(); } } @@ -286,7 +283,6 @@ private void onCompletionFinished(int level, CallStack callStack) { if (callStack.tryUpdateLevel(level, currentState, currentState.increaseHappenedCompletionFinishedCount())) { break; } - Thread.onSpinWait(); } // due to synchronous DataFetcher the completion calls on higher levels @@ -348,7 +344,6 @@ public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCa if (callStack.tryUpdateLevel(0, currentState, currentState.increaseHappenedExecuteObjectCalls())) { break; } - Thread.onSpinWait(); } onCompletionFinished(0, callStack); } From 49fbe60281b5d92cc7380e344b2813923d9906c3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 22:02:05 +0000 Subject: [PATCH 20/40] Add performance results for commit bf3752790305d563f28174ef3343288a7b18b54f --- ...305d563f28174ef3343288a7b18b54f-jdk17.json | 1225 +++++++++++++++++ 1 file changed, 1225 insertions(+) create mode 100644 performance-results/2025-09-24T22:01:42Z-bf3752790305d563f28174ef3343288a7b18b54f-jdk17.json diff --git a/performance-results/2025-09-24T22:01:42Z-bf3752790305d563f28174ef3343288a7b18b54f-jdk17.json b/performance-results/2025-09-24T22:01:42Z-bf3752790305d563f28174ef3343288a7b18b54f-jdk17.json new file mode 100644 index 000000000..8f8673e0a --- /dev/null +++ b/performance-results/2025-09-24T22:01:42Z-bf3752790305d563f28174ef3343288a7b18b54f-jdk17.json @@ -0,0 +1,1225 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "5" + }, + "primaryMetric" : { + "score" : 3.3231476944845446, + "scoreError" : 0.05576763148549442, + "scoreConfidence" : [ + 3.26738006299905, + 3.378915325970039 + ], + "scorePercentiles" : { + "0.0" : 3.3105681887881118, + "50.0" : 3.3263610998001942, + "90.0" : 3.329300389549678, + "95.0" : 3.329300389549678, + "99.0" : 3.329300389549678, + "99.9" : 3.329300389549678, + "99.99" : 3.329300389549678, + "99.999" : 3.329300389549678, + "99.9999" : 3.329300389549678, + "100.0" : 3.329300389549678 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.324532924420686, + 3.329300389549678 + ], + [ + 3.3105681887881118, + 3.3281892751797026 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "10" + }, + "primaryMetric" : { + "score" : 1.673522800594215, + "scoreError" : 0.011992732645477735, + "scoreConfidence" : [ + 1.6615300679487373, + 1.685515533239693 + ], + "scorePercentiles" : { + "0.0" : 1.6710786181254627, + "50.0" : 1.6738182254695424, + "90.0" : 1.6753761333123123, + "95.0" : 1.6753761333123123, + "99.0" : 1.6753761333123123, + "99.9" : 1.6753761333123123, + "99.99" : 1.6753761333123123, + "99.999" : 1.6753761333123123, + "99.9999" : 1.6753761333123123, + "100.0" : 1.6753761333123123 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.6710786181254627, + 1.6744304126336462 + ], + [ + 1.6753761333123123, + 1.6732060383054388 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "20" + }, + "primaryMetric" : { + "score" : 0.8421733222098159, + "scoreError" : 0.05639745071895826, + "scoreConfidence" : [ + 0.7857758714908576, + 0.8985707729287742 + ], + "scorePercentiles" : { + "0.0" : 0.8294524478277855, + "50.0" : 0.8456688500567878, + "90.0" : 0.8479031408979021, + "95.0" : 0.8479031408979021, + "99.0" : 0.8479031408979021, + "99.9" : 0.8479031408979021, + "99.99" : 0.8479031408979021, + "99.999" : 0.8479031408979021, + "99.9999" : 0.8479031408979021, + "100.0" : 0.8479031408979021 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.8294524478277855, + 0.8479031408979021 + ], + [ + 0.843498316866776, + 0.8478393832467996 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 16.088623045270147, + "scoreError" : 0.21721500433002625, + "scoreConfidence" : [ + 15.871408040940121, + 16.305838049600172 + ], + "scorePercentiles" : { + "0.0" : 15.987394154754861, + "50.0" : 16.080145178605214, + "90.0" : 16.183393031782632, + "95.0" : 16.183393031782632, + "99.0" : 16.183393031782632, + "99.9" : 16.183393031782632, + "99.99" : 16.183393031782632, + "99.999" : 16.183393031782632, + "99.9999" : 16.183393031782632, + "100.0" : 16.183393031782632 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 16.048931726057265, + 15.987394154754861, + 16.035500066178074 + ], + [ + 16.165160661694888, + 16.111358631153166, + 16.183393031782632 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput_getImmediateFields", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2674.1967718242245, + "scoreError" : 275.451747785103, + "scoreConfidence" : [ + 2398.7450240391213, + 2949.6485196093276 + ], + "scorePercentiles" : { + "0.0" : 2577.6714732189, + "50.0" : 2672.2660062051855, + "90.0" : 2777.0927789771727, + "95.0" : 2777.0927789771727, + "99.0" : 2777.0927789771727, + "99.9" : 2777.0927789771727, + "99.99" : 2777.0927789771727, + "99.999" : 2777.0927789771727, + "99.9999" : 2777.0927789771727, + "100.0" : 2777.0927789771727 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 2577.6714732189, + 2588.056523892936, + 2588.8455115893316 + ], + [ + 2777.0927789771727, + 2755.686500821039, + 2757.8278424459695 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 77188.55397778591, + "scoreError" : 1355.7922697502684, + "scoreConfidence" : [ + 75832.76170803564, + 78544.34624753617 + ], + "scorePercentiles" : { + "0.0" : 76725.66787864313, + "50.0" : 77191.39761701284, + "90.0" : 77656.63956431513, + "95.0" : 77656.63956431513, + "99.0" : 77656.63956431513, + "99.9" : 77656.63956431513, + "99.99" : 77656.63956431513, + "99.999" : 77656.63956431513, + "99.9999" : 77656.63956431513, + "100.0" : 77656.63956431513 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 76734.40630395035, + 76783.54232299031, + 76725.66787864313 + ], + [ + 77599.25291103538, + 77631.81488578107, + 77656.63956431513 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 343.34084509571943, + "scoreError" : 22.532472115448, + "scoreConfidence" : [ + 320.80837298027143, + 365.87331721116743 + ], + "scorePercentiles" : { + "0.0" : 335.7897845360169, + "50.0" : 343.19190842152534, + "90.0" : 351.2292382317256, + "95.0" : 351.2292382317256, + "99.0" : 351.2292382317256, + "99.9" : 351.2292382317256, + "99.99" : 351.2292382317256, + "99.999" : 351.2292382317256, + "99.9999" : 351.2292382317256, + "100.0" : 351.2292382317256 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 336.1767970869616, + 335.7897845360169, + 336.07142653517315 + ], + [ + 351.2292382317256, + 350.20701975608915, + 350.57080442835013 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 112.38151335489005, + "scoreError" : 7.0127894170091025, + "scoreConfidence" : [ + 105.36872393788094, + 119.39430277189915 + ], + "scorePercentiles" : { + "0.0" : 109.85899414170567, + "50.0" : 112.30411326109922, + "90.0" : 114.84925754221614, + "95.0" : 114.84925754221614, + "99.0" : 114.84925754221614, + "99.9" : 114.84925754221614, + "99.99" : 114.84925754221614, + "99.999" : 114.84925754221614, + "99.9999" : 114.84925754221614, + "100.0" : 114.84925754221614 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 110.14104747794393, + 110.33136452413314, + 109.85899414170567 + ], + [ + 114.84925754221614, + 114.8315544452761, + 114.2768619980653 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.06175043821743703, + "scoreError" : 3.2647425496025006E-4, + "scoreConfidence" : [ + 0.061423963962476784, + 0.06207691247239728 + ], + "scorePercentiles" : { + "0.0" : 0.06156763646829941, + "50.0" : 0.06174904444054971, + "90.0" : 0.061895949753657996, + "95.0" : 0.061895949753657996, + "99.0" : 0.061895949753657996, + "99.9" : 0.061895949753657996, + "99.99" : 0.061895949753657996, + "99.999" : 0.061895949753657996, + "99.9999" : 0.061895949753657996, + "100.0" : 0.061895949753657996 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.06170244482699047, + 0.061838509374574864, + 0.061895949753657996 + ], + [ + 0.06178853313973246, + 0.06170955574136697, + 0.06156763646829941 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime_getImmediateFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3.856778035658799E-4, + "scoreError" : 2.4676566450271538E-5, + "scoreConfidence" : [ + 3.610012371156084E-4, + 4.1035437001615143E-4 + ], + "scorePercentiles" : { + "0.0" : 3.7755603787877756E-4, + "50.0" : 3.8541237400743485E-4, + "90.0" : 3.9454129757862465E-4, + "95.0" : 3.9454129757862465E-4, + "99.0" : 3.9454129757862465E-4, + "99.9" : 3.9454129757862465E-4, + "99.99" : 3.9454129757862465E-4, + "99.999" : 3.9454129757862465E-4, + "99.9999" : 3.9454129757862465E-4, + "100.0" : 3.9454129757862465E-4 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.7780081177138397E-4, + 3.7755603787877756E-4, + 3.776152396684678E-4 + ], + [ + 3.935294982545399E-4, + 3.930239362434858E-4, + 3.9454129757862465E-4 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.01313944650746763, + "scoreError" : 3.3036500535129596E-4, + "scoreConfidence" : [ + 0.012809081502116333, + 0.013469811512818926 + ], + "scorePercentiles" : { + "0.0" : 0.013026900289713856, + "50.0" : 0.01313486772305534, + "90.0" : 0.013256904513246766, + "95.0" : 0.013256904513246766, + "99.0" : 0.013256904513246766, + "99.9" : 0.013256904513246766, + "99.99" : 0.013256904513246766, + "99.999" : 0.013256904513246766, + "99.9999" : 0.013256904513246766, + "100.0" : 0.013256904513246766 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.013035628478839531, + 0.013026900289713856, + 0.013033896908802035 + ], + [ + 0.013249241886932443, + 0.013256904513246766, + 0.01323410696727115 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF2Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.9925912770043442, + "scoreError" : 0.00515487370601758, + "scoreConfidence" : [ + 0.9874364032983267, + 0.9977461507103618 + ], + "scorePercentiles" : { + "0.0" : 0.9905894818740095, + "50.0" : 0.9922810043250647, + "90.0" : 0.9949423251417769, + "95.0" : 0.9949423251417769, + "99.0" : 0.9949423251417769, + "99.9" : 0.9949423251417769, + "99.99" : 0.9949423251417769, + "99.999" : 0.9949423251417769, + "99.9999" : 0.9949423251417769, + "100.0" : 0.9949423251417769 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.9949423251417769, + 0.9942933991847286, + 0.9933356795788637 + ], + [ + 0.9911604471754212, + 0.9912263290712657, + 0.9905894818740095 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "2" + }, + "primaryMetric" : { + "score" : 0.010761148406008184, + "scoreError" : 8.811072557120488E-4, + "scoreConfidence" : [ + 0.009880041150296134, + 0.011642255661720233 + ], + "scorePercentiles" : { + "0.0" : 0.010463606288831737, + "50.0" : 0.01075893932734923, + "90.0" : 0.011056569420765753, + "95.0" : 0.011056569420765753, + "99.0" : 0.011056569420765753, + "99.9" : 0.011056569420765753, + "99.99" : 0.011056569420765753, + "99.999" : 0.011056569420765753, + "99.9999" : 0.011056569420765753, + "100.0" : 0.011056569420765753 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.010479100573610562, + 0.010480554989855121, + 0.010463606288831737 + ], + [ + 0.011056569420765753, + 0.01103732366484334, + 0.011049735498142586 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "10" + }, + "primaryMetric" : { + "score" : 3.3629554933279664, + "scoreError" : 0.07084706215816614, + "scoreConfidence" : [ + 3.2921084311698, + 3.4338025554861327 + ], + "scorePercentiles" : { + "0.0" : 3.332798313790806, + "50.0" : 3.3605197265445237, + "90.0" : 3.392697289009498, + "95.0" : 3.392697289009498, + "99.0" : 3.392697289009498, + "99.9" : 3.392697289009498, + "99.99" : 3.392697289009498, + "99.999" : 3.392697289009498, + "99.9999" : 3.392697289009498, + "100.0" : 3.392697289009498 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.332798313790806, + 3.3430916290106953, + 3.347131188085676 + ], + [ + 3.392697289009498, + 3.388106275067751, + 3.3739082650033714 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.9354392314440556, + "scoreError" : 0.05115472897876458, + "scoreConfidence" : [ + 2.8842845024652912, + 2.98659396042282 + ], + "scorePercentiles" : { + "0.0" : 2.9136747786192836, + "50.0" : 2.936426058380065, + "90.0" : 2.9573701972205795, + "95.0" : 2.9573701972205795, + "99.0" : 2.9573701972205795, + "99.9" : 2.9573701972205795, + "99.99" : 2.9573701972205795, + "99.999" : 2.9573701972205795, + "99.9999" : 2.9573701972205795, + "100.0" : 2.9573701972205795 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.9182054037339555, + 2.9268742999707347, + 2.9136747786192836 + ], + [ + 2.945977816789396, + 2.9505328923303833, + 2.9573701972205795 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkDeepAbstractConcrete", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.18308782767424345, + "scoreError" : 0.03048334682725773, + "scoreConfidence" : [ + 0.15260448084698572, + 0.21357117450150118 + ], + "scorePercentiles" : { + "0.0" : 0.17305646879867095, + "50.0" : 0.1830986727799045, + "90.0" : 0.19310122084266626, + "95.0" : 0.19310122084266626, + "99.0" : 0.19310122084266626, + "99.9" : 0.19310122084266626, + "99.99" : 0.19310122084266626, + "99.999" : 0.19310122084266626, + "99.9999" : 0.19310122084266626, + "100.0" : 0.19310122084266626 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.19310122084266626, + 0.19298346324707152, + 0.19294850380103418 + ], + [ + 0.1732488417587748, + 0.1731884675972429, + 0.17305646879867095 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.3400980680966395, + "scoreError" : 0.03444656442815107, + "scoreConfidence" : [ + 0.3056515036684884, + 0.3745446325247906 + ], + "scorePercentiles" : { + "0.0" : 0.3232931979762713, + "50.0" : 0.34131120267884263, + "90.0" : 0.35398818665486725, + "95.0" : 0.35398818665486725, + "99.0" : 0.35398818665486725, + "99.9" : 0.35398818665486725, + "99.99" : 0.35398818665486725, + "99.999" : 0.35398818665486725, + "99.9999" : 0.35398818665486725, + "100.0" : 0.35398818665486725 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.33611216391624377, + 0.3298062128157773, + 0.3232931979762713 + ], + [ + 0.34651024144144144, + 0.35087840577523594, + 0.35398818665486725 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.1502561927593922, + "scoreError" : 0.009203914482233668, + "scoreConfidence" : [ + 0.14105227827715852, + 0.15946010724162588 + ], + "scorePercentiles" : { + "0.0" : 0.14706316475242284, + "50.0" : 0.15025330358786043, + "90.0" : 0.1533787646165644, + "95.0" : 0.1533787646165644, + "99.0" : 0.1533787646165644, + "99.9" : 0.1533787646165644, + "99.99" : 0.1533787646165644, + "99.999" : 0.1533787646165644, + "99.9999" : 0.1533787646165644, + "100.0" : 0.1533787646165644 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.15305326886344853, + 0.1533787646165644, + 0.15331390580587792 + ], + [ + 0.14727471420576713, + 0.14745333831227236, + 0.14706316475242284 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.4050257256483299, + "scoreError" : 0.006761442110198147, + "scoreConfidence" : [ + 0.39826428353813176, + 0.411787167758528 + ], + "scorePercentiles" : { + "0.0" : 0.40190211722863, + "50.0" : 0.40632125634744065, + "90.0" : 0.40693219995930824, + "95.0" : 0.40693219995930824, + "99.0" : 0.40693219995930824, + "99.9" : 0.40693219995930824, + "99.99" : 0.40693219995930824, + "99.999" : 0.40693219995930824, + "99.9999" : 0.40693219995930824, + "100.0" : 0.40693219995930824 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.40670188197974705, + 0.4066440817338972, + 0.40599843096098415 + ], + [ + 0.40693219995930824, + 0.40197564202741265, + 0.40190211722863 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.15717311502003936, + "scoreError" : 0.020348306551943675, + "scoreConfidence" : [ + 0.1368248084680957, + 0.17752142157198303 + ], + "scorePercentiles" : { + "0.0" : 0.150462264131923, + "50.0" : 0.1571170464237227, + "90.0" : 0.16415767261445527, + "95.0" : 0.16415767261445527, + "99.0" : 0.16415767261445527, + "99.9" : 0.16415767261445527, + "99.99" : 0.16415767261445527, + "99.999" : 0.16415767261445527, + "99.9999" : 0.16415767261445527, + "100.0" : 0.16415767261445527 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.15070725198926999, + 0.15048676344183107, + 0.150462264131923 + ], + [ + 0.16415767261445527, + 0.16369789708458152, + 0.1635268408581754 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkRepeatedFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.04669520571657638, + "scoreError" : 0.004501776176268937, + "scoreConfidence" : [ + 0.04219342954030744, + 0.051196981892845314 + ], + "scorePercentiles" : { + "0.0" : 0.04521263395876662, + "50.0" : 0.04669549864524105, + "90.0" : 0.04818418672455081, + "95.0" : 0.04818418672455081, + "99.0" : 0.04818418672455081, + "99.9" : 0.04818418672455081, + "99.99" : 0.04818418672455081, + "99.999" : 0.04818418672455081, + "99.9999" : 0.04818418672455081, + "100.0" : 0.04818418672455081 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.04521263395876662, + 0.04524873039402002, + 0.04522801630447073 + ], + [ + 0.04818418672455081, + 0.04815540002118807, + 0.04814226689646208 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 8884653.787414482, + "scoreError" : 420885.2406286423, + "scoreConfidence" : [ + 8463768.546785839, + 9305539.028043125 + ], + "scorePercentiles" : { + "0.0" : 8726034.162162162, + "50.0" : 8890614.237676539, + "90.0" : 9033791.406504065, + "95.0" : 9033791.406504065, + "99.0" : 9033791.406504065, + "99.9" : 9033791.406504065, + "99.99" : 9033791.406504065, + "99.999" : 9033791.406504065, + "99.9999" : 9033791.406504065, + "100.0" : 9033791.406504065 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 8783079.978050921, + 8738461.64978166, + 8726034.162162162 + ], + [ + 8998148.497302158, + 9028407.03068592, + 9033791.406504065 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + From f5d7d2399515f9b3183896faa812a4f302baf84c Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Fri, 26 Sep 2025 07:29:30 +1000 Subject: [PATCH 21/40] cleanup and comments --- src/jmh/java/benchmark/IntMapBenchmark.java | 43 ------- .../performance/DataLoaderPerformance.java | 18 ++- .../instrumentation/dataloader/LevelMap.java | 79 ------------ .../PerLevelDataLoaderDispatchStrategy.java | 54 ++++++++- .../dataloader/LevelMapTest.groovy | 113 ------------------ 5 files changed, 65 insertions(+), 242 deletions(-) delete mode 100644 src/jmh/java/benchmark/IntMapBenchmark.java delete mode 100644 src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java delete mode 100644 src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy diff --git a/src/jmh/java/benchmark/IntMapBenchmark.java b/src/jmh/java/benchmark/IntMapBenchmark.java deleted file mode 100644 index b5b5272e4..000000000 --- a/src/jmh/java/benchmark/IntMapBenchmark.java +++ /dev/null @@ -1,43 +0,0 @@ -package benchmark; - -import graphql.execution.instrumentation.dataloader.LevelMap; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; -import org.openjdk.jmh.infra.Blackhole; - -import java.util.LinkedHashMap; -import java.util.Map; - -@State(Scope.Benchmark) -@Warmup(iterations = 2, time = 5) -@Measurement(iterations = 3) -@Fork(2) -public class IntMapBenchmark { - - @Benchmark - public void benchmarkLinkedHashMap(Blackhole blackhole) { - Map result = new LinkedHashMap<>(); - for (int i = 0; i < 30; i++) { - int level = i % 10; - int count = i * 2; - result.put(level, result.getOrDefault(level, 0) + count); - blackhole.consume(result.get(level)); - } - } - - @Benchmark - public void benchmarkIntMap(Blackhole blackhole) { - LevelMap result = new LevelMap(16); - for (int i = 0; i < 30; i++) { - int level = i % 10; - int count = i * 2; - result.increment(level, count); - blackhole.consume(result.get(level)); - } - } -} - diff --git a/src/jmh/java/performance/DataLoaderPerformance.java b/src/jmh/java/performance/DataLoaderPerformance.java index 20e144abd..6f81408d6 100644 --- a/src/jmh/java/performance/DataLoaderPerformance.java +++ b/src/jmh/java/performance/DataLoaderPerformance.java @@ -4,6 +4,7 @@ import graphql.ExecutionInput; import graphql.ExecutionResult; import graphql.GraphQL; +import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys; import graphql.schema.DataFetcher; import graphql.schema.GraphQLSchema; import graphql.schema.idl.RuntimeWiring; @@ -14,16 +15,28 @@ import org.dataloader.DataLoader; import org.dataloader.DataLoaderFactory; import org.dataloader.DataLoaderRegistry; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +@State(Scope.Benchmark) +@Warmup(iterations = 2, time = 5) +@Measurement(iterations = 3) +@Fork(2) public class DataLoaderPerformance { static Owner o1 = new Owner("O-1", "Andi", List.of("P-1", "P-2", "P-3")); @@ -560,6 +573,9 @@ public void setup() { } + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) public void executeRequestWithDataLoaders(MyState myState, Blackhole blackhole) { DataLoader ownerDL = DataLoaderFactory.newDataLoader(ownerBatchLoader); DataLoader petDL = DataLoaderFactory.newDataLoader(petBatchLoader); @@ -571,7 +587,7 @@ public void executeRequestWithDataLoaders(MyState myState, Blackhole blackhole) .dataLoaderRegistry(registry) // .profileExecution(true) .build(); -// executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, true); + executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, true); ExecutionResult execute = myState.graphQL.execute(executionInput); // ProfilerResult profilerResult = executionInput.getGraphQLContext().get(ProfilerResult.PROFILER_CONTEXT_KEY); // System.out.println("execute: " + execute); diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java b/src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java deleted file mode 100644 index 45fdca37b..000000000 --- a/src/main/java/graphql/execution/instrumentation/dataloader/LevelMap.java +++ /dev/null @@ -1,79 +0,0 @@ -package graphql.execution.instrumentation.dataloader; - -import graphql.Internal; - -import java.util.Arrays; - -/** - * This data structure tracks the number of expected calls on a given level - */ -@Internal -public class LevelMap { - - // A reasonable default that guarantees no additional allocations for most use cases. - private static final int DEFAULT_INITIAL_SIZE = 16; - - // this array is mutable in both size and contents. - private int[] countsByLevel; - - public LevelMap(int initialSize) { - if (initialSize < 0) { - throw new IllegalArgumentException("negative size " + initialSize); - } - countsByLevel = new int[initialSize]; - } - - public LevelMap() { - this(DEFAULT_INITIAL_SIZE); - } - - public int get(int level) { - maybeResize(level); - return countsByLevel[level]; - } - - public void increment(int level, int by) { - maybeResize(level); - countsByLevel[level] += by; - } - - public void set(int level, int newValue) { - maybeResize(level); - countsByLevel[level] = newValue; - } - - private void maybeResize(int level) { - if (level < 0) { - throw new IllegalArgumentException("negative level " + level); - } - if (level + 1 > countsByLevel.length) { - int newSize = level == 0 ? 1 : level * 2; - countsByLevel = Arrays.copyOf(countsByLevel, newSize); - } - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append("IntMap["); - for (int i = 0; i < countsByLevel.length; i++) { - result.append("[level=").append(i).append(",count=").append(countsByLevel[i]).append("] "); - } - result.append("]"); - return result.toString(); - } - - public String toString(int level) { - StringBuilder result = new StringBuilder(); - result.append("IntMap["); - for (int i = 1; i <= level; i++) { - result.append("level=").append(i).append(",count=").append(countsByLevel[i]).append(" "); - } - result.append("]"); - return result.toString(); - } - - public void clear() { - Arrays.fill(countsByLevel, 0); - } -} diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 943bae4ff..ae9516613 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -72,9 +72,16 @@ public StateForLevel(@Nullable DataLoaderInvocation dataLoaderInvocation, StateForLevel currentState = currentStateRef.get(); - boolean dispatchingStarted = currentState != null && currentState.dispatchingStarted; - boolean dispatchingFinished = currentState != null && currentState.dispatchingFinished; - boolean currentlyDelayedDispatching = currentState != null && currentState.currentlyDelayedDispatching; + boolean dispatchingStarted = false; + boolean dispatchingFinished = false; + boolean currentlyDelayedDispatching = false; + + if (currentState != null) { + dispatchingStarted = currentState.dispatchingStarted; + dispatchingFinished = currentState.dispatchingFinished; + currentlyDelayedDispatching = currentState.currentlyDelayedDispatching; + + } if (!chained) { if (normalDispatchOrDelayed) { @@ -107,10 +114,16 @@ public boolean newDataLoaderInvocation(DataLoaderInvocation dataLoaderInvocation while (true) { StateForLevel currentState = currentStateRef.get(); + boolean dispatchingStarted = false; + boolean dispatchingFinished = false; + boolean currentlyDelayedDispatching = false; - boolean dispatchingStarted = currentState != null && currentState.dispatchingStarted; - boolean dispatchingFinished = currentState != null && currentState.dispatchingFinished; - boolean currentlyDelayedDispatching = currentState != null && currentState.currentlyDelayedDispatching; + if (currentState != null) { + dispatchingStarted = currentState.dispatchingStarted; + dispatchingFinished = currentState.dispatchingFinished; + currentlyDelayedDispatching = currentState.currentlyDelayedDispatching; + + } // we need to start a new delayed dispatching if // the normal dispatching is finished and there is no currently delayed dispatching for this level @@ -135,6 +148,35 @@ public void clear() { private static class CallStack { + /** + * We track three things per level: + * - the number of execute object calls + * - the number of object completion calls + * - if the level is already dispatched + *

+ * The number of execute object calls is the number of times the execution + * of a field with sub selection (meaning it is an object) started. + *

+ * For each execute object call there will be one matching object completion call, + * indicating that the all fields in the sub selection have been fetched AND completed. + * Completion implies the fetched value is "resolved" (CompletableFuture is completed if it was a CF) + * and it the engine has processed it and called any needed subsequent execute object calls (if the result + * was none null and of Object of [Object] (or [[Object]] etc). + *

+ * Together we know a that a level is ready for dispatch if: + * - the parent was dispatched + * - the #executeObject == #completionFinished in the grandparent level. + *

+ * The second condition implies that all execute object calls in the parent level happened + * which again implies that all fetch fields in the current level have happened. + *

+ * For the first level we track only if all expected fetched field calls have happened. + */ + + /** + * The whole algo is impleted lock free and relies purely on CAS methods to handle concurrency. + */ + static class StateForLevel { private final int happenedCompletionFinishedCount; private final int happenedExecuteObjectCalls; diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy deleted file mode 100644 index 1f0069fb1..000000000 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/LevelMapTest.groovy +++ /dev/null @@ -1,113 +0,0 @@ -package graphql.execution.instrumentation.dataloader - -import spock.lang.Specification - -class LevelMapTest extends Specification { - - def "increase adds levels"() { - given: - LevelMap sut = new LevelMap(0) // starts empty - - when: - sut.increment(2, 42) // level 2 has count 42 - - then: - sut.get(0) == 0 - sut.get(1) == 0 - sut.get(2) == 42 - } - - def "increase count by 10 for every level"() { - given: - LevelMap sut = new LevelMap(0) - - when: - 5.times {Integer level -> - sut.increment(level, 10) - } - - then: - 5.times { Integer level -> - sut.get(level) == 10 - } - } - def "increase yields new count"() { - given: - LevelMap sut = new LevelMap(0) - - when: - sut.increment(1, 0) - - then: - sut.get(1) == 0 - - when: - sut.increment(1, 1) - - then: - sut.get(1) == 1 - - when: - sut.increment(1, 100) - - then: - sut.get(1) == 101 - } - - def "set yields new value"() { - given: - LevelMap sut = new LevelMap(0) - - when: - sut.set(1, 1) - - then: - sut.get(1) == 1 - - when: - sut.increment(1, 100) - - then: - sut.get(1) == 101 - - when: - sut.set(1, 666) - - then: - sut.get(1) == 666 - } - - def "toString() is important for debugging"() { - given: - LevelMap sut = new LevelMap(0) - - when: - sut.toString() - - then: - sut.toString() == "IntMap[]" - - when: - sut.increment(0, 42) - - then: - sut.toString() == "IntMap[[level=0,count=42] ]" - - when: - sut.increment(1, 1) - - then: - sut.toString() == "IntMap[[level=0,count=42] [level=1,count=1] ]" - } - - def "can get outside of its size"() { - given: - LevelMap sut = new LevelMap(0) - - when: - sut.get(1) - - then: - sut.get(1) == 0 - } -} From 179817b3923b9ef9beb3e30848cabbbbe2e2ce43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 22:52:17 +0000 Subject: [PATCH 22/40] Add performance results for commit 8044c9f9e5a411c83dc6ec8f1ba419dbb7be0111 --- ...5a411c83dc6ec8f1ba419dbb7be0111-jdk17.json | 1279 +++++++++++++++++ 1 file changed, 1279 insertions(+) create mode 100644 performance-results/2025-09-25T22:51:54Z-8044c9f9e5a411c83dc6ec8f1ba419dbb7be0111-jdk17.json diff --git a/performance-results/2025-09-25T22:51:54Z-8044c9f9e5a411c83dc6ec8f1ba419dbb7be0111-jdk17.json b/performance-results/2025-09-25T22:51:54Z-8044c9f9e5a411c83dc6ec8f1ba419dbb7be0111-jdk17.json new file mode 100644 index 000000000..5887ba79e --- /dev/null +++ b/performance-results/2025-09-25T22:51:54Z-8044c9f9e5a411c83dc6ec8f1ba419dbb7be0111-jdk17.json @@ -0,0 +1,1279 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "5" + }, + "primaryMetric" : { + "score" : 3.3203538141842515, + "scoreError" : 0.06843195450057515, + "scoreConfidence" : [ + 3.2519218596836765, + 3.3887857686848264 + ], + "scorePercentiles" : { + "0.0" : 3.310512942014138, + "50.0" : 3.3203396584728004, + "90.0" : 3.3302229977772653, + "95.0" : 3.3302229977772653, + "99.0" : 3.3302229977772653, + "99.9" : 3.3302229977772653, + "99.99" : 3.3302229977772653, + "99.999" : 3.3302229977772653, + "99.9999" : 3.3302229977772653, + "100.0" : 3.3302229977772653 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.310512942014138, + 3.328771601048764 + ], + [ + 3.3119077158968375, + 3.3302229977772653 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "10" + }, + "primaryMetric" : { + "score" : 1.6753101783662656, + "scoreError" : 0.06576345939874756, + "scoreConfidence" : [ + 1.609546718967518, + 1.7410736377650131 + ], + "scorePercentiles" : { + "0.0" : 1.6625179798556808, + "50.0" : 1.677170636525328, + "90.0" : 1.6843814605587257, + "95.0" : 1.6843814605587257, + "99.0" : 1.6843814605587257, + "99.9" : 1.6843814605587257, + "99.99" : 1.6843814605587257, + "99.999" : 1.6843814605587257, + "99.9999" : 1.6843814605587257, + "100.0" : 1.6843814605587257 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.6625179798556808, + 1.6717919318042744 + ], + [ + 1.6825493412463817, + 1.6843814605587257 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "20" + }, + "primaryMetric" : { + "score" : 0.8441513970844166, + "scoreError" : 0.034194105502912873, + "scoreConfidence" : [ + 0.8099572915815036, + 0.8783455025873295 + ], + "scorePercentiles" : { + "0.0" : 0.8365719449310407, + "50.0" : 0.8455726558218887, + "90.0" : 0.848888331762848, + "95.0" : 0.848888331762848, + "99.0" : 0.848888331762848, + "99.9" : 0.848888331762848, + "99.99" : 0.848888331762848, + "99.999" : 0.848888331762848, + "99.9999" : 0.848888331762848, + "100.0" : 0.848888331762848 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.8453780773671984, + 0.845767234276579 + ], + [ + 0.8365719449310407, + 0.848888331762848 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 16.03294025280983, + "scoreError" : 0.1976556805950903, + "scoreConfidence" : [ + 15.83528457221474, + 16.23059593340492 + ], + "scorePercentiles" : { + "0.0" : 15.92770032875591, + "50.0" : 16.040820422105245, + "90.0" : 16.109845560843876, + "95.0" : 16.109845560843876, + "99.0" : 16.109845560843876, + "99.9" : 16.109845560843876, + "99.99" : 16.109845560843876, + "99.999" : 16.109845560843876, + "99.9999" : 16.109845560843876, + "100.0" : 16.109845560843876 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 15.984878534303371, + 15.92770032875591, + 16.011319494491513 + ], + [ + 16.070321349718977, + 16.09357624874532, + 16.109845560843876 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput_getImmediateFields", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2665.039836112213, + "scoreError" : 210.95958249609416, + "scoreConfidence" : [ + 2454.0802536161186, + 2875.999418608307 + ], + "scorePercentiles" : { + "0.0" : 2591.9228508739297, + "50.0" : 2664.515271634845, + "90.0" : 2739.3715729044493, + "95.0" : 2739.3715729044493, + "99.0" : 2739.3715729044493, + "99.9" : 2739.3715729044493, + "99.99" : 2739.3715729044493, + "99.999" : 2739.3715729044493, + "99.9999" : 2739.3715729044493, + "100.0" : 2739.3715729044493 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 2739.3715729044493, + 2728.967405412545, + 2732.4770578174202 + ], + [ + 2591.9228508739297, + 2597.4369918077855, + 2600.063137857145 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 77753.14366768643, + "scoreError" : 1647.367701229895, + "scoreConfidence" : [ + 76105.77596645652, + 79400.51136891633 + ], + "scorePercentiles" : { + "0.0" : 77206.67910571207, + "50.0" : 77756.5331582586, + "90.0" : 78301.04017976095, + "95.0" : 78301.04017976095, + "99.0" : 78301.04017976095, + "99.9" : 78301.04017976095, + "99.99" : 78301.04017976095, + "99.999" : 78301.04017976095, + "99.9999" : 78301.04017976095, + "100.0" : 78301.04017976095 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 77235.95262380512, + 77208.33979848209, + 77206.67910571207 + ], + [ + 78277.11369271205, + 78289.7366056462, + 78301.04017976095 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 349.5743070034512, + "scoreError" : 12.160742174102838, + "scoreConfidence" : [ + 337.4135648293484, + 361.73504917755406 + ], + "scorePercentiles" : { + "0.0" : 345.0800448966692, + "50.0" : 349.7980760372046, + "90.0" : 353.9929245741677, + "95.0" : 353.9929245741677, + "99.0" : 353.9929245741677, + "99.9" : 353.9929245741677, + "99.99" : 353.9929245741677, + "99.999" : 353.9929245741677, + "99.9999" : 353.9929245741677, + "100.0" : 353.9929245741677 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 345.0800448966692, + 346.40421016010043, + 345.4447822060659 + ], + [ + 353.9929245741677, + 353.19194191430876, + 353.33193826939544 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 112.77131852196857, + "scoreError" : 4.598849033798956, + "scoreConfidence" : [ + 108.17246948816961, + 117.37016755576752 + ], + "scorePercentiles" : { + "0.0" : 110.95237506881116, + "50.0" : 112.86997057982165, + "90.0" : 114.36707453124868, + "95.0" : 114.36707453124868, + "99.0" : 114.36707453124868, + "99.9" : 114.36707453124868, + "99.99" : 114.36707453124868, + "99.999" : 114.36707453124868, + "99.9999" : 114.36707453124868, + "100.0" : 114.36707453124868 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 114.36707453124868, + 114.06962242683949, + 114.31637936326293 + ], + [ + 111.25214100884533, + 110.95237506881116, + 111.67031873280384 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.06221255257751246, + "scoreError" : 7.461314301691277E-4, + "scoreConfidence" : [ + 0.06146642114734333, + 0.06295868400768159 + ], + "scorePercentiles" : { + "0.0" : 0.06179716534216608, + "50.0" : 0.062264965051082685, + "90.0" : 0.06248170116651775, + "95.0" : 0.06248170116651775, + "99.0" : 0.06248170116651775, + "99.9" : 0.06248170116651775, + "99.99" : 0.06248170116651775, + "99.999" : 0.06248170116651775, + "99.9999" : 0.06248170116651775, + "100.0" : 0.06248170116651775 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.062045573153404684, + 0.06179716534216608, + 0.06213808889303135 + ], + [ + 0.06239184120913401, + 0.06248170116651775, + 0.062420945700820823 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime_getImmediateFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3.638945930167579E-4, + "scoreError" : 1.5624370855895026E-5, + "scoreConfidence" : [ + 3.4827022216086286E-4, + 3.7951896387265294E-4 + ], + "scorePercentiles" : { + "0.0" : 3.582909813280584E-4, + "50.0" : 3.6394213113750636E-4, + "90.0" : 3.69441621723546E-4, + "95.0" : 3.69441621723546E-4, + "99.0" : 3.69441621723546E-4, + "99.9" : 3.69441621723546E-4, + "99.99" : 3.69441621723546E-4, + "99.999" : 3.69441621723546E-4, + "99.9999" : 3.69441621723546E-4, + "100.0" : 3.69441621723546E-4 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.5986307320535533E-4, + 3.5840853006221336E-4, + 3.582909813280584E-4 + ], + [ + 3.69441621723546E-4, + 3.680211890696574E-4, + 3.693421627117169E-4 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DataLoaderPerformance.executeRequestWithDataLoaders", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.4188472974603, + "scoreError" : 0.07351996236762309, + "scoreConfidence" : [ + 2.345327335092677, + 2.492367259827923 + ], + "scorePercentiles" : { + "0.0" : 2.3821655207241546, + "50.0" : 2.4219387257152247, + "90.0" : 2.4530300706401764, + "95.0" : 2.4530300706401764, + "99.0" : 2.4530300706401764, + "99.9" : 2.4530300706401764, + "99.99" : 2.4530300706401764, + "99.999" : 2.4530300706401764, + "99.9999" : 2.4530300706401764, + "100.0" : 2.4530300706401764 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.4530300706401764, + 2.4373710175481356, + 2.4161307424498673 + ], + [ + 2.4277467089805826, + 2.3966397244188835, + 2.3821655207241546 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.013284746179323487, + "scoreError" : 7.35070455023514E-5, + "scoreConfidence" : [ + 0.013211239133821136, + 0.013358253224825837 + ], + "scorePercentiles" : { + "0.0" : 0.013260811453736315, + "50.0" : 0.013277683403965193, + "90.0" : 0.013317628319385478, + "95.0" : 0.013317628319385478, + "99.0" : 0.013317628319385478, + "99.9" : 0.013317628319385478, + "99.99" : 0.013317628319385478, + "99.999" : 0.013317628319385478, + "99.9999" : 0.013317628319385478, + "100.0" : 0.013317628319385478 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.013262359456728167, + 0.013260811453736315, + 0.013263177676507374 + ], + [ + 0.013312311038160581, + 0.013317628319385478, + 0.01329218913142301 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF2Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.0524298727676078, + "scoreError" : 0.31651896165090876, + "scoreConfidence" : [ + 0.735910911116699, + 1.3689488344185166 + ], + "scorePercentiles" : { + "0.0" : 0.9482974781907832, + "50.0" : 1.0522439812975302, + "90.0" : 1.1560902230057803, + "95.0" : 1.1560902230057803, + "99.0" : 1.1560902230057803, + "99.9" : 1.1560902230057803, + "99.99" : 1.1560902230057803, + "99.999" : 1.1560902230057803, + "99.9999" : 1.1560902230057803, + "100.0" : 1.1560902230057803 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 1.1560902230057803, + 1.1560513331406774, + 1.1542553313711912 + ], + [ + 0.9482974781907832, + 0.9502326312238693, + 0.9496522396733453 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "2" + }, + "primaryMetric" : { + "score" : 0.010418188836098465, + "scoreError" : 3.314317211051785E-4, + "scoreConfidence" : [ + 0.010086757114993286, + 0.010749620557203644 + ], + "scorePercentiles" : { + "0.0" : 0.010306873812164262, + "50.0" : 0.010417321032912506, + "90.0" : 0.010531600576274185, + "95.0" : 0.010531600576274185, + "99.0" : 0.010531600576274185, + "99.9" : 0.010531600576274185, + "99.99" : 0.010531600576274185, + "99.999" : 0.010531600576274185, + "99.9999" : 0.010531600576274185, + "100.0" : 0.010531600576274185 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.010521872718128503, + 0.010531600576274185, + 0.010524613871535379 + ], + [ + 0.010306873812164262, + 0.010311402690791956, + 0.010312769347696508 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "10" + }, + "primaryMetric" : { + "score" : 3.143070142953624, + "scoreError" : 0.15924950116588002, + "scoreConfidence" : [ + 2.983820641787744, + 3.3023196441195037 + ], + "scorePercentiles" : { + "0.0" : 3.07903597044335, + "50.0" : 3.144520015235258, + "90.0" : 3.2052303288461537, + "95.0" : 3.2052303288461537, + "99.0" : 3.2052303288461537, + "99.9" : 3.2052303288461537, + "99.99" : 3.2052303288461537, + "99.999" : 3.2052303288461537, + "99.9999" : 3.2052303288461537, + "100.0" : 3.2052303288461537 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.2052303288461537, + 3.191565874282068, + 3.185463788535032 + ], + [ + 3.07903597044335, + 3.0935486536796537, + 3.103576241935484 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.906543587131805, + "scoreError" : 0.03034544518526469, + "scoreConfidence" : [ + 2.8761981419465403, + 2.9368890323170698 + ], + "scorePercentiles" : { + "0.0" : 2.891932198091382, + "50.0" : 2.91206557131654, + "90.0" : 2.9155620335276966, + "95.0" : 2.9155620335276966, + "99.0" : 2.9155620335276966, + "99.9" : 2.9155620335276966, + "99.99" : 2.9155620335276966, + "99.999" : 2.9155620335276966, + "99.9999" : 2.9155620335276966, + "100.0" : 2.9155620335276966 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.9140065979020977, + 2.910162496654059, + 2.9155620335276966 + ], + [ + 2.893629550636574, + 2.913968645979021, + 2.891932198091382 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkDeepAbstractConcrete", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.17725705435945885, + "scoreError" : 6.055690093922831E-4, + "scoreConfidence" : [ + 0.17665148535006656, + 0.17786262336885114 + ], + "scorePercentiles" : { + "0.0" : 0.1769843884395519, + "50.0" : 0.1772270733808966, + "90.0" : 0.17753531285838556, + "95.0" : 0.17753531285838556, + "99.0" : 0.17753531285838556, + "99.9" : 0.17753531285838556, + "99.99" : 0.17753531285838556, + "99.999" : 0.17753531285838556, + "99.9999" : 0.17753531285838556, + "100.0" : 0.17753531285838556 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.17733039430425762, + 0.177115752966597, + 0.1769843884395519 + ], + [ + 0.17745272513042554, + 0.17753531285838556, + 0.17712375245753556 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.3261513059580012, + "scoreError" : 0.013117146293980968, + "scoreConfidence" : [ + 0.3130341596640202, + 0.33926845225198216 + ], + "scorePercentiles" : { + "0.0" : 0.32120384329029356, + "50.0" : 0.32638564338564535, + "90.0" : 0.330541314966616, + "95.0" : 0.330541314966616, + "99.0" : 0.330541314966616, + "99.9" : 0.330541314966616, + "99.99" : 0.330541314966616, + "99.999" : 0.330541314966616, + "99.9999" : 0.330541314966616, + "100.0" : 0.330541314966616 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.3304295516933752, + 0.330541314966616, + 0.3302385647909649 + ], + [ + 0.32120384329029356, + 0.3219618390264319, + 0.32253272198032573 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.14875283208564885, + "scoreError" : 0.0012435358783135042, + "scoreConfidence" : [ + 0.14750929620733536, + 0.14999636796396235 + ], + "scorePercentiles" : { + "0.0" : 0.14815042370596426, + "50.0" : 0.1487523356597178, + "90.0" : 0.14923021421536442, + "95.0" : 0.14923021421536442, + "99.0" : 0.14923021421536442, + "99.9" : 0.14923021421536442, + "99.99" : 0.14923021421536442, + "99.999" : 0.14923021421536442, + "99.9999" : 0.14923021421536442, + "100.0" : 0.14923021421536442 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.1491745153124394, + 0.14923021421536442, + 0.1490045715882169 + ], + [ + 0.14845716796068942, + 0.14815042370596426, + 0.14850009973121872 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.4172252503987513, + "scoreError" : 0.06007039679088737, + "scoreConfidence" : [ + 0.3571548536078639, + 0.4772956471896387 + ], + "scorePercentiles" : { + "0.0" : 0.39726845087991103, + "50.0" : 0.41712020490577295, + "90.0" : 0.4372320730587618, + "95.0" : 0.4372320730587618, + "99.0" : 0.4372320730587618, + "99.9" : 0.4372320730587618, + "99.99" : 0.4372320730587618, + "99.999" : 0.4372320730587618, + "99.9999" : 0.4372320730587618, + "100.0" : 0.4372320730587618 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.3977801517899761, + 0.3979708047596307, + 0.39726845087991103 + ], + [ + 0.43683041685231294, + 0.4362696050519152, + 0.4372320730587618 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.15898513961172192, + "scoreError" : 0.012389838642356354, + "scoreConfidence" : [ + 0.14659530096936557, + 0.17137497825407827 + ], + "scorePercentiles" : { + "0.0" : 0.15537523358503466, + "50.0" : 0.15668613429757094, + "90.0" : 0.1662426866262156, + "95.0" : 0.1662426866262156, + "99.0" : 0.1662426866262156, + "99.9" : 0.1662426866262156, + "99.99" : 0.1662426866262156, + "99.999" : 0.1662426866262156, + "99.9999" : 0.1662426866262156, + "100.0" : 0.1662426866262156 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.156546629492799, + 0.15623203763533253, + 0.15682563910234293 + ], + [ + 0.1662426866262156, + 0.15537523358503466, + 0.16268861122860676 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkRepeatedFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.04693592709633288, + "scoreError" : 0.002368394365338667, + "scoreConfidence" : [ + 0.044567532730994217, + 0.049304321461671546 + ], + "scorePercentiles" : { + "0.0" : 0.04609010241968936, + "50.0" : 0.04698496834144105, + "90.0" : 0.04770849034154068, + "95.0" : 0.04770849034154068, + "99.0" : 0.04770849034154068, + "99.9" : 0.04770849034154068, + "99.99" : 0.04770849034154068, + "99.999" : 0.04770849034154068, + "99.9999" : 0.04770849034154068, + "100.0" : 0.04770849034154068 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.04770849034154068, + 0.04770098846605165, + 0.047705795030078095 + ], + [ + 0.04609010241968936, + 0.04614123810380706, + 0.046268948216830454 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 9363977.672261452, + "scoreError" : 567382.0574290771, + "scoreConfidence" : [ + 8796595.614832375, + 9931359.72969053 + ], + "scorePercentiles" : { + "0.0" : 9161486.075091574, + "50.0" : 9360385.903708858, + "90.0" : 9563297.985659655, + "95.0" : 9563297.985659655, + "99.0" : 9563297.985659655, + "99.9" : 9563297.985659655, + "99.99" : 9563297.985659655, + "99.999" : 9563297.985659655, + "99.9999" : 9563297.985659655, + "100.0" : 9563297.985659655 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 9191993.295036765, + 9161486.075091574, + 9185890.162534434 + ], + [ + 9528778.512380952, + 9563297.985659655, + 9552420.00286533 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + From 2cb5354da49cf94f8ff959aeca9235c8bf0b004d Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 10:58:59 +1000 Subject: [PATCH 23/40] wip --- .../execution/AsyncExecutionStrategy.java | 3 +- .../AsyncSerialExecutionStrategy.java | 1 + .../execution/DataLoaderDispatchStrategy.java | 4 + .../java/graphql/execution/Execution.java | 5 +- .../graphql/execution/ExecutionStrategy.java | 1 + .../ExhaustedDataLoaderDispatchStrategy.java | 271 ++++++++++++++++++ .../PerLevelDataLoaderDispatchStrategy.java | 3 +- .../schema/DataFetchingEnvironmentImpl.java | 7 +- .../graphql/schema/DataLoaderWithContext.java | 6 +- 9 files changed, 289 insertions(+), 12 deletions(-) create mode 100644 src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java diff --git a/src/main/java/graphql/execution/AsyncExecutionStrategy.java b/src/main/java/graphql/execution/AsyncExecutionStrategy.java index d355bfd24..8d1d43058 100644 --- a/src/main/java/graphql/execution/AsyncExecutionStrategy.java +++ b/src/main/java/graphql/execution/AsyncExecutionStrategy.java @@ -55,8 +55,9 @@ public CompletableFuture execute(ExecutionContext executionCont DeferredExecutionSupport deferredExecutionSupport = createDeferredExecutionSupport(executionContext, parameters); dataLoaderDispatcherStrategy.executionStrategy(executionContext, parameters, deferredExecutionSupport.getNonDeferredFieldNames(fieldNames).size()); - Async.CombinedBuilder futures = getAsyncFieldValueInfo(executionContext, parameters, deferredExecutionSupport); + dataLoaderDispatcherStrategy.finishedFetching(executionContext, parameters); + CompletableFuture overallResult = new CompletableFuture<>(); executionStrategyCtx.onDispatched(); diff --git a/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java b/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java index 665777731..b5ff7cd5f 100644 --- a/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java +++ b/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java @@ -71,6 +71,7 @@ private Object resolveSerialField(ExecutionContext executionContext, dataLoaderDispatcherStrategy.executionSerialStrategy(executionContext, newParameters); Object fieldWithInfo = resolveFieldWithInfo(executionContext, newParameters); + dataLoaderDispatcherStrategy.finishedFetching(executionContext, newParameters); if (fieldWithInfo instanceof CompletableFuture) { //noinspection unchecked return ((CompletableFuture) fieldWithInfo).thenCompose(fvi -> { diff --git a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java index 8763d650f..d57d5cb1e 100644 --- a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java @@ -64,4 +64,8 @@ default void newSubscriptionExecution(AlternativeCallContext alternativeCallCont default void subscriptionEventCompletionDone(AlternativeCallContext alternativeCallContext) { } + + default void finishedFetching(ExecutionContext executionContext, ExecutionStrategyParameters newParameters) { + + } } diff --git a/src/main/java/graphql/execution/Execution.java b/src/main/java/graphql/execution/Execution.java index 9245a9457..eed7e576f 100644 --- a/src/main/java/graphql/execution/Execution.java +++ b/src/main/java/graphql/execution/Execution.java @@ -15,7 +15,7 @@ import graphql.execution.instrumentation.Instrumentation; import graphql.execution.instrumentation.InstrumentationContext; import graphql.execution.instrumentation.InstrumentationState; -import graphql.execution.instrumentation.dataloader.PerLevelDataLoaderDispatchStrategy; +import graphql.execution.instrumentation.dataloader.ExhaustedDataLoaderDispatchStrategy; import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters; import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters; import graphql.extensions.ExtensionsBuilder; @@ -262,7 +262,8 @@ private DataLoaderDispatchStrategy createDataLoaderDispatchStrategy(ExecutionCon if (executionContext.getDataLoaderRegistry() == EMPTY_DATALOADER_REGISTRY || doNotAutomaticallyDispatchDataLoader) { return DataLoaderDispatchStrategy.NO_OP; } - return new PerLevelDataLoaderDispatchStrategy(executionContext); +// return new PerLevelDataLoaderDispatchStrategy(executionContext); + return new ExhaustedDataLoaderDispatchStrategy(executionContext); } diff --git a/src/main/java/graphql/execution/ExecutionStrategy.java b/src/main/java/graphql/execution/ExecutionStrategy.java index a6061a15c..4105a74a7 100644 --- a/src/main/java/graphql/execution/ExecutionStrategy.java +++ b/src/main/java/graphql/execution/ExecutionStrategy.java @@ -210,6 +210,7 @@ protected Object executeObject(ExecutionContext executionContext, ExecutionStrat List fieldsExecutedOnInitialResult = deferredExecutionSupport.getNonDeferredFieldNames(fieldNames); dataLoaderDispatcherStrategy.executeObject(executionContext, parameters, fieldsExecutedOnInitialResult.size()); Async.CombinedBuilder resolvedFieldFutures = getAsyncFieldValueInfo(executionContext, parameters, deferredExecutionSupport); + dataLoaderDispatcherStrategy.finishedFetching(executionContext, parameters); CompletableFuture> overallResult = new CompletableFuture<>(); BiConsumer, Throwable> handleResultsConsumer = buildFieldValueMap(fieldsExecutedOnInitialResult, overallResult, executionContext); diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java new file mode 100644 index 000000000..598516b95 --- /dev/null +++ b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java @@ -0,0 +1,271 @@ +package graphql.execution.instrumentation.dataloader; + +import graphql.Assert; +import graphql.Internal; +import graphql.Profiler; +import graphql.execution.DataLoaderDispatchStrategy; +import graphql.execution.ExecutionContext; +import graphql.execution.ExecutionStrategyParameters; +import graphql.execution.FieldValueInfo; +import graphql.execution.incremental.AlternativeCallContext; +import org.dataloader.DataLoader; +import org.dataloader.DataLoaderRegistry; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +@Internal +@NullMarked +public class ExhaustedDataLoaderDispatchStrategy implements DataLoaderDispatchStrategy { + + private final CallStack initialCallStack; + private final ExecutionContext executionContext; + + private final Profiler profiler; + + private final Map alternativeCallContextMap = new ConcurrentHashMap<>(); + + + private static class CallStack { + + + static class State { + final int objectRunningCount; + final boolean dataLoaderToDispatch; + final boolean currentlyDispatching; + + State(int objectRunningCount, boolean dataLoaderToDispatch, boolean currentlyDispatching) { + this.objectRunningCount = objectRunningCount; + this.dataLoaderToDispatch = dataLoaderToDispatch; + this.currentlyDispatching = currentlyDispatching; + } + + public State copy() { + return new State(objectRunningCount, dataLoaderToDispatch, currentlyDispatching); + } + + public State incrementObjectRunningCount() { + return new State(objectRunningCount + 1, dataLoaderToDispatch, currentlyDispatching); + } + + public State decrementObjetRunningCount() { + return new State(objectRunningCount - 1, dataLoaderToDispatch, currentlyDispatching); + } + + public State dataLoaderToDispatch() { + return new State(objectRunningCount, true, currentlyDispatching); + } + + public State startDispatching() { + return new State(objectRunningCount, false, true); + } + + public State stopDispatching() { + return new State(objectRunningCount, false, false); + } + + + @Override + public String toString() { + return "State{" + + "objectRunningCount=" + objectRunningCount + + ", dataLoaderToDispatch=" + dataLoaderToDispatch + + '}'; + } + } + + private final AtomicLong state = new AtomicLong(); + private final AtomicReference stateRef = new AtomicReference<>(new State(0, false, false)); + + public State getState() { + return Assert.assertNotNull(stateRef.get()); + } + + public boolean tryUpdateState(State oldState, State newState) { + System.out.println("updateState: " + oldState + " -> " + newState); + return stateRef.compareAndSet(oldState, newState); + } + + private final AtomicInteger deferredFragmentRootFieldsCompleted = new AtomicInteger(); + + public CallStack() { + } + + + public void clear() { + deferredFragmentRootFieldsCompleted.set(0); + stateRef.set(new State(0, false, false)); + } + } + + public ExhaustedDataLoaderDispatchStrategy(ExecutionContext executionContext) { + this.initialCallStack = new CallStack(); + this.executionContext = executionContext; + + this.profiler = executionContext.getProfiler(); + } + + + @Override + public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { + Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); + // no concurrency access happening + CallStack.State state = initialCallStack.getState(); + Assert.assertTrue(initialCallStack.tryUpdateState(state, state.incrementObjectRunningCount())); + } + + @Override + public void finishedFetching(ExecutionContext executionContext, ExecutionStrategyParameters newParameters) { + CallStack callStack = getCallStack(newParameters); + decrementObjectRunningAndMaybeDispatch(callStack); + } + + @Override + public void executionSerialStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters) { + CallStack callStack = getCallStack(parameters); + callStack.clear(); + CallStack.State state = callStack.getState(); + // no concurrency access happening + Assert.assertTrue(callStack.tryUpdateState(state, state.incrementObjectRunningCount())); + } + + + @Override + public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { + CallStack callStack = getCallStack(parameters); + while (true) { + CallStack.State state = callStack.getState(); + if (callStack.tryUpdateState(state, state.incrementObjectRunningCount())) { + break; + } + } + } + + + @Override + public void newSubscriptionExecution(AlternativeCallContext alternativeCallContext) { + CallStack callStack = new CallStack(); + alternativeCallContextMap.put(alternativeCallContext, callStack); + } + + @Override + public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable throwable, ExecutionStrategyParameters parameters) { + CallStack callStack = getCallStack(parameters); + int deferredFragmentRootFieldsCompleted = callStack.deferredFragmentRootFieldsCompleted.incrementAndGet(); + Assert.assertNotNull(parameters.getDeferredCallContext()); + if (deferredFragmentRootFieldsCompleted == parameters.getDeferredCallContext().getFields()) { + decrementObjectRunningAndMaybeDispatch(callStack); + } + + } + + private CallStack getCallStack(ExecutionStrategyParameters parameters) { + return getCallStack(parameters.getDeferredCallContext()); + } + + private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallContext) { + if (alternativeCallContext == null) { + return this.initialCallStack; + } else { + return alternativeCallContextMap.computeIfAbsent(alternativeCallContext, k -> { + /* + This is only for handling deferred cases. Subscription cases will also get a new callStack, but + it is explicitly created in `newSubscriptionExecution`. + The reason we are doing this lazily is, because we don't have explicit startDeferred callback. + */ + CallStack callStack = new CallStack(); + return callStack; + }); + } + } + + + private void decrementObjectRunningAndMaybeDispatch(CallStack callStack) { + CallStack.State oldState; + CallStack.State newState; + while (true) { + oldState = callStack.getState(); + newState = oldState.decrementObjetRunningCount(); + if (callStack.tryUpdateState(oldState, newState)) { + break; + } + } + // this means we have not fetching running and we can execute + if (newState.objectRunningCount == 0 && !newState.currentlyDispatching) { + dispatchImpl(callStack); + } + } + + private void newDataLoaderInvocationMaybeDispatch(CallStack callStack) { + CallStack.State oldState; + CallStack.State newState; + while (true) { + oldState = callStack.getState(); + newState = oldState.dataLoaderToDispatch(); + if (callStack.tryUpdateState(oldState, newState)) { + break; + } + } +// System.out.println("new data loader invocation maybe with state: " + newState); + // this means we are not waiting for some fetching to be finished and we need to dispatch + if (newState.objectRunningCount == 0 && !newState.currentlyDispatching) { + dispatchImpl(callStack); + } + + } + + + private void dispatchImpl(CallStack callStack) { + + CallStack.State oldState; + while (true) { + oldState = callStack.getState(); + if (!oldState.dataLoaderToDispatch) { + CallStack.State newState = oldState.stopDispatching(); + if (callStack.tryUpdateState(oldState, newState)) { + return; + } + } + CallStack.State newState = oldState.startDispatching(); + if (callStack.tryUpdateState(oldState, newState)) { + break; + } + } + + DataLoaderRegistry dataLoaderRegistry = executionContext.getDataLoaderRegistry(); + List> dataLoaders = dataLoaderRegistry.getDataLoaders(); + List>> allDispatchedCFs = new ArrayList<>(); + for (DataLoader dataLoader : dataLoaders) { + CompletableFuture> dispatch = dataLoader.dispatch(); + allDispatchedCFs.add(dispatch); + } + CompletableFuture.allOf(allDispatchedCFs.toArray(new CompletableFuture[0])) + .whenComplete((unused, throwable) -> { + dispatchImpl(callStack); + }); + + } + + + public void newDataLoaderInvocation(String resultPath, + int level, + DataLoader dataLoader, + String dataLoaderName, + Object key, + @Nullable AlternativeCallContext alternativeCallContext) { +// DataLoaderInvocation dataLoaderInvocation = new DataLoaderInvocation(resultPath, level, dataLoader, dataLoaderName, key); + CallStack callStack = getCallStack(alternativeCallContext); + newDataLoaderInvocationMaybeDispatch(callStack); + } + + +} + diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index ae9516613..501194d7a 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -391,8 +391,7 @@ public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCa } @Override - public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable - throwable, ExecutionStrategyParameters parameters) { + public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable throwable, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); int deferredFragmentRootFieldsCompleted = callStack.deferredFragmentRootFieldsCompleted.incrementAndGet(); Assert.assertNotNull(parameters.getDeferredCallContext()); diff --git a/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java b/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java index 5cf2685d1..6fa51421f 100644 --- a/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java +++ b/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java @@ -15,7 +15,6 @@ import graphql.execution.MergedField; import graphql.execution.directives.QueryDirectives; import graphql.execution.incremental.AlternativeCallContext; -import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys; import graphql.language.Document; import graphql.language.Field; import graphql.language.FragmentDefinition; @@ -233,9 +232,9 @@ public ExecutionStepInfo getExecutionStepInfo() { if (dataLoader == null) { return null; } - if (!graphQLContext.getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false)) { - return dataLoader; - } +// if (!graphQLContext.getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false)) { +// return dataLoader; +// } return new DataLoaderWithContext<>(this, dataLoaderName, dataLoader); } diff --git a/src/main/java/graphql/schema/DataLoaderWithContext.java b/src/main/java/graphql/schema/DataLoaderWithContext.java index 92403dfdd..5c3daba3e 100644 --- a/src/main/java/graphql/schema/DataLoaderWithContext.java +++ b/src/main/java/graphql/schema/DataLoaderWithContext.java @@ -2,7 +2,7 @@ import graphql.Internal; import graphql.execution.incremental.AlternativeCallContext; -import graphql.execution.instrumentation.dataloader.PerLevelDataLoaderDispatchStrategy; +import graphql.execution.instrumentation.dataloader.ExhaustedDataLoaderDispatchStrategy; import org.dataloader.DataLoader; import org.dataloader.DelegatingDataLoader; import org.jspecify.annotations.NonNull; @@ -32,11 +32,11 @@ public CompletableFuture load(@NonNull K key, @Nullable Object keyContext) { DataFetchingEnvironmentImpl dfeImpl = (DataFetchingEnvironmentImpl) dfe; DataFetchingEnvironmentImpl.DFEInternalState dfeInternalState = (DataFetchingEnvironmentImpl.DFEInternalState) dfeImpl.toInternal(); dfeInternalState.getProfiler().dataLoaderUsed(dataLoaderName); - if (dfeInternalState.getDataLoaderDispatchStrategy() instanceof PerLevelDataLoaderDispatchStrategy) { + if (dfeInternalState.getDataLoaderDispatchStrategy() instanceof ExhaustedDataLoaderDispatchStrategy) { AlternativeCallContext alternativeCallContext = dfeInternalState.getDeferredCallContext(); int level = dfe.getExecutionStepInfo().getPath().getLevel(); String path = dfe.getExecutionStepInfo().getPath().toString(); - ((PerLevelDataLoaderDispatchStrategy) dfeInternalState.dataLoaderDispatchStrategy).newDataLoaderInvocation(path, level, delegate, dataLoaderName, key, alternativeCallContext); + ((ExhaustedDataLoaderDispatchStrategy) dfeInternalState.dataLoaderDispatchStrategy).newDataLoaderInvocation(path, level, delegate, dataLoaderName, key, alternativeCallContext); } return result; } From 0407946b7080c035bf37557f0620ec115792ed8f Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 12:23:22 +1000 Subject: [PATCH 24/40] working exhausted strategy --- .../ExhaustedDataLoaderDispatchStrategy.java | 170 +++++++++--------- 1 file changed, 90 insertions(+), 80 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java index 598516b95..6d18d30fc 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java @@ -19,8 +19,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; @Internal @NullMarked @@ -36,62 +34,100 @@ public class ExhaustedDataLoaderDispatchStrategy implements DataLoaderDispatchSt private static class CallStack { + // 30 bits for objectRunningCount + // 1 bit for dataLoaderToDispatch + // 1 bit for currentlyDispatching - static class State { - final int objectRunningCount; - final boolean dataLoaderToDispatch; - final boolean currentlyDispatching; + // Bit positions (from right to left) + static final int currentlyDispatchingShift = 0; + static final int dataLoaderToDispatchShift = 1; + static final int objectRunningCountShift = 2; - State(int objectRunningCount, boolean dataLoaderToDispatch, boolean currentlyDispatching) { - this.objectRunningCount = objectRunningCount; - this.dataLoaderToDispatch = dataLoaderToDispatch; - this.currentlyDispatching = currentlyDispatching; - } + // mask + static final int booleanMask = 1; + static final int objectRunningCountMask = (1 << 30) - 1; - public State copy() { - return new State(objectRunningCount, dataLoaderToDispatch, currentlyDispatching); - } - public State incrementObjectRunningCount() { - return new State(objectRunningCount + 1, dataLoaderToDispatch, currentlyDispatching); - } + public static int getObjectRunningCount(int state) { + return (state >> objectRunningCountShift) & objectRunningCountMask; + } - public State decrementObjetRunningCount() { - return new State(objectRunningCount - 1, dataLoaderToDispatch, currentlyDispatching); - } + public static int setObjectRunningCount(int state, int objectRunningCount) { + return (state & ~(objectRunningCountMask << objectRunningCountShift)) | + (objectRunningCount << objectRunningCountShift); + } - public State dataLoaderToDispatch() { - return new State(objectRunningCount, true, currentlyDispatching); - } + public static int setDataLoaderToDispatch(int state, boolean dataLoaderToDispatch) { + return (state & ~(booleanMask << dataLoaderToDispatchShift)) | + ((dataLoaderToDispatch ? 1 : 0) << dataLoaderToDispatchShift); + } - public State startDispatching() { - return new State(objectRunningCount, false, true); - } + public static int setCurrentlyDispatching(int state, boolean currentlyDispatching) { + return (state & ~(booleanMask << currentlyDispatchingShift)) | + ((currentlyDispatching ? 1 : 0) << currentlyDispatchingShift); + } - public State stopDispatching() { - return new State(objectRunningCount, false, false); + + public static boolean getDataLoaderToDispatch(int state) { + return ((state >> dataLoaderToDispatchShift) & booleanMask) != 0; + } + + public static boolean getCurrentlyDispatching(int state) { + return ((state >> currentlyDispatchingShift) & booleanMask) != 0; + } + +// public static int newState(int objectRunningCount, boolean dataLoaderToDispatch, boolean currentlyDispatching) { +// return (objectRunningCount << objectRunningCountShift) | +// ((dataLoaderToDispatch ? 1 : 0) << dataLoaderToDispatchShift) | +// ((currentlyDispatching ? 1 : 0) << currentlyDispatchingShift); +// } + + public void incrementObjectRunningCount() { + while (true) { + int oldState = getState(); + int objectRunningCount = getObjectRunningCount(oldState); + int newState = setObjectRunningCount(oldState, objectRunningCount + 1); + if (tryUpdateState(oldState, newState)) { + return; + } } + } + public int decrementObjectRunningCount() { + while (true) { + int oldState = getState(); + int objectRunningCount = getObjectRunningCount(oldState); + int newState = setObjectRunningCount(oldState, objectRunningCount - 1); + if (tryUpdateState(oldState, newState)) { + return newState; + } + } + } - @Override - public String toString() { - return "State{" + - "objectRunningCount=" + objectRunningCount + - ", dataLoaderToDispatch=" + dataLoaderToDispatch + - '}'; + public int dataLoaderToDispatch() { + while (true) { + int oldState = getState(); + int newState = setDataLoaderToDispatch(oldState, true); + if (tryUpdateState(oldState, newState)) { + return newState; + } } } - private final AtomicLong state = new AtomicLong(); - private final AtomicReference stateRef = new AtomicReference<>(new State(0, false, false)); + public static String printState(int state) { + return "objectRunningCount: " + getObjectRunningCount(state) + + ",dataLoaderToDispatch: " + getDataLoaderToDispatch(state) + + ",currentlyDispatching: " + getCurrentlyDispatching(state); + } - public State getState() { - return Assert.assertNotNull(stateRef.get()); + private final AtomicInteger state = new AtomicInteger(); + + public int getState() { + return state.get(); } - public boolean tryUpdateState(State oldState, State newState) { - System.out.println("updateState: " + oldState + " -> " + newState); - return stateRef.compareAndSet(oldState, newState); + public boolean tryUpdateState(int oldState, int newState) { + return state.compareAndSet(oldState, newState); } private final AtomicInteger deferredFragmentRootFieldsCompleted = new AtomicInteger(); @@ -102,7 +138,7 @@ public CallStack() { public void clear() { deferredFragmentRootFieldsCompleted.set(0); - stateRef.set(new State(0, false, false)); + state.set(0); } } @@ -118,8 +154,7 @@ public ExhaustedDataLoaderDispatchStrategy(ExecutionContext executionContext) { public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); // no concurrency access happening - CallStack.State state = initialCallStack.getState(); - Assert.assertTrue(initialCallStack.tryUpdateState(state, state.incrementObjectRunningCount())); + initialCallStack.incrementObjectRunningCount(); } @Override @@ -132,21 +167,15 @@ public void finishedFetching(ExecutionContext executionContext, ExecutionStrateg public void executionSerialStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); callStack.clear(); - CallStack.State state = callStack.getState(); // no concurrency access happening - Assert.assertTrue(callStack.tryUpdateState(state, state.incrementObjectRunningCount())); + callStack.incrementObjectRunningCount(); } @Override public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { CallStack callStack = getCallStack(parameters); - while (true) { - CallStack.State state = callStack.getState(); - if (callStack.tryUpdateState(state, state.incrementObjectRunningCount())) { - break; - } - } + callStack.incrementObjectRunningCount(); } @@ -189,52 +218,33 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC private void decrementObjectRunningAndMaybeDispatch(CallStack callStack) { - CallStack.State oldState; - CallStack.State newState; - while (true) { - oldState = callStack.getState(); - newState = oldState.decrementObjetRunningCount(); - if (callStack.tryUpdateState(oldState, newState)) { - break; - } - } + int newState = callStack.decrementObjectRunningCount(); // this means we have not fetching running and we can execute - if (newState.objectRunningCount == 0 && !newState.currentlyDispatching) { + if (CallStack.getObjectRunningCount(newState) == 0 && !CallStack.getCurrentlyDispatching(newState)) { dispatchImpl(callStack); } } private void newDataLoaderInvocationMaybeDispatch(CallStack callStack) { - CallStack.State oldState; - CallStack.State newState; - while (true) { - oldState = callStack.getState(); - newState = oldState.dataLoaderToDispatch(); - if (callStack.tryUpdateState(oldState, newState)) { - break; - } - } -// System.out.println("new data loader invocation maybe with state: " + newState); + int newState = callStack.dataLoaderToDispatch(); // this means we are not waiting for some fetching to be finished and we need to dispatch - if (newState.objectRunningCount == 0 && !newState.currentlyDispatching) { + if (CallStack.getObjectRunningCount(newState) == 0 && !CallStack.getCurrentlyDispatching(newState)) { dispatchImpl(callStack); } - } private void dispatchImpl(CallStack callStack) { - - CallStack.State oldState; while (true) { - oldState = callStack.getState(); - if (!oldState.dataLoaderToDispatch) { - CallStack.State newState = oldState.stopDispatching(); + int oldState = callStack.getState(); + if (!CallStack.getDataLoaderToDispatch(oldState)) { + int newState = CallStack.setCurrentlyDispatching(oldState, false); if (callStack.tryUpdateState(oldState, newState)) { return; } } - CallStack.State newState = oldState.startDispatching(); + int newState = CallStack.setCurrentlyDispatching(oldState, true); + newState = CallStack.setDataLoaderToDispatch(newState, false); if (callStack.tryUpdateState(oldState, newState)) { break; } From 2e5c616dd229e78c45d426b4c4e3223611f27ea4 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 12:38:16 +1000 Subject: [PATCH 25/40] cleanup --- .../performance/DataLoaderPerformance.java | 22 ++++++++++++++----- .../graphql/GraphQLUnusualConfiguration.java | 18 ++++++++++++++- .../java/graphql/execution/Execution.java | 11 +++++++--- .../DataLoaderDispatchingContextKeys.java | 16 ++++++++++++++ .../ExhaustedDataLoaderDispatchStrategy.java | 8 +------ .../schema/DataFetchingEnvironmentImpl.java | 12 +++++----- .../graphql/schema/DataLoaderWithContext.java | 8 +++++-- 7 files changed, 71 insertions(+), 24 deletions(-) diff --git a/src/jmh/java/performance/DataLoaderPerformance.java b/src/jmh/java/performance/DataLoaderPerformance.java index 6f81408d6..98a365c2d 100644 --- a/src/jmh/java/performance/DataLoaderPerformance.java +++ b/src/jmh/java/performance/DataLoaderPerformance.java @@ -483,6 +483,11 @@ public Pet(String id, String name, String ownerId, List friendsIds) { static BatchLoader ownerBatchLoader = list -> { List collect = list.stream().map(key -> { Owner owner = owners.get(key); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } return owner; }).collect(Collectors.toList()); return CompletableFuture.completedFuture(collect); @@ -490,6 +495,11 @@ public Pet(String id, String name, String ownerId, List friendsIds) { static BatchLoader petBatchLoader = list -> { List collect = list.stream().map(key -> { Pet owner = pets.get(key); + try { + Thread.sleep(5); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } return owner; }).collect(Collectors.toList()); return CompletableFuture.completedFuture(collect); @@ -532,20 +542,20 @@ public void setup() { }); DataFetcher petsDf = (env -> { Owner owner = env.getSource(); - return env.getDataLoader(petDLName).loadMany((List) owner.petIds) - .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result)); + return env.getDataLoader(petDLName).loadMany((List) owner.petIds); +// .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result)); }); DataFetcher petFriendsDF = (env -> { Pet pet = env.getSource(); - return env.getDataLoader(petDLName).loadMany((List) pet.friendsIds) - .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result)); + return env.getDataLoader(petDLName).loadMany((List) pet.friendsIds); +// .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result)); }); DataFetcher petOwnerDF = (env -> { Pet pet = env.getSource(); - return env.getDataLoader(ownerDLName).load(pet.ownerId) - .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result)); + return env.getDataLoader(ownerDLName).load(pet.ownerId); +// .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result)); }); diff --git a/src/main/java/graphql/GraphQLUnusualConfiguration.java b/src/main/java/graphql/GraphQLUnusualConfiguration.java index d7a7eb9fb..3e3443c07 100644 --- a/src/main/java/graphql/GraphQLUnusualConfiguration.java +++ b/src/main/java/graphql/GraphQLUnusualConfiguration.java @@ -7,6 +7,7 @@ import static graphql.Assert.assertNotNull; import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING; +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING; /** * This allows you to control "unusual" aspects of the GraphQL system @@ -344,12 +345,16 @@ private DataloaderConfig(GraphQLContextConfiguration contextConfig) { } /** - * @return true if @defer and @stream behaviour is enabled for this execution. + * returns true if chained data loader dispatching is enabled */ public boolean isDataLoaderChainingEnabled() { return contextConfig.getBoolean(ENABLE_DATA_LOADER_CHAINING); } + public boolean isDataLoaderExhaustedDispatchingEnabled() { + return contextConfig.get(ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING); + } + /** * Enables the ability that chained DataLoaders are dispatched automatically. */ @@ -359,6 +364,17 @@ public DataloaderConfig enableDataLoaderChaining(boolean enable) { return this; } + /** + * Enables a dispatching strategy that will dispatch as long as there is no + * other data fetcher or batch loader running. + */ + @ExperimentalApi + public DataloaderConfig enableDataLoaderExhaustedDispatching(boolean enable) { + contextConfig.put(ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, enable); + return this; + } + + } public static class ResponseMapFactoryConfig extends BaseContextConfig { diff --git a/src/main/java/graphql/execution/Execution.java b/src/main/java/graphql/execution/Execution.java index eed7e576f..149ec3fa7 100644 --- a/src/main/java/graphql/execution/Execution.java +++ b/src/main/java/graphql/execution/Execution.java @@ -15,7 +15,9 @@ import graphql.execution.instrumentation.Instrumentation; import graphql.execution.instrumentation.InstrumentationContext; import graphql.execution.instrumentation.InstrumentationState; +import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys; import graphql.execution.instrumentation.dataloader.ExhaustedDataLoaderDispatchStrategy; +import graphql.execution.instrumentation.dataloader.PerLevelDataLoaderDispatchStrategy; import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters; import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters; import graphql.extensions.ExtensionsBuilder; @@ -262,8 +264,10 @@ private DataLoaderDispatchStrategy createDataLoaderDispatchStrategy(ExecutionCon if (executionContext.getDataLoaderRegistry() == EMPTY_DATALOADER_REGISTRY || doNotAutomaticallyDispatchDataLoader) { return DataLoaderDispatchStrategy.NO_OP; } -// return new PerLevelDataLoaderDispatchStrategy(executionContext); - return new ExhaustedDataLoaderDispatchStrategy(executionContext); + if (executionContext.getGraphQLContext().getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, false)) { + return new ExhaustedDataLoaderDispatchStrategy(executionContext); + } + return new PerLevelDataLoaderDispatchStrategy(executionContext); } @@ -274,7 +278,8 @@ private void addExtensionsBuilderNotPresent(GraphQLContext graphQLContext) { } } - private ExecutionResult mergeExtensionsBuilderIfPresent(ExecutionResult executionResult, GraphQLContext graphQLContext) { + private ExecutionResult mergeExtensionsBuilderIfPresent(ExecutionResult executionResult, GraphQLContext + graphQLContext) { Object builder = graphQLContext.get(ExtensionsBuilder.class); if (builder instanceof ExtensionsBuilder) { ExtensionsBuilder extensionsBuilder = (ExtensionsBuilder) builder; diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/DataLoaderDispatchingContextKeys.java b/src/main/java/graphql/execution/instrumentation/dataloader/DataLoaderDispatchingContextKeys.java index 4fc6284a3..c41196e05 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/DataLoaderDispatchingContextKeys.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/DataLoaderDispatchingContextKeys.java @@ -25,6 +25,13 @@ private DataLoaderDispatchingContextKeys() { public static final String ENABLE_DATA_LOADER_CHAINING = "__GJ_enable_data_loader_chaining"; + /** + * Enabled a different dispatching strategy that mimics the JS event loop based one: + * DataLoader will be dispatched as soon as there is no data fetcher or batch loader currently running. + * + */ + public static final String ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING = "__GJ_enable_data_loader_exhausted_dispatching"; + /** * Enables the ability that chained DataLoaders are dispatched automatically. * @@ -34,5 +41,14 @@ public static void setEnableDataLoaderChaining(GraphQLContext graphQLContext, bo graphQLContext.put(ENABLE_DATA_LOADER_CHAINING, enabled); } + /** + * Enables the ability that chained DataLoaders are dispatched automatically. + * + * @param graphQLContext + */ + public static void setEnableDataLoaderExhaustedDispatching(GraphQLContext graphQLContext, boolean enabled) { + graphQLContext.put(ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, enabled); + } + } diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java index 6d18d30fc..529b1a1f3 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java @@ -265,13 +265,7 @@ private void dispatchImpl(CallStack callStack) { } - public void newDataLoaderInvocation(String resultPath, - int level, - DataLoader dataLoader, - String dataLoaderName, - Object key, - @Nullable AlternativeCallContext alternativeCallContext) { -// DataLoaderInvocation dataLoaderInvocation = new DataLoaderInvocation(resultPath, level, dataLoader, dataLoaderName, key); + public void newDataLoaderInvocation(@Nullable AlternativeCallContext alternativeCallContext) { CallStack callStack = getCallStack(alternativeCallContext); newDataLoaderInvocationMaybeDispatch(callStack); } diff --git a/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java b/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java index 6fa51421f..82f8bf1a4 100644 --- a/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java +++ b/src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java @@ -15,6 +15,7 @@ import graphql.execution.MergedField; import graphql.execution.directives.QueryDirectives; import graphql.execution.incremental.AlternativeCallContext; +import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys; import graphql.language.Document; import graphql.language.Field; import graphql.language.FragmentDefinition; @@ -232,9 +233,10 @@ public ExecutionStepInfo getExecutionStepInfo() { if (dataLoader == null) { return null; } -// if (!graphQLContext.getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false)) { -// return dataLoader; -// } + if (!graphQLContext.getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false) + && !graphQLContext.getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, false)) { + return dataLoader; + } return new DataLoaderWithContext<>(this, dataLoaderName, dataLoader); } @@ -272,8 +274,8 @@ public Object toInternal() { @Override public String toString() { return "DataFetchingEnvironmentImpl{" + - "executionStepInfo=" + executionStepInfo + - '}'; + "executionStepInfo=" + executionStepInfo + + '}'; } @NullUnmarked diff --git a/src/main/java/graphql/schema/DataLoaderWithContext.java b/src/main/java/graphql/schema/DataLoaderWithContext.java index 5c3daba3e..8090e0325 100644 --- a/src/main/java/graphql/schema/DataLoaderWithContext.java +++ b/src/main/java/graphql/schema/DataLoaderWithContext.java @@ -3,6 +3,7 @@ import graphql.Internal; import graphql.execution.incremental.AlternativeCallContext; import graphql.execution.instrumentation.dataloader.ExhaustedDataLoaderDispatchStrategy; +import graphql.execution.instrumentation.dataloader.PerLevelDataLoaderDispatchStrategy; import org.dataloader.DataLoader; import org.dataloader.DelegatingDataLoader; import org.jspecify.annotations.NonNull; @@ -32,11 +33,14 @@ public CompletableFuture load(@NonNull K key, @Nullable Object keyContext) { DataFetchingEnvironmentImpl dfeImpl = (DataFetchingEnvironmentImpl) dfe; DataFetchingEnvironmentImpl.DFEInternalState dfeInternalState = (DataFetchingEnvironmentImpl.DFEInternalState) dfeImpl.toInternal(); dfeInternalState.getProfiler().dataLoaderUsed(dataLoaderName); - if (dfeInternalState.getDataLoaderDispatchStrategy() instanceof ExhaustedDataLoaderDispatchStrategy) { + if (dfeInternalState.getDataLoaderDispatchStrategy() instanceof PerLevelDataLoaderDispatchStrategy) { AlternativeCallContext alternativeCallContext = dfeInternalState.getDeferredCallContext(); int level = dfe.getExecutionStepInfo().getPath().getLevel(); String path = dfe.getExecutionStepInfo().getPath().toString(); - ((ExhaustedDataLoaderDispatchStrategy) dfeInternalState.dataLoaderDispatchStrategy).newDataLoaderInvocation(path, level, delegate, dataLoaderName, key, alternativeCallContext); + ((PerLevelDataLoaderDispatchStrategy) dfeInternalState.dataLoaderDispatchStrategy).newDataLoaderInvocation(path, level, delegate, dataLoaderName, key, alternativeCallContext); + } else if (dfeInternalState.getDataLoaderDispatchStrategy() instanceof ExhaustedDataLoaderDispatchStrategy) { + AlternativeCallContext alternativeCallContext = dfeInternalState.getDeferredCallContext(); + ((ExhaustedDataLoaderDispatchStrategy) dfeInternalState.dataLoaderDispatchStrategy).newDataLoaderInvocation(alternativeCallContext); } return result; } From f952bf13db966e11fe1ace4b51caf9065dd3a2d4 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 12:47:27 +1000 Subject: [PATCH 26/40] cleanup --- src/main/java/graphql/execution/Execution.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/Execution.java b/src/main/java/graphql/execution/Execution.java index 149ec3fa7..ac8c5ae32 100644 --- a/src/main/java/graphql/execution/Execution.java +++ b/src/main/java/graphql/execution/Execution.java @@ -278,8 +278,7 @@ private void addExtensionsBuilderNotPresent(GraphQLContext graphQLContext) { } } - private ExecutionResult mergeExtensionsBuilderIfPresent(ExecutionResult executionResult, GraphQLContext - graphQLContext) { + private ExecutionResult mergeExtensionsBuilderIfPresent(ExecutionResult executionResult, GraphQLContext graphQLContext) { Object builder = graphQLContext.get(ExtensionsBuilder.class); if (builder instanceof ExtensionsBuilder) { ExtensionsBuilder extensionsBuilder = (ExtensionsBuilder) builder; From 5f27d3d5113bad43b9f4f35295f75af89aaec6df Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 20:25:59 +1000 Subject: [PATCH 27/40] test ambiguous config check --- .../java/graphql/execution/Execution.java | 4 ++ .../graphql/ChainedDataLoaderTest.groovy | 63 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/main/java/graphql/execution/Execution.java b/src/main/java/graphql/execution/Execution.java index ac8c5ae32..37d43a471 100644 --- a/src/main/java/graphql/execution/Execution.java +++ b/src/main/java/graphql/execution/Execution.java @@ -9,6 +9,7 @@ import graphql.GraphQL; import graphql.GraphQLContext; import graphql.GraphQLError; +import graphql.GraphQLException; import graphql.Internal; import graphql.Profiler; import graphql.execution.incremental.IncrementalCallState; @@ -265,6 +266,9 @@ private DataLoaderDispatchStrategy createDataLoaderDispatchStrategy(ExecutionCon return DataLoaderDispatchStrategy.NO_OP; } if (executionContext.getGraphQLContext().getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, false)) { + if (executionContext.getGraphQLContext().getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false)) { + throw new GraphQLException("enabling data loader chaining and exhausted dispatching at the same time ambiguous"); + } return new ExhaustedDataLoaderDispatchStrategy(executionContext); } return new PerLevelDataLoaderDispatchStrategy(executionContext); diff --git a/src/test/groovy/graphql/ChainedDataLoaderTest.groovy b/src/test/groovy/graphql/ChainedDataLoaderTest.groovy index 1a2e77f8c..98986b32c 100644 --- a/src/test/groovy/graphql/ChainedDataLoaderTest.groovy +++ b/src/test/groovy/graphql/ChainedDataLoaderTest.groovy @@ -1,6 +1,5 @@ package graphql - import graphql.schema.DataFetcher import org.awaitility.Awaitility import org.dataloader.BatchLoader @@ -9,16 +8,20 @@ import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderRegistry import spock.lang.RepeatUntilFailure import spock.lang.Specification +import spock.lang.Unroll +import java.util.concurrent.ExecutionException import java.util.concurrent.atomic.AtomicInteger import static graphql.ExecutionInput.newExecutionInput import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.setEnableDataLoaderChaining +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.setEnableDataLoaderExhaustedDispatching import static java.util.concurrent.CompletableFuture.supplyAsync class ChainedDataLoaderTest extends Specification { + @Unroll def "chained data loaders"() { given: def sdl = ''' @@ -69,7 +72,7 @@ class ChainedDataLoaderTest extends Specification { def query = "{ dogName catName } " def ei = newExecutionInput(query).dataLoaderRegistry(dataLoaderRegistry).build() - setEnableDataLoaderChaining(ei.graphQLContext, true) + chainedDataLoaderOrExhaustedDispatcher ? setEnableDataLoaderChaining(ei.graphQLContext, true) : setEnableDataLoaderExhaustedDispatching(ei.graphQLContext, true) when: def efCF = graphQL.executeAsync(ei) @@ -78,8 +81,12 @@ class ChainedDataLoaderTest extends Specification { then: er.data == [dogName: "Luna", catName: "Tiger"] batchLoadCalls == 2 + + where: + chainedDataLoaderOrExhaustedDispatcher << [true, false] } + @Unroll @RepeatUntilFailure(maxAttempts = 20, ignoreRest = false) def "parallel different data loaders"() { given: @@ -161,7 +168,7 @@ class ChainedDataLoaderTest extends Specification { def query = "{ hello helloDelayed} " def ei = newExecutionInput(query).dataLoaderRegistry(dataLoaderRegistry).build() - setEnableDataLoaderChaining(ei.graphQLContext, true) + chainedDataLoaderOrExhaustedDispatcher ? setEnableDataLoaderChaining(ei.graphQLContext, true) : setEnableDataLoaderExhaustedDispatching(ei.graphQLContext, true) when: def efCF = graphQL.executeAsync(ei) @@ -171,9 +178,14 @@ class ChainedDataLoaderTest extends Specification { er.data == [hello: "friendsLunakey1Skipperkey2", helloDelayed: "friendsLunakey1-delayedSkipperkey2-delayed"] batchLoadCalls.get() == 6 + where: + chainedDataLoaderOrExhaustedDispatcher << [true, false] + + } + @Unroll def "more complicated chained data loader for one DF"() { given: def sdl = ''' @@ -251,7 +263,7 @@ class ChainedDataLoaderTest extends Specification { def query = "{ foo } " def ei = newExecutionInput(query).dataLoaderRegistry(dataLoaderRegistry).build() - setEnableDataLoaderChaining(ei.graphQLContext, true) + chainedDataLoaderOrExhaustedDispatcher ? setEnableDataLoaderChaining(ei.graphQLContext, true) : setEnableDataLoaderExhaustedDispatching(ei.graphQLContext, true) when: def efCF = graphQL.executeAsync(ei) @@ -261,9 +273,13 @@ class ChainedDataLoaderTest extends Specification { er.data == [foo: "start-batchloader1-otherCF1-otherCF2-start-batchloader1-batchloader2-apply"] batchLoadCalls1 == 1 batchLoadCalls2 == 1 + where: + chainedDataLoaderOrExhaustedDispatcher << [true, false] + } + @Unroll def "chained data loaders with an delayed data loader"() { given: def sdl = ''' @@ -320,7 +336,7 @@ class ChainedDataLoaderTest extends Specification { def query = "{ dogName catName } " def ei = newExecutionInput(query).dataLoaderRegistry(dataLoaderRegistry).build() - setEnableDataLoaderChaining(ei.graphQLContext, true) + chainedDataLoaderOrExhaustedDispatcher ? setEnableDataLoaderChaining(ei.graphQLContext, true) : setEnableDataLoaderExhaustedDispatching(ei.graphQLContext, true) when: def efCF = graphQL.executeAsync(ei) @@ -329,8 +345,12 @@ class ChainedDataLoaderTest extends Specification { then: er.data == [dogName: "Luna2", catName: "Tiger2"] batchLoadCalls == 3 + where: + chainedDataLoaderOrExhaustedDispatcher << [true, false] + } + @Unroll def "chained data loaders with two delayed data loaders"() { given: def sdl = ''' @@ -382,7 +402,7 @@ class ChainedDataLoaderTest extends Specification { def eiBuilder = ExecutionInput.newExecutionInput(query) def ei = eiBuilder.dataLoaderRegistry(dataLoaderRegistry).build() - setEnableDataLoaderChaining(ei.graphQLContext, true); + chainedDataLoaderOrExhaustedDispatcher ? setEnableDataLoaderChaining(ei.graphQLContext, true) : setEnableDataLoaderExhaustedDispatching(ei.graphQLContext, true) when: @@ -392,6 +412,10 @@ class ChainedDataLoaderTest extends Specification { then: er.data == [foo: "fooFirstValue", bar: "barFirstValue"] batchLoadCalls.get() == 1 || batchLoadCalls.get() == 2 // depending on timing, it can be 1 or 2 calls + + where: + chainedDataLoaderOrExhaustedDispatcher << [true, false] + } def "handling of chained DataLoaders is disabled by default"() { @@ -454,4 +478,31 @@ class ChainedDataLoaderTest extends Specification { } + def "setting chained and exhausted at the same time caused error"() { + given: + def sdl = ''' + + type Query { + echo:String + } + ''' + def schema = TestUtil.schema(sdl, [:]) + def graphQL = GraphQL.newGraphQL(schema).build() + + def query = "{echo} " + def ei = newExecutionInput(query).dataLoaderRegistry(new DataLoaderRegistry()).build() + setEnableDataLoaderChaining(ei.graphQLContext, true) + setEnableDataLoaderExhaustedDispatching(ei.graphQLContext, true) + + + when: + def er = graphQL.executeAsync(ei) + er.get() + + then: + def e = thrown(ExecutionException) + e.getCause().getMessage() == "enabling data loader chaining and exhausted dispatching at the same time ambiguous" + } + + } From dab44bfd4e0cee27aa85fcbb315b78c4a2173623 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 20:44:37 +1000 Subject: [PATCH 28/40] tests --- .../dataloader/DataLoaderHangingTest.groovy | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderHangingTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderHangingTest.groovy index f6670cc30..f3b908707 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderHangingTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderHangingTest.groovy @@ -33,6 +33,8 @@ import java.util.concurrent.TimeUnit import java.util.stream.Collectors import static graphql.ExecutionInput.newExecutionInput +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring class DataLoaderHangingTest extends Specification { @@ -137,10 +139,11 @@ class DataLoaderHangingTest extends Specification { def futures = Async.ofExpectedSize(NUM_OF_REPS) for (int i = 0; i < NUM_OF_REPS; i++) { DataLoaderRegistry dataLoaderRegistry = mkNewDataLoaderRegistry(executor) + def contextMap = contextKey == null ? Collections.emptyMap() : [(contextKey): true] def result = graphql.executeAsync(newExecutionInput() .dataLoaderRegistry(dataLoaderRegistry) - .graphQLContext([(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): enableDataLoaderChaining] as Map) + .graphQLContext(contextMap) .query(""" query getArtistsWithData { listArtists(limit: 1) { @@ -183,7 +186,7 @@ class DataLoaderHangingTest extends Specification { .join() where: - enableDataLoaderChaining << [true, false] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } @@ -370,7 +373,7 @@ class DataLoaderHangingTest extends Specification { ExecutionInput executionInput = newExecutionInput() .query(query) .graphQLContext(["registry": registry]) - .graphQLContext([(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): false]) + .graphQLContext([(ENABLE_DATA_LOADER_CHAINING): false]) .dataLoaderRegistry(registry) .build() From 583c27889f563d8643cef37352a16af9870ecb85 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 21:15:59 +1000 Subject: [PATCH 29/40] testing --- .../ExhaustedDataLoaderDispatchStrategy.java | 14 ++++++++------ .../SubscriptionExecutionStrategyTest.groovy | 11 +++++++++-- .../dataloader/DeferWithDataLoaderTest.groovy | 9 +++++++-- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java index 529b1a1f3..3bd721c6b 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java @@ -47,7 +47,6 @@ private static class CallStack { static final int booleanMask = 1; static final int objectRunningCountMask = (1 << 30) - 1; - public static int getObjectRunningCount(int state) { return (state >> objectRunningCountShift) & objectRunningCountMask; } @@ -76,11 +75,6 @@ public static boolean getCurrentlyDispatching(int state) { return ((state >> currentlyDispatchingShift) & booleanMask) != 0; } -// public static int newState(int objectRunningCount, boolean dataLoaderToDispatch, boolean currentlyDispatching) { -// return (objectRunningCount << objectRunningCountShift) | -// ((dataLoaderToDispatch ? 1 : 0) << dataLoaderToDispatchShift) | -// ((currentlyDispatching ? 1 : 0) << currentlyDispatchingShift); -// } public void incrementObjectRunningCount() { while (true) { @@ -114,6 +108,7 @@ public int dataLoaderToDispatch() { } } + // for debugging public static String printState(int state) { return "objectRunningCount: " + getObjectRunningCount(state) + ",dataLoaderToDispatch: " + getDataLoaderToDispatch(state) + @@ -183,6 +178,13 @@ public void executeObject(ExecutionContext executionContext, ExecutionStrategyPa public void newSubscriptionExecution(AlternativeCallContext alternativeCallContext) { CallStack callStack = new CallStack(); alternativeCallContextMap.put(alternativeCallContext, callStack); + callStack.incrementObjectRunningCount(); + } + + @Override + public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCallContext) { + CallStack callStack = getCallStack(alternativeCallContext); + decrementObjectRunningAndMaybeDispatch(callStack); } @Override diff --git a/src/test/groovy/graphql/execution/SubscriptionExecutionStrategyTest.groovy b/src/test/groovy/graphql/execution/SubscriptionExecutionStrategyTest.groovy index 3c3b8d6b0..5168593d5 100644 --- a/src/test/groovy/graphql/execution/SubscriptionExecutionStrategyTest.groovy +++ b/src/test/groovy/graphql/execution/SubscriptionExecutionStrategyTest.groovy @@ -11,6 +11,7 @@ import graphql.TestUtil import graphql.TypeMismatchError import graphql.execution.instrumentation.InstrumentationState import graphql.execution.instrumentation.LegacyTestingInstrumentation +import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters import graphql.execution.pubsub.CapturingSubscriber import graphql.execution.pubsub.FlowMessagePublisher @@ -32,8 +33,8 @@ import spock.lang.Specification import spock.lang.Unroll import java.util.concurrent.CompletableFuture -import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.atomic.AtomicInteger import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring @@ -776,7 +777,7 @@ class SubscriptionExecutionStrategyTest extends Specification { executionInput.cancel() // make things over the subscription - promises.forEach {it.run()} + promises.forEach { it.run() } then: @@ -801,6 +802,7 @@ class SubscriptionExecutionStrategyTest extends Specification { } + @Unroll def "DataLoader works on each subscription event"() { given: def sdl = """ @@ -856,6 +858,9 @@ class SubscriptionExecutionStrategyTest extends Specification { def graphQL = GraphQL.newGraphQL(schema) .build() + if (exhaustedStrategy) { + ei.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) + } when: def executionResult = graphQL.execute(ei) @@ -873,5 +878,7 @@ class SubscriptionExecutionStrategyTest extends Specification { events[1].data == ["newDogs": [[name: "Luna"], [name: "Skipper"]]] events[2].data == ["newDogs": [[name: "Luna"], [name: "Skipper"]]] + where: + exhaustedStrategy << [false, true] } } diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy index 362206f64..d526d1f8d 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy @@ -13,6 +13,7 @@ import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderRegistry import spock.lang.RepeatUntilFailure import spock.lang.Specification +import spock.lang.Unroll import java.util.concurrent.CompletableFuture @@ -348,7 +349,8 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 } - @RepeatUntilFailure(maxAttempts = 50, ignoreRest = false) + @Unroll + @RepeatUntilFailure(maxAttempts = 20, ignoreRest = false) def "dataloader in initial result and chained dataloader inside nested defer block"() { given: def sdl = ''' @@ -446,7 +448,7 @@ class DeferWithDataLoaderTest extends Specification { def graphQL = GraphQL.newGraphQL(schema).build() def ei = ExecutionInput.newExecutionInput(query).dataLoaderRegistry(dataLoaderRegistry).build() ei.getGraphQLContext().put(ExperimentalApi.ENABLE_INCREMENTAL_SUPPORT, true) - ei.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, true) + dataLoaderChainingOrExhaustedDispatching ? ei.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, true) : ei.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) when: CompletableFuture erCF = graphQL.executeAsync(ei) @@ -477,6 +479,9 @@ class DeferWithDataLoaderTest extends Specification { ] ) + where: + dataLoaderChainingOrExhaustedDispatching << [true, false] + } } From 8a24dcab90f632084dbe6878d9537be71cb5a2a7 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sat, 27 Sep 2025 22:40:29 +1000 Subject: [PATCH 30/40] testing and fixes delayed list of objects case --- .../execution/DataLoaderDispatchStrategy.java | 12 ++++++ .../graphql/execution/ExecutionStrategy.java | 10 ++++- .../incremental/DeferredExecutionSupport.java | 2 + .../ExhaustedDataLoaderDispatchStrategy.java | 22 +++++++--- .../PerLevelDataLoaderDispatchStrategy.java | 2 +- .../dataloader/DeferWithDataLoaderTest.groovy | 40 ++++++++++++++++++- 6 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java index d57d5cb1e..ae73dc2fe 100644 --- a/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/DataLoaderDispatchStrategy.java @@ -68,4 +68,16 @@ default void subscriptionEventCompletionDone(AlternativeCallContext alternativeC default void finishedFetching(ExecutionContext executionContext, ExecutionStrategyParameters newParameters) { } + + default void deferFieldFetched(ExecutionStrategyParameters executionStrategyParameters) { + + } + + default void startComplete(ExecutionStrategyParameters parameters) { + + } + + default void stopComplete(ExecutionStrategyParameters parameters) { + + } } diff --git a/src/main/java/graphql/execution/ExecutionStrategy.java b/src/main/java/graphql/execution/ExecutionStrategy.java index 4105a74a7..5de13d8d2 100644 --- a/src/main/java/graphql/execution/ExecutionStrategy.java +++ b/src/main/java/graphql/execution/ExecutionStrategy.java @@ -361,15 +361,21 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi Object fetchedValueObj = fetchField(executionContext, parameters); if (fetchedValueObj instanceof CompletableFuture) { CompletableFuture fetchFieldFuture = (CompletableFuture) fetchedValueObj; - CompletableFuture result = fetchFieldFuture.thenApply((fetchedValue) -> - completeField(fieldDef, executionContext, parameters, fetchedValue)); + CompletableFuture result = fetchFieldFuture.thenApply((fetchedValue) -> { + executionContext.getDataLoaderDispatcherStrategy().startComplete(parameters); + FieldValueInfo completeFieldResult = completeField(fieldDef, executionContext, parameters, fetchedValue); + executionContext.getDataLoaderDispatcherStrategy().stopComplete(parameters); + return completeFieldResult; + }); fieldCtx.onDispatched(); result.whenComplete(fieldCtx::onCompleted); return result; } else { try { + executionContext.getDataLoaderDispatcherStrategy().startComplete(parameters); FieldValueInfo fieldValueInfo = completeField(fieldDef, executionContext, parameters, fetchedValueObj); + executionContext.getDataLoaderDispatcherStrategy().stopComplete(parameters); fieldCtx.onDispatched(); fieldCtx.onCompleted(FetchedValue.getFetchedValue(fetchedValueObj), null); return fieldValueInfo; diff --git a/src/main/java/graphql/execution/incremental/DeferredExecutionSupport.java b/src/main/java/graphql/execution/incremental/DeferredExecutionSupport.java index 6e428041a..6e453345b 100644 --- a/src/main/java/graphql/execution/incremental/DeferredExecutionSupport.java +++ b/src/main/java/graphql/execution/incremental/DeferredExecutionSupport.java @@ -182,6 +182,8 @@ private Supplier deferredFieldCtx = nonNullCtx(instrumentation.beginDeferredField(fieldParameters, executionContext.getInstrumentationState())); CompletableFuture fieldValueResult = resolveFieldWithInfoFn.apply(this.executionContext, executionStrategyParameters); + executionContext.getDataLoaderDispatcherStrategy().deferFieldFetched(executionStrategyParameters); + deferredFieldCtx.onDispatched(); diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java index 3bd721c6b..fd68b26e1 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java @@ -6,7 +6,6 @@ import graphql.execution.DataLoaderDispatchStrategy; import graphql.execution.ExecutionContext; import graphql.execution.ExecutionStrategyParameters; -import graphql.execution.FieldValueInfo; import graphql.execution.incremental.AlternativeCallContext; import org.dataloader.DataLoader; import org.dataloader.DataLoaderRegistry; @@ -76,13 +75,13 @@ public static boolean getCurrentlyDispatching(int state) { } - public void incrementObjectRunningCount() { + public int incrementObjectRunningCount() { while (true) { int oldState = getState(); int objectRunningCount = getObjectRunningCount(oldState); int newState = setObjectRunningCount(oldState, objectRunningCount + 1); if (tryUpdateState(oldState, newState)) { - return; + return newState; } } } @@ -149,7 +148,7 @@ public ExhaustedDataLoaderDispatchStrategy(ExecutionContext executionContext) { public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); // no concurrency access happening - initialCallStack.incrementObjectRunningCount(); + int newState = initialCallStack.incrementObjectRunningCount(); } @Override @@ -170,7 +169,7 @@ public void executionSerialStrategy(ExecutionContext executionContext, Execution @Override public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { CallStack callStack = getCallStack(parameters); - callStack.incrementObjectRunningCount(); + int newState = callStack.incrementObjectRunningCount(); } @@ -188,14 +187,24 @@ public void subscriptionEventCompletionDone(AlternativeCallContext alternativeCa } @Override - public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo, Throwable throwable, ExecutionStrategyParameters parameters) { + public void deferFieldFetched(ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); int deferredFragmentRootFieldsCompleted = callStack.deferredFragmentRootFieldsCompleted.incrementAndGet(); Assert.assertNotNull(parameters.getDeferredCallContext()); if (deferredFragmentRootFieldsCompleted == parameters.getDeferredCallContext().getFields()) { decrementObjectRunningAndMaybeDispatch(callStack); } + } + + @Override + public void startComplete(ExecutionStrategyParameters parameters) { + getCallStack(parameters).incrementObjectRunningCount(); + } + @Override + public void stopComplete(ExecutionStrategyParameters parameters) { + CallStack callStack = getCallStack(parameters); + decrementObjectRunningAndMaybeDispatch(callStack); } private CallStack getCallStack(ExecutionStrategyParameters parameters) { @@ -213,6 +222,7 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC The reason we are doing this lazily is, because we don't have explicit startDeferred callback. */ CallStack callStack = new CallStack(); + callStack.incrementObjectRunningCount(); return callStack; }); } diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java index 501194d7a..221219171 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java @@ -422,7 +422,7 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC // how many fields are deferred on this level int fields = k.getFields(); if (startLevel > 1) { - // parent level is considered dispatched and all fields completed + // parent level is considered dispatched and all fields completed (meaning the grandparent level has all object completion call happened) callStack.dispatchedLevels.add(startLevel - 1); CallStack.StateForLevel stateForLevel = callStack.get(startLevel - 2); CallStack.StateForLevel newStateForLevel = stateForLevel.increaseHappenedExecuteObjectCalls().increaseHappenedCompletionFinishedCount(); diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy index d526d1f8d..c391c7552 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy @@ -61,6 +61,7 @@ class DeferWithDataLoaderTest extends Specification { } } + @Unroll def "query with single deferred field"() { given: def query = getQuery(true, false) @@ -82,6 +83,9 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() + if (exhaustedStrategy) { + executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) + } IncrementalExecutionResult result = graphQL.execute(executionInput) @@ -103,8 +107,12 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 3 batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 3 + + where: + exhaustedStrategy << [false, true] } + @Unroll def "multiple fields on same defer block"() { given: def query = """ @@ -139,6 +147,9 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() + if (exhaustedStrategy) { + executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) + } IncrementalExecutionResult result = graphQL.execute(executionInput) @@ -176,8 +187,13 @@ class DeferWithDataLoaderTest extends Specification { ] batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 3 batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 + + where: + exhaustedStrategy << [false, true] + } + @Unroll def "query with nested deferred fields"() { given: def query = getQuery(true, true) @@ -199,6 +215,10 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() + if (exhaustedStrategy) { + executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) + } + ExecutionResult result = graphQL.execute(executionInput) @@ -227,8 +247,13 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 3 batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 9 + + where: + exhaustedStrategy << [false, true] + } + @Unroll def "query with top-level deferred field"() { given: def query = """ @@ -242,7 +267,7 @@ class DeferWithDataLoaderTest extends Specification { expensiveShops { name } - } + } } """ @@ -262,6 +287,10 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() + if (exhaustedStrategy) { + executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) + } + IncrementalExecutionResult result = graphQL.execute(executionInput) @@ -290,8 +319,13 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 1 batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 + + where: + exhaustedStrategy << [false, true] + } + @Unroll def "query with multiple deferred fields"() { given: def query = getExpensiveQuery(true) @@ -347,6 +381,10 @@ class DeferWithDataLoaderTest extends Specification { // TODO: Why the load counters are only 1? batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 1 batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 + + where: + exhaustedStrategy << [false, true] + } @Unroll From f40a4e5cb46caa5112ac0f07fdefca412b7acf09 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 07:08:39 +1000 Subject: [PATCH 31/40] testing --- .../DataLoaderDispatcherTest.groovy | 74 +++++++++++++++---- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderDispatcherTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderDispatcherTest.groovy index 2aaad6090..f62ae0022 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderDispatcherTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderDispatcherTest.groovy @@ -19,6 +19,7 @@ import org.dataloader.DataLoaderRegistry import org.reactivestreams.Publisher import reactor.core.publisher.Mono import spock.lang.Specification +import spock.lang.Unroll import java.time.Duration import java.util.concurrent.CompletableFuture @@ -26,6 +27,8 @@ import java.util.concurrent.CompletionStage import static graphql.ExecutionInput.newExecutionInput import static graphql.StarWarsSchema.starWarsSchema +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring @@ -56,6 +59,7 @@ class DataLoaderDispatcherTest extends Specification { ] + @Unroll def "basic dataloader dispatch test"() { def dispatchedCalled = false def dataLoaderRegistry = new DataLoaderRegistry() @@ -69,7 +73,7 @@ class DataLoaderDispatcherTest extends Specification { def graphQL = GraphQL.newGraphQL(starWarsSchema).build() def executionInput = newExecutionInput().dataLoaderRegistry(dataLoaderRegistry).query('{ hero { name } }').build() - executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false) + executionInput.getGraphQLContext().putAll(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) when: def er = graphQL.executeAsync(executionInput) @@ -77,6 +81,9 @@ class DataLoaderDispatcherTest extends Specification { then: er.get().data == [hero: [name: 'R2-D2']] + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] + } def "enhanced execution input is respected"() { @@ -112,6 +119,7 @@ class DataLoaderDispatcherTest extends Specification { } + @Unroll def "ensure DataLoaderDispatcher works for async serial execution strategy"() { given: @@ -126,7 +134,10 @@ class DataLoaderDispatcherTest extends Specification { when: - def asyncResult = graphql.executeAsync(newExecutionInput().query(query).dataLoaderRegistry(dlRegistry)) + def asyncResult = graphql.executeAsync(newExecutionInput().query(query) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) + .dataLoaderRegistry(dlRegistry)) + Awaitility.await().atMost(Duration.ofMillis(200)).until { -> asyncResult.isDone() } def er = asyncResult.join() @@ -134,8 +145,12 @@ class DataLoaderDispatcherTest extends Specification { then: er.data == expectedQueryData + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] + } + @Unroll def "basic batch loading is possible"() { given: @@ -146,7 +161,9 @@ class DataLoaderDispatcherTest extends Specification { when: - def asyncResult = graphql.executeAsync(newExecutionInput().query(query).dataLoaderRegistry(dlRegistry)) + def asyncResult = graphql.executeAsync(newExecutionInput().query(query) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) + .dataLoaderRegistry(dlRegistry)) def er = asyncResult.join() @@ -170,9 +187,14 @@ class DataLoaderDispatcherTest extends Specification { // // if we didn't have batch loading it would have these many character load calls starWarsWiring.naiveLoadCount == 15 + + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] + } + @Unroll def "non list queries work as expected"() { given: @@ -201,7 +223,9 @@ class DataLoaderDispatcherTest extends Specification { } """ - def asyncResult = graphql.executeAsync(newExecutionInput().query(query).dataLoaderRegistry(dlRegistry)) + def asyncResult = graphql.executeAsync(newExecutionInput().query(query) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) + .dataLoaderRegistry(dlRegistry)) def er = asyncResult.join() @@ -213,8 +237,13 @@ class DataLoaderDispatcherTest extends Specification { starWarsWiring.rawCharacterLoadCount == 4 starWarsWiring.batchFunctionLoadCount == 2 starWarsWiring.naiveLoadCount == 8 + + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] + } + @Unroll def "can be efficient with lazily computed data loaders"() { def sdl = ''' @@ -225,11 +254,10 @@ class DataLoaderDispatcherTest extends Specification { BatchLoader batchLoader = { keys -> CompletableFuture.completedFuture(keys) } - DataFetcher df = { env -> - def dataLoader = env.getDataLoaderRegistry().computeIfAbsent("key", { key -> DataLoaderFactory.newDataLoader(batchLoader) }) - + def df = { env -> + def dataLoader = env.getDataLoader("key") return dataLoader.load("working as expected") - } + } as DataFetcher def runtimeWiring = newRuntimeWiring().type( newTypeWiring("Query").dataFetcher("field", df).build() ).build() @@ -237,32 +265,37 @@ class DataLoaderDispatcherTest extends Specification { def graphql = TestUtil.graphQL(sdl, runtimeWiring).build() DataLoaderRegistry dataLoaderRegistry = new DataLoaderRegistry() + def loader = DataLoaderFactory.newDataLoader("key", batchLoader) + dataLoaderRegistry.register("key", loader) when: def executionInput = newExecutionInput().dataLoaderRegistry(dataLoaderRegistry).query('{ field }').build() - executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false) - def er = graphql.execute(executionInput) + executionInput.getGraphQLContext().putAll(contextKey == null ? Collections.emptyMap() : [(contextKey): true]); + def erCF = graphql.executeAsync(executionInput) then: - er.errors.isEmpty() - er.data["field"] == "working as expected" + Awaitility.await().until { erCF.isDone() } + erCF.get().errors.isEmpty() + erCF.get().data["field"] == "working as expected" + + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } + @Unroll def "handles deep async queries when a data loader registry is present"() { given: def support = new DeepDataFetchers() def dummyDataloaderRegistry = new DataLoaderRegistry() def graphql = GraphQL.newGraphQL(support.schema()) .build() - // FieldLevelTrackingApproach uses LevelMaps with a default size of 16. - // Use a value greater than 16 to ensure that the underlying LevelMaps are resized - // as expected def depth = 50 when: def asyncResult = graphql.executeAsync( newExecutionInput() .query(support.buildQuery(depth)) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) .dataLoaderRegistry(dummyDataloaderRegistry) ) def er = asyncResult.join() @@ -270,8 +303,13 @@ class DataLoaderDispatcherTest extends Specification { then: er.errors.isEmpty() er.data == support.buildResponse(depth) + + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] + } + @Unroll def "issue 3662 - dataloader dispatching can work with subscriptions"() { def sdl = ''' @@ -298,7 +336,7 @@ class DataLoaderDispatcherTest extends Specification { } DataFetcher dlDF = { DataFetchingEnvironment env -> - def dataLoader = env.getDataLoaderRegistry().getDataLoader("dl") + def dataLoader = env.getDataLoader("dl") return dataLoader.load("working as expected") } DataFetcher dlSub = { DataFetchingEnvironment env -> @@ -332,6 +370,7 @@ class DataLoaderDispatcherTest extends Specification { def executionInput = newExecutionInput() .dataLoaderRegistry(dataLoaderRegistry) .query(query) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) .build() def er = graphql.execute(executionInput) @@ -347,5 +386,8 @@ class DataLoaderDispatcherTest extends Specification { def msgER = subscriber.getEvents()[0] as ExecutionResult msgER.data == [onSub: [x: "working as expected", y: "working as expected"]] + + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } } From 8ce7be7bdc68666ebbdac41d5779849011ce9c47 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 07:32:01 +1000 Subject: [PATCH 32/40] testing --- .../dataloader/DeferWithDataLoaderTest.groovy | 33 ++++++++----------- .../Issue1178DataLoaderDispatchTest.groovy | 8 +++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy index c391c7552..86a0b3464 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy @@ -18,6 +18,8 @@ import spock.lang.Unroll import java.util.concurrent.CompletableFuture import static graphql.ExperimentalApi.ENABLE_INCREMENTAL_SUPPORT +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING import static graphql.execution.instrumentation.dataloader.DataLoaderPerformanceData.combineExecutionResults import static graphql.execution.instrumentation.dataloader.DataLoaderPerformanceData.expectedData import static graphql.execution.instrumentation.dataloader.DataLoaderPerformanceData.expectedExpensiveData @@ -83,9 +85,7 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() - if (exhaustedStrategy) { - executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) - } + executionInput.getGraphQLContext().putAll(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) IncrementalExecutionResult result = graphQL.execute(executionInput) @@ -109,7 +109,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 3 where: - exhaustedStrategy << [false, true] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } @Unroll @@ -147,9 +147,7 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() - if (exhaustedStrategy) { - executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) - } + executionInput.getGraphQLContext().putAll(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) IncrementalExecutionResult result = graphQL.execute(executionInput) @@ -189,7 +187,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 where: - exhaustedStrategy << [false, true] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } @@ -215,9 +213,7 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() - if (exhaustedStrategy) { - executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) - } + executionInput.getGraphQLContext().putAll(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) ExecutionResult result = graphQL.execute(executionInput) @@ -249,7 +245,7 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 9 where: - exhaustedStrategy << [false, true] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } @@ -287,9 +283,7 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() - if (exhaustedStrategy) { - executionInput.getGraphQLContext().put(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, true) - } + executionInput.getGraphQLContext().putAll(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) IncrementalExecutionResult result = graphQL.execute(executionInput) @@ -321,11 +315,12 @@ class DeferWithDataLoaderTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 0 where: - exhaustedStrategy << [false, true] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } @Unroll + @RepeatUntilFailure(maxAttempts = 5, ignoreRest = false) def "query with multiple deferred fields"() { given: def query = getExpensiveQuery(true) @@ -351,6 +346,7 @@ class DeferWithDataLoaderTest extends Specification { .dataLoaderRegistry(dataLoaderRegistry) .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): true]) .build() + executionInput.getGraphQLContext().putAll(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) IncrementalExecutionResult result = graphQL.execute(executionInput) @@ -378,12 +374,11 @@ class DeferWithDataLoaderTest extends Specification { combined.errors == null combined.data == expectedExpensiveData - // TODO: Why the load counters are only 1? - batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 1 + batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == (contextKey != ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING ? 1 : 2) batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 where: - exhaustedStrategy << [false, true] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/Issue1178DataLoaderDispatchTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/Issue1178DataLoaderDispatchTest.groovy index ff0981bfd..dc0e1c422 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/Issue1178DataLoaderDispatchTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/Issue1178DataLoaderDispatchTest.groovy @@ -12,16 +12,20 @@ import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderRegistry import spock.lang.RepeatUntilFailure import spock.lang.Specification +import spock.lang.Unroll import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletionStage import java.util.concurrent.Executors +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring class Issue1178DataLoaderDispatchTest extends Specification { + @Unroll @RepeatUntilFailure(maxAttempts = 100, ignoreRest = false) def "shouldn't dispatch twice in multithreaded env"() { setup: @@ -81,7 +85,7 @@ class Issue1178DataLoaderDispatchTest extends Specification { then: "execution shouldn't error" def ei = ExecutionInput.newExecutionInput() - .graphQLContext([(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): enableDataLoaderChaining]) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) .dataLoaderRegistry(dataLoaderRegistry) .query(""" query { @@ -120,7 +124,7 @@ class Issue1178DataLoaderDispatchTest extends Specification { Awaitility.await().until { resultCF.isDone() } assert resultCF.get().errors.empty where: - enableDataLoaderChaining << [true, false] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } From f0b2b09bcfbdd516f39c5c2720e278301777a303 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 07:38:52 +1000 Subject: [PATCH 33/40] testing --- .../DataLoaderPerformanceTest.groovy | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderPerformanceTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderPerformanceTest.groovy index 5d9b1609c..1ee790ded 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderPerformanceTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DataLoaderPerformanceTest.groovy @@ -4,8 +4,11 @@ import graphql.ExecutionInput import graphql.GraphQL import org.dataloader.DataLoaderRegistry import spock.lang.Specification +import spock.lang.Unroll import static graphql.ExperimentalApi.ENABLE_INCREMENTAL_SUPPORT +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING import static graphql.execution.instrumentation.dataloader.DataLoaderPerformanceData.expectedExpensiveData import static graphql.execution.instrumentation.dataloader.DataLoaderPerformanceData.getExpectedData import static graphql.execution.instrumentation.dataloader.DataLoaderPerformanceData.getExpensiveQuery @@ -24,12 +27,14 @@ class DataLoaderPerformanceTest extends Specification { graphQL = dataLoaderPerformanceData.setupGraphQL() } + @Unroll def "760 ensure data loader is performant for lists"() { when: ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query(getQuery()) .dataLoaderRegistry(dataLoaderRegistry) - .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport, (DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): enableDataLoaderChaining]) + .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport]) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) .build() def result = graphQL.execute(executionInput) @@ -41,10 +46,16 @@ class DataLoaderPerformanceTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 where: - incrementalSupport << [true, false] - enableDataLoaderChaining << [true, false] + incrementalSupport | contextKey + false | ENABLE_DATA_LOADER_CHAINING + true | ENABLE_DATA_LOADER_CHAINING + false | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + true | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + false | null + true | null } + @Unroll def "970 ensure data loader is performant for multiple field with lists"() { when: @@ -52,7 +63,8 @@ class DataLoaderPerformanceTest extends Specification { ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query(getExpensiveQuery(false)) .dataLoaderRegistry(dataLoaderRegistry) - .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport, (DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): enableDataLoaderChaining]) + .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport]) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) .build() def result = graphQL.execute(executionInput) @@ -63,10 +75,16 @@ class DataLoaderPerformanceTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() <= 2 where: - incrementalSupport << [true, false] - enableDataLoaderChaining << [true, false] + incrementalSupport | contextKey + false | ENABLE_DATA_LOADER_CHAINING + true | ENABLE_DATA_LOADER_CHAINING + false | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + true | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + false | null + true | null } + @Unroll def "ensure data loader is performant for lists using async batch loading"() { when: @@ -76,7 +94,8 @@ class DataLoaderPerformanceTest extends Specification { ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query(getQuery()) .dataLoaderRegistry(dataLoaderRegistry) - .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport, (DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): enableDataLoaderChaining]) + .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport]) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) .build() def result = graphQL.execute(executionInput) @@ -89,10 +108,16 @@ class DataLoaderPerformanceTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 where: - incrementalSupport << [true, false] - enableDataLoaderChaining << [true, false] + incrementalSupport | contextKey + false | ENABLE_DATA_LOADER_CHAINING + true | ENABLE_DATA_LOADER_CHAINING + false | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + true | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + false | null + true | null } + @Unroll def "970 ensure data loader is performant for multiple field with lists using async batch loading"() { when: @@ -102,7 +127,8 @@ class DataLoaderPerformanceTest extends Specification { ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query(getExpensiveQuery(false)) .dataLoaderRegistry(dataLoaderRegistry) - .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport, (DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): enableDataLoaderChaining]) + .graphQLContext([(ENABLE_INCREMENTAL_SUPPORT): incrementalSupport]) + .graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) .build() def result = graphQL.execute(executionInput) @@ -114,8 +140,12 @@ class DataLoaderPerformanceTest extends Specification { batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() <= 2 where: - incrementalSupport << [true, false] - enableDataLoaderChaining << [true, false] - + incrementalSupport | contextKey + false | ENABLE_DATA_LOADER_CHAINING + true | ENABLE_DATA_LOADER_CHAINING + false | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + true | ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + false | null + true | null } } From 570e5c67ddf82a8ab44d9688e16edcce92238b1c Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 07:45:23 +1000 Subject: [PATCH 34/40] testing --- src/test/groovy/graphql/MutationTest.groovy | 23 ++++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/test/groovy/graphql/MutationTest.groovy b/src/test/groovy/graphql/MutationTest.groovy index a253d4065..aa5813fe5 100644 --- a/src/test/groovy/graphql/MutationTest.groovy +++ b/src/test/groovy/graphql/MutationTest.groovy @@ -1,6 +1,6 @@ package graphql -import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys + import graphql.schema.DataFetcher import org.awaitility.Awaitility import org.dataloader.BatchLoader @@ -12,6 +12,9 @@ import spock.lang.Unroll import java.util.concurrent.CompletableFuture +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING +import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING + class MutationTest extends Specification { @@ -162,6 +165,7 @@ class MutationTest extends Specification { ] } + @Unroll def "simple async mutation with DataLoader"() { def sdl = """ type Query { @@ -214,7 +218,8 @@ class MutationTest extends Specification { plus2(arg:10) plus3(arg:10) } - """).dataLoaderRegistry(dlReg).build() + """).graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]) + .dataLoaderRegistry(dlReg).build() when: def er = graphQL.execute(ei) @@ -225,6 +230,8 @@ class MutationTest extends Specification { plus2: 12, plus3: 13, ] + where: + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } /* @@ -439,7 +446,7 @@ class MutationTest extends Specification { } } } - """).dataLoaderRegistry(dlReg).graphQLContext([DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING]: enableDataLoaderChaining).build() + """).dataLoaderRegistry(dlReg).graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]).build() when: def cf = graphQL.executeAsync(ei) @@ -465,7 +472,7 @@ class MutationTest extends Specification { ] where: - enableDataLoaderChaining << [true, false] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } @@ -475,16 +482,16 @@ class MutationTest extends Specification { // concurrency bugs are hard to find, so run this test a lot of times for (int i = 0; i < 150; i++) { println "iteration $i" - runTest(enableDataLoaderChaining) + runTest(contextKey) } then: noExceptionThrown() where: - enableDataLoaderChaining << [true, false] + contextKey << [ENABLE_DATA_LOADER_CHAINING, ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, null] } - def runTest(boolean enableDataLoaderChaining) { + def runTest(String contextKey) { def sdl = """ type Query { q : String @@ -690,7 +697,7 @@ class MutationTest extends Specification { } } } - """).dataLoaderRegistry(dlReg).graphQLContext([(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING): enableDataLoaderChaining]).build() + """).dataLoaderRegistry(dlReg).graphQLContext(contextKey == null ? Collections.emptyMap() : [(contextKey): true]).build() def cf = graphQL.executeAsync(ei) Awaitility.await().until { cf.isDone() } From 860a0bd528fd548b5b7fdc67f5727550d19a54d7 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 08:08:15 +1000 Subject: [PATCH 35/40] remove not needed start stop complete call --- src/main/java/graphql/execution/ExecutionStrategy.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/graphql/execution/ExecutionStrategy.java b/src/main/java/graphql/execution/ExecutionStrategy.java index 5de13d8d2..bdb42df3f 100644 --- a/src/main/java/graphql/execution/ExecutionStrategy.java +++ b/src/main/java/graphql/execution/ExecutionStrategy.java @@ -373,9 +373,7 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi return result; } else { try { - executionContext.getDataLoaderDispatcherStrategy().startComplete(parameters); FieldValueInfo fieldValueInfo = completeField(fieldDef, executionContext, parameters, fetchedValueObj); - executionContext.getDataLoaderDispatcherStrategy().stopComplete(parameters); fieldCtx.onDispatched(); fieldCtx.onCompleted(FetchedValue.getFetchedValue(fetchedValueObj), null); return fieldValueInfo; From b4f1d4b5aa89bc5397c966c66df62c09c60129ea Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 19:54:45 +1000 Subject: [PATCH 36/40] make test stable --- .../dataloader/DeferWithDataLoaderTest.groovy | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy index 86a0b3464..0fe86e3fb 100644 --- a/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy +++ b/src/test/groovy/graphql/execution/instrumentation/dataloader/DeferWithDataLoaderTest.groovy @@ -374,7 +374,13 @@ class DeferWithDataLoaderTest extends Specification { combined.errors == null combined.data == expectedExpensiveData - batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == (contextKey != ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING ? 1 : 2) + if (contextKey == ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING) { + // based on the timing of shops vs expensiveShops DF it could be one or two batch loader calls + batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 1 || batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 2 + } else { + batchCompareDataFetchers.departmentsForShopsBatchLoaderCounter.get() == 1 + + } batchCompareDataFetchers.productsForDepartmentsBatchLoaderCounter.get() == 1 where: From a96ba08e423d4f06ef195385dc2ecc3c6a18d6b5 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 20:14:07 +1000 Subject: [PATCH 37/40] no field fetching callback for execute object needed --- src/main/java/graphql/execution/ExecutionStrategy.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/graphql/execution/ExecutionStrategy.java b/src/main/java/graphql/execution/ExecutionStrategy.java index bdb42df3f..a8354a6a7 100644 --- a/src/main/java/graphql/execution/ExecutionStrategy.java +++ b/src/main/java/graphql/execution/ExecutionStrategy.java @@ -210,7 +210,6 @@ protected Object executeObject(ExecutionContext executionContext, ExecutionStrat List fieldsExecutedOnInitialResult = deferredExecutionSupport.getNonDeferredFieldNames(fieldNames); dataLoaderDispatcherStrategy.executeObject(executionContext, parameters, fieldsExecutedOnInitialResult.size()); Async.CombinedBuilder resolvedFieldFutures = getAsyncFieldValueInfo(executionContext, parameters, deferredExecutionSupport); - dataLoaderDispatcherStrategy.finishedFetching(executionContext, parameters); CompletableFuture> overallResult = new CompletableFuture<>(); BiConsumer, Throwable> handleResultsConsumer = buildFieldValueMap(fieldsExecutedOnInitialResult, overallResult, executionContext); From 563abe9aff5661305a7e899a23077d99bf430b62 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 20:15:05 +1000 Subject: [PATCH 38/40] improve performance by not handling executeObject (and field fetched on executeObject) because it is not needed --- .../ExhaustedDataLoaderDispatchStrategy.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java index fd68b26e1..f0de5554e 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java @@ -147,8 +147,7 @@ public ExhaustedDataLoaderDispatchStrategy(ExecutionContext executionContext) { @Override public void executionStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { Assert.assertTrue(parameters.getExecutionStepInfo().getPath().isRootPath()); - // no concurrency access happening - int newState = initialCallStack.incrementObjectRunningCount(); + initialCallStack.incrementObjectRunningCount(); } @Override @@ -161,18 +160,9 @@ public void finishedFetching(ExecutionContext executionContext, ExecutionStrateg public void executionSerialStrategy(ExecutionContext executionContext, ExecutionStrategyParameters parameters) { CallStack callStack = getCallStack(parameters); callStack.clear(); - // no concurrency access happening callStack.incrementObjectRunningCount(); } - - @Override - public void executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, int fieldCount) { - CallStack callStack = getCallStack(parameters); - int newState = callStack.incrementObjectRunningCount(); - } - - @Override public void newSubscriptionExecution(AlternativeCallContext alternativeCallContext) { CallStack callStack = new CallStack(); From 94f0301b0d2e66c1086d6f83fccaf2079d093bf4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 Sep 2025 11:37:48 +0000 Subject: [PATCH 39/40] Add performance results for commit 3f0de4a7b48ad20c3e30e5c7fea0bf3f57ce5839 --- ...48ad20c3e30e5c7fea0bf3f57ce5839-jdk17.json | 1279 +++++++++++++++++ 1 file changed, 1279 insertions(+) create mode 100644 performance-results/2025-09-28T11:37:28Z-3f0de4a7b48ad20c3e30e5c7fea0bf3f57ce5839-jdk17.json diff --git a/performance-results/2025-09-28T11:37:28Z-3f0de4a7b48ad20c3e30e5c7fea0bf3f57ce5839-jdk17.json b/performance-results/2025-09-28T11:37:28Z-3f0de4a7b48ad20c3e30e5c7fea0bf3f57ce5839-jdk17.json new file mode 100644 index 000000000..5c49c2f34 --- /dev/null +++ b/performance-results/2025-09-28T11:37:28Z-3f0de4a7b48ad20c3e30e5c7fea0bf3f57ce5839-jdk17.json @@ -0,0 +1,1279 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "5" + }, + "primaryMetric" : { + "score" : 3.314008789774307, + "scoreError" : 0.04241462006234165, + "scoreConfidence" : [ + 3.2715941697119653, + 3.356423409836649 + ], + "scorePercentiles" : { + "0.0" : 3.3058563388945497, + "50.0" : 3.314677463634016, + "90.0" : 3.320823892934646, + "95.0" : 3.320823892934646, + "99.0" : 3.320823892934646, + "99.9" : 3.320823892934646, + "99.99" : 3.320823892934646, + "99.999" : 3.320823892934646, + "99.9999" : 3.320823892934646, + "100.0" : 3.320823892934646 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.31189856928945, + 3.317456357978582 + ], + [ + 3.3058563388945497, + 3.320823892934646 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "10" + }, + "primaryMetric" : { + "score" : 1.6752113643392523, + "scoreError" : 0.0208028090179944, + "scoreConfidence" : [ + 1.654408555321258, + 1.6960141733572467 + ], + "scorePercentiles" : { + "0.0" : 1.673019823637084, + "50.0" : 1.6739201551979241, + "90.0" : 1.6799853233240771, + "95.0" : 1.6799853233240771, + "99.0" : 1.6799853233240771, + "99.9" : 1.6799853233240771, + "99.99" : 1.6799853233240771, + "99.999" : 1.6799853233240771, + "99.9999" : 1.6799853233240771, + "100.0" : 1.6799853233240771 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.673634774989389, + 1.6742055354064591 + ], + [ + 1.673019823637084, + 1.6799853233240771 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ComplexQueryPerformance.benchMarkSimpleQueriesThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "howManyItems" : "20" + }, + "primaryMetric" : { + "score" : 0.8329697163970288, + "scoreError" : 0.05088711275775986, + "scoreConfidence" : [ + 0.782082603639269, + 0.8838568291547886 + ], + "scorePercentiles" : { + "0.0" : 0.8222081936816599, + "50.0" : 0.8351943924105409, + "90.0" : 0.8392818870853733, + "95.0" : 0.8392818870853733, + "99.0" : 0.8392818870853733, + "99.9" : 0.8392818870853733, + "99.99" : 0.8392818870853733, + "99.999" : 0.8392818870853733, + "99.9999" : 0.8392818870853733, + "100.0" : 0.8392818870853733 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.8222081936816599, + 0.8383949343930645 + ], + [ + 0.8319938504280173, + 0.8392818870853733 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 16.01824741218742, + "scoreError" : 0.6005330335344947, + "scoreConfidence" : [ + 15.417714378652926, + 16.618780445721917 + ], + "scorePercentiles" : { + "0.0" : 15.7934490563086, + "50.0" : 16.017956958849943, + "90.0" : 16.235885357111663, + "95.0" : 16.235885357111663, + "99.0" : 16.235885357111663, + "99.9" : 16.235885357111663, + "99.99" : 16.235885357111663, + "99.999" : 16.235885357111663, + "99.9999" : 16.235885357111663, + "100.0" : 16.235885357111663 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 15.815825584355034, + 15.865855375482065, + 15.7934490563086 + ], + [ + 16.235885357111663, + 16.228410557649354, + 16.170058542217824 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkThroughput_getImmediateFields", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2577.5107578640273, + "scoreError" : 111.47374040521964, + "scoreConfidence" : [ + 2466.0370174588074, + 2688.984498269247 + ], + "scorePercentiles" : { + "0.0" : 2522.7080349621524, + "50.0" : 2588.7759700682336, + "90.0" : 2617.167645128689, + "95.0" : 2617.167645128689, + "99.0" : 2617.167645128689, + "99.9" : 2617.167645128689, + "99.99" : 2617.167645128689, + "99.999" : 2617.167645128689, + "99.9999" : 2617.167645128689, + "100.0" : 2617.167645128689 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 2522.7080349621524, + 2537.3380664679185, + 2574.9443412598657 + ], + [ + 2617.167645128689, + 2610.2988604889374, + 2602.607598876601 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 74536.45891510353, + "scoreError" : 760.9350853352792, + "scoreConfidence" : [ + 73775.52382976825, + 75297.39400043881 + ], + "scorePercentiles" : { + "0.0" : 74173.98060139695, + "50.0" : 74534.04451030455, + "90.0" : 74963.69515943294, + "95.0" : 74963.69515943294, + "99.0" : 74963.69515943294, + "99.9" : 74963.69515943294, + "99.99" : 74963.69515943294, + "99.999" : 74963.69515943294, + "99.9999" : 74963.69515943294, + "100.0" : 74963.69515943294 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 74599.14211702555, + 74173.98060139695, + 74358.22370189102 + ], + [ + 74468.94690358356, + 74654.7650072912, + 74963.69515943294 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 349.37271673467336, + "scoreError" : 16.44807856446468, + "scoreConfidence" : [ + 332.9246381702087, + 365.820795299138 + ], + "scorePercentiles" : { + "0.0" : 341.9506007561679, + "50.0" : 351.2272547031589, + "90.0" : 354.8430323995652, + "95.0" : 354.8430323995652, + "99.0" : 354.8430323995652, + "99.9" : 354.8430323995652, + "99.99" : 354.8430323995652, + "99.999" : 354.8430323995652, + "99.9999" : 354.8430323995652, + "100.0" : 354.8430323995652 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 354.3449355411413, + 354.8430323995652, + 353.4770494067884 + ], + [ + 348.97745999952934, + 342.643222304848, + 341.9506007561679 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationThroughput", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 111.53757013026215, + "scoreError" : 3.695342388965278, + "scoreConfidence" : [ + 107.84222774129688, + 115.23291251922743 + ], + "scorePercentiles" : { + "0.0" : 110.19823139333693, + "50.0" : 111.61922092653654, + "90.0" : 113.78792427929345, + "95.0" : 113.78792427929345, + "99.0" : 113.78792427929345, + "99.9" : 113.78792427929345, + "99.99" : 113.78792427929345, + "99.999" : 113.78792427929345, + "99.9999" : 113.78792427929345, + "100.0" : 113.78792427929345 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 111.72446258808411, + 111.51397926498898, + 110.19823139333693 + ], + [ + 113.78792427929345, + 111.77900920988479, + 110.22181404598467 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.06257253346192261, + "scoreError" : 0.0010809347824334002, + "scoreConfidence" : [ + 0.06149159867948921, + 0.06365346824435601 + ], + "scorePercentiles" : { + "0.0" : 0.06227081769951181, + "50.0" : 0.06237118887658796, + "90.0" : 0.06317758539867456, + "95.0" : 0.06317758539867456, + "99.0" : 0.06317758539867456, + "99.9" : 0.06317758539867456, + "99.99" : 0.06317758539867456, + "99.999" : 0.06317758539867456, + "99.9999" : 0.06317758539867456, + "100.0" : 0.06317758539867456 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.06317758539867456, + 0.06293695945673791, + 0.062400109822225276 + ], + [ + 0.06234226793095064, + 0.06227081769951181, + 0.06230746046343545 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DFSelectionSetPerformance.benchMarkAvgTime_getImmediateFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3.8104422908853084E-4, + "scoreError" : 2.9555531497728788E-5, + "scoreConfidence" : [ + 3.51488697590802E-4, + 4.1059976058625965E-4 + ], + "scorePercentiles" : { + "0.0" : 3.691059545201157E-4, + "50.0" : 3.805522832350023E-4, + "90.0" : 3.933463908654126E-4, + "95.0" : 3.933463908654126E-4, + "99.0" : 3.933463908654126E-4, + "99.9" : 3.933463908654126E-4, + "99.99" : 3.933463908654126E-4, + "99.999" : 3.933463908654126E-4, + "99.9999" : 3.933463908654126E-4, + "100.0" : 3.933463908654126E-4 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.691059545201157E-4, + 3.7277062434607806E-4, + 3.7301779090383755E-4 + ], + [ + 3.933463908654126E-4, + 3.89937838329574E-4, + 3.88086775566167E-4 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.DataLoaderPerformance.executeRequestWithDataLoaders", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.5147762815884227, + "scoreError" : 0.09343401572962383, + "scoreConfidence" : [ + 2.421342265858799, + 2.6082102973180463 + ], + "scorePercentiles" : { + "0.0" : 2.4809094906970977, + "50.0" : 2.502931031156156, + "90.0" : 2.5740077578486877, + "95.0" : 2.5740077578486877, + "99.0" : 2.5740077578486877, + "99.9" : 2.5740077578486877, + "99.99" : 2.5740077578486877, + "99.999" : 2.5740077578486877, + "99.9999" : 2.5740077578486877, + "100.0" : 2.5740077578486877 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.5740077578486877, + 2.5031390735735735, + 2.4809094906970977 + ], + [ + 2.5314534720323967, + 2.5027229887387388, + 2.49642490664004 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF1Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.013211917134388703, + "scoreError" : 9.018885064487795E-5, + "scoreConfidence" : [ + 0.013121728283743826, + 0.01330210598503358 + ], + "scorePercentiles" : { + "0.0" : 0.013163604345771449, + "50.0" : 0.013222687797023899, + "90.0" : 0.013245836489541927, + "95.0" : 0.013245836489541927, + "99.0" : 0.013245836489541927, + "99.9" : 0.013245836489541927, + "99.99" : 0.013245836489541927, + "99.999" : 0.013245836489541927, + "99.9999" : 0.013245836489541927, + "100.0" : 0.013245836489541927 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.013217681109002184, + 0.013182078220074452, + 0.013163604345771449 + ], + [ + 0.013227694485045615, + 0.013245836489541927, + 0.013234608156896584 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENF2Performance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 0.9963920224707087, + "scoreError" : 0.1162429171424352, + "scoreConfidence" : [ + 0.8801491053282735, + 1.1126349396131439 + ], + "scorePercentiles" : { + "0.0" : 0.9579113626436782, + "50.0" : 0.9957960038934729, + "90.0" : 1.0357600411185914, + "95.0" : 1.0357600411185914, + "99.0" : 1.0357600411185914, + "99.9" : 1.0357600411185914, + "99.99" : 1.0357600411185914, + "99.999" : 1.0357600411185914, + "99.9999" : 1.0357600411185914, + "100.0" : 1.0357600411185914 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.9579113626436782, + 0.9590306858457998, + 0.9587477846050614 + ], + [ + 1.0357600411185914, + 1.032561321941146, + 1.0343409386699762 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "2" + }, + "primaryMetric" : { + "score" : 0.01040161657914577, + "scoreError" : 4.2741789208510704E-4, + "scoreConfidence" : [ + 0.009974198687060664, + 0.010829034471230877 + ], + "scorePercentiles" : { + "0.0" : 0.010244133399986888, + "50.0" : 0.01041135940838391, + "90.0" : 0.010548536998907206, + "95.0" : 0.010548536998907206, + "99.0" : 0.010548536998907206, + "99.9" : 0.010548536998907206, + "99.99" : 0.010548536998907206, + "99.999" : 0.010548536998907206, + "99.9999" : 0.010548536998907206, + "100.0" : 0.010548536998907206 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.010548536998907206, + 0.010544492568442452, + 0.010525658277917065 + ], + [ + 0.010297060538850756, + 0.010244133399986888, + 0.010249817690770257 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFDeepIntrospectionPerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "5 s", + "measurementBatchSize" : 1, + "params" : { + "howDeep" : "10" + }, + "primaryMetric" : { + "score" : 3.439188849709909, + "scoreError" : 0.6665965339509904, + "scoreConfidence" : [ + 2.7725923157589185, + 4.1057853836608995 + ], + "scorePercentiles" : { + "0.0" : 3.205009333119795, + "50.0" : 3.4269708064235713, + "90.0" : 3.677051331617647, + "95.0" : 3.677051331617647, + "99.0" : 3.677051331617647, + "99.9" : 3.677051331617647, + "99.99" : 3.677051331617647, + "99.999" : 3.677051331617647, + "99.9999" : 3.677051331617647, + "100.0" : 3.677051331617647 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 3.205009333119795, + 3.2333436063348415, + 3.230903568475452 + ], + [ + 3.677051331617647, + 3.6682272521994137, + 3.620598006512301 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.ENFExtraLargePerformance.benchMarkAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.904007474328752, + "scoreError" : 0.11602715317106929, + "scoreConfidence" : [ + 2.7879803211576824, + 3.0200346274998213 + ], + "scorePercentiles" : { + "0.0" : 2.8619051696709583, + "50.0" : 2.9044654440418958, + "90.0" : 2.946489165291691, + "95.0" : 2.946489165291691, + "99.0" : 2.946489165291691, + "99.9" : 2.946489165291691, + "99.99" : 2.946489165291691, + "99.999" : 2.946489165291691, + "99.9999" : 2.946489165291691, + "100.0" : 2.946489165291691 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 2.9331919228739003, + 2.9441706856049454, + 2.946489165291691 + ], + [ + 2.8619051696709583, + 2.862548937321122, + 2.875738965209891 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkDeepAbstractConcrete", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.18632433509154134, + "scoreError" : 0.026608797695635573, + "scoreConfidence" : [ + 0.15971553739590577, + 0.2129331327871769 + ], + "scorePercentiles" : { + "0.0" : 0.17736152262206695, + "50.0" : 0.18608439647790226, + "90.0" : 0.19589980917959568, + "95.0" : 0.19589980917959568, + "99.0" : 0.19589980917959568, + "99.9" : 0.19589980917959568, + "99.99" : 0.19589980917959568, + "99.999" : 0.19589980917959568, + "99.9999" : 0.19589980917959568, + "100.0" : 0.19589980917959568 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.19428908323133415, + 0.19589980917959568, + 0.19472617065524292 + ], + [ + 0.17787970972447037, + 0.17778971513653818, + 0.17736152262206695 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.32866715540648106, + "scoreError" : 8.780975902669096E-4, + "scoreConfidence" : [ + 0.32778905781621415, + 0.329545252996748 + ], + "scorePercentiles" : { + "0.0" : 0.3283038378910738, + "50.0" : 0.3285750315159803, + "90.0" : 0.32920356144451396, + "95.0" : 0.32920356144451396, + "99.0" : 0.32920356144451396, + "99.9" : 0.32920356144451396, + "99.99" : 0.32920356144451396, + "99.999" : 0.32920356144451396, + "99.9999" : 0.32920356144451396, + "100.0" : 0.32920356144451396 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.3283038378910738, + 0.32920356144451396, + 0.3285161100160967 + ], + [ + 0.3288293600552413, + 0.32852787493429697, + 0.3286221880976636 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkNoOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.14574331270470028, + "scoreError" : 0.004478775253212766, + "scoreConfidence" : [ + 0.1412645374514875, + 0.15022208795791306 + ], + "scorePercentiles" : { + "0.0" : 0.14421321207620091, + "50.0" : 0.14557489910836663, + "90.0" : 0.1474142089536838, + "95.0" : 0.1474142089536838, + "99.0" : 0.1474142089536838, + "99.9" : 0.1474142089536838, + "99.99" : 0.1474142089536838, + "99.999" : 0.1474142089536838, + "99.9999" : 0.1474142089536838, + "100.0" : 0.1474142089536838 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.14435521397329484, + 0.14421321207620091, + 0.14432962018849135 + ], + [ + 0.14679458424343844, + 0.14735303679309228, + 0.1474142089536838 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.4034246492513369, + "scoreError" : 0.008997344566457217, + "scoreConfidence" : [ + 0.3944273046848797, + 0.41242199381779415 + ], + "scorePercentiles" : { + "0.0" : 0.4002134101568753, + "50.0" : 0.40292043651474885, + "90.0" : 0.4075895747299776, + "95.0" : 0.4075895747299776, + "99.0" : 0.4075895747299776, + "99.9" : 0.4075895747299776, + "99.99" : 0.4075895747299776, + "99.999" : 0.4075895747299776, + "99.9999" : 0.4075895747299776, + "100.0" : 0.4075895747299776 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.401076211718938, + 0.4002134101568753, + 0.4005795036651312 + ], + [ + 0.4063245339265399, + 0.4075895747299776, + 0.40476466131055977 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkOverlapNoFrag", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.16576659391325677, + "scoreError" : 0.017149104156448592, + "scoreConfidence" : [ + 0.14861748975680816, + 0.18291569806970537 + ], + "scorePercentiles" : { + "0.0" : 0.1599088135663687, + "50.0" : 0.16560058402485228, + "90.0" : 0.17208362872334934, + "95.0" : 0.17208362872334934, + "99.0" : 0.17208362872334934, + "99.9" : 0.17208362872334934, + "99.99" : 0.17208362872334934, + "99.999" : 0.17208362872334934, + "99.9999" : 0.17208362872334934, + "100.0" : 0.17208362872334934 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.17126788484329508, + 0.17208362872334934, + 0.1706394701385571 + ], + [ + 0.1605616979111475, + 0.1599088135663687, + 0.16013806829682295 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.benchmarkRepeatedFields", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 0.04717768998541607, + "scoreError" : 0.001771405082294385, + "scoreConfidence" : [ + 0.04540628490312169, + 0.04894909506771045 + ], + "scorePercentiles" : { + "0.0" : 0.04658995523243354, + "50.0" : 0.04713105965922479, + "90.0" : 0.04792876627397602, + "95.0" : 0.04792876627397602, + "99.0" : 0.04792876627397602, + "99.9" : 0.04792876627397602, + "99.99" : 0.04792876627397602, + "99.999" : 0.04792876627397602, + "99.9999" : 0.04792876627397602, + "100.0" : 0.04792876627397602 + }, + "scoreUnit" : "ms/op", + "rawData" : [ + [ + 0.04660038300232066, + 0.04658995523243354, + 0.04663569766498314 + ], + [ + 0.0476849160853166, + 0.04762642165346643, + 0.04792876627397602 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "performance.OverlappingFieldValidationPerformance.overlappingFieldValidationAvgTime", + "mode" : "avgt", + "threads" : 1, + "forks" : 2, + "jvm" : "/home/ec2-user/.sdkman/candidates/java/17.0.10-amzn/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "17.0.10", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "17.0.10+7-LTS", + "warmupIterations" : 2, + "warmupTime" : "5 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "100" + }, + "primaryMetric" : { + "score" : 9213264.924470434, + "scoreError" : 868967.8667856371, + "scoreConfidence" : [ + 8344297.057684797, + 1.008223279125607E7 + ], + "scorePercentiles" : { + "0.0" : 8886337.555950267, + "50.0" : 9140098.366477784, + "90.0" : 9639563.648362234, + "95.0" : 9639563.648362234, + "99.0" : 9639563.648362234, + "99.9" : 9639563.648362234, + "99.99" : 9639563.648362234, + "99.999" : 9639563.648362234, + "99.9999" : 9639563.648362234, + "100.0" : 9639563.648362234 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 9128992.959854014, + 8937190.236818587, + 8886337.555950267 + ], + [ + 9639563.648362234, + 9536301.37273594, + 9151203.773101555 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + From 6c9d2679ed3e89e4558ecf6d9db2ec157c89da38 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Sun, 28 Sep 2025 21:39:13 +1000 Subject: [PATCH 40/40] performance improvements --- .../ExhaustedDataLoaderDispatchStrategy.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java index f0de5554e..f237622ec 100644 --- a/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java +++ b/src/main/java/graphql/execution/instrumentation/dataloader/ExhaustedDataLoaderDispatchStrategy.java @@ -97,16 +97,6 @@ public int decrementObjectRunningCount() { } } - public int dataLoaderToDispatch() { - while (true) { - int oldState = getState(); - int newState = setDataLoaderToDispatch(oldState, true); - if (tryUpdateState(oldState, newState)) { - return newState; - } - } - } - // for debugging public static String printState(int state) { return "objectRunningCount: " + getObjectRunningCount(state) + @@ -221,16 +211,26 @@ private CallStack getCallStack(@Nullable AlternativeCallContext alternativeCallC private void decrementObjectRunningAndMaybeDispatch(CallStack callStack) { int newState = callStack.decrementObjectRunningCount(); - // this means we have not fetching running and we can execute - if (CallStack.getObjectRunningCount(newState) == 0 && !CallStack.getCurrentlyDispatching(newState)) { + if (CallStack.getObjectRunningCount(newState) == 0 && CallStack.getDataLoaderToDispatch(newState) && !CallStack.getCurrentlyDispatching(newState)) { dispatchImpl(callStack); } } private void newDataLoaderInvocationMaybeDispatch(CallStack callStack) { - int newState = callStack.dataLoaderToDispatch(); - // this means we are not waiting for some fetching to be finished and we need to dispatch - if (CallStack.getObjectRunningCount(newState) == 0 && !CallStack.getCurrentlyDispatching(newState)) { + int currentState; + while (true) { + int oldState = callStack.getState(); + if (CallStack.getDataLoaderToDispatch(oldState)) { + return; + } + int newState = CallStack.setDataLoaderToDispatch(oldState, true); + if (callStack.tryUpdateState(oldState, newState)) { + currentState = newState; + break; + } + } + + if (CallStack.getObjectRunningCount(currentState) == 0 && !CallStack.getCurrentlyDispatching(currentState)) { dispatchImpl(callStack); } }