blob: 8549ab609ad2e2fcc2e394a17bc6c7ecb184d793 [file] [edit]
/*
Copyright 2024 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 bigtable
import (
"errors"
"strconv"
"strings"
"time"
btpb "cloud.google.com/go/bigtable/apiv2/bigtablepb"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
)
const (
defaultCluster = "<unspecified>"
defaultZone = "global"
defaultTable = "<unspecified>"
)
// get GFE latency in ms from response metadata
func extractServerLatency(headerMD metadata.MD, trailerMD metadata.MD) (float64, error) {
serverTimingStr := ""
// Check whether server latency available in response header metadata
if headerMD != nil {
headerMDValues := headerMD.Get(serverTimingMDKey)
if len(headerMDValues) != 0 {
serverTimingStr = headerMDValues[0]
}
}
if len(serverTimingStr) == 0 {
// Check whether server latency available in response trailer metadata
if trailerMD != nil {
trailerMDValues := trailerMD.Get(serverTimingMDKey)
if len(trailerMDValues) != 0 {
serverTimingStr = trailerMDValues[0]
}
}
}
serverLatencyMillisStr := strings.TrimPrefix(serverTimingStr, serverTimingValPrefix)
serverLatencyMillis, err := strconv.ParseFloat(strings.TrimSpace(serverLatencyMillisStr), 64)
if !strings.HasPrefix(serverTimingStr, serverTimingValPrefix) || err != nil {
return serverLatencyMillis, err
}
return serverLatencyMillis, nil
}
// Obtain cluster and zone from response metadata
// Check both headers and trailers because in different environments the metadata could
// be returned in headers or trailers
func extractLocation(headerMD metadata.MD, trailerMD metadata.MD) (string, string, error) {
var locationMetadata []string
// Check whether location metadata available in response header metadata
if headerMD != nil {
locationMetadata = headerMD.Get(locationMDKey)
}
if locationMetadata == nil {
// Check whether location metadata available in response trailer metadata
// if none found in response header metadata
if trailerMD != nil {
locationMetadata = trailerMD.Get(locationMDKey)
}
}
if len(locationMetadata) < 1 {
return defaultCluster, defaultZone, errors.New("failed to get location metadata")
}
// Unmarshal binary location metadata
responseParams := &btpb.ResponseParams{}
err := proto.Unmarshal([]byte(locationMetadata[0]), responseParams)
if err != nil {
return defaultCluster, defaultZone, err
}
return responseParams.GetClusterId(), responseParams.GetZoneId(), nil
}
func convertToMs(d time.Duration) float64 {
return float64(d.Nanoseconds()) / 1000000
}