VictoriaMetrics/vendor/cloud.google.com/go/storage/option.go
2024-11-29 13:48:50 +01:00

227 lines
7.7 KiB
Go

// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package storage
import (
"os"
"strconv"
"time"
"cloud.google.com/go/storage/experimental"
storageinternal "cloud.google.com/go/storage/internal"
"go.opentelemetry.io/otel/sdk/metric"
"google.golang.org/api/option"
"google.golang.org/api/option/internaloption"
)
const (
dynamicReadReqIncreaseRateEnv = "DYNAMIC_READ_REQ_INCREASE_RATE"
dynamicReadReqInitialTimeoutEnv = "DYNAMIC_READ_REQ_INITIAL_TIMEOUT"
defaultDynamicReadReqIncreaseRate = 15.0
defaultDynamicReqdReqMaxTimeout = 1 * time.Hour
defaultDynamicReadReqMinTimeout = 500 * time.Millisecond
defaultTargetPercentile = 0.99
)
func init() {
// initialize experimental options
storageinternal.WithMetricExporter = withMetricExporter
storageinternal.WithMetricInterval = withMetricInterval
storageinternal.WithReadStallTimeout = withReadStallTimeout
}
// getDynamicReadReqIncreaseRateFromEnv returns the value set in the env variable.
// It returns defaultDynamicReadReqIncreaseRate if env is not set or the set value is invalid.
func getDynamicReadReqIncreaseRateFromEnv() float64 {
increaseRate := os.Getenv(dynamicReadReqIncreaseRateEnv)
if increaseRate == "" {
return defaultDynamicReadReqIncreaseRate
}
val, err := strconv.ParseFloat(increaseRate, 64)
if err != nil {
return defaultDynamicReadReqIncreaseRate
}
return val
}
// getDynamicReadReqInitialTimeoutSecFromEnv returns the value set in the env variable.
// It returns the passed defaultVal if env is not set or the set value is invalid.
func getDynamicReadReqInitialTimeoutSecFromEnv(defaultVal time.Duration) time.Duration {
initialTimeout := os.Getenv(dynamicReadReqInitialTimeoutEnv)
if initialTimeout == "" {
return defaultVal
}
val, err := time.ParseDuration(initialTimeout)
if err != nil {
return defaultVal
}
return val
}
// set through storageClientOptions.
type storageConfig struct {
useJSONforReads bool
readAPIWasSet bool
disableClientMetrics bool
metricExporter *metric.Exporter
metricInterval time.Duration
readStallTimeoutConfig *experimental.ReadStallTimeoutConfig
}
// newStorageConfig generates a new storageConfig with all the given
// storageClientOptions applied.
func newStorageConfig(opts ...option.ClientOption) storageConfig {
var conf storageConfig
for _, opt := range opts {
if storageOpt, ok := opt.(storageClientOption); ok {
storageOpt.ApplyStorageOpt(&conf)
}
}
return conf
}
// A storageClientOption is an option for a Google Storage client.
type storageClientOption interface {
option.ClientOption
ApplyStorageOpt(*storageConfig)
}
// WithJSONReads is an option that may be passed to [NewClient].
// It sets the client to use the Cloud Storage JSON API for object
// reads. Currently, the default API used for reads is XML, but JSON will
// become the default in a future release.
//
// Setting this option is required to use the GenerationNotMatch condition. We
// also recommend using JSON reads to ensure consistency with other client
// operations (all of which use JSON by default).
//
// Note that when this option is set, reads will return a zero date for
// [ReaderObjectAttrs].LastModified and may return a different value for
// [ReaderObjectAttrs].CacheControl.
func WithJSONReads() option.ClientOption {
return &withReadAPI{useJSON: true}
}
// WithXMLReads is an option that may be passed to [NewClient].
// It sets the client to use the Cloud Storage XML API for object reads.
//
// This is the current default, but the default will switch to JSON in a future
// release.
func WithXMLReads() option.ClientOption {
return &withReadAPI{useJSON: false}
}
type withReadAPI struct {
internaloption.EmbeddableAdapter
useJSON bool
}
func (w *withReadAPI) ApplyStorageOpt(c *storageConfig) {
c.useJSONforReads = w.useJSON
c.readAPIWasSet = true
}
type withDisabledClientMetrics struct {
internaloption.EmbeddableAdapter
disabledClientMetrics bool
}
// WithDisabledClientMetrics is an option that may be passed to [NewClient].
// gRPC metrics are enabled by default in the GCS client and will export the
// gRPC telemetry discussed in [gRFC/66] and [gRFC/78] to
// [Google Cloud Monitoring]. The option is used to disable metrics.
// Google Cloud Support can use this information to more quickly diagnose
// problems related to GCS and gRPC.
// Sending this data does not incur any billing charges, and requires minimal
// CPU (a single RPC every few minutes) or memory (a few KiB to batch the
// telemetry).
//
// The default is to enable client metrics. To opt-out of metrics collected use
// this option.
//
// [gRFC/66]: https://github.com/grpc/proposal/blob/master/A66-otel-stats.md
// [gRFC/78]: https://github.com/grpc/proposal/blob/master/A78-grpc-metrics-wrr-pf-xds.md
// [Google Cloud Monitoring]: https://cloud.google.com/monitoring/docs
func WithDisabledClientMetrics() option.ClientOption {
return &withDisabledClientMetrics{disabledClientMetrics: true}
}
func (w *withDisabledClientMetrics) ApplyStorageOpt(c *storageConfig) {
c.disableClientMetrics = w.disabledClientMetrics
}
type withMeterOptions struct {
internaloption.EmbeddableAdapter
// set sampling interval
interval time.Duration
}
func withMetricInterval(interval time.Duration) option.ClientOption {
return &withMeterOptions{interval: interval}
}
func (w *withMeterOptions) ApplyStorageOpt(c *storageConfig) {
c.metricInterval = w.interval
}
type withMetricExporterConfig struct {
internaloption.EmbeddableAdapter
// exporter override
metricExporter *metric.Exporter
}
func withMetricExporter(ex *metric.Exporter) option.ClientOption {
return &withMetricExporterConfig{metricExporter: ex}
}
func (w *withMetricExporterConfig) ApplyStorageOpt(c *storageConfig) {
c.metricExporter = w.metricExporter
}
// WithReadStallTimeout is an option that may be passed to [NewClient].
// It enables the client to retry the stalled read request, happens as part of
// storage.Reader creation. As the name suggest, timeout is adjusted dynamically
// based on past observed read-req latencies.
//
// This is only supported for the read operation and that too for http(XML) client.
// Grpc read-operation will be supported soon.
func withReadStallTimeout(rstc *experimental.ReadStallTimeoutConfig) option.ClientOption {
// TODO (raj-prince): To keep separate dynamicDelay instance for different BucketHandle.
// Currently, dynamicTimeout is kept at the client and hence shared across all the
// BucketHandle, which is not the ideal state. As latency depends on location of VM
// and Bucket, and read latency of different buckets may lie in different range.
// Hence having a separate dynamicTimeout instance at BucketHandle level will
// be better
if rstc.Min == time.Duration(0) {
rstc.Min = defaultDynamicReadReqMinTimeout
}
if rstc.TargetPercentile == 0 {
rstc.TargetPercentile = defaultTargetPercentile
}
return &withReadStallTimeoutConfig{
readStallTimeoutConfig: rstc,
}
}
type withReadStallTimeoutConfig struct {
internaloption.EmbeddableAdapter
readStallTimeoutConfig *experimental.ReadStallTimeoutConfig
}
func (wrstc *withReadStallTimeoutConfig) ApplyStorageOpt(config *storageConfig) {
config.readStallTimeoutConfig = wrstc.readStallTimeoutConfig
}