@@ -137,8 +137,9 @@ type result struct {
137137 loaderHookContext context.Context
138138
139139 httpResponseContext * httpclient.ResponseContext
140- out []byte
141- singleFlightStats * singleFlightStats
140+ // out is the subgraph response body
141+ out []byte
142+ singleFlightStats * singleFlightStats
142143}
143144
144145func (r * result ) init (postProcessing PostProcessingConfiguration , info * FetchInfo ) {
@@ -182,6 +183,14 @@ type Loader struct {
182183
183184 taintedObjs taintedObjects
184185
186+ // jsonArena is the arena to allocation json, supplied by the Resolver
187+ // Disclaimer: this arena is NOT thread safe!
188+ // Only use from main goroutine
189+ // Don't Reset or Release, the Resolver handles this
190+ // Disclaimer: When parsing json into the arena, the underlying bytes must also be allocated on the arena!
191+ // This is very important to "tie" their lifecycles together
192+ // If you're not doing this, you will see segfaults
193+ // Example of correct usage in func "mergeResult"
185194 jsonArena arena.Arena
186195 sf * SingleFlight
187196}
@@ -773,9 +782,11 @@ func (l *Loader) mergeErrors(res *result, fetchItem *FetchItem, value *astjson.V
773782 return err
774783 }
775784 }
776-
777- // If the error propagation mode is pass-through, we append the errors to the root array
785+ // for efficiency purposes, resolvable.errors is not initialized
786+ // don't change this, it's measurable
787+ // downside: we have to verify it's initialized before appending to it
778788 l .resolvable .ensureErrorsInitialized ()
789+ // If the error propagation mode is pass-through, we append the errors to the root array
779790 l .resolvable .errors .AppendArrayItems (value )
780791 return nil
781792 }
@@ -811,7 +822,9 @@ func (l *Loader) mergeErrors(res *result, fetchItem *FetchItem, value *astjson.V
811822 if err := l .addApolloRouterCompatibilityError (res ); err != nil {
812823 return err
813824 }
814-
825+ // for efficiency purposes, resolvable.errors is not initialized
826+ // don't change this, it's measurable
827+ // downside: we have to verify it's initialized before appending to it
815828 l .resolvable .ensureErrorsInitialized ()
816829 astjson .AppendToArray (l .resolvable .errors , errorObject )
817830
@@ -1066,7 +1079,9 @@ func (l *Loader) addApolloRouterCompatibilityError(res *result) error {
10661079 if err != nil {
10671080 return err
10681081 }
1069-
1082+ // for efficiency purposes, resolvable.errors is not initialized
1083+ // don't change this, it's measurable
1084+ // downside: we have to verify it's initialized before appending to it
10701085 l .resolvable .ensureErrorsInitialized ()
10711086 astjson .AppendToArray (l .resolvable .errors , apolloRouterStatusError )
10721087
@@ -1081,6 +1096,9 @@ func (l *Loader) renderErrorsFailedDeps(fetchItem *FetchItem, res *result) error
10811096 return err
10821097 }
10831098 l .setSubgraphStatusCode ([]* astjson.Value {errorObject }, res .statusCode )
1099+ // for efficiency purposes, resolvable.errors is not initialized
1100+ // don't change this, it's measurable
1101+ // downside: we have to verify it's initialized before appending to it
10841102 l .resolvable .ensureErrorsInitialized ()
10851103 astjson .AppendToArray (l .resolvable .errors , errorObject )
10861104 return nil
@@ -1093,6 +1111,9 @@ func (l *Loader) renderErrorsFailedToFetch(fetchItem *FetchItem, res *result, re
10931111 return err
10941112 }
10951113 l .setSubgraphStatusCode ([]* astjson.Value {errorObject }, res .statusCode )
1114+ // for efficiency purposes, resolvable.errors is not initialized
1115+ // don't change this, it's measurable
1116+ // downside: we have to verify it's initialized before appending to it
10961117 l .resolvable .ensureErrorsInitialized ()
10971118 astjson .AppendToArray (l .resolvable .errors , errorObject )
10981119 return nil
@@ -1112,6 +1133,9 @@ func (l *Loader) renderErrorsStatusFallback(fetchItem *FetchItem, res *result, s
11121133 }
11131134
11141135 l .setSubgraphStatusCode ([]* astjson.Value {errorObject }, res .statusCode )
1136+ // for efficiency purposes, resolvable.errors is not initialized
1137+ // don't change this, it's measurable
1138+ // downside: we have to verify it's initialized before appending to it
11151139 l .resolvable .ensureErrorsInitialized ()
11161140 astjson .AppendToArray (l .resolvable .errors , errorObject )
11171141 return nil
@@ -1137,6 +1161,9 @@ func (l *Loader) renderAuthorizationRejectedErrors(fetchItem *FetchItem, res *re
11371161 }
11381162 pathPart := l .renderAtPathErrorPart (fetchItem .ResponsePath )
11391163 extensionErrorCode := fmt .Sprintf (`"extensions":{"code":"%s"}` , errorcodes .UnauthorizedFieldOrType )
1164+ // for efficiency purposes, resolvable.errors is not initialized
1165+ // don't change this, it's measurable
1166+ // downside: we have to verify it's initialized before appending to it
11401167 l .resolvable .ensureErrorsInitialized ()
11411168 if res .ds .Name == "" {
11421169 for _ , reason := range res .authorizationRejectedReasons {
@@ -1216,6 +1243,9 @@ func (l *Loader) renderRateLimitRejectedErrors(fetchItem *FetchItem, res *result
12161243 return err
12171244 }
12181245 }
1246+ // for efficiency purposes, resolvable.errors is not initialized
1247+ // don't change this, it's measurable
1248+ // downside: we have to verify it's initialized before appending to it
12191249 l .resolvable .ensureErrorsInitialized ()
12201250 astjson .AppendToArray (l .resolvable .errors , errorObject )
12211251 return nil
@@ -1417,7 +1447,7 @@ func (l *Loader) loadBatchEntityFetch(ctx context.Context, fetchItem *FetchItem,
14171447 }
14181448 }
14191449 }
1420-
1450+ // I tried using arena here but it only worsened the situation
14211451 preparedInput := bytes .NewBuffer (make ([]byte , 0 , 64 ))
14221452 itemInput := bytes .NewBuffer (make ([]byte , 0 , 32 ))
14231453 keyGen := pool .Hash64 .Get ()
@@ -1579,6 +1609,7 @@ const (
15791609 operationTypeContextKey loaderContextKey = "operationType"
15801610)
15811611
1612+ // GetOperationTypeFromContext can be used, e.g. by the transport, to check if the operation is a Mutation
15821613func GetOperationTypeFromContext (ctx context.Context ) ast.OperationType {
15831614 if ctx == nil {
15841615 return ast .OperationTypeQuery
@@ -1638,6 +1669,7 @@ func (l *Loader) loadByContext(ctx context.Context, source DataSource, fetchItem
16381669 return nil
16391670 }
16401671
1672+ // helps the http client to create buffers at the right size
16411673 ctx = httpclient .WithHTTPClientSizeHint (ctx , item .sizeHint )
16421674
16431675 defer l .sf .Finish (sfKey , fetchKey , item )
@@ -1851,6 +1883,9 @@ func (l *Loader) compactJSON(data []byte) ([]byte, error) {
18511883 return nil , err
18521884 }
18531885 out := dst .Bytes ()
1886+ // don't use arena here or segfault
1887+ // it's also not a hot path and not important to optimize
1888+ // arena requires the parsed content to be on the arena as well
18541889 v , err := astjson .ParseBytes (out )
18551890 if err != nil {
18561891 return nil , err
0 commit comments