| // Copyright (c) 2017 Uber Technologies, Inc. |
| // |
| // 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 rpcmetrics |
| |
| import "sync" |
| |
| // normalizedEndpoints is a cache for endpointName -> safeName mappings. |
| type normalizedEndpoints struct { |
| names map[string]string |
| maxSize int |
| defaultName string |
| normalizer NameNormalizer |
| mux sync.RWMutex |
| } |
| |
| func newNormalizedEndpoints(maxSize int, normalizer NameNormalizer) *normalizedEndpoints { |
| return &normalizedEndpoints{ |
| maxSize: maxSize, |
| normalizer: normalizer, |
| names: make(map[string]string, maxSize), |
| } |
| } |
| |
| // normalize looks up the name in the cache, if not found it uses normalizer |
| // to convert the name to a safe name. If called with more than maxSize unique |
| // names it returns "" for all other names beyond those already cached. |
| func (n *normalizedEndpoints) normalize(name string) string { |
| n.mux.RLock() |
| norm, ok := n.names[name] |
| l := len(n.names) |
| n.mux.RUnlock() |
| if ok { |
| return norm |
| } |
| if l >= n.maxSize { |
| return "" |
| } |
| return n.normalizeWithLock(name) |
| } |
| |
| func (n *normalizedEndpoints) normalizeWithLock(name string) string { |
| norm := n.normalizer.Normalize(name) |
| n.mux.Lock() |
| defer n.mux.Unlock() |
| // cache may have grown while we were not holding the lock |
| if len(n.names) >= n.maxSize { |
| return "" |
| } |
| n.names[name] = norm |
| return norm |
| } |