github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/metric/store.go (about)

     1  /*
     2  Copyright 2022 The Katalyst Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package metric
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"sync"
    23  	"time"
    24  )
    25  
    26  // MetricData represents the standard response data for metric getter functions
    27  type MetricData struct {
    28  	Value float64
    29  
    30  	// Time may have different meanings in different scenarios
    31  	// - for single metric: it represents the exact collecting time
    32  	// - for aggregated metric: it represents the newest time among all metric items
    33  	Time *time.Time
    34  }
    35  
    36  // MetricStore stores those metric data. Including:
    37  // 1. raw data collected from agent.MetricsFetcher.
    38  // 2. data calculated based on raw data.
    39  type MetricStore struct {
    40  	mutex sync.RWMutex
    41  
    42  	nodeMetricMap             map[string]MetricData                                  // map[metricName]data
    43  	numaMetricMap             map[int]map[string]MetricData                          // map[numaID]map[metricName]data
    44  	deviceMetricMap           map[string]map[string]MetricData                       // map[deviceName]map[metricName]data
    45  	networkMetricMap          map[string]map[string]MetricData                       // map[networkName]map[metricName]data
    46  	cpuMetricMap              map[int]map[string]MetricData                          // map[cpuID]map[metricName]data
    47  	podContainerMetricMap     map[string]map[string]map[string]MetricData            // map[podUID]map[containerName]map[metricName]data
    48  	podContainerNumaMetricMap map[string]map[string]map[string]map[string]MetricData // map[podUID]map[containerName]map[numaNode]map[metricName]data
    49  	podVolumeMetricMap        map[string]map[string]map[string]MetricData            // map[podUID]map[volumeName]map[metricName]data
    50  	cgroupMetricMap           map[string]map[string]MetricData                       // map[cgroupPath]map[metricName]value
    51  	cgroupNumaMetricMap       map[string]map[int]map[string]MetricData               // map[cgroupPath]map[numaNode]map[metricName]value
    52  }
    53  
    54  func NewMetricStore() *MetricStore {
    55  	return &MetricStore{
    56  		nodeMetricMap:             make(map[string]MetricData),
    57  		numaMetricMap:             make(map[int]map[string]MetricData),
    58  		deviceMetricMap:           make(map[string]map[string]MetricData),
    59  		networkMetricMap:          make(map[string]map[string]MetricData),
    60  		cpuMetricMap:              make(map[int]map[string]MetricData),
    61  		podContainerMetricMap:     make(map[string]map[string]map[string]MetricData),
    62  		podContainerNumaMetricMap: make(map[string]map[string]map[string]map[string]MetricData),
    63  		podVolumeMetricMap:        make(map[string]map[string]map[string]MetricData),
    64  		cgroupMetricMap:           make(map[string]map[string]MetricData),
    65  		cgroupNumaMetricMap:       make(map[string]map[int]map[string]MetricData),
    66  	}
    67  }
    68  
    69  func (c *MetricStore) SetNodeMetric(metricName string, data MetricData) {
    70  	c.mutex.Lock()
    71  	defer c.mutex.Unlock()
    72  	c.nodeMetricMap[metricName] = data
    73  }
    74  
    75  func (c *MetricStore) SetNumaMetric(numaID int, metricName string, data MetricData) {
    76  	c.mutex.Lock()
    77  	defer c.mutex.Unlock()
    78  	if _, ok := c.numaMetricMap[numaID]; !ok {
    79  		c.numaMetricMap[numaID] = make(map[string]MetricData)
    80  	}
    81  	c.numaMetricMap[numaID][metricName] = data
    82  }
    83  
    84  func (c *MetricStore) SetDeviceMetric(deviceName string, metricName string, data MetricData) {
    85  	c.mutex.Lock()
    86  	defer c.mutex.Unlock()
    87  	if _, ok := c.deviceMetricMap[deviceName]; !ok {
    88  		c.deviceMetricMap[deviceName] = make(map[string]MetricData)
    89  	}
    90  	c.deviceMetricMap[deviceName][metricName] = data
    91  }
    92  
    93  func (c *MetricStore) SetNetworkMetric(networkName string, metricName string, data MetricData) {
    94  	c.mutex.Lock()
    95  	defer c.mutex.Unlock()
    96  	if _, ok := c.networkMetricMap[networkName]; !ok {
    97  		c.networkMetricMap[networkName] = make(map[string]MetricData)
    98  	}
    99  	c.networkMetricMap[networkName][metricName] = data
   100  }
   101  
   102  func (c *MetricStore) SetCPUMetric(cpuID int, metricName string, data MetricData) {
   103  	c.mutex.Lock()
   104  	defer c.mutex.Unlock()
   105  	if _, ok := c.cpuMetricMap[cpuID]; !ok {
   106  		c.cpuMetricMap[cpuID] = make(map[string]MetricData)
   107  	}
   108  	c.cpuMetricMap[cpuID][metricName] = data
   109  }
   110  
   111  func (c *MetricStore) SetContainerMetric(podUID, containerName, metricName string, data MetricData) {
   112  	c.mutex.Lock()
   113  	defer c.mutex.Unlock()
   114  	if _, ok := c.podContainerMetricMap[podUID]; !ok {
   115  		c.podContainerMetricMap[podUID] = make(map[string]map[string]MetricData)
   116  	}
   117  
   118  	if _, ok := c.podContainerMetricMap[podUID][containerName]; !ok {
   119  		c.podContainerMetricMap[podUID][containerName] = make(map[string]MetricData)
   120  	}
   121  	c.podContainerMetricMap[podUID][containerName][metricName] = data
   122  }
   123  
   124  func (c *MetricStore) SetContainerNumaMetric(podUID, containerName, numaNode, metricName string, data MetricData) {
   125  	c.mutex.Lock()
   126  	defer c.mutex.Unlock()
   127  
   128  	if _, ok := c.podContainerNumaMetricMap[podUID]; !ok {
   129  		c.podContainerNumaMetricMap[podUID] = make(map[string]map[string]map[string]MetricData)
   130  	}
   131  
   132  	if _, ok := c.podContainerNumaMetricMap[podUID][containerName]; !ok {
   133  		c.podContainerNumaMetricMap[podUID][containerName] = make(map[string]map[string]MetricData)
   134  	}
   135  
   136  	if _, ok := c.podContainerNumaMetricMap[podUID][containerName][numaNode]; !ok {
   137  		c.podContainerNumaMetricMap[podUID][containerName][numaNode] = make(map[string]MetricData)
   138  	}
   139  	c.podContainerNumaMetricMap[podUID][containerName][numaNode][metricName] = data
   140  }
   141  
   142  func (c *MetricStore) SetPodVolumeMetric(podUID, volumeName, metricName string, data MetricData) {
   143  	c.mutex.Lock()
   144  	defer c.mutex.Unlock()
   145  
   146  	if _, ok := c.podVolumeMetricMap[podUID]; !ok {
   147  		c.podVolumeMetricMap[podUID] = make(map[string]map[string]MetricData)
   148  	}
   149  
   150  	if _, ok := c.podVolumeMetricMap[podUID][volumeName]; !ok {
   151  		c.podVolumeMetricMap[podUID][volumeName] = make(map[string]MetricData)
   152  	}
   153  
   154  	c.podVolumeMetricMap[podUID][volumeName][metricName] = data
   155  }
   156  
   157  func (c *MetricStore) GetNodeMetric(metricName string) (MetricData, error) {
   158  	c.mutex.RLock()
   159  	defer c.mutex.RUnlock()
   160  	if data, ok := c.nodeMetricMap[metricName]; ok {
   161  		return data, nil
   162  	} else {
   163  		return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v", metricName))
   164  	}
   165  }
   166  
   167  func (c *MetricStore) GetNumaMetric(numaID int, metricName string) (MetricData, error) {
   168  	c.mutex.RLock()
   169  	defer c.mutex.RUnlock()
   170  	if c.numaMetricMap[numaID] != nil {
   171  		if data, ok := c.numaMetricMap[numaID][metricName]; ok {
   172  			return data, nil
   173  		} else {
   174  			return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v, numaID=%v", metricName, numaID))
   175  		}
   176  	}
   177  	return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] empty map, metric=%v, numaID=%v", metricName, numaID))
   178  }
   179  
   180  func (c *MetricStore) GetDeviceMetric(deviceName string, metricName string) (MetricData, error) {
   181  	c.mutex.RLock()
   182  	defer c.mutex.RUnlock()
   183  	if c.deviceMetricMap[deviceName] != nil {
   184  		if data, ok := c.deviceMetricMap[deviceName][metricName]; ok {
   185  			return data, nil
   186  		} else {
   187  			return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v, deviceName=%v", metricName, deviceName))
   188  		}
   189  	}
   190  	return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] empty map, metric=%v, deviceName=%v", metricName, deviceName))
   191  }
   192  
   193  func (c *MetricStore) GetNetworkMetric(networkName string, metricName string) (MetricData, error) {
   194  	c.mutex.RLock()
   195  	defer c.mutex.RUnlock()
   196  	if c.networkMetricMap[networkName] != nil {
   197  		if data, ok := c.networkMetricMap[networkName][metricName]; ok {
   198  			return data, nil
   199  		} else {
   200  			return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v, networkName=%v", metricName, networkName))
   201  		}
   202  	}
   203  	return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] empty map, metric=%v, networkName=%v", metricName, networkName))
   204  }
   205  
   206  func (c *MetricStore) GetCPUMetric(coreID int, metricName string) (MetricData, error) {
   207  	c.mutex.RLock()
   208  	defer c.mutex.RUnlock()
   209  	if c.cpuMetricMap[coreID] != nil {
   210  		if data, ok := c.cpuMetricMap[coreID][metricName]; ok {
   211  			return data, nil
   212  		} else {
   213  			return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v, coreID=%v", metricName, coreID))
   214  		}
   215  	}
   216  	return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] empty map, metric=%v, coreID=%v", metricName, coreID))
   217  }
   218  
   219  func (c *MetricStore) GetContainerMetric(podUID, containerName, metricName string) (MetricData, error) {
   220  	c.mutex.RLock()
   221  	defer c.mutex.RUnlock()
   222  	if c.podContainerMetricMap[podUID] != nil {
   223  		if c.podContainerMetricMap[podUID][containerName] != nil {
   224  			if data, ok := c.podContainerMetricMap[podUID][containerName][metricName]; ok {
   225  				return data, nil
   226  			} else {
   227  				return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v, podUID=%v, containerName=%v", metricName, podUID, containerName))
   228  			}
   229  		}
   230  	}
   231  	return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] empty map, metric=%v, podUID=%v, containerName=%v", metricName, podUID, containerName))
   232  }
   233  
   234  func (c *MetricStore) GetContainerNumaMetric(podUID, containerName, numaNode, metricName string) (MetricData, error) {
   235  	c.mutex.RLock()
   236  	defer c.mutex.RUnlock()
   237  	if c.podContainerNumaMetricMap[podUID] != nil {
   238  		if c.podContainerNumaMetricMap[podUID][containerName] != nil {
   239  			if c.podContainerNumaMetricMap[podUID][containerName][numaNode] != nil {
   240  				if data, ok := c.podContainerNumaMetricMap[podUID][containerName][numaNode][metricName]; ok {
   241  					return data, nil
   242  				} else {
   243  					return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v, podUID=%v, containerName=%v, numaNode=%v", metricName, podUID, containerName, numaNode))
   244  				}
   245  			}
   246  		}
   247  	}
   248  	return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] empty map, metric=%v, podUID=%v, containerName=%v, numaNode=%v", metricName, podUID, containerName, numaNode))
   249  }
   250  
   251  func (c *MetricStore) GetPodVolumeMetric(podUID, volumeName, metricName string) (MetricData, error) {
   252  	c.mutex.RLock()
   253  	defer c.mutex.RUnlock()
   254  
   255  	if c.podVolumeMetricMap[podUID] != nil {
   256  		if c.podVolumeMetricMap[podUID][volumeName] != nil {
   257  			if data, ok := c.podVolumeMetricMap[podUID][volumeName][metricName]; ok {
   258  				return data, nil
   259  			} else {
   260  				return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] load value failed, metric=%v, podUID=%v, volumeName=%v", metricName, podUID, volumeName))
   261  			}
   262  		}
   263  	}
   264  	return MetricData{}, errors.New(fmt.Sprintf("[MetricStore] empty map, metric=%v, podUID=%v, volumeName=%v", metricName, podUID, volumeName))
   265  }
   266  
   267  func (c *MetricStore) GCPodsMetric(livingPodUIDSet map[string]bool) {
   268  	c.mutex.Lock()
   269  	defer c.mutex.Unlock()
   270  	for podUID := range c.podContainerMetricMap {
   271  		if _, ok := livingPodUIDSet[podUID]; !ok {
   272  			delete(c.podContainerMetricMap, podUID)
   273  			delete(c.podContainerNumaMetricMap, podUID)
   274  		}
   275  	}
   276  }
   277  
   278  func (c *MetricStore) SetCgroupMetric(cgroupPath, metricName string, data MetricData) {
   279  	c.mutex.Lock()
   280  	defer c.mutex.Unlock()
   281  	metrics, ok := c.cgroupMetricMap[cgroupPath]
   282  	if !ok {
   283  		metrics = make(map[string]MetricData)
   284  		c.cgroupMetricMap[cgroupPath] = metrics
   285  	}
   286  	metrics[metricName] = data
   287  }
   288  
   289  func (c *MetricStore) GetCgroupMetric(cgroupPath, metricName string) (MetricData, error) {
   290  	c.mutex.RLock()
   291  	defer c.mutex.RUnlock()
   292  
   293  	metrics, ok := c.cgroupMetricMap[cgroupPath]
   294  	if !ok {
   295  		return MetricData{}, fmt.Errorf("[MetricStore] load value for %v failed", cgroupPath)
   296  	}
   297  	data, ok := metrics[metricName]
   298  	if !ok {
   299  		return MetricData{}, fmt.Errorf("[MetricStore] load value for %v failed", metricName)
   300  	}
   301  	return data, nil
   302  }
   303  
   304  func (c *MetricStore) SetCgroupNumaMetric(cgroupPath string, numaNode int, metricName string, data MetricData) {
   305  	c.mutex.Lock()
   306  	defer c.mutex.Unlock()
   307  
   308  	numaMetrics, ok := c.cgroupNumaMetricMap[cgroupPath]
   309  	if !ok {
   310  		numaMetrics = make(map[int]map[string]MetricData)
   311  		c.cgroupNumaMetricMap[cgroupPath] = numaMetrics
   312  	}
   313  	metrics, ok := numaMetrics[numaNode]
   314  	if !ok {
   315  		metrics = make(map[string]MetricData)
   316  		numaMetrics[numaNode] = metrics
   317  	}
   318  	metrics[metricName] = data
   319  }
   320  
   321  func (c *MetricStore) GetCgroupNumaMetric(cgroupPath string, numaNode int, metricName string) (MetricData, error) {
   322  	c.mutex.RLock()
   323  	defer c.mutex.RUnlock()
   324  	numaMetrics, ok := c.cgroupNumaMetricMap[cgroupPath]
   325  	if !ok {
   326  		return MetricData{}, fmt.Errorf("[MetricStore] load value for %v failed", cgroupPath)
   327  	}
   328  	metrics, ok := numaMetrics[numaNode]
   329  	if !ok {
   330  		return MetricData{}, fmt.Errorf("[MetricStore] load value for %v failed", numaNode)
   331  	}
   332  	metric, ok := metrics[metricName]
   333  	if !ok {
   334  		return MetricData{}, fmt.Errorf("[MetricStore] load value for %v failed", metricName)
   335  	}
   336  	return metric, nil
   337  }