in router/core/graph_server.go [365:481]
func (s *graphMux) buildOperationCaches(srv *graphServer) (computeSha256 bool, err error) {
// We create a new execution plan cache for each operation planner which is coupled to
// the specific engine configuration. This is necessary because otherwise we would return invalid plans.
//
// when an execution plan was generated, which can be quite expensive, we want to cache it
// this means that we can hash the input and cache the generated plan
// the next time we get the same input, we can just return the cached plan
// the engine is smart enough to first do normalization and then hash the input
// this means that we can cache the normalized input and don't have to worry about
// different inputs that would generate the same execution plan
if srv.engineExecutionConfiguration.ExecutionPlanCacheSize > 0 {
planCacheConfig := &ristretto.Config[uint64, *planWithMetaData]{
Metrics: srv.metricConfig.OpenTelemetry.GraphqlCache || srv.metricConfig.Prometheus.GraphqlCache,
MaxCost: srv.engineExecutionConfiguration.ExecutionPlanCacheSize,
NumCounters: srv.engineExecutionConfiguration.ExecutionPlanCacheSize * 10,
IgnoreInternalCost: true,
BufferItems: 64,
}
s.planCache, err = ristretto.NewCache[uint64, *planWithMetaData](planCacheConfig)
if err != nil {
return computeSha256, fmt.Errorf("failed to create planner cache: %w", err)
}
}
if srv.engineExecutionConfiguration.EnablePersistedOperationsCache || srv.automaticPersistedQueriesConfig.Enabled {
cacheSize := int64(1024)
persistedOperationCacheConfig := &ristretto.Config[uint64, NormalizationCacheEntry]{
MaxCost: cacheSize,
NumCounters: cacheSize * 10,
IgnoreInternalCost: true,
BufferItems: 64,
Metrics: true,
}
s.persistedOperationCache, _ = ristretto.NewCache[uint64, NormalizationCacheEntry](persistedOperationCacheConfig)
}
if srv.engineExecutionConfiguration.EnableNormalizationCache && srv.engineExecutionConfiguration.NormalizationCacheSize > 0 {
normalizationCacheConfig := &ristretto.Config[uint64, NormalizationCacheEntry]{
Metrics: srv.metricConfig.OpenTelemetry.GraphqlCache || srv.metricConfig.Prometheus.GraphqlCache,
MaxCost: srv.engineExecutionConfiguration.NormalizationCacheSize,
NumCounters: srv.engineExecutionConfiguration.NormalizationCacheSize * 10,
IgnoreInternalCost: true,
BufferItems: 64,
}
s.normalizationCache, err = ristretto.NewCache[uint64, NormalizationCacheEntry](normalizationCacheConfig)
if err != nil {
return computeSha256, fmt.Errorf("failed to create normalization cache: %w", err)
}
}
if srv.engineExecutionConfiguration.EnableValidationCache && srv.engineExecutionConfiguration.ValidationCacheSize > 0 {
validationCacheConfig := &ristretto.Config[uint64, bool]{
Metrics: srv.metricConfig.OpenTelemetry.GraphqlCache || srv.metricConfig.Prometheus.GraphqlCache,
MaxCost: srv.engineExecutionConfiguration.ValidationCacheSize,
NumCounters: srv.engineExecutionConfiguration.ValidationCacheSize * 10,
IgnoreInternalCost: true,
BufferItems: 64,
}
s.validationCache, err = ristretto.NewCache[uint64, bool](validationCacheConfig)
if err != nil {
return computeSha256, fmt.Errorf("failed to create validation cache: %w", err)
}
}
if srv.securityConfiguration.ComplexityCalculationCache != nil && srv.securityConfiguration.ComplexityCalculationCache.Enabled && srv.securityConfiguration.ComplexityCalculationCache.CacheSize > 0 {
complexityCalculationCacheConfig := &ristretto.Config[uint64, ComplexityCacheEntry]{
Metrics: srv.metricConfig.OpenTelemetry.GraphqlCache || srv.metricConfig.Prometheus.GraphqlCache,
MaxCost: srv.securityConfiguration.ComplexityCalculationCache.CacheSize,
NumCounters: srv.securityConfiguration.ComplexityCalculationCache.CacheSize * 10,
IgnoreInternalCost: true,
BufferItems: 64,
}
s.complexityCalculationCache, err = ristretto.NewCache[uint64, ComplexityCacheEntry](complexityCalculationCacheConfig)
if err != nil {
return computeSha256, fmt.Errorf("failed to create query depth cache: %w", err)
}
}
// Currently, we only support custom attributes from the context for OTLP metrics
if len(srv.metricConfig.Attributes) > 0 {
for _, customAttribute := range srv.metricConfig.Attributes {
if customAttribute.ValueFrom != nil && customAttribute.ValueFrom.ContextField == ContextFieldOperationSha256 {
computeSha256 = true
break
}
}
} else if srv.accessLogsConfig != nil {
for _, customAttribute := range append(srv.accessLogsConfig.Attributes, srv.accessLogsConfig.SubgraphAttributes...) {
if customAttribute.ValueFrom != nil && customAttribute.ValueFrom.ContextField == ContextFieldOperationSha256 {
computeSha256 = true
break
}
}
} else if srv.persistedOperationsConfig.Safelist.Enabled || srv.persistedOperationsConfig.LogUnknown {
// In these case, we'll want to compute the sha256 for every operation, in order to check that the operation
// is present in the Persisted Operation cache
computeSha256 = true
}
if computeSha256 {
operationHashCacheConfig := &ristretto.Config[uint64, string]{
MaxCost: srv.engineExecutionConfiguration.OperationHashCacheSize,
NumCounters: srv.engineExecutionConfiguration.OperationHashCacheSize * 10,
IgnoreInternalCost: true,
BufferItems: 64,
Metrics: srv.metricConfig.OpenTelemetry.GraphqlCache || srv.metricConfig.Prometheus.GraphqlCache,
}
s.operationHashCache, err = ristretto.NewCache[uint64, string](operationHashCacheConfig)
if err != nil {
return computeSha256, fmt.Errorf("failed to create operation hash cache: %w", err)
}
}
return computeSha256, nil
}